注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

widebright的个人空间

// 编程和生活

 
 
 

日志

 
 

gettimeofday 和32机器上的64位整型数uint64_t除法的性能问题对比测试  

2013-01-11 17:51:36|  分类: 程序设计 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |


//#include <winsock2.h>
//#include <ws2tcpip.h>

#include <iomanip>
#include <fstream>
#include <iostream>
#include <map>
#include <sstream>
#include <list>
#include <vector>
//
//#include <boost/shared_ptr.hpp>
//#include <boost/weak_ptr.hpp>

#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/timeb.h>
#include <time.h>


#include <Windows.h>

#include "Trace.h"

using namespace std;



int UpdateTimeString(char * outputTimeString, int size)
{
int writtenLen = 0;
struct timeb timebuffer;

#ifdef WIN32
uint64_t intervals;
FILETIME ft;
GetSystemTimeAsFileTime(&ft);
ULARGE_INTEGER ltime;
ltime.LowPart = ft.dwLowDateTime;
ltime.HighPart = ft.dwHighDateTime;

//timebuffer.millitm = (ltime.QuadPart / 10000 ) % 1000;
////970-01-01 00:00:00 +0000 (UTC) - 1, 1601 UTC = 11644473600
//timebuffer.time = ltime.QuadPart/10000000 - 11644473600;

ltime.QuadPart -= 116444736000000000;
timebuffer.time = ltime.QuadPart / 10000000;
timebuffer.millitm = (ltime.QuadPart % 10000000)/10000;

#else
ftime(&timebuffer);
#endif

static time_t lastTime = 0;
static char lastTimeString[32] = "";

if (timebuffer.time == lastTime) {
strcpy(outputTimeString, lastTimeString);
writtenLen += 20;
} else {
lastTime = timebuffer.time;
struct tm * now = localtime(&lastTime);
// strftime is about 7 times faster than snprintf
writtenLen += strftime(lastTimeString,32,"%Y-%m-%d %H:%M:%S.",now);
strcpy(outputTimeString, lastTimeString);
}

int a = timebuffer.millitm / 100;
int b = timebuffer.millitm % 100;
outputTimeString[writtenLen] = '0' + a;
outputTimeString[writtenLen+1] = '0' + b / 10;
outputTimeString[writtenLen+2] = '0' + b % 10;
outputTimeString[writtenLen+3] = '\0';
writtenLen +=3;

return writtenLen;
}



int UpdateTimeString2(char * outputTimeString, int size)
{
int writtenLen = 0;
struct timeb timebuffer;

#ifdef WIN32
uint64_t intervals;
FILETIME ft;
GetSystemTimeAsFileTime(&ft);

intervals = ((uint64_t) ft.dwHighDateTime << 32) | ft.dwLowDateTime;
intervals -= 116444736000000000;
timebuffer.time = intervals / 10000000;
//timebuffer.millitm = (intervals % 10000000)/10000;
timebuffer.millitm = (ft.dwHighDateTime/1000) % 1000;
#else
ftime(&timebuffer);
#endif

static time_t lastTime = 0;
static char lastTimeString[32] = "";

if (timebuffer.time == lastTime) {
strcpy(outputTimeString, lastTimeString);
writtenLen += 20;
} else {
lastTime = timebuffer.time;
struct tm * now = localtime(&lastTime);
// strftime is about 7 times faster than snprintf
writtenLen += strftime(lastTimeString,32,"%Y-%m-%d %H:%M:%S.",now);
strcpy(outputTimeString, lastTimeString);
}

int a = timebuffer.millitm / 100;
int b = timebuffer.millitm % 100;
outputTimeString[writtenLen] = '0' + a;
outputTimeString[writtenLen+1] = '0' + b / 10;
outputTimeString[writtenLen+2] = '0' + b % 10;
outputTimeString[writtenLen+3] = '\0';
writtenLen +=3;

return writtenLen;
}


int main (int, char**)
{

LARGE_INTEGER freq, t0, t1;
QueryPerformanceFrequency(&freq);
size_t number = 100000000;
int total_counter = 0;

char date[64];

QueryPerformanceCounter(&t0);
for (int i=0; i< number; i++) {
total_counter += UpdateTimeString2(date,64);
}
QueryPerformanceCounter(&t1);

int time2 = (((t1.QuadPart-t0.QuadPart)*1000000)/freq.QuadPart);
std::cout << "执行 " << number <<" 次, 耗时 " << time2 << " 微秒" << std::endl;

std::cout << total_counter;
//int a;
//cin >> a;
return 0;
}


gettimeofday 和32机器上的64位整型数uint64_t除法的性能问题对比测试 - widebright - widebright的个人空间
这个故意改成32位的整型数除法,可以看看红色那行的对比,左边的cpu占用的百分比。

 
gettimeofday 和32机器上的64位整型数uint64_t除法的性能问题对比测试 - widebright - widebright的个人空间
 


