[英]localtime() takes 24 times more than gmtime() performance issue on linux
由于项目的性能问题,我制作了以下测试程序(甚至使用不同的变量进行完整性检查):
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;
}
我得到的结果非常奇怪,localtime花费的时间大约是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。 同样,它已经在不同的物理机器上进行了测试,并且性能差异相似。
为什么会有如此(巨大)的性能差异?
如果在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
, gmtime
和__tz_convert
glibc
源代码。
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
工作的零部件localtime
和gmtime
缓存。
因此,只有对这些功能之一的首次调用才能完成实际工作,即读取/etc/localtime
以获取本地时区。 即使可能没有必要,也会对gmtime()
执行此操作。
为了获得可靠的结果,请在首次测量之前致电gmtime
或localtime
。 这两个功能的性能应相似。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.