在 Linux 上,localtime() 的性能问题是 gmtime() 性能问题的 24 倍

mig*_*els 3 c c++ 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;
}
Run Code Online (Sandbox Code Playgroud)

我得到的结果很奇怪,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
Run Code Online (Sandbox Code Playgroud)

我用 gcc 5 和 4.x 版本编译它,我用过 linux Mint(更新到今天)和 CentOS5。并且已经在不同的物理机上进行了测试,性能差异是相似的。

为什么会有如此(巨大)的性能差异?

Max*_*kin 6

如果您在下面运行此代码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")
Run Code Online (Sandbox Code Playgroud)

查看, 和 的 glibc源代码。localtimegmtime__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     
Run Code Online (Sandbox Code Playgroud)