可以看看UpdateTimeString的函数的性能分析,对比一下,第二个UpdateTimeString2估计改成32 除法的计算。

在32位的机器上  uint64_t这种的除法运算是调用 微软提供的运行时库里面的_aulldiv  函数来实现的。通过测试的知道,这种 64位的整数除法比普通的32位数除法要慢 20倍以上,比strcpy复制连续20个字符串要慢 3倍.(这里其实时间字符串长度已经知道用memcpy性能更好?)。所以在32位的机器上还是要尽量避免使用64位整型数的使用才行,特别是这种除法操作。   gettimeofday这种返回的时间可能不需要很多除法操作了。但这个GetSystemTimeAsFileTime 的返回要计算肯定是要除法的了,不便于后续使用啊。

GetSystemTimeAsFileTime 这种时间函数是很快的,估计内部实现就是几个内存访问吧。 稍微几个除法的性能消耗就要比它花的时间要多了。  所以格式化时间戳的时候,单纯的cache这类gettimeofday函数的返回值效果不是很明显,关键是要减少格式化字符串时的snprinf之类的调用。像这个函数的实现的话,每秒才格式化一次,一秒之内就使用cache的,因为每秒这个格式化处理的字符串都是一样的。   这样都能减少 很多localtime 和 strtime之类的格式化开销了。



那个strcpy如果替换为memcpy的话,系统直接优化为5个32位整数的赋值,对应就是5个mov汇编指令。strcpy的话是个每个字符赋值的循环。memcpy好像是要比strcpy好快很多,看看cpu消耗由14%降到1.2%了。不过那个64位整数的除法好像没有什么办法优化一下啦? 那个才是主要的
gettimeofday 和32机器上的64位整型数uint64_t除法的性能问题对比测试 - widebright - widebright的个人空间
 




再把代码改一下,先转换一下类型成unsigned long再做除法可以避免一次64位的除法__aulldiv函数调用,要快一点。 另外转成unsigned long 类型要比 转成 long要快。类型转换要专门的汇编指令来做的,可能一开始个最后的数据都是unsigned的,少了一些转换? 同样下面用 unsigned int的 a b c也要比用int的要好。  最好的性能测试,好像普通的整数除法也是很慢啊,后面那个%100的地方也占20%几,__aulldiv 也不算太慢?  



int UpdateTimeString(char * outputTimeString, int size)
{
int writtenLen = 0;
struct timeb timebuffer;

#ifdef WIN32
uint64_t intervals;
FILETIME ft;
GetSystemTimeAsFileTime(&ft);
ULARGE_INTEGER ltime;
ltime.LowPart = ft.dwLowDateTime;
ltime.HighPart = ft.dwHighDateTime;

//timebuffer.millitm = (ltime.QuadPart / 10000 ) % 1000;
////970-01-01 00:00:00 +0000 (UTC) - 1, 1601 UTC = 11644473600
//timebuffer.time = ltime.QuadPart/10000000 - 11644473600;

ltime.QuadPart -= 116444736000000000;
timebuffer.time = ltime.QuadPart / 10000000;
// 先转成unsigned long类型,避免了一次 __aulldiv的64位整数除法操作
timebuffer.millitm = ((unsigned long)(ltime.QuadPart % 10000000))/10000;
#else
ftime(&timebuffer);
#endif

static time_t lastTime = 0;
static char lastTimeString[32] = "";

if (timebuffer.time == lastTime) {
//strcpy(outputTimeString, lastTimeString);
// memcpy 被优化为5个 mov指令的32位整数赋值,要比strcpy的
// 单字节循环要快很多
memcpy(outputTimeString, lastTimeString,20);
writtenLen += 20;
} else {
lastTime = timebuffer.time;
struct tm * now = localtime(&lastTime);
// strftime is about 7 times faster than snprintf
writtenLen += strftime(lastTimeString,32,"%Y-%m-%d %H:%M:%S.",now);
strcpy(outputTimeString, lastTimeString);
}

// 改为一次整数赋值可以让这个函数快5%
unsigned int a = timebuffer.millitm / 100;
unsigned int b = timebuffer.millitm % 100;
unsigned int c = b %10;
b /=10;
unsigned int d = (('0' + c) << 16) | (('0' + b) << 8 )| ('0' + a) ;
*(unsigned int *)(&outputTimeString[writtenLen]) = d;
writtenLen +=3;

return writtenLen;
}

gettimeofday 和32机器上的64位整型数uint64_t除法的性能问题对比测试 - widebright - widebright的个人空间
 
  评论这张
 
阅读(929)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017