前言: 有同事讨论到gettimeofday的性能问题。想起来大约四五年前,在linux-2.6.x上的时候,用一种很极端的方法实现过time函数。 下面就简单分析一下几种gettimeofday的实现。当然,实现方法是包括但不限于以下。 分析: 1,int 0x80 在早期阶段,x86上的syscall通过int 0x80实现的。 3,vDSO 有一些syscall,例如time、gettimeofday等,这些只是从kernel中请求数据,kernel的实现上,甚至只是把内核变量copy到用户buf上。 目前x86上可以通过特定的地址访问到gettimeofday,time,getcpu三个syscall。 gettimeofday test 4813905443 cycles, everage 481 cycles VSYSCALL gettimeofday test 12802716166 cycles
(s, e)); gettimeofday(&s, NULL); bzero(b, sizeof(b)); gettimeofday(&e, NULL); printf (“bzero 1m: %d/n”, TIMEDIFF(s, e)); gettimeofday(&s, NULL); bzero(c, sizeof(c)); gettimeofday TIMEDIFF(s, e)); gettimeofday(&s, NULL); memset(c, 0, sizeof(c)); gettimeofday(&e, NULL gettimeofday(&s, NULL); for(int i=0; i<sizeof(b); ++i) b[i]=0; gettimeofday(& b[i]=0; gettimeofday(&e, NULL); printf(“for 1M: %d/n”, TIMEDIFF(s, e)); gettimeofday(&
\n"); unsetenv("TZ"); // test1 { struct tm* result1; gettimeofday(&tv1 ); for (i=0; i<M; ++i) { localtime_r(&now, &result1); } gettimeofday )/1000); } // test2 { struct tm result2; result2.tm_isdst = 0; gettimeofday ); for (i=0; i<M; ++i) { localtime_r(&now, &result2); } gettimeofday /1000); } // test3 { struct tm result3; result3.tm_isdst = -1; gettimeofday
unsetenv("TZ"); // test1 { struct tm* result1; gettimeofday TZ", "Asia/Shanghai", 0); // test3 { struct tm* result3; gettimeofday unsetenv("TZ"); // test1 { struct tm result1; gettimeofday &result4, sizeof(result4_)); localtime_r(&now, &result4_); } gettimeofday ("TZ", "Asia/Shanghai", 0); // test9 { struct tm result9; gettimeofday
(&st, NULL); for(int i = 0; i < kRunTime1; ++i) { mp.insert(make_pair(i, i)); } gettimeofday(&et, NULL (&st, NULL); for(int i = 0; i < kRunTime1; ++i) { unordermp.insert(make_pair(i, i)); } gettimeofday(& (&st, NULL); for(int i = 0; i < kRunTime2; ++i) { mp.insert(make_pair(i, i)); } gettimeofday(&et, NULL (&st, NULL); for(int i = 0; i < kRunTime2; ++i) { unordermp.insert(make_pair(i, i)); } gettimeofday(& (&st, NULL); for(int i = 0; i < kRunTime2; ++i) { unordermp.emplace(make_pair(i, i)); } gettimeofday(
<time.h> int main() { time_t timep; time (&timep); printf(“%s”,ctime(&timep)); return 0; } gettimeofday 调用 通过gettimeofday调用返回来的是一个timeval的结构体,其中tv_sec是秒数,tv_usec是微秒数,通过这两个数共同标志当前时间 #ifndef _STRUCT_TIMEVAL endif /* _STRUCT_TIMEVAL */ 该函数的使用如下 #include <sys/time.h> int main(void) { struct timeval time; gettimeofday Current Time Seconds: %ld,uSeconds:%ld\n", time.tv_sec,time.tv_usec); return 0; } 注意 因为在手机上测试的时候,通过gettimeofday 比如,当前通过gettimeofday获取到的t.tv_sec为1534132538,而t.tv_sec*1000的结果为8292133328。
long tv_usec; /*微秒*/ }; 来看下使用的小栗子: struct timeval start, end; double timeuse; int sum = 0; gettimeofday (&start, NULL); for (int i = 0; i < 10000; i++){ sum += i; } gettimeofday (&end, NULL); timeuse width * height; i++){ m[i] = 1.0; n[i] = 2.0; } struct timeval t1,t2; gettimeofday (&t1,NULL); double timeuse; matMul(m, n, p, w); gettimeofday(&t2,NULL); timeuse = t2 1) / blockSize.x, (height + blockSize.y - 1) / blockSize.y); struct timeval t1,t2; gettimeofday
(); } int main() { string ss, plus, append, sprintf; struct timeval sTime, eTime; gettimeofday ; i<OUT_IN_REPEATE_NUM; i++) { sprintf=""; sprintfTest(sprintf); } gettimeofday i=0; i<OUT_IN_REPEATE_NUM; i++) { append=""; appendTest(append); } gettimeofday AppendTime = (eTime.tv_sec-sTime.tv_sec)*1000000+(eTime.tv_usec-sTime.tv_usec); //exeTime 单位是微秒 gettimeofday for(int i=0; i<OUT_IN_REPEATE_NUM; i++) { ss=""; ssTest(ss); } gettimeofday
0000000000000d40 w DF .text 00000000000001c1 LINUX_2.6 gettimeofday 0000000000000f10 g DF 假如我们能控制RIP,就通过ROP执行内核函数set_memory_rw()来完成对用户态vdso段属性的更改,然后在用户态对vdso段的gettimeofday()函数代码进行覆盖为我们的shellcode ,当root权限的进程调用gettimeofday()函数的时候就完成了对shellcode的执行。 假如我们实现的是任意地址写,就通过内核态的任意地址写来更改vdso段中gettimeofday()函数的内容,改为我们的shellcode,同样当root权限的进程调用gettimeofday()函数的时候就完成了对 3、shellcode的编写 shellcode编写需要注意两个方面:一个是只对uid=0的用户进行反弹,另外一个是对于正常的gettimeofday()函数仍旧需要进行返回,所以我们就开启一个子进程进行
0000000000000d40 w DF .text 00000000000001c1 LINUX_2.6 gettimeofday 0000000000000f10 g DF ()函数代码进行覆盖为我们的shellcode,当root权限的进程调用gettimeofday()函数的时候就完成了对shellcode的执行。 假如我们实现的是任意地址写,就通过内核态的任意地址写来更改vdso段中gettimeofday()函数的内容,改为我们的shellcode,同样当root权限的进程调用gettimeofday()函数的时候就完成了对 为了实现这两个思路,需要解决如下几个问题: 1、如果要使用set_memory_rw()来完成对用户态vdso段属性的更改,需要知道vDSO段的用户态地址 2、如果要通过内核态的任意地址写来更改vdso段中gettimeofday 3、shellcode的编写 shellcode编写需要注意两个方面:一个是只对uid=0的用户进行反弹,另外一个是对于正常的gettimeofday()函数仍旧需要进行返回,所以我们就开启一个子进程进行
,&tz); 9 printf("tv_sec; %d\n",tv1.tv_sec); 10 printf("tv_usec; %d\n",tv1.tv_usec); 11 gettimeofday 97){ 19 printf("%c",char(j)); 20 break; 21 } 22 } 23 system(sleep(0.5)); 24 gettimeofday 26 while(1){ 27 c=getchar(); 28 sum++; 29 if (c==char(j)) 30 break; 31 } 32 gettimeofday (&tv1,&tz); 37 for(i=2;i<=n;i++){ 38 prime1(i); 39 } 40 gettimeofday(&tv2,&tz); 41 (&tv3,&tz); 45 for(i=2;i<=n;i++){ 46 prime2(i); 47 } 48 gettimeofday(&tv4,&tz); 49
高精度时间函数 C 语言中也可以使用函数 gettimeofday() 来获得时间,它的精度可以达到微秒,而且可以获取当地时区的信息。 具体的函数原型及涉及的结构体如下: #include <sys/time.h> int gettimeofday(struct timeval *tv, \ struct struct timeval tv1; struct timeval tv2; gettimeofday(&tv1, NULL); ... ... // 代码片段 gettimeofday(&tv2, 和 gettimeofday 一样,我们可以方便的用它来计算程序某一段语句所消耗的时间。 内容还是比较多的,这里再次简单总结下几类函数使用: time_t 类型时间:从 1970 年距离当前时间的秒数,相关函数 time() mktime() gettimeofday() struct tm
tp.tv_nsec); return result; } else { timeval time; // 调用C库函数,底层调用系统调用 int status = gettimeofday ", 8) = 8 gettimeofday({tv_sec=1638243469, tv_usec=142774}, NULL) = 0 write(1, "\n", 1) = 1 clock_gettime(CLOCK_MONOTONIC, {tv_sec=35737, tv_nsec=962287000}) = 0 gettimeofday ({tv_sec=1638243469, tv_usec=143295}, NULL) = 0 gettimeofday({tv_sec=1638243469, tv_usec=143447}, NULL ) = 0 gettimeofday({tv_sec=1638243469, tv_usec=143568}, NULL) = 0 write(1, "35737962287000", 14)
} } struct timeval start, end; double timeuse; int sum = 0; gettimeofday ( &start, NULL ); transposeCPU( in, out ); gettimeofday( &end, NULL ); timeuse = end.tv_sec in[i * N + j] = i * N + j; struct timeval start, end; double timeuse; gettimeofday ( &start, NULL ); transposeSerial << < 1, 1 >> > (in, out); cudaDeviceSynchronize(); gettimeofday K, N / K ); dim3 threads( K, K ); struct timeval start, end; double timeuse; gettimeofday
在c/c++中有两个用来确定时间的函数:time/gettimeofday 一、time time_t time(time_t *timer); time 函数返回当前时间的时间戳(自 1970 年 1 tm_mday, local_time->tm_hour, local_time->tm_min, local_time->tm_sec); return 0; } 二、gettimeofday int gettimeofday(struct timeval *tv, struct timezone *tz); gettimeofday 函数获取当前时间,并将其存储在 struct timeval int tz_minuteswest; // 格林尼治时间西部时区和当前时区的分钟差值 int tz_dsttime; // DST(夏令时)是否生效 }; gettimeofday
N]; int process[N]; int i = 0; uint64_t usetime; struct timeval start; struct timeval end; gettimeofday pthread_create(&id[i],NULL,test_func,&process[i]); } for(i=0;i<N;++i) { pthread_join(id[i],NULL); } gettimeofday { pthread_t id[20]; int i = 0; uint64_t usetime; struct timeval start; struct timeval end; gettimeofday pthread_create(&id[i],NULL,test_func,NULL); } for(i=0;i<N;++i) { pthread_join(id[i],NULL); } gettimeofday
gettimeofday()的开销 在Linux中,Nginx通过gettimeofday()获取系统当前时间; gettimeofday是C库提供的函数(不是系统调用),它封装了内核里的sys_gettimeofday 然而除了基本的系统调用外,x86_64还提供了sysenter/vsyscall方式获取内核态数据,vsyscall在内存中创建内核态的共享页面,用户态也有权访问,可不经过系统中断和陷入内核获取内核信息; gettimeofday 更新时间缓存 为避免每次都调用OS的gettimeofday,nginx采用时间缓存,每个worker进程都能自行维护; 为控制并发访问,每次更新时间缓存前需申请锁,而读时间缓存无须加锁; 为避免分裂读 ngx_trylock(&ngx_time_lock)) {--更新缓存前需获取ngx_time_lock return; } ngx_gettimeofday(&tv) ;--宏定义,调用os的gettimeofday(tp, null) sec = tv.tv_sec; msec = tv.tv_usec / 1000; ngx_current_msec
str1.resize(100000000); unsigned long realtime; struct timeval ts; unsigned long timecount; gettimeofday time:" << timecount << endl; for (size_t i = 0; i < 100000000; i++) { str1.append("1"); } gettimeofday ; timecount = realtime; for (size_t i = 0; i < 100000000; i++) { str2.append("1"); } gettimeofday
); delete tmp; return; } void *SendMsg(void* p) { struct timeval tv_begin, tv_end; gettimeofday tv_begin, NULL); int i = 0; while (i++ < MAXLEN) { enque((list*)p, i); } gettimeofday cost %llu us\n", timeinterval); } void *SendMsg2(void* p) { struct timeval tv_begin, tv_end; gettimeofday tv_begin, NULL); int i = 0; while (i++ < MAXLEN) { enque_lock((list*)p, i); } gettimeofday
(&t1, NULL); for(int i = 0; i < ARRAY_SIZE; i += stride){ array[i]++; } gettimeofday # Loop 1 gettimeofday(&t1, NULL); for(int i = 0; i < ARRAY_SIZE - 1; i++){ array[0] ++; array [0] ++; } # Loop 2 gettimeofday(&t2, NULL); for(int i = 0; i < ARRAY_SIZE - 1; i++){ array[0] ++ ; array[1] ++; }gettimeofday(&t3, NULL); loop1_time = time_diff(t1, t2); loop2_time = time_diff( (&t2, NULL); diff = time_diff(t1, t2); printf("%f\n", diff); // False Sharing gettimeofday