点击(此处)折叠或打开
-
// 编译方法:g++ -g -o x x.cpp或g++ -O2 -o x x.cpp,两种编译方式性能基本相同。
-
//
-
// 结论:
-
// 1) 环境变量TZ和isdst均不影响localtime_r的性能
-
// 2) 环境变量TZ严重影响mktime和localtime的性能
-
// 3) mktime性能不受isdst值的影响,localtime性能与isdst值无关
-
// *4) 另外需要注意localtime_r为非信号安全函数,
-
// 不能在信号处理过程中调用,否则可能发生死锁等问题
-
//
-
// 64位机器性能数据(与32位CPU不同):
-
/*
-
$ ./x 1000000
-
test: localtime ...
-
TZ is NULL: 2629ms
-
TZ is empty: 177ms
-
TZ is Asia/Shanghai: 177ms
-
-
test: localtime_r ...
-
TZ is NULL and isdst=1: 124ms
-
TZ is NULL and isdst=0: 125ms
-
TZ is NULL and isdst=-1: 124ms
-
TZ is NULL and isdst undefined: 124ms
-
TZ is empty and isdst=1: 124ms
-
TZ is empty and isdst=0: 124ms
-
TZ is empty and isdst=-1: 124ms
-
TZ is empty and isdst undefined: 124ms
-
TZ is Asia/Shanghai and isdst=1: 124ms
-
TZ is Asia/Shanghai and isdst=0: 125ms
-
TZ is Asia/Shanghai and isdst=-1: 124ms
-
TZ is Asia/Shanghai and isdst undefined: 124ms
-
-
test: mktime ...
-
TZ is NULL and isdst=1: 2657ms
-
TZ is NULL and isdst=0: 2654ms
-
TZ is NULL and isdst=-1: 2661ms
-
TZ is NULL and isdst undefined: 2672ms
-
TZ is empty and isdst=1: 232ms
-
TZ is empty and isdst=0: 232ms
-
TZ is empty and isdst=-1: 232ms
-
TZ is empty and isdst undefined: 230ms
-
TZ is Asia/Shanghai and isdst=1: 233ms
-
TZ is Asia/Shanghai and isdst=0: 231ms
-
TZ is Asia/Shanghai and isdst=-1: 232ms
-
TZ is Asia/Shanghai and isdst undefined: 231ms
-
*/
-
// 32位机器性能数据(与64位CPU不同):
-
/*
-
> ./x 1000000
-
test: localtime ...
-
TZ is NULL: 1510ms
-
TZ is empty: 252ms
-
TZ is Asia/Shanghai: 255ms
-
-
test: localtime_r ...
-
TZ is NULL and isdst=1: 157ms
-
TZ is NULL and isdst=0: 159ms
-
TZ is NULL and isdst=-1: 159ms
-
TZ is NULL and isdst undefined: 158ms
-
TZ is empty and isdst=1: 158ms
-
TZ is empty and isdst=0: 160ms
-
TZ is empty and isdst=-1: 157ms
-
TZ is empty and isdst undefined: 158ms
-
TZ is Asia/Shanghai and isdst=1: 157ms
-
TZ is Asia/Shanghai and isdst=0: 156ms
-
TZ is Asia/Shanghai and isdst=-1: 156ms
-
TZ is Asia/Shanghai and isdst undefined: 157ms
-
-
test: mktime ...
-
TZ is NULL and isdst=1: 1542ms
-
TZ is NULL and isdst=0: 1547ms
-
TZ is NULL and isdst=-1: 1542ms
-
TZ is NULL and isdst undefined: 1566ms
-
TZ is empty and isdst=1: 327ms
-
TZ is empty and isdst=0: 324ms
-
TZ is empty and isdst=-1: 325ms
-
TZ is empty and isdst undefined: 323ms
-
TZ is Asia/Shanghai and isdst=1: 323ms
-
TZ is Asia/Shanghai and isdst=0: 326ms
-
TZ is Asia/Shanghai and isdst=-1: 326ms
-
TZ is Asia/Shanghai and isdst undefined: 324ms
-
*/
-
// 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 == '\0')
-
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为全内存计算,因此无性能问题
-
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 <stdio.h>
-
#include <sys/time.h>
-
#include <time.h>
-
#include <stdlib.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("\n");
-
test_localtime_r(M);
-
printf("\n");
-
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 ...\n");
-
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\n", (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\n", (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\n", (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 ...\n");
-
unsetenv("TZ");
-
-
// test1
-
{
-
struct tm result1;
-
result1.tm_isdst = 1;
-
gettimeofday(&tv1, NULL);
-
for (i=0; i<M; ++i)
-
{
-
localtime_r(&now, &result1);
-
}
-
gettimeofday(&tv2, NULL);
-
printf("TZ is NULL and isdst=1: %ums\n", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
-
}
-
-
// test2
-
{
-
struct tm result2;
-
result2.tm_isdst = 0;
-
gettimeofday(&tv1, NULL);
-
for (i=0; i<M; ++i)
-
{
-
localtime_r(&now, &result2);
-
}
-
gettimeofday(&tv2, NULL);
-
printf("TZ is NULL and isdst=0: %ums\n", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
-
}
-
-
// test3
-
{
-
struct tm result3;
-
result3.tm_isdst = -1;
-
gettimeofday(&tv1, NULL);
-
for (i=0; i<M; ++i)
-
{
-
localtime_r(&now, &result3);
-
}
-
gettimeofday(&tv2, NULL);
-
printf("TZ is NULL and isdst=-1: %ums\n", (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)
-
{
-
localtime_r(&now, &result4);
-
}
-
gettimeofday(&tv2, NULL);
-
printf("TZ is NULL and isdst undefined: %ums\n", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
-
}
-
-
setenv("TZ", "", 0);
-
-
// test5
-
{
-
struct tm result5;
-
result5.tm_isdst = 1;
-
gettimeofday(&tv1, NULL);
-
for (i=0; i<M; ++i)
-
{
-
localtime_r(&now, &result5);
-
}
-
gettimeofday(&tv2, NULL);
-
printf("TZ is empty and isdst=1: %ums\n", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
-
}
-
-
// test6
-
{
-
struct tm result6;
-
result6.tm_isdst = 0;
-
gettimeofday(&tv1, NULL);
-
for (i=0; i<M; ++i)
-
{
-
localtime_r(&now, &result6);
-
}
-
gettimeofday(&tv2, NULL);
-
printf("TZ is empty and isdst=0: %ums\n", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
-
}
-
-
// test7
-
{
-
struct tm result7;
-
result7.tm_isdst = -1;
-
gettimeofday(&tv1, NULL);
-
for (i=0; i<M; ++i)
-
{
-
localtime_r(&now, &result7);
-
}
-
gettimeofday(&tv2, NULL);
-
printf("TZ is empty and isdst=-1: %ums\n", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
-
}
-
-
// test8
-
{
-
struct tm result8;
-
result8.tm_isdst = -1;
-
gettimeofday(&tv1, NULL);
-
for (i=0; i<M; ++i)
-
{
-
localtime_r(&now, &result8);
-
}
-
gettimeofday(&tv2, NULL);
-
printf("TZ is empty and isdst undefined: %ums\n", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
-
}
-
-
setenv("TZ", "Asia/Shanghai", 0);
-
-
// test9
-
{
-
struct tm result9;
-
result9.tm_isdst = 1;
-
gettimeofday(&tv1, NULL);
-
for (i=0; i<M; ++i)
-
{
-
localtime_r(&now, &result9);
-
}
-
gettimeofday(&tv2, NULL);
-
printf("TZ is Asia/Shanghai and isdst=1: %ums\n", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
-
}
-
-
// test10
-
{
-
struct tm result10;
-
result10.tm_isdst = 0;
-
gettimeofday(&tv1, NULL);
-
for (i=0; i<M; ++i)
-
{
-
localtime_r(&now, &result10);
-
}
-
gettimeofday(&tv2, NULL);
-
printf("TZ is Asia/Shanghai and isdst=0: %ums\n", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
-
}
-
-
// test11
-
{
-
struct tm result11;
-
result11.tm_isdst = -1;
-
gettimeofday(&tv1, NULL);
-
for (i=0; i<M; ++i)
-
{
-
localtime_r(&now, &result11);
-
}
-
gettimeofday(&tv2, NULL);
-
printf("TZ is Asia/Shanghai and isdst=-1: %ums\n", (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)
-
{
-
localtime_r(&now, &result12);
-
}
-
gettimeofday(&tv2, NULL);
-
printf("TZ is Asia/Shanghai and isdst undefined: %ums\n", (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 ...\n");
-
unsetenv("TZ");
-
-
// test1
-
{
-
struct tm result1;
-
localtime_r(&now, &result1);
-
result1.tm_isdst = 1;
-
gettimeofday(&tv1, NULL);
-
for (i=0; i<M; ++i)
-
{
-
mktime(&result1);
-
}
-
gettimeofday(&tv2, NULL);
-
printf("TZ is NULL and isdst=1: %ums\n", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
-
}
-
-
// test2
-
{
-
struct tm result2;
-
localtime_r(&now, &result2);
-
result2.tm_isdst = 0;
-
gettimeofday(&tv1, NULL);
-
for (i=0; i<M; ++i)
-
{
-
mktime(&result2);
-
}
-
gettimeofday(&tv2, NULL);
-
printf("TZ is NULL and isdst=0: %ums\n", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
-
}
-
-
// test3
-
{
-
struct tm result3;
-
localtime_r(&now, &result3);
-
result3.tm_isdst = -1;
-
gettimeofday(&tv1, NULL);
-
for (i=0; i<M; ++i)
-
{
-
mktime(&result3);
-
}
-
gettimeofday(&tv2, NULL);
-
printf("TZ is NULL and isdst=-1: %ums\n", (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)
-
{
-
mktime(&result4);
-
}
-
gettimeofday(&tv2, NULL);
-
printf("TZ is NULL and isdst undefined: %ums\n", (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);
-
result5.tm_isdst = 1;
-
gettimeofday(&tv1, NULL);
-
for (i=0; i<M; ++i)
-
{
-
mktime(&result5);
-
}
-
gettimeofday(&tv2, NULL);
-
printf("TZ is empty and isdst=1: %ums\n", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
-
}
-
-
// test6
-
{
-
struct tm result6;
-
localtime_r(&now, &result6);
-
result6.tm_isdst = 0;
-
gettimeofday(&tv1, NULL);
-
for (i=0; i<M; ++i)
-
{
-
mktime(&result6);
-
}
-
gettimeofday(&tv2, NULL);
-
printf("TZ is empty and isdst=0: %ums\n", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
-
}
-
-
// test7
-
{
-
struct tm result7;
-
localtime_r(&now, &result7);
-
result7.tm_isdst = -1;
-
gettimeofday(&tv1, NULL);
-
for (i=0; i<M; ++i)
-
{
-
mktime(&result7);
-
}
-
gettimeofday(&tv2, NULL);
-
printf("TZ is empty and isdst=-1: %ums\n", (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)
-
{
-
mktime(&result8);
-
}
-
gettimeofday(&tv2, NULL);
-
printf("TZ is empty and isdst undefined: %ums\n", (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);
-
result9.tm_isdst = 1;
-
gettimeofday(&tv1, NULL);
-
for (i=0; i<M; ++i)
-
{
-
mktime(&result9);
-
}
-
gettimeofday(&tv2, NULL);
-
printf("TZ is Asia/Shanghai and isdst=1: %ums\n", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
-
}
-
-
// test10
-
{
-
struct tm result10;
-
localtime_r(&now, &result10);
-
result10.tm_isdst = 0;
-
gettimeofday(&tv1, NULL);
-
for (i=0; i<M; ++i)
-
{
-
mktime(&result10);
-
}
-
gettimeofday(&tv2, NULL);
-
printf("TZ is Asia/Shanghai and isdst=0: %ums\n", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
-
}
-
-
// test11
-
{
-
struct tm result11;
-
localtime_r(&now, &result11);
-
result11.tm_isdst = -1;
-
gettimeofday(&tv1, NULL);
-
for (i=0; i<M; ++i)
-
{
-
mktime(&result11);
-
}
-
gettimeofday(&tv2, NULL);
-
printf("TZ is Asia/Shanghai and isdst=-1: %ums\n", (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)
-
{
-
mktime(&result12);
-
}
-
gettimeofday(&tv2, NULL);
-
printf("TZ is Asia/Shanghai and isdst undefined: %ums\n", (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_usec-tv1.tv_usec)/1000);
-
}
- }