liangbch 发表于 2008-4-30 15:28:08

原帖由 无心人 于 2008-4-30 15:16 发表 http://images.5d6d.net/dz60/common/back.gif
复制存在一个问题

块小了用movdqa快, 大了用movntdq快

不知道如何判断

大体规则为:
    当源内存块 + 目标内存块 < L2 cache size, 使用movdqa,这是写操作主要在 L2 cache 中进行,当然RAM 也会同步更新,但 L2 cache 几乎不会发生换入换出操作。
    当源内存块 + 目标内存块 > L2 cache size, 如果使用movdqa,L2 cache 经常发生换入换出操作,效率很低。这时使用写透方式,直接更新RAM 而不更新L2 cache 有较好的性能。

无心人 发表于 2008-4-30 16:48:30

:)

我也知道这么做

你如何获得L2 Cache大小?

gxqcn 发表于 2008-4-30 16:53:31

回复 22# 的帖子

用 CPUID 指令啊。。。
我的 HugeCalc.ini 中的信息都是这么来的。

无心人 发表于 2008-4-30 16:55:39

:)

我也知道用那个啊

不过,似乎CPUID里的L2信息不同的CPU其表达是不同的
我在别的帖子里求过例程
没有多少人回应

你有详细做法?

liangbch 发表于 2008-4-30 16:58:37

幸运的是,我去年曾经写过获取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
        {

        }
}

liangbch 发表于 2008-4-30 17:01:29

补上 楼上漏掉的一个函数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
        }
}

无心人 发表于 2008-4-30 17:10:27

首先谢谢你共享你的代码

其次诅咒万恶的Intel

最后你的函数还需要更新
缺少Core 2的信息

无心人 发表于 2008-4-30 17:18:19

我清零的测试表明
在超越L2 Cache的边界的时候
两种不同做法的差别是很大的
超过50%的差异

另外,测试表明,并不是正好在L2 cache尺寸的边界发生变化
复制也许稍微不同,但是估计也会发生这种情况

即尺寸边界大于L2 Cache大小,但也绝不是L2 Cache +L1 Cache
这是我目前尚未得到答案的问题之一

你能得到解决的方法么?

附上清零的测试程序

liangbch 发表于 2008-4-30 17:21:29

我用的关于 Intel CPU spec 的手册是2007.5发布的,但依然没有关于Core 2 L2 cache 的spec,哪位有更新的spec,告诉我一声。

liangbch 发表于 2008-4-30 17:30:16

基于下面的两个原因,我不考虑使用 movntdq 指令,也不去花时间去尝试他。
   1.使用 movntdq会造成兼容性问题。
   2.我主要想设计一个速度一流的大数运算库,在做大数运算时,特别大的内存块复制并不常用,也非大数运算的瓶颈。

我的观点是有所为,有所不为,尽量集中精力做重要的工作,而不是广种薄收。
页: 1 2 [3] 4
查看完整版本: B计划之大整数的内存复制