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

[讨论] 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. char support_MMX;
  27. char support_SSE;
  28. char support_SSE2;
  29. char support_SSE3;
  30. char no[32];
  31. }CPU_INFO;
  32. void getIntelCPUCacheSize(CPU_INFO *p)
  33. {
  34. CPU_REG cpuReg;
  35. BYTE cacheDesTab[32];
  36. BYTE *pt;
  37. int i,idx;
  38. //---------------------
  39. idx=0;
  40. CPUID(2,&cpuReg);
  41. for (i=0;i<4;i++)
  42. {
  43. switch(i)
  44. {
  45. case 0: pt=(BYTE *)(&(cpuReg.eax)); break;
  46. case 1: pt=(BYTE *)(&(cpuReg.ebx)); break;
  47. case 2: pt=(BYTE *)(&(cpuReg.ecx)); break;
  48. case 3: pt=(BYTE *)(&(cpuReg.edx)); break;
  49. }
  50. if ( (pt[3] & 128) ==0)
  51. {
  52. if (pt[0] !=0)
  53. cacheDesTab[idx++]=pt[0];
  54. if (pt[1] !=0)
  55. cacheDesTab[idx++]=pt[1];
  56. if (pt[2] !=0)
  57. cacheDesTab[idx++]=pt[2];
  58. if (pt[3] !=0)
  59. cacheDesTab[idx++]=pt[3];
  60. }
  61. }
  62. for (i=0;i<idx;i++)
  63. {
  64. BYTE flag;
  65. flag= cacheDesTab[i];
  66. switch (flag)
  67. {
  68. case 6: p->L1_inst_cache=8; break;
  69. case 8: p->L1_inst_cache=16; break;
  70. case 0x0a: p->L1_data_cache=8; break;
  71. case 0x0c: p->L1_data_cache=16; break;
  72. case 0x2c: p->L1_data_cache=32; break;
  73. case 0x30: p->L1_inst_cache=32; break;
  74. case 0x41: p->L2_cache =128; break;
  75. case 0x42: p->L2_cache =256; break;
  76. case 0x43: p->L2_cache =512; break;
  77. case 0x44: p->L2_cache =1024; break;
  78. case 0x45: p->L2_cache =2048; break;
  79. case 0x66: p->L1_data_cache=8; break;
  80. case 0x67: p->L1_data_cache=16; break;
  81. case 0x68: p->L1_data_cache=32; break;
  82. case 0x70:
  83. if ( p->L1_inst_cache==0 ) //have not been set
  84. p->L1_inst_cache=12;
  85. break;
  86. case 0x71:
  87. if ( p->L1_inst_cache==0 ) //have not been set
  88. p->L1_inst_cache=16;
  89. break;
  90. case 0x72:
  91. if ( p->L1_inst_cache==0 ) //have not been set
  92. p->L1_inst_cache=32;
  93. break;
  94. case 0x78: p->L2_cache=1024; break;
  95. case 0x79: p->L2_cache=128; break;
  96. case 0x7A: p->L2_cache=256; break;
  97. case 0x7B: p->L2_cache=512; break;
  98. case 0x7C: p->L2_cache=1024; break;
  99. case 0x7D: p->L2_cache=2048; break;
  100. case 0x82: p->L2_cache=256; break;
  101. case 0x83: p->L2_cache=512; break;
  102. case 0x84: p->L2_cache=1024; break;
  103. case 0x85: p->L2_cache=2048; break;
  104. case 0x86: p->L2_cache=512; break;
  105. case 0x87: p->L2_cache=1024; break;
  106. }
  107. }
  108. }
  109. void getAMDCPUCacheSize(CPU_INFO *p)
  110. {
  111. DWORD maxCPUFunction;
  112. CPU_REG cpuReg;
  113. //----------------------------
  114. CPUID(0x80000000,&cpuReg);
  115. maxCPUFunction=cpuReg.eax;
  116. if (maxCPUFunction>=0x80000005)
  117. {
  118. CPUID(0x80000005,&cpuReg);
  119. /*
  120. ECX 31:24 L1DcSize. L1 data cache size in KB.
  121. EDX 31:24 L1IcSize. L1 instruction cache size KB.
  122. */
  123. p->L1_data_cache= (cpuReg.ecx >> 24);
  124. p->L1_inst_cache= (cpuReg.edx >> 24);
  125. }
  126. if (maxCPUFunction>=0x80000006)
  127. {
  128. CPUID(0x80000006,&cpuReg);
  129. //ECX 31:16 L2Size. L2 cache size in KB.
  130. p->L2_cache = (cpuReg.ecx >> 16);
  131. }
  132. }
  133. void getCacheSize(CPU_INFO *p)
  134. {
  135. CPU_REG cpuReg;
  136. BYTE cacheDesTab[32];
  137. BYTE *pt;
  138. int i,idx;
  139. memset(cacheDesTab,0,sizeof(cacheDesTab));
  140. p->L1_data_cache=0;
  141. p->L1_inst_cache=0;
  142. p->L2_cache=0;
  143. if (strcmp(p->vendor,"GenuineIntel")==0)
  144. {
  145. getIntelCPUCacheSize(p);
  146. }
  147. else if ( strcmp(p->vendor,"AuthenticAMD")==0 )
  148. {
  149. getAMDCPUCacheSize(p);
  150. }
  151. else //for other CPU
  152. {
  153. }
  154. }
复制代码
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 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. mov eax,no
  8. mov esi,result
  9. _emit 0x0f ; cpuid
  10. _emit 0xa2
  11. mov dword ptr [esi+0],eax
  12. mov dword ptr [esi+4],ebx
  13. mov dword ptr [esi+8],ecx
  14. mov dword ptr [esi+12],edx
  15. pop esi
  16. pop ebx
  17. }
  18. }
复制代码
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 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-11-22 01:00 , Processed in 0.030982 second(s), 18 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

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