由于项目的性能问题,我制作了以下测试程序(甚至使用不同的变量进行健全性检查):
int main()
{
struct tm *timeinfo;
time_t rawtime;
clock_t begin, end, begin1, end1,begin2,end2;
double time_spent;
begin = clock();
for (int i = 0; i < 1000000; i++){
time ( &rawtime );
timeinfo = localtime(&rawtime);
}
end = clock();
time_spent = (double)(end - begin) / CLOCKS_PER_SEC;
printf("Time elapsed using localtime() : %fs\n", time_spent);
//--------------------------------
begin1 = clock();
for (int i = 0; i < 1000000; i++){
time ( &rawtime );
timeinfo = gmtime(&rawtime);
}
end1 = clock();
time_spent = (double)(end1 - begin1) / CLOCKS_PER_SEC;
printf("Time elapsed using gmtime() : %fs\n", time_spent);
//--------------------------------
begin2 = clock();
for (int i = 0; i < 1000000; i++){
time ( &rawtime );
localtime_r( &rawtime, timeinfo);
}
end2 = clock();
time_spent = (double)(end2 - begin2) / CLOCKS_PER_SEC;
printf("Time elapsed using localtime_r() : %fs\n", time_spent);
return 0;
}
我得到的结果非常奇怪,本地时间需要大约24倍的时间,localtime_r()函数似乎比localtime()少,但仍然比gmtime()更多:
Time elapsed using localtime() : 0.958033s
Time elapsed using gmtime() : 0.038769s
Time elapsed using localtime_r() : 0.860276s
我用gcc 5以及4.x版本编译了它,我使用了linux Mint(更新到今天)和CentOS5。此外,它已在不同的物理机器上进行了测试,性能差异也很相似。
为什么会出现如此(巨大)的性能差异?
答案 0 :(得分:4)
如果您在perf record
下运行此代码然后执行perf report
,您会注意到localtime
在每次迭代时调用getenv("TZ")
。而gmtime
没有。
查看glibc
的源代码确认调用图:
gmtime
__tz_convert(, 0, )
tzset_internal(0, 1)
mktime
__tz_convert(, 1, )
tzset_internal(1, 1)
getenv("TZ")
查看localtime
的glibc
源代码,
gmtime
和
__tz_convert
perf report
:
Samples: 78K of event 'cycles:u', Event count (approx.): 21051445406
Children Self Samples Command Shared Object Symbol ▒
+ 99.48% 0.59% 349 test test [.] main ▒
+ 99.48% 0.00% 0 test libc-2.23.so [.] __libc_start_main ▒
+ 99.48% 0.00% 0 test test [.] _start ▒
+ 98.02% 7.07% 4208 test libc-2.23.so [.] __tz_convert ◆
- 24.51% 23.87% 20812 test libc-2.23.so [.] getenv ▒
- 23.87% _start ▒
__libc_start_main ▒
main ▒
__tz_convert ▒
getenv ▒
+ 0.64% getenv ▒
+ 22.41% 12.75% 9877 test libc-2.23.so [.] __tzfile_compute ▒
+ 15.49% 15.49% 8025 test libc-2.23.so [.] __offtime ▒
+ 12.72% 6.28% 5476 test libc-2.23.so [.] __tzfile_read ▒
+ 9.66% 3.54% 3086 test libc-2.23.so [.] __tzstring ▒
+ 8.36% 1.40% 1221 test libc-2.23.so [.] __strdup ▒
+ 7.68% 3.38% 2946 test libc-2.23.so [.] free ▒
+ 5.98% 3.07% 2682 test libc-2.23.so [.] malloc ▒
+ 4.96% 0.68% 611 test libc-2.23.so [.] __xstat64 ▒
+ 4.30% 4.30% 3750 test libc-2.23.so [.] _int_free ▒
+ 4.28% 4.28% 3731 test [kernel.kallsyms] [k] entry_SYSCALL_64 ▒
+ 4.08% 4.08% 3564 test libc-2.23.so [.] strlen ▒
+ 3.64% 3.64% 3168 test libc-2.23.so [.] __memcmp_sse2 ▒
+ 2.91% 2.91% 2561 test libc-2.23.so [.] _int_malloc ▒
+ 1.25% 1.25% 1094 test libc-2.23.so [.] __memcpy_sse2 ▒
+ 0.68% 0.68% 587 test libc-2.23.so [.] localtime ▒
0.26% 0.26% 222 test libc-2.23.so [.] 0x000000000001f910 ▒
0.18% 0.18% 37 test test [.] gmtime@plt ▒
0.15% 0.15% 126 test test [.] localtime@plt ▒
0.11% 0.11% 23 test libc-2.23.so [.] gmtime ▒
0.01% 0.01% 6 test [kernel.kallsyms] [k] __irqentry_text_start ▒
0.00% 0.00% 3 test ld-2.23.so [.] _dl_lookup_symbol_x ▒
0.00% 0.00% 5 test ld-2.23.so [.] do_lookup_x ▒
0.00% 0.00% 2 test ld-2.23.so [.] _dl_relocate_object ▒
0.00% 0.00% 1 test libc-2.23.so [.] 0x000000000001f8e8 ▒
0.00% 0.00% 1 test ld-2.23.so [.] strlen ▒
0.00% 0.00% 1 test ld-2.23.so [.] _dl_debug_initialize ▒
0.00% 0.00% 1 test ld-2.23.so [.] _dl_start ▒
0.00% 0.00% 1 test [kernel.kallsyms] [k] page_fault ▒
0.00% 0.00% 6 test ld-2.23.so [.] _start
答案 1 :(得分:0)
localtime
和gmtime
的部分工作已缓存。
因此,只有第一次调用其中一个函数才能真正起作用,即读取/etc/localtime
以获取本地时区。即使可能没有必要,也会对gmtime()
执行此操作。
要获得可靠的结果,请在第一次测量之前拨打gmtime
或localtime
。两种功能的性能应该相似。