找回密码
 欢迎注册
楼主: 无心人

[讨论] B计划之大整数的内存复制

[复制链接]
发表于 2008-4-30 15:28:08 | 显示全部楼层
原帖由 无心人 于 2008-4-30 15:16 发表
复制存在一个问题

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

不知道如何判断


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

评分

参与人数 1威望 +2 贡献 +2 鲜花 +2 收起 理由
gxqcn + 2 + 2 + 2 长见识了。

查看全部评分

毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2008-4-30 16:48:30 | 显示全部楼层


我也知道这么做

你如何获得L2 Cache大小?
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2008-4-30 16:53:31 | 显示全部楼层

回复 22# 的帖子

用 CPUID 指令啊。。。
我的 HugeCalc.ini 中的信息都是这么来的。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2008-4-30 16:55:39 | 显示全部楼层


我也知道用那个啊

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

你有详细做法?
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2008-4-30 16:58:37 | 显示全部楼层
幸运的是,我去年曾经写过获取CPU信息的代码,这里一并贡献出来,下面的代码仅列出获取CPU Cache size 的代码,通过getCacheSize 函数可得到Intel或者AMD Cpu L2 cache2的大小。
  1. typedef struct _cpuReg
  2. {
  3.         DWORD eax;
  4.         DWORD ebx;
  5.         DWORD ecx;
  6.         DWORD edx;
  7. }CPU_REG;


  8. typedef unsigned long DWORD;
  9. typedef unsigned char BYTE;

  10. typedef struct _cpuInfo
  11. {
  12.         DWORD version;
  13.         DWORD featureID;
  14.         DWORD extFeatureID;
  15.         DWORD L1_inst_cache;
  16.         DWORD L1_data_cache;
  17.         DWORD L2_cache;
  18.         DWORD brandIdx;

  19.         char vendor[16];
  20.         char brand[64];
  21.         char name[64];

  22.         char type;
  23.         char family;
  24.         char model;
  25.         char stepping;
  26.        
  27.         char support_MMX;
  28.         char support_SSE;
  29.         char support_SSE2;
  30.         char support_SSE3;
  31.         char no[32];
  32. }CPU_INFO;

  33. void getIntelCPUCacheSize(CPU_INFO *p)
  34. {       
  35.         CPU_REG cpuReg;
  36.         BYTE cacheDesTab[32];
  37.         BYTE *pt;
  38.         int i,idx;
  39.         //---------------------
  40.         idx=0;
  41.         CPUID(2,&cpuReg);
  42.         for (i=0;i<4;i++)
  43.         {
  44.                 switch(i)
  45.                 {
  46.                 case 0: pt=(BYTE *)(&(cpuReg.eax)); break;
  47.                 case 1: pt=(BYTE *)(&(cpuReg.ebx)); break;
  48.                 case 2: pt=(BYTE *)(&(cpuReg.ecx)); break;
  49.                 case 3: pt=(BYTE *)(&(cpuReg.edx)); break;
  50.                 }

  51.                 if ( (pt[3] & 128) ==0)
  52.                 {
  53.                         if (pt[0] !=0)
  54.                                 cacheDesTab[idx++]=pt[0];
  55.                         if (pt[1] !=0)
  56.                                 cacheDesTab[idx++]=pt[1];
  57.                         if (pt[2] !=0)
  58.                                 cacheDesTab[idx++]=pt[2];
  59.                         if (pt[3] !=0)
  60.                                 cacheDesTab[idx++]=pt[3];
  61.                 }
  62.        
  63.         }
  64.        
  65.         for (i=0;i<idx;i++)
  66.         {
  67.                 BYTE flag;
  68.                 flag= cacheDesTab[i];
  69.                 switch (flag)
  70.                 {
  71.                 case 6:                p->L1_inst_cache=8;                break;
  72.                 case 8:                p->L1_inst_cache=16;        break;
  73.                 case 0x0a:  p->L1_data_cache=8;                break;
  74.                 case 0x0c:  p->L1_data_cache=16;        break;
  75.                 case 0x2c:  p->L1_data_cache=32;        break;
  76.                 case 0x30:  p->L1_inst_cache=32;        break;
  77.                 case 0x41:  p->L2_cache =128;        break;
  78.                 case 0x42:  p->L2_cache =256;        break;
  79.                 case 0x43:  p->L2_cache =512;        break;
  80.                 case 0x44:  p->L2_cache =1024;        break;
  81.                 case 0x45:  p->L2_cache =2048;        break;
  82.                 case 0x66:  p->L1_data_cache=8;        break;
  83.                 case 0x67:  p->L1_data_cache=16;        break;
  84.                 case 0x68:  p->L1_data_cache=32;        break;
  85.                
  86.                 case 0x70:
  87.                         if ( p->L1_inst_cache==0 )   //have not been set
  88.                                 p->L1_inst_cache=12;       
  89.                         break;

  90.                 case 0x71:
  91.                         if ( p->L1_inst_cache==0 ) //have not been set
  92.                                 p->L1_inst_cache=16;       
  93.                         break;

  94.                 case 0x72:
  95.                         if ( p->L1_inst_cache==0 ) //have not been set
  96.                                 p->L1_inst_cache=32;       
  97.                         break;

  98.                 case 0x78:  p->L2_cache=1024;        break;
  99.                 case 0x79:  p->L2_cache=128;        break;
  100.                 case 0x7A:  p->L2_cache=256;        break;
  101.                 case 0x7B:  p->L2_cache=512;        break;
  102.                 case 0x7C:  p->L2_cache=1024;        break;
  103.                 case 0x7D:  p->L2_cache=2048;        break;
  104.                 case 0x82:  p->L2_cache=256;        break;
  105.                 case 0x83:  p->L2_cache=512;        break;
  106.                 case 0x84:  p->L2_cache=1024;        break;
  107.                 case 0x85:  p->L2_cache=2048;        break;
  108.                 case 0x86:  p->L2_cache=512;        break;
  109.                 case 0x87:  p->L2_cache=1024;        break;
  110.                 }
  111.         }
  112. }


  113. void getAMDCPUCacheSize(CPU_INFO *p)
  114. {
  115.         DWORD maxCPUFunction;
  116.         CPU_REG cpuReg;
  117.         //----------------------------
  118.         CPUID(0x80000000,&cpuReg);
  119.         maxCPUFunction=cpuReg.eax;
  120.        
  121.         if (maxCPUFunction>=0x80000005)
  122.         {
  123.                 CPUID(0x80000005,&cpuReg);
  124.                 /*
  125.                 ECX 31:24 L1DcSize. L1 data cache size in KB.
  126.                 EDX 31:24 L1IcSize. L1 instruction cache size KB.
  127.                 */
  128.                 p->L1_data_cache= (cpuReg.ecx >> 24);
  129.                 p->L1_inst_cache= (cpuReg.edx >> 24);
  130.         }
  131.        
  132.         if (maxCPUFunction>=0x80000006)
  133.         {
  134.                 CPUID(0x80000006,&cpuReg);
  135.                 //ECX 31:16 L2Size. L2 cache size in KB.
  136.                 p->L2_cache = (cpuReg.ecx >> 16);
  137.         }
  138. }


  139. void getCacheSize(CPU_INFO *p)
  140. {
  141.         CPU_REG cpuReg;
  142.         BYTE cacheDesTab[32];
  143.         BYTE *pt;
  144.         int i,idx;
  145.        
  146.         memset(cacheDesTab,0,sizeof(cacheDesTab));
  147.         p->L1_data_cache=0;
  148.         p->L1_inst_cache=0;
  149.         p->L2_cache=0;

  150.         if (strcmp(p->vendor,"GenuineIntel")==0)
  151.         {
  152.                 getIntelCPUCacheSize(p);
  153.         }
  154.         else if ( strcmp(p->vendor,"AuthenticAMD")==0 )
  155.         {
  156.                 getAMDCPUCacheSize(p);
  157.         }
  158.         else //for other CPU
  159.         {

  160.         }
  161. }
