gettimeofday: avoid per-cpu data in calculation

Because it is difficult to safely update per-cpu data of other cpus in
settimeofday().
This commit is contained in:
NAKAMURA Gou
2015-10-15 15:16:10 +09:00
parent cad72a8562
commit 153a59a6f4
4 changed files with 43 additions and 41 deletions

View File

@ -73,11 +73,6 @@ struct cpu_local_var {
int in_interrupt;
int no_preempt;
int timer_enabled;
unsigned long tv_sec;
unsigned long tv_nsec;
unsigned long last_tsc;
} __attribute__((aligned(64)));

View File

@ -16,6 +16,7 @@
#include <ihk/context.h>
#include <ihk/memconst.h>
#include <rlimit.h>
#include <time.h>
#define NUM_SYSCALLS 255
@ -286,4 +287,9 @@ struct procfs_file {
};
extern void terminate(int, int);
/* kernel/syscall.c */
extern struct timespec origin_ts; /* realtime when tsc=0 */
extern unsigned long clocks_per_sec;
#endif

View File

@ -201,11 +201,21 @@ static void pc_test(void)
}
extern void ihk_mc_get_boot_time(unsigned long *tv_sec, unsigned long *tv_nsec);
extern unsigned long ihk_mc_get_ns_per_tsc(void);
static void time_init(void)
{
ihk_mc_get_boot_time(&cpu_local_var(tv_sec),
&cpu_local_var(tv_nsec));
cpu_local_var(last_tsc) = 0;
unsigned long tv_sec, tv_nsec;
unsigned long ns_per_kclock;
ihk_mc_get_boot_time(&tv_sec, &tv_nsec);
ns_per_kclock = ihk_mc_get_ns_per_tsc();
origin_ts.tv_sec = tv_sec;
origin_ts.tv_nsec = tv_nsec;
clocks_per_sec = (1000L * NS_PER_SEC) / ns_per_kclock;
return;
}
static void rest_init(void)
@ -233,11 +243,9 @@ static void rest_init(void)
int host_ikc_inited = 0;
extern int num_processors;
extern void zero_tsc(void);
extern void update_cpu_local_time(void);
static void post_init(void)
{
int i;
cpu_enable_interrupt();
while (!host_ikc_inited) {
@ -253,16 +261,9 @@ static void post_init(void)
ihk_mc_spinlock_init(&syscall_lock);
}
/* Update time elapsed so far during boot, distribute the current
* date to all cores and zero TSC.
/* Zero TSC.
* All AP cores are wait spinning for ap_start() and they will zero
* their TSC immediatly. */
update_cpu_local_time();
cpu_local_var(last_tsc) = 0;
for (i = 0; i < num_processors; ++i) {
get_cpu_local_var(i)->tv_sec = cpu_local_var(tv_sec);
get_cpu_local_var(i)->tv_nsec = cpu_local_var(tv_nsec);
}
zero_tsc();
ap_start();

View File

@ -94,6 +94,9 @@ static char *syscall_name[] MCKERNEL_UNUSED = {
#undef SYSCALL_DELEGATED
};
struct timespec origin_ts;
unsigned long clocks_per_sec;
void check_signal(unsigned long, void *, int);
void do_signal(long rc, void *regs, struct thread *thread, struct sig_pending *pending, int num);
extern unsigned long do_kill(struct thread *thread, int pid, int tid, int sig, struct siginfo *info, int ptracecont);
@ -4786,30 +4789,26 @@ SYSCALL_DECLARE(get_cpu_id)
return ihk_mc_get_processor_id();
}
void __update_time_from_tsc_delta(unsigned long *tv_sec,
unsigned long *tv_nsec,
unsigned long tsc_delta)
static void calculate_time_from_tsc(struct timespec *ts)
{
unsigned long ns_delta = tsc_delta * ihk_mc_get_ns_per_tsc() / 1000;
unsigned long current_tsc;
time_t sec_delta;
long ns_delta;
*tv_sec += (ns_delta / NS_PER_SEC);
*tv_nsec += (ns_delta % NS_PER_SEC);
if (*tv_nsec > NS_PER_SEC) {
*tv_nsec -= NS_PER_SEC;
++*tv_sec;
current_tsc = rdtsc();
sec_delta = current_tsc / clocks_per_sec;
ns_delta = NS_PER_SEC * (current_tsc % clocks_per_sec)
/ clocks_per_sec;
/* calc. of ns_delta overflows if clocks_per_sec exceeds 18.44 GHz */
ts->tv_sec = origin_ts.tv_sec + sec_delta;
ts->tv_nsec = origin_ts.tv_nsec + ns_delta;
if (ts->tv_nsec >= NS_PER_SEC) {
ts->tv_nsec -= NS_PER_SEC;
++ts->tv_sec;
}
}
void update_cpu_local_time(void)
{
unsigned long tsc = rdtsc();
__update_time_from_tsc_delta(
&cpu_local_var(tv_sec),
&cpu_local_var(tv_nsec),
tsc - cpu_local_var(last_tsc));
cpu_local_var(last_tsc) = tsc;
return;
}
@ -4820,6 +4819,7 @@ SYSCALL_DECLARE(gettimeofday)
struct timezone *tz = (struct timezone *)ihk_mc_syscall_arg1(ctx);
struct timeval atv;
int error;
struct timespec ats;
if (!tv && !tz) {
/* nothing to do */
@ -4828,10 +4828,10 @@ SYSCALL_DECLARE(gettimeofday)
/* Do it locally if supported */
if (!tz && gettime_local_support) {
update_cpu_local_time();
calculate_time_from_tsc(&ats);
atv.tv_sec = cpu_local_var(tv_sec);
atv.tv_usec = cpu_local_var(tv_nsec) / 1000;
atv.tv_sec = ats.tv_sec;
atv.tv_usec = ats.tv_nsec / 1000;
error = copy_to_user(tv, &atv, sizeof(atv));