测试mktime和localtime_r性能及优化方法

2713阅读 0评论2011-12-22 Aquester
分类:LINUX


点击(此处)折叠或打开

  1. // 编译方法:g++ -g -o x x.cpp或g++ -O2 -o x x.cpp,两种编译方式性能基本相同。
  2. //
  3. // 结论:
  4. // 1) 环境变量TZ和isdst均不影响localtime_r的性能
  5. // 2) 环境变量TZ严重影响mktime和localtime的性能
  6. // 3) mktime性能不受isdst值的影响,localtime性能与isdst值无关
  7. // *4) 另外需要注意localtime_r为非信号安全函数,
  8. // 不能在信号处理过程中调用,否则可能发生死锁等问题
  9. //
  10. // 64位机器性能数据(与32位CPU不同):
  11. /*
  12. $ ./x 1000000
  13. test: localtime ...
  14. TZ is NULL: 2629ms
  15. TZ is empty: 177ms
  16. TZ is Asia/Shanghai: 177ms

  17. test: localtime_r ...
  18. TZ is NULL and isdst=1: 124ms
  19. TZ is NULL and isdst=0: 125ms
  20. TZ is NULL and isdst=-1: 124ms
  21. TZ is NULL and isdst undefined: 124ms
  22. TZ is empty and isdst=1: 124ms
  23. TZ is empty and isdst=0: 124ms
  24. TZ is empty and isdst=-1: 124ms
  25. TZ is empty and isdst undefined: 124ms
  26. TZ is Asia/Shanghai and isdst=1: 124ms
  27. TZ is Asia/Shanghai and isdst=0: 125ms
  28. TZ is Asia/Shanghai and isdst=-1: 124ms
  29. TZ is Asia/Shanghai and isdst undefined: 124ms

  30. test: mktime ...
  31. TZ is NULL and isdst=1: 2657ms
  32. TZ is NULL and isdst=0: 2654ms
  33. TZ is NULL and isdst=-1: 2661ms
  34. TZ is NULL and isdst undefined: 2672ms
  35. TZ is empty and isdst=1: 232ms
  36. TZ is empty and isdst=0: 232ms
  37. TZ is empty and isdst=-1: 232ms
  38. TZ is empty and isdst undefined: 230ms
  39. TZ is Asia/Shanghai and isdst=1: 233ms
  40. TZ is Asia/Shanghai and isdst=0: 231ms
  41. TZ is Asia/Shanghai and isdst=-1: 232ms
  42. TZ is Asia/Shanghai and isdst undefined: 231ms
  43. */
  44. // 32位机器性能数据(与64位CPU不同):
  45. /*
  46. > ./x 1000000
  47. test: localtime ...
  48. TZ is NULL: 1510ms
  49. TZ is empty: 252ms
  50. TZ is Asia/Shanghai: 255ms

  51. test: localtime_r ...
  52. TZ is NULL and isdst=1: 157ms
  53. TZ is NULL and isdst=0: 159ms
  54. TZ is NULL and isdst=-1: 159ms
  55. TZ is NULL and isdst undefined: 158ms
  56. TZ is empty and isdst=1: 158ms
  57. TZ is empty and isdst=0: 160ms
  58. TZ is empty and isdst=-1: 157ms
  59. TZ is empty and isdst undefined: 158ms
  60. TZ is Asia/Shanghai and isdst=1: 157ms
  61. TZ is Asia/Shanghai and isdst=0: 156ms
  62. TZ is Asia/Shanghai and isdst=-1: 156ms
  63. TZ is Asia/Shanghai and isdst undefined: 157ms

  64. test: mktime ...
  65. TZ is NULL and isdst=1: 1542ms
  66. TZ is NULL and isdst=0: 1547ms
  67. TZ is NULL and isdst=-1: 1542ms
  68. TZ is NULL and isdst undefined: 1566ms
  69. TZ is empty and isdst=1: 327ms
  70. TZ is empty and isdst=0: 324ms
  71. TZ is empty and isdst=-1: 325ms
  72. TZ is empty and isdst undefined: 323ms
  73. TZ is Asia/Shanghai and isdst=1: 323ms
  74. TZ is Asia/Shanghai and isdst=0: 326ms
  75. TZ is Asia/Shanghai and isdst=-1: 326ms
  76. TZ is Asia/Shanghai and isdst undefined: 324ms
  77. */
  78. // localtime_r相关源代码:
  79. /*
  80. // The C Standard says that localtime and gmtime return the same pointer.
  81. struct tm _tmbuf; // 全局变量

  82. struct tm * __localtime_r (t, tp)
  83.      const time_t *t;
  84.      struct tm *tp;
  85. {
  86.   return __tz_convert (t, 1, tp);
  87. }

  88. // 非线程安全版本,用到了全局变量_tmbuf
  89. struct tm * localtime(t)
  90.      const time_t *t;
  91. {
  92.   return __tz_convert (t, 1, &_tmbuf);
  93. }

  94. struct tm * __tz_convert (const time_t *timer, int use_localtime, struct tm *tp)
  95. {
  96.   。。。
  97.   // 信号处理函数中调用非信号安全函数,可能造成死锁的地方
  98.   __libc_lock_lock (tzset_lock);
  99.   
  100.   // localtime_r未用到_tmbuf,只是localtime使用它!!!
  101.   // 因此对于localtime_r,传递给tzset_internal的第一个参数总是为0(tp != &_tmpbuf),
  102.   // 而对于localtime,它传递给tzset_internal的第一个参数总是为1
  103.   tzset_internal (tp == &_tmbuf && use_localtime, 1);
  104.   。。。
  105. }

  106. // 决定性能的函数,原因是可能涉及文件操作,
  107. // 因此要想提升性能,则应当想办法避免操作文件!!!
  108. static void internal_function
  109. tzset_internal (always, explicit)
  110.      int always;
  111.      int explicit;
  112. {
  113.   static int is_initialized; // 静态变量
  114.   const char *tz;

  115.   // 对于mktime,参数always值总是为1
  116.   // 对于localtime,参数always值总是为1
  117.   // 对于localtime_r,参数always值总是为0
  118.   if (is_initialized && !always)
  119.     return; // 对于localtime_r第一次调用后,后续都在这里直接返回!
  120.   is_initialized = 1;

  121.   tz = getenv ("TZ");
  122.   if (tz == NULL && !explicit)
  123.     tz = TZDEFAULT;
  124.   if (tz && *tz == '\0')
  125.     tz = "Universal";
  126.   if (tz && *tz == ':')
  127.     ++tz;

  128.   // 如果不设置环境变量TZ,则下面这个if语句总是不成立!!!
  129.   // 因此只有设置了环境变量TZ,才有可能在这里直接返回而不进入读文件操作__tzfile_read
  130.   if (old_tz != NULL && tz != NULL && strcmp (tz, old_tz) == 0)
  131.     return; // 在这里返回则可以避免走到文件操作__tzfile_read
  132.   if (tz == NULL)
  133.     tz = TZDEFAULT;

  134.   tz_rules[0].name = NULL;
  135.   tz_rules[1].name = NULL;

  136.   // Save the value of `tz'.
  137.   free (old_tz);
  138.   old_tz = tz ? __strdup (tz) : NULL;

  139.   // 读文件,性能慢的原因
  140.   __tzfile_read (tz, 0, NULL); // Try to read a data file.
  141.   if (__use_tzfile)
  142.     return;
  143.   。。。
  144. }
  145. */
  146. // mktime相关源代码:
  147. /*
  148. time_t mktime (struct tm *tp)
  149. {
  150. #ifdef _LIBC
  151.   // POSIX.1 8.1.1 requires that whenever mktime() is called, the
  152.   // time zone names contained in the external variable 'tzname' shall
  153.   // be set as if the tzset() function had been called.
  154.   __tzset ();
  155. #endif

  156.   // __mktime_internal为全内存计算,因此无性能问题
  157.   return __mktime_internal (tp, __localtime_r, &localtime_offset);
  158. }

  159. void __tzset (void)
  160. {
  161.   __libc_lock_lock (tzset_lock);

  162.   // 和localtime_r一样也会调用tzset_internal
  163.   tzset_internal (1, 1);

  164.   if (!__use_tzfile)
  165.     {
  166.       // Set `tzname'.
  167.       __tzname[0] = (char *) tz_rules[0].name;
  168.       __tzname[1] = (char *) tz_rules[1].name;
  169.     }

  170.   __libc_lock_unlock (tzset_lock);
  171. }
  172. */
  173. #include <stdio.h>
  174. #include <sys/time.h>
  175. #include <time.h>
  176. #include <stdlib.h>

  177. static void test_localtime(int M); // 测试localtime性能
  178. static void test_localtime_r(int M); // 测试localtime_r性能
  179. static void test_mktime(int M); // 测试mktime性能

  180. int main(int argc, char* argv[])
  181. {
  182.     const int M = (argc<2)? 1000000: atoi(argv[1]);

  183.     test_localtime(M);
  184.     printf("\n");
  185.     test_localtime_r(M);
  186.     printf("\n");
  187.     test_mktime(M);

  188.     return 0;
  189. }

  190. // test_localtime
  191. void test_localtime(int M)
  192. {
  193.     int i;
  194.     time_t now = time(NULL);
  195.     struct timeval tv1, tv2;

  196.     printf("test: localtime ...\n");
  197.     unsetenv("TZ");

  198.     // test1
  199.     {
  200.         struct tm* result1;
  201.         gettimeofday(&tv1, NULL);
  202.         for (i=0; i<M; ++i)
  203.         {
  204.             result1 = localtime(&now);
  205.         }
  206.         gettimeofday(&tv2, NULL);
  207.         printf("TZ is NULL: %ums\n", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
  208.     }
  209.     
  210.     setenv("TZ", "", 0);

  211.     // test2
  212.     {
  213.         struct tm* result2;
  214.         gettimeofday(&tv1, NULL);
  215.         for (i=0; i<M; ++i)
  216.         {
  217.             result2 = localtime(&now);
  218.         }
  219.         gettimeofday(&tv2, NULL);
  220.         printf("TZ is empty: %ums\n", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
  221.     }

  222.     setenv("TZ", "Asia/Shanghai", 0);

  223.     // test3
  224.     {
  225.         struct tm* result3;
  226.         gettimeofday(&tv1, NULL);
  227.         for (i=0; i<M; ++i)
  228.         {
  229.             result3 = localtime(&now);
  230.         }
  231.         gettimeofday(&tv2, NULL);
  232.         printf("TZ is Asia/Shanghai: %ums\n", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
  233.     }
  234. }

  235. // test_localtime_r
  236. void test_localtime_r(int M)
  237. {
  238.     int i;
  239.     time_t now = time(NULL);
  240.     struct timeval tv1, tv2;
  241.   
  242.     printf("test: localtime_r ...\n");
  243.     unsetenv("TZ");

  244.     // test1
  245.     {
  246.         struct tm result1;
  247.         result1.tm_isdst = 1;
  248.         gettimeofday(&tv1, NULL);
  249.         for (i=0; i<M; ++i)
  250.         {
  251.             localtime_r(&now, &result1);
  252.         }
  253.         gettimeofday(&tv2, NULL);
  254.         printf("TZ is NULL and isdst=1: %ums\n", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
  255.     }

  256.     // test2
  257.     {
  258.         struct tm result2;
  259.         result2.tm_isdst = 0;
  260.         gettimeofday(&tv1, NULL);
  261.         for (i=0; i<M; ++i)
  262.         {
  263.             localtime_r(&now, &result2);
  264.         }
  265.         gettimeofday(&tv2, NULL);
  266.         printf("TZ is NULL and isdst=0: %ums\n", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
  267.     }

  268.     // test3
  269.     {
  270.         struct tm result3;
  271.         result3.tm_isdst = -1;
  272.         gettimeofday(&tv1, NULL);
  273.         for (i=0; i<M; ++i)
  274.         {
  275.             localtime_r(&now, &result3);
  276.         }
  277.         gettimeofday(&tv2, NULL);
  278.         printf("TZ is NULL and isdst=-1: %ums\n", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
  279.     }

  280.     // test4
  281.     {
  282.         struct tm result4;
  283.         gettimeofday(&tv1, NULL);
  284.         for (i=0; i<M; ++i)
  285.         {
  286.             localtime_r(&now, &result4);
  287.         }
  288.         gettimeofday(&tv2, NULL);
  289.         printf("TZ is NULL and isdst undefined: %ums\n", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
  290.     }
  291.     
  292.     setenv("TZ", "", 0);

  293.     // test5
  294.     {
  295.         struct tm result5;
  296.         result5.tm_isdst = 1;
  297.         gettimeofday(&tv1, NULL);
  298.         for (i=0; i<M; ++i)
  299.         {
  300.             localtime_r(&now, &result5);
  301.         }
  302.         gettimeofday(&tv2, NULL);
  303.         printf("TZ is empty and isdst=1: %ums\n", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
  304.     }

  305.     // test6
  306.     {
  307.         struct tm result6;
  308.         result6.tm_isdst = 0;
  309.         gettimeofday(&tv1, NULL);
  310.         for (i=0; i<M; ++i)
  311.         {
  312.             localtime_r(&now, &result6);
  313.         }
  314.         gettimeofday(&tv2, NULL);
  315.         printf("TZ is empty and isdst=0: %ums\n", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
  316.     }

  317.     // test7
  318.     {
  319.         struct tm result7;
  320.         result7.tm_isdst = -1;
  321.         gettimeofday(&tv1, NULL);
  322.         for (i=0; i<M; ++i)
  323.         {
  324.             localtime_r(&now, &result7);
  325.         }
  326.         gettimeofday(&tv2, NULL);
  327.         printf("TZ is empty and isdst=-1: %ums\n", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
  328.     }

  329.     // test8
  330.     {
  331.         struct tm result8;
  332.         result8.tm_isdst = -1;
  333.         gettimeofday(&tv1, NULL);
  334.         for (i=0; i<M; ++i)
  335.         {
  336.             localtime_r(&now, &result8);
  337.         }
  338.         gettimeofday(&tv2, NULL);
  339.         printf("TZ is empty and isdst undefined: %ums\n", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
  340.     }

  341.     setenv("TZ", "Asia/Shanghai", 0);

  342.     // test9
  343.     {
  344.         struct tm result9;
  345.         result9.tm_isdst = 1;
  346.         gettimeofday(&tv1, NULL);
  347.         for (i=0; i<M; ++i)
  348.         {
  349.             localtime_r(&now, &result9);
  350.         }
  351.         gettimeofday(&tv2, NULL);
  352.         printf("TZ is Asia/Shanghai and isdst=1: %ums\n", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
  353.     }

  354.     // test10
  355.     {
  356.         struct tm result10;
  357.         result10.tm_isdst = 0;
  358.         gettimeofday(&tv1, NULL);
  359.         for (i=0; i<M; ++i)
  360.         {
  361.             localtime_r(&now, &result10);
  362.         }
  363.         gettimeofday(&tv2, NULL);
  364.         printf("TZ is Asia/Shanghai and isdst=0: %ums\n", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
  365.     }

  366.     // test11
  367.     {
  368.         struct tm result11;
  369.         result11.tm_isdst = -1;
  370.         gettimeofday(&tv1, NULL);
  371.         for (i=0; i<M; ++i)
  372.         {
  373.             localtime_r(&now, &result11);
  374.         }
  375.         gettimeofday(&tv2, NULL);
  376.         printf("TZ is Asia/Shanghai and isdst=-1: %ums\n", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
  377.     }

  378.     // test12
  379.     {
  380.         struct tm result12;
  381.         gettimeofday(&tv1, NULL);
  382.         for (i=0; i<M; ++i)
  383.         {
  384.             localtime_r(&now, &result12);
  385.         }
  386.         gettimeofday(&tv2, NULL);
  387.         printf("TZ is Asia/Shanghai and isdst undefined: %ums\n", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
  388.     }
  389. }

  390. // test_mktime
  391. void test_mktime(int M)
  392. {
  393.     int i;
  394.     time_t now = time(NULL);
  395.     struct timeval tv1, tv2;

  396.     printf("test: mktime ...\n");
  397.     unsetenv("TZ");

  398.     // test1
  399.     {
  400.         struct tm result1;
  401.         localtime_r(&now, &result1);
  402.         result1.tm_isdst = 1;
  403.         gettimeofday(&tv1, NULL);
  404.         for (i=0; i<M; ++i)
  405.         {
  406.             mktime(&result1);
  407.         }
  408.         gettimeofday(&tv2, NULL);
  409.         printf("TZ is NULL and isdst=1: %ums\n", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
  410.     }

  411.     // test2
  412.     {
  413.         struct tm result2;
  414.         localtime_r(&now, &result2);
  415.         result2.tm_isdst = 0;
  416.         gettimeofday(&tv1, NULL);
  417.         for (i=0; i<M; ++i)
  418.         {
  419.             mktime(&result2);
  420.         }
  421.         gettimeofday(&tv2, NULL);
  422.         printf("TZ is NULL and isdst=0: %ums\n", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
  423.     }

  424.     // test3
  425.     {
  426.         struct tm result3;
  427.         localtime_r(&now, &result3);
  428.         result3.tm_isdst = -1;
  429.         gettimeofday(&tv1, NULL);
  430.         for (i=0; i<M; ++i)
  431.         {
  432.             mktime(&result3);
  433.         }
  434.         gettimeofday(&tv2, NULL);
  435.         printf("TZ is NULL and isdst=-1: %ums\n", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
  436.     }

  437.     // test4
  438.     {
  439.         struct tm result4;
  440.         localtime_r(&now, &result4);
  441.         gettimeofday(&tv1, NULL);
  442.         for (i=0; i<M; ++i)
  443.         {
  444.             mktime(&result4);
  445.         }
  446.         gettimeofday(&tv2, NULL);
  447.         printf("TZ is NULL and isdst undefined: %ums\n", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
  448.     }

  449.     setenv("TZ", "", 0);

  450.     // test5
  451.     {
  452.         struct tm result5;
  453.         localtime_r(&now, &result5);
  454.         result5.tm_isdst = 1;
  455.         gettimeofday(&tv1, NULL);
  456.         for (i=0; i<M; ++i)
  457.         {
  458.             mktime(&result5);
  459.         }
  460.         gettimeofday(&tv2, NULL);
  461.         printf("TZ is empty and isdst=1: %ums\n", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
  462.     }

  463.     // test6
  464.     {
  465.         struct tm result6;
  466.         localtime_r(&now, &result6);
  467.         result6.tm_isdst = 0;
  468.         gettimeofday(&tv1, NULL);
  469.         for (i=0; i<M; ++i)
  470.         {
  471.             mktime(&result6);
  472.         }
  473.         gettimeofday(&tv2, NULL);
  474.         printf("TZ is empty and isdst=0: %ums\n", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
  475.     }

  476.     // test7
  477.     {
  478.         struct tm result7;
  479.         localtime_r(&now, &result7);
  480.         result7.tm_isdst = -1;
  481.         gettimeofday(&tv1, NULL);
  482.         for (i=0; i<M; ++i)
  483.         {
  484.             mktime(&result7);
  485.         }
  486.         gettimeofday(&tv2, NULL);
  487.         printf("TZ is empty and isdst=-1: %ums\n", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
  488.     }

  489.     // test8
  490.     {
  491.         struct tm result8;
  492.         localtime_r(&now, &result8);
  493.         gettimeofday(&tv1, NULL);
  494.         for (i=0; i<M; ++i)
  495.         {
  496.             mktime(&result8);
  497.         }
  498.         gettimeofday(&tv2, NULL);
  499.         printf("TZ is empty and isdst undefined: %ums\n", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
  500.     }

  501.     setenv("TZ", "Asia/Shanghai", 0);

  502.     // test9
  503.     {
  504.         struct tm result9;
  505.         localtime_r(&now, &result9);
  506.         result9.tm_isdst = 1;
  507.         gettimeofday(&tv1, NULL);
  508.         for (i=0; i<M; ++i)
  509.         {
  510.             mktime(&result9);
  511.         }
  512.         gettimeofday(&tv2, NULL);
  513.         printf("TZ is Asia/Shanghai and isdst=1: %ums\n", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
  514.     }

  515.     // test10
  516.     {
  517.         struct tm result10;
  518.         localtime_r(&now, &result10);
  519.         result10.tm_isdst = 0;
  520.         gettimeofday(&tv1, NULL);
  521.         for (i=0; i<M; ++i)
  522.         {
  523.             mktime(&result10);
  524.         }
  525.         gettimeofday(&tv2, NULL);
  526.         printf("TZ is Asia/Shanghai and isdst=0: %ums\n", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
  527.     }

  528.     // test11
  529.     {
  530.         struct tm result11;
  531.         localtime_r(&now, &result11);
  532.         result11.tm_isdst = -1;
  533.         gettimeofday(&tv1, NULL);
  534.         for (i=0; i<M; ++i)
  535.         {
  536.             mktime(&result11);
  537.         }
  538.         gettimeofday(&tv2, NULL);
  539.         printf("TZ is Asia/Shanghai and isdst=-1: %ums\n", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
  540.     }

  541.     // test12
  542.     {
  543.         struct tm result12;
  544.         localtime_r(&now, &result12);
  545.         gettimeofday(&tv1, NULL);
  546.         for (i=0; i<M; ++i)
  547.         {
  548.             mktime(&result12);
  549.         }
  550.         gettimeofday(&tv2, NULL);
  551.         printf("TZ is Asia/Shanghai and isdst undefined: %ums\n", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
  552.     }
  553. }

上一篇:awk给外部变量赋值
下一篇:高效的使用stl::map和std::set