复制代码
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2008-4-30 17:01:29 | 显示全部楼层
补上 楼上漏掉的一个函数
  1. void CPUID(int no,CPU_REG *result)
  2. {
  3.         _asm
  4.         {
  5.                 push ebx
  6.                 push esi
  7.                
  8.                 mov eax,no
  9.                 mov esi,result
  10.                
  11.                 _emit 0x0f                                        ; cpuid
  12.                 _emit 0xa2
  13.                
  14.                 mov dword ptr [esi+0],eax
  15.                 mov dword ptr [esi+4],ebx
  16.                 mov dword ptr [esi+8],ecx
  17.                 mov dword ptr [esi+12],edx
  18.                
  19.                 pop esi
  20.                 pop ebx
  21.         }
  22. }
复制代码
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 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
这是我目前尚未得到答案的问题之一

你能得到解决的方法么?

附上清零的测试程序
ZeroMemory.rar (1.24 KB, 下载次数: 2)
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2008-4-30 17:21:29 | 显示全部楼层
我用的关于 Intel CPU spec 的手册是2007.5发布的,但依然没有关于Core 2 L2 cache 的spec,哪位有更新的spec,告诉我一声。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2008-4-30 17:30:16 | 显示全部楼层
基于下面的两个原因,我不考虑使用 movntdq 指令,也不去花时间去尝试他。
   1.使用 movntdq  会造成兼容性问题。
   2.我主要想设计一个速度一流的大数运算库,在做大数运算时,特别大的内存块复制并不常用,也非大数运算的瓶颈。

我的观点是有所为,有所不为,尽量集中精力做重要的工作,而不是广种薄收。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
您需要登录后才可以回帖 登录 | 欢迎注册

本版积分规则

小黑屋|手机版|数学研发网 ( 苏ICP备07505100号 )

GMT+8, 2024-5-3 19:34 , Processed in 0.055504 second(s), 18 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表