复制存在一个问题
块小了用movdqa快, 大了用movntdq快
不知道如何判断
大体规则为:
当源内存块 + 目标内存块 < L2 cache size, 使用movdqa,这是写操作主要在 L2 cache 中进行,当然RAM 也会同步更新,但 L2 cache 几乎不会发生换入换出操作。
当源内存块 + 目标内存块 > L2 cache size, 如果使用movdqa,L2 cache 经常发生换入换出操作,效率很低。这时使用写透方式,直接更新RAM 而不更新L2 cache 有较好的性能。 :)
我也知道这么做
你如何获得L2 Cache大小?
回复 22# 的帖子
用 CPUID 指令啊。。。我的 HugeCalc.ini 中的信息都是这么来的。 :)
我也知道用那个啊
不过,似乎CPUID里的L2信息不同的CPU其表达是不同的
我在别的帖子里求过例程
没有多少人回应
你有详细做法? 幸运的是,我去年曾经写过获取CPU信息的代码,这里一并贡献出来,下面的代码仅列出获取CPU Cache size 的代码,通过getCacheSize 函数可得到Intel或者AMD Cpu L2 cache2的大小。typedef struct _cpuReg
{
DWORD eax;
DWORD ebx;
DWORD ecx;
DWORD edx;
}CPU_REG;
typedef unsigned long DWORD;
typedef unsigned char BYTE;
typedef struct _cpuInfo
{
DWORD version;
DWORD featureID;
DWORD extFeatureID;
DWORD L1_inst_cache;
DWORD L1_data_cache;
DWORD L2_cache;
DWORD brandIdx;
char vendor;
char brand;
char name;
char type;
char family;
char model;
char stepping;
char support_MMX;
char support_SSE;
char support_SSE2;
char support_SSE3;
char no;
}CPU_INFO;
void getIntelCPUCacheSize(CPU_INFO *p)
{
CPU_REG cpuReg;
BYTE cacheDesTab;
BYTE *pt;
int i,idx;
//---------------------
idx=0;
CPUID(2,&cpuReg);
for (i=0;i<4;i++)
{
switch(i)
{
case 0: pt=(BYTE *)(&(cpuReg.eax)); break;
case 1: pt=(BYTE *)(&(cpuReg.ebx)); break;
case 2: pt=(BYTE *)(&(cpuReg.ecx)); break;
case 3: pt=(BYTE *)(&(cpuReg.edx)); break;
}
if ( (pt & 128) ==0)
{
if (pt !=0)
cacheDesTab=pt;
if (pt !=0)
cacheDesTab=pt;
if (pt !=0)
cacheDesTab=pt;
if (pt !=0)
cacheDesTab=pt;
}
}
for (i=0;i<idx;i++)
{
BYTE flag;
flag= cacheDesTab;
switch (flag)
{
case 6: p->L1_inst_cache=8; break;
case 8: p->L1_inst_cache=16; break;
case 0x0a:p->L1_data_cache=8; break;
case 0x0c:p->L1_data_cache=16; break;
case 0x2c:p->L1_data_cache=32; break;
case 0x30:p->L1_inst_cache=32; break;
case 0x41:p->L2_cache =128; break;
case 0x42:p->L2_cache =256; break;
case 0x43:p->L2_cache =512; break;
case 0x44:p->L2_cache =1024; break;
case 0x45:p->L2_cache =2048; break;
case 0x66:p->L1_data_cache=8; break;
case 0x67:p->L1_data_cache=16; break;
case 0x68:p->L1_data_cache=32; break;
case 0x70:
if ( p->L1_inst_cache==0 ) //have not been set
p->L1_inst_cache=12;
break;
case 0x71:
if ( p->L1_inst_cache==0 ) //have not been set
p->L1_inst_cache=16;
break;
case 0x72:
if ( p->L1_inst_cache==0 ) //have not been set
p->L1_inst_cache=32;
break;
case 0x78:p->L2_cache=1024; break;
case 0x79:p->L2_cache=128; break;
case 0x7A:p->L2_cache=256; break;
case 0x7B:p->L2_cache=512; break;
case 0x7C:p->L2_cache=1024; break;
case 0x7D:p->L2_cache=2048; break;
case 0x82:p->L2_cache=256; break;
case 0x83:p->L2_cache=512; break;
case 0x84:p->L2_cache=1024; break;
case 0x85:p->L2_cache=2048; break;
case 0x86:p->L2_cache=512; break;
case 0x87:p->L2_cache=1024; break;
}
}
}
void getAMDCPUCacheSize(CPU_INFO *p)
{
DWORD maxCPUFunction;
CPU_REG cpuReg;
//----------------------------
CPUID(0x80000000,&cpuReg);
maxCPUFunction=cpuReg.eax;
if (maxCPUFunction>=0x80000005)
{
CPUID(0x80000005,&cpuReg);
/*
ECX 31:24 L1DcSize. L1 data cache size in KB.
EDX 31:24 L1IcSize. L1 instruction cache size KB.
*/
p->L1_data_cache= (cpuReg.ecx >> 24);
p->L1_inst_cache= (cpuReg.edx >> 24);
}
if (maxCPUFunction>=0x80000006)
{
CPUID(0x80000006,&cpuReg);
//ECX 31:16 L2Size. L2 cache size in KB.
p->L2_cache = (cpuReg.ecx >> 16);
}
}
void getCacheSize(CPU_INFO *p)
{
CPU_REG cpuReg;
BYTE cacheDesTab;
BYTE *pt;
int i,idx;
memset(cacheDesTab,0,sizeof(cacheDesTab));
p->L1_data_cache=0;
p->L1_inst_cache=0;
p->L2_cache=0;
if (strcmp(p->vendor,"GenuineIntel")==0)
{
getIntelCPUCacheSize(p);
}
else if ( strcmp(p->vendor,"AuthenticAMD")==0 )
{
getAMDCPUCacheSize(p);
}
else //for other CPU
{
}
} 补上 楼上漏掉的一个函数void CPUID(int no,CPU_REG *result)
{
_asm
{
push ebx
push esi
mov eax,no
mov esi,result
_emit 0x0f ; cpuid
_emit 0xa2
mov dword ptr ,eax
mov dword ptr ,ebx
mov dword ptr ,ecx
mov dword ptr ,edx
pop esi
pop ebx
}
} 首先谢谢你共享你的代码
其次诅咒万恶的Intel
最后你的函数还需要更新
缺少Core 2的信息 我清零的测试表明
在超越L2 Cache的边界的时候
两种不同做法的差别是很大的
超过50%的差异
另外,测试表明,并不是正好在L2 cache尺寸的边界发生变化
复制也许稍微不同,但是估计也会发生这种情况
即尺寸边界大于L2 Cache大小,但也绝不是L2 Cache +L1 Cache
这是我目前尚未得到答案的问题之一
你能得到解决的方法么?
附上清零的测试程序
我用的关于 Intel CPU spec 的手册是2007.5发布的,但依然没有关于Core 2 L2 cache 的spec,哪位有更新的spec,告诉我一声。 基于下面的两个原因,我不考虑使用 movntdq 指令,也不去花时间去尝试他。
1.使用 movntdq会造成兼容性问题。
2.我主要想设计一个速度一流的大数运算库,在做大数运算时,特别大的内存块复制并不常用,也非大数运算的瓶颈。
我的观点是有所为,有所不为,尽量集中精力做重要的工作,而不是广种薄收。