zoukankan      html  css  js  c++  java
  • 测试mktime和localtime_r性能及优化方法

    // 测试mktime和localtime_r性能及优化方法
    //
    // 编译方法:g++ -g -o x x.cpp或g++ -O2 -o x x.cpp,两种编译方式性能基本相同。
    //
    // 结论:
    // 1) 环境变量TZ和isdst均不影响localtime_r的性能(第一次调用了除外)
    // 2) 环境变量TZ严重影响localtime的性能
    // 3) 环境变量TZ和isdst均会严重影响mktime的性能
    // *4) 注意mktime的参数即是输入参数也是输出参数,它会修改isdst值
    // *5) 另外需要注意localtime_r为非信号安全函数,
    //     不能在信号处理过程中调用,否则可能发生死锁等问题
    //
    // 64位机器性能数据(与32位CPU不同):
    /*
    $ ./x 1000000
    test: localtime ...
    TZ is NULL: 2457ms
    TZ is empty: 172ms
    TZ is Asia/Shanghai: 173ms
    
    test: localtime_r ...
    TZ is NULL and isdst=1: 125ms
    TZ is NULL and isdst=0: 125ms
    TZ is NULL and isdst=-1: 125ms
    TZ is NULL and isdst undefined: 125ms
    TZ is empty and isdst=1: 125ms
    TZ is empty and isdst=0: 125ms
    TZ is empty and isdst=-1: 125ms
    TZ is empty and isdst undefined: 127ms
    TZ is Asia/Shanghai and isdst=1: 126ms
    TZ is Asia/Shanghai and isdst=0: 125ms
    TZ is Asia/Shanghai and isdst=-1: 125ms
    TZ is Asia/Shanghai and isdst undefined: 125ms
    
    test: mktime ...
    TZ is NULL and isdst=1: 635841ms
    TZ is NULL and isdst=0: 2583ms
    TZ is NULL and isdst=-1: 2596ms
    TZ is NULL and isdst undefined: 2579ms
    TZ is empty and isdst=1: 122377ms
    TZ is empty and isdst=0: 229ms
    TZ is empty and isdst=-1: 230ms
    TZ is empty and isdst undefined: 229ms
    TZ is Asia/Shanghai and isdst=1: 122536ms
    TZ is Asia/Shanghai and isdst=0: 228ms
    TZ is Asia/Shanghai and isdst=-1: 230ms
    TZ is Asia/Shanghai and isdst undefined: 228ms
    */
    
    // 32位机器性能数据(与64位CPU不同):
    /*
    $ ./x 1000000
    test: localtime ...
    TZ is NULL: 1445ms
    TZ is empty: 252ms
    TZ is Asia/Shanghai: 252ms
    
    test: localtime_r ...
    TZ is NULL and isdst=1: 161ms
    TZ is NULL and isdst=0: 160ms
    TZ is NULL and isdst=-1: 161ms
    TZ is NULL and isdst undefined: 161ms
    TZ is empty and isdst=1: 160ms
    TZ is empty and isdst=0: 161ms
    TZ is empty and isdst=-1: 161ms
    TZ is empty and isdst undefined: 161ms
    TZ is Asia/Shanghai and isdst=1: 161ms
    TZ is Asia/Shanghai and isdst=0: 161ms
    TZ is Asia/Shanghai and isdst=-1: 161ms
    TZ is Asia/Shanghai and isdst undefined: 161ms
    
    test: mktime ...
    TZ is NULL and isdst=1: 199375ms
    TZ is NULL and isdst=0: 1488ms
    TZ is NULL and isdst=-1: 1483ms
    TZ is NULL and isdst undefined: 1497ms
    TZ is empty and isdst=1: 161057ms
    TZ is empty and isdst=0: 325ms
    TZ is empty and isdst=-1: 328ms
    TZ is empty and isdst undefined: 326ms
    TZ is Asia/Shanghai and isdst=1: 161558ms
    TZ is Asia/Shanghai and isdst=0: 321ms
    TZ is Asia/Shanghai and isdst=-1: 335ms
    TZ is Asia/Shanghai and isdst undefined: 328ms
    */
    // localtime_r相关源代码:
    /*
    // The C Standard says that localtime and gmtime return the same pointer.
    struct tm _tmbuf; // 全局变量
    
    struct tm * __localtime_r (t, tp)
         const time_t *t;
         struct tm *tp;
    {
      return __tz_convert (t, 1, tp);
    }
    
    // 非线程安全版本,用到了全局变量_tmbuf
    struct tm * localtime(t)
         const time_t *t;
    {
      return __tz_convert (t, 1, &_tmbuf);
    }
    
    struct tm * __tz_convert (const time_t *timer, int use_localtime, struct tm *tp)
    {
      。。。
      // 信号处理函数中调用非信号安全函数,可能造成死锁的地方
      __libc_lock_lock (tzset_lock);
      
      // localtime_r未用到_tmbuf,只是localtime使用它!!!
      // 因此对于localtime_r,传递给tzset_internal的第一个参数总是为0(tp != &_tmpbuf),
      // 而对于localtime,它传递给tzset_internal的第一个参数总是为1
      tzset_internal (tp == &_tmbuf && use_localtime, 1);
      。。。
    }
    
    // 决定性能的函数,原因是可能涉及文件操作,
    // 因此要想提升性能,则应当想办法避免操作文件!!!
    static void internal_function
    tzset_internal (always, explicit)
         int always;
         int explicit;
    {
      static int is_initialized; // 静态变量
      const char *tz;
    
      // 对于mktime,参数always值总是为1
      // 对于localtime,参数always值总是为1
      // 对于localtime_r,参数always值总是为0    
      if (is_initialized && !always)
        return; // 对于localtime_r第一次调用后,后续都在这里直接返回!
      is_initialized = 1;
    
      tz = getenv ("TZ");
      if (tz == NULL && !explicit)
        tz = TZDEFAULT;
      if (tz && *tz == '')
        tz = "Universal";
      if (tz && *tz == ':')
        ++tz;
    
      // 如果不设置环境变量TZ,则下面这个if语句总是不成立!!!
      // 因此只有设置了环境变量TZ,才有可能在这里直接返回而不进入读文件操作__tzfile_read
      if (old_tz != NULL && tz != NULL && strcmp (tz, old_tz) == 0)
        return; // 在这里返回则可以避免走到文件操作__tzfile_read
      if (tz == NULL)
        tz = TZDEFAULT;
    
      tz_rules[0].name = NULL;
      tz_rules[1].name = NULL;
    
      // Save the value of `tz'.
      free (old_tz);
      old_tz = tz ? __strdup (tz) : NULL;
    
      // 读文件,性能慢的原因  
      __tzfile_read (tz, 0, NULL); // Try to read a data file.
      if (__use_tzfile)
        return;
      。。。
    }
    */
    // mktime相关源代码:
    /*
    time_t mktime (struct tm *tp)
    {
    #ifdef _LIBC
      // POSIX.1 8.1.1 requires that whenever mktime() is called, the
      //   time zone names contained in the external variable 'tzname' shall
      //   be set as if the tzset() function had been called.
      __tzset ();
    #endif
    
      // __mktime_internal会调用localtime_r,
      // isdst的取值在这里会严重影响到mktime的性能
      return __mktime_internal (tp, __localtime_r, &localtime_offset);
    }
    
    void __tzset (void)
    {
      __libc_lock_lock (tzset_lock);
    
      // 和localtime_r一样也会调用tzset_internal
      tzset_internal (1, 1);
    
      if (!__use_tzfile)
        {
          // Set `tzname'.
          __tzname[0] = (char *) tz_rules[0].name;
          __tzname[1] = (char *) tz_rules[1].name;
        }
    
      __libc_lock_unlock (tzset_lock);
    }
    */
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include <sys/time.h>
    #include <time.h>
    
    static void test_localtime(int M); // 测试localtime性能
    static void test_localtime_r(int M); // 测试localtime_r性能
    static void test_mktime(int M); // 测试mktime性能
    
    int main(int argc, char* argv[])
    {
        const int M = (argc<2)? 1000000: atoi(argv[1]);
    
        test_localtime(M);
        printf("
    ");
        test_localtime_r(M);
        printf("
    ");
        test_mktime(M);
    
        return 0;
    }
    
    // test_localtime
    void test_localtime(int M)
    {
        int i;
        time_t now = time(NULL);
        struct timeval tv1, tv2;
    
        printf("test: localtime ...
    ");
        unsetenv("TZ");
    
        // test1
        {
            struct tm* result1;
            gettimeofday(&tv1, NULL);
            for (i=0; i<M; ++i)
            {
                result1 = localtime(&now);
            }
            gettimeofday(&tv2, NULL);
            printf("TZ is NULL: %ums
    ", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
        }
        
        setenv("TZ", "", 0);
    
        // test2
        {
            struct tm* result2;
            gettimeofday(&tv1, NULL);
            for (i=0; i<M; ++i)
            {
                result2 = localtime(&now);
            }
            gettimeofday(&tv2, NULL);
            printf("TZ is empty: %ums
    ", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
        }
    
        setenv("TZ", "Asia/Shanghai", 0);
    
        // test3
        {        
            struct tm* result3;
            gettimeofday(&tv1, NULL);
            for (i=0; i<M; ++i)
            {
                result3 = localtime(&now);
            }
            gettimeofday(&tv2, NULL);
            printf("TZ is Asia/Shanghai: %ums
    ", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
        }
    }
    
    // test_localtime_r
    void test_localtime_r(int M)
    {
        int i;
        time_t now = time(NULL);
        struct timeval tv1, tv2;
    
        printf("test: localtime_r ...
    ");
        unsetenv("TZ");
    
        // test1
        {        
            struct tm result1;
            gettimeofday(&tv1, NULL);
            for (i=0; i<M; ++i)
            {
                struct tm result1_;
                memcpy(&result1_, &result1, sizeof(result1_));
                result1_.tm_isdst = 1;
                localtime_r(&now, &result1_);
            }
            gettimeofday(&tv2, NULL);
            printf("TZ is NULL and isdst=1: %ums
    ", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
        }
    
        // test2
        {
            struct tm result2;        
            gettimeofday(&tv1, NULL);
            for (i=0; i<M; ++i)
            {
                struct tm result2_;
                memcpy(&result2_, &result2, sizeof(result2_));
                result2_.tm_isdst = 0;
                localtime_r(&now, &result2_);
            }
            gettimeofday(&tv2, NULL);
            printf("TZ is NULL and isdst=0: %ums
    ", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
        }
    
        // test3
        {
            struct tm result3;
            gettimeofday(&tv1, NULL);
            for (i=0; i<M; ++i)
            {
                struct tm result3_;
                memcpy(&result3_, &result3, sizeof(result3_));
                result3_.tm_isdst = -1;
                localtime_r(&now, &result3_);
            }
            gettimeofday(&tv2, NULL);
            printf("TZ is NULL and isdst=-1: %ums
    ", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
        }
    
        // test4
        {
            struct tm result4;
            gettimeofday(&tv1, NULL);
            for (i=0; i<M; ++i)
            {
                struct tm result4_;
                memcpy(&result4_, &result4, sizeof(result4_));
                localtime_r(&now, &result4_);
            }
            gettimeofday(&tv2, NULL);
            printf("TZ is NULL and isdst undefined: %ums
    ", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
        }
    
        setenv("TZ", "", 0);
    
        // test5
        {
            struct tm result5;
            gettimeofday(&tv1, NULL);
            for (i=0; i<M; ++i)
            {
                struct tm result5_;
                memcpy(&result5_, &result5, sizeof(result5_));
                result5_.tm_isdst = 1;
                localtime_r(&now, &result5_);
            }
            gettimeofday(&tv2, NULL);
            printf("TZ is empty and isdst=1: %ums
    ", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
        }
    
        // test6
        {
            struct tm result6;
            gettimeofday(&tv1, NULL);
            for (i=0; i<M; ++i)
            {
                struct tm result6_;
                memcpy(&result6_, &result6, sizeof(result6_));
                result6_.tm_isdst = 0;
                localtime_r(&now, &result6_);
            }
            gettimeofday(&tv2, NULL);
            printf("TZ is empty and isdst=0: %ums
    ", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
        }
    
        // test7
        {
            struct tm result7;
            gettimeofday(&tv1, NULL);
            for (i=0; i<M; ++i)
            {
                struct tm result7_;
                memcpy(&result7_, &result7, sizeof(result7_));
                result7_.tm_isdst = -1;
                localtime_r(&now, &result7_);
            }
            gettimeofday(&tv2, NULL);
            printf("TZ is empty and isdst=-1: %ums
    ", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
        }
    
        // test8
        {
            struct tm result8;
            gettimeofday(&tv1, NULL);
            for (i=0; i<M; ++i)
            {
                struct tm result8_;
                memcpy(&result8_, &result8, sizeof(result8_));
                result8_.tm_isdst = -1;
                localtime_r(&now, &result8_);
            }
            gettimeofday(&tv2, NULL);
            printf("TZ is empty and isdst undefined: %ums
    ", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
        }
    
        setenv("TZ", "Asia/Shanghai", 0);
    
        // test9
        {
            struct tm result9;
            gettimeofday(&tv1, NULL);
            for (i=0; i<M; ++i)
            {
                struct tm result9_;
                memcpy(&result9_, &result9, sizeof(result9_));
                result9_.tm_isdst = 1;
                localtime_r(&now, &result9_);
            }
            gettimeofday(&tv2, NULL);
            printf("TZ is Asia/Shanghai and isdst=1: %ums
    ", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
        }
    
        // test10
        {
            struct tm result10;
            gettimeofday(&tv1, NULL);
            for (i=0; i<M; ++i)
            {
                struct tm result10_;
                memcpy(&result10_, &result10, sizeof(result10_));
                result10_.tm_isdst = 0;
                localtime_r(&now, &result10_);
            }
            gettimeofday(&tv2, NULL);
            printf("TZ is Asia/Shanghai and isdst=0: %ums
    ", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
        }
    
        // test11
        {
            struct tm result11;
            gettimeofday(&tv1, NULL);
            for (i=0; i<M; ++i)
            {
                struct tm result11_;
                memcpy(&result11_, &result11, sizeof(result11_));
                result11_.tm_isdst = -1;
                localtime_r(&now, &result11_);
            }
            gettimeofday(&tv2, NULL);
            printf("TZ is Asia/Shanghai and isdst=-1: %ums
    ", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
        }
    
        // test12
        {
            struct tm result12;
            gettimeofday(&tv1, NULL);
            for (i=0; i<M; ++i)
            {
                struct tm result12_;
                memcpy(&result12_, &result12, sizeof(result12_));
                localtime_r(&now, &result12_);
            }
            gettimeofday(&tv2, NULL);
            printf("TZ is Asia/Shanghai and isdst undefined: %ums
    ", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
        }
    }
    
    // test_mktime
    void test_mktime(int M)
    {
        int i;  
        time_t now = time(NULL);
        struct timeval tv1, tv2;
    
        printf("test: mktime ...
    ");
        unsetenv("TZ");
    
        // test1
        {
            struct tm result1;
            localtime_r(&now, &result1);
            gettimeofday(&tv1, NULL);
            for (i=0; i<M; ++i)
            {
                struct tm result1_;
                memcpy(&result1_, &result1, sizeof(result1_));
                result1_.tm_isdst = 1;
                mktime(&result1_);
            }
            gettimeofday(&tv2, NULL);
            printf("TZ is NULL and isdst=1: %ums
    ", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
        }
    
        // test2
        {
            struct tm result2;
            localtime_r(&now, &result2);
            gettimeofday(&tv1, NULL);
            for (i=0; i<M; ++i)
            {
                struct tm result2_;
                memcpy(&result2_, &result2, sizeof(result2_));
                result2_.tm_isdst = 0;
                mktime(&result2_);
            }
            gettimeofday(&tv2, NULL);
            printf("TZ is NULL and isdst=0: %ums
    ", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
        }
    
        // test3
        {
            struct tm result3;
            localtime_r(&now, &result3);
            gettimeofday(&tv1, NULL);
            for (i=0; i<M; ++i)
            {
                struct tm result3_;
                memcpy(&result3_, &result3, sizeof(result3_));
                result3_.tm_isdst = -1;
                mktime(&result3_);
            }
            gettimeofday(&tv2, NULL);
            printf("TZ is NULL and isdst=-1: %ums
    ", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
        }
    
        // test4
        {
            struct tm result4;
            localtime_r(&now, &result4);
            gettimeofday(&tv1, NULL);
            for (i=0; i<M; ++i)
            {
                struct tm result4_;
                memcpy(&result4_, &result4, sizeof(result4_));
                mktime(&result4_);
            }
            gettimeofday(&tv2, NULL);
            printf("TZ is NULL and isdst undefined: %ums
    ", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
        }
    
        setenv("TZ", "", 0);
    
        // test5
        {
            struct tm result5;
            localtime_r(&now, &result5);
            gettimeofday(&tv1, NULL);
            for (i=0; i<M; ++i)
            {
                struct tm result5_;
                memcpy(&result5_, &result5, sizeof(result5_));
                result5_.tm_isdst = 1;
                mktime(&result5_);
            }
            gettimeofday(&tv2, NULL);
            printf("TZ is empty and isdst=1: %ums
    ", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
        }
    
        // test6
        {
            struct tm result6;
            localtime_r(&now, &result6);
            gettimeofday(&tv1, NULL);
            for (i=0; i<M; ++i)
            {
                struct tm result6_;
                memcpy(&result6_, &result6, sizeof(result6_));
                result6_.tm_isdst = 0;
                mktime(&result6_);
            }
            gettimeofday(&tv2, NULL);
            printf("TZ is empty and isdst=0: %ums
    ", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
        }
    
        // test7
        {
            struct tm result7;
            localtime_r(&now, &result7);
            gettimeofday(&tv1, NULL);
            for (i=0; i<M; ++i)
            {
                struct tm result7_;
                memcpy(&result7_, &result7, sizeof(result7_));
                result7_.tm_isdst = -1;
                mktime(&result7_);
            }
            gettimeofday(&tv2, NULL);
            printf("TZ is empty and isdst=-1: %ums
    ", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
        }
    
        // test8
        {
            struct tm result8;
            localtime_r(&now, &result8);
            gettimeofday(&tv1, NULL);
            for (i=0; i<M; ++i)
            {
                struct tm result8_;
                memcpy(&result8_, &result8, sizeof(result8_));
                mktime(&result8_);
            }
            gettimeofday(&tv2, NULL);
            printf("TZ is empty and isdst undefined: %ums
    ", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
        }
    
        setenv("TZ", "Asia/Shanghai", 0);
    
        // test9
        {
            struct tm result9;
            localtime_r(&now, &result9);
            gettimeofday(&tv1, NULL);
            for (i=0; i<M; ++i)
            {
                struct tm result9_;
                memcpy(&result9_, &result9, sizeof(result9_));
                result9_.tm_isdst = 1;
                mktime(&result9_);
            }
            gettimeofday(&tv2, NULL);
            printf("TZ is Asia/Shanghai and isdst=1: %ums
    ", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
        }
    
        // test10
        {
            struct tm result10;
            localtime_r(&now, &result10);
            gettimeofday(&tv1, NULL);
            for (i=0; i<M; ++i)
            {
                struct tm result10_;
                memcpy(&result10_, &result10, sizeof(result10_));
                result10_.tm_isdst = 0;
                mktime(&result10_);
            }
            gettimeofday(&tv2, NULL);
            printf("TZ is Asia/Shanghai and isdst=0: %ums
    ", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
        }
    
        // test11
        {
            struct tm result11;
            localtime_r(&now, &result11);
            gettimeofday(&tv1, NULL);
            for (i=0; i<M; ++i)
            {
                struct tm result11_;
                memcpy(&result11_, &result11, sizeof(result11_));
                result11_.tm_isdst = -1;
                mktime(&result11_);
            }
            gettimeofday(&tv2, NULL);
            printf("TZ is Asia/Shanghai and isdst=-1: %ums
    ", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
        }
    
        // test12
        {
            struct tm result12;
            localtime_r(&now, &result12);
            gettimeofday(&tv1, NULL);
            for (i=0; i<M; ++i)
            {
                struct tm result12_;
                memcpy(&result12_, &result12, sizeof(result12_));
                mktime(&result12_);
            }
            gettimeofday(&tv2, NULL);
            printf("TZ is Asia/Shanghai and isdst undefined: %ums
    ", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
        }
    }
    

  • 相关阅读:
    源码阅读(18):Java中主要的Map结构——HashMap容器(中)
    源码阅读(17):红黑树在Java中的实现和应用
    java中创建文件并写入的方法
    源码阅读(16):Java中主要的Map结构——HashMap容器(上)
    源码阅读(15):Java中主要的Map结构——概述
    从源码分析:Java中的AQS
    源码阅读(14):Java中主要的Queue、Deque结构——PriorityQueue集合(下)
    源码阅读(13):Java中主要的Queue、Deque结构——PriorityQueue集合(中)
    java 归并排序与快速排序
    python中的容器、可迭代对象、迭代器、生成器
  • 原文地址:https://www.cnblogs.com/aquester/p/9891510.html
Copyright © 2011-2022 走看看