#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define DUMPCOPY for(i = 0; i < 65536; i++){\
destination = source;\
}
#define SMARTCOPY memcpy(destination, source ,65536);
int main(void)
{
char source, destination;
int i, j;
for(j = 0; j < 100; j++){
SMARTCOPY
// DUMPCOPY
}
return 0;
}
在DUMPCOPY方式下运行time ./a.out
real 0m0.333s
user 0m0.047s
sys 0m0.001s
在SMARTCOPY方式下运信time ./a.out
real 0m0.018s
user 0m0.010s
sys 0m0.001s
C专家编程中的解释:
之所以出现性能的下降,因为destination和source的大小正好是
cache容量的整数倍,且
cache行的填充使用的是一种优化
的算法:填充于同一
cache行的主存地址恰好是该
cache行大小的整数倍,所以只有地址的高位才会放入
cache行的标签中,
这样destiantion和source便遍不可能同时出现在
cache中,于是导致了性能的下降。
在DUMPCOPY方式下:destination 和source在使用同一
cache行的情况下,会导致每次对内存的引用都没发命中
cache,
使cpu的利用率大大下降,因为它不 得不等待常规的内存操作完成。
而在SMARTCOPY方式下:memcpy()函数经过特别优化来提高性能,它把先读取一个
cache行再对它进行写入这个循环分分解
开来,避免了上述问题。
上面的解释我看的不太明白,请大家帮我 分析一下性能下降的原因。谢谢!建议了解一下
cache 的结构,记忆中
cache 是n-set/n-way 结构吧,1个set 好像是 64 Byte吧
cache fill 行为至少需加载 1set 吧,memcpy的实现大概是这样的(用的当然是汇编代码):
for(i=0;i<65536;i+=8){
int temp; //temp其实是寄存器。
temp=source;
temp=source;
temp=source;
temp=source;
temp=source;
temp=source;
temp=source;
temp=source;
destination[--i]=temp;
destination[--i]=temp;
destination[--i]=temp;
destination[--i]=temp;
destination[--i]=temp;
destination[--i]=temp;
destination[--i]=temp;
destination[--i]=temp;
}
原帖由 xiaozhu2007 于 2007-10-20 22:11 发表http://bbs.chinaunix.net/images/common/back.gif
#include
#include
#include
#define DUMPCOPY for(i = 0; i < 65536; i++){\
destination = source;\
}
#define SMARTCOPY memcpy(destination, sourc ...
这个问题很难两三句话就讲清楚,但可以肯定的告诉lz,你看到的性能降低不是因为书上说的原因,除非你使用了书上提到的sparcCPU。这里简单介绍一下http://www.xmenwolverine.com:
首先抛开复杂的
cache结构,lz可以把
cache想象成一个大
数组,
数组的每个元素为一个
cache
line,我们假定一个
cacheline为64 bytes。要把内存中的内容缓存到
cache这个
数组中,就需要一个索引,确定它存到哪一个
cacheline。CPU是用地址作为索引的,当然不是整个地址,而是地址的一部分。下图中,书上提到的SPARC使用了地址的高几位作为索引,而大部分架构使用地址的中间几位作为索引。现在就可以看出为什么sparc上这种方式性能低下了。
当程序中使用到
数组时,由于
数组地址是连续的,那么
数组每个元素地址的高几位都是相同的,它们通通对应
cache中同一个
cacheline。我们假设地址的高4位作为索引(再假设对于source这个
数组,它地址的高4位是0011)。那么当程序顺序扫描
数组时,cpu先读入64bytes,放到第3个
cache
line中,go on。当读到第65个字节时,CPU再次读入64 bytes,然后把第3个
cacheline清空,把新的数据放进去……反复如此。这样,整个source
数组在同一时刻就只有64bytes数据在
cache中,每读入新的64bytes数据,就要把旧的清空,新的放入。这样反复的访存效率是很低下的,
cache也没充分利用。并且这里dest
数组是和source
数组紧临的,也就是说source和dest
数组地址的高几位都相同,它们都对应同一个
cacheline!
如果用地址的中间几位作为索引,由于是低位地址,
数组的不同部分它们通常是不同的。这样同一个
数组的的不同部分就可以对应到
cache中不同的
cacheline去,那么source
数组就可以被整个放到
cache中去,而不是读64
byte新数据就把64bytes老数据冲掉了。减少了
cache的“颠簸”。
(当然,这里举的例子可能不恰当,如果仅仅用4 bit做索引,而
cache line又只有64bytes的话,
cache显然太小了。而且4位做索引,中间几位通常也都是相同的。但如果用中间10bit做索引,
数组不同部分显然索引就不一样了。这里为了方便讲解,用了4bit。具体的规范,应该查所用cpu的
cache规范。)
lz这里看到的性能不同,是因为memcpy用了movsb这条指令做拷贝,性能当然比笨循环的方式高。当然还有库函数针对
cacheline对齐做的一些优化等等
备注一下:实际上index索引的是组,组里有很多
cache line,index确定内存对应哪个组后,由偏移寻址对应的
cacheline。
[ 本帖最后由 zx_wing 于 2007-10-21 22:26 编辑]此外上面举例中关于
cache的用语都是不正规的,只是为了说明问题简化而已。为了避免一些专业朋友给我纠正用语,还是先说了好。免得后面又来讨论
cache结构,麻烦又跑题:mrgreen:不错,赞一个,我认为4楼已经把
cache说得很明白了解释的不错,补充一个n-way的理解
http://blog.chinaunix.net/u1/43233/showart_339984.html回复 #4 zx_wing的帖子谢谢,讲的很好,明白 了,继续学下下呵呵回复 #4 zx_wing 的帖子还有点问题,
1。就是memcpy()函数你说的由于使用了movsb指令,所以效率比较高,根据3楼兄弟的理解,是不是因为memcpy()函数在每次循环中拷贝了8个字符,而且是通过寄存器来缓存而不是
cache,所以它的效率更高。
2。我不太熟悉
cache缓存的过程,就按上面的DUMPCOPY方式举个例子,在从source
数组拷贝一个字符给destination的过程中,是不是首先存内存中读一个字符,然后放入
cache缓存的一个
cache行中,然后当下一个从source过来的数据再次要把数据写
求教-谁能提供ntohl htonl 的函数源码
入到该
cache行中时,此时
cache把这一行原先缓存的数据发送到destination
数组中,再在该
cache行中放入新的数据,过程是不是这样的?还有
cache是怎么知道要把缓存http://www.51mingyu.com/的
cache行发送到destionation的某个位置上呢(
cache知道destination的地址吗)?
C专家编程上写的,
cache主要有两种类型,一种是全写法:就是发往目的地址的同时保存到
cache中;令一种是写回法,就是发往目的地址数据的时候,先不发往目的地址对应的内存,而是先写入
cache中对应的一个
cache行,当下一次内存再次往这个
cache行写数据的时候,就把原先在该行缓存的数据写入内存,然后缓存新的数据。
我想根据书上理解的,我的
cache应该是采取写回法的方式吧?!
3。呵呵,我基础不好,能给我说说,在数据复制的过程中,cpu,寄存器,内存,和
cache它们之间是怎么相互合作完成这个过程的?以及它们各自的作用是什么?
谢谢!!!!!!!!!!:)回复 #9 xiaozhu2007的帖子呵呵,lz这些问题,说实话,问的太宽了。不容易说清楚,也不容易说严谨。我只能简单说一下。
1.在x86中,memcpy确实是使用movs指令簇(这里b是个后缀,表示一次拷贝的字节数,也可能是w、d、q)。它之所以快,是因为你只需要指定source地址和dest地址,拷贝工作就由硬件为你完成了。在现代cpu中,只要涉及到了访问内存,就离不开
cache,没有寄存器直接和内存打交道的说法,都要通过
cache(只有一种例外,就是写操作的not-write-allocate)。一句话,CPU只和寄存器和
cache打交到,
cache和物理内存的交互、同步都是北桥中的内存控制器做的(限于intel的CPU,amd的也有类似的机制)。在实际硬件中,cpu都以
cacheline为单位读入数据,
cache
line长度一般都大于8个字节,所以即使你只操作了一个字节的数据,它还是会读入一个
cacheline长度的数据,只是多于的没用到而已。所以你这里的8个字节说法不成立。当然,3楼的兄台演示的“循环展开”确实是一种优化的方法,这里就不多讨论了。
2.上面说了cpu只和
cache打交道,并不和实际的内存打交道。就用你的程序例子来解释你的第二个问题,它的流程是这样的:
从source第一字节开始,读入source(一次读一个
cache line长度),放入对应的
cache line中-------> 向dest
数组写数据,写到dest
数组对应的
cacheline中(从dest第一字节开始)
-------->根据
cache的策略同步回物理内存---------->反复
这里
cache的策略就是lz提到的两种方法。一个叫write-through(直写),一个叫write-back(写回)。对于前者,cpu直接把dest中
cacheline的内容写到内存中的dest
数组去。对于后者,尽量推迟将
cache
line同步内存中的时间,通常只在该行
cacheline需要被新的内容占用时才同步回内存。现代cpu通常采用write-back,但在un-cacheable的内存上(即该内存不能被
cache,通常是MMIO空间)使用write-through。地址到
cacheline的转换类似于hash表,文字很难说清楚,得画图,lz想了解应查阅相关资料。
(注意,上面举例画的流程图是以write-allocate举例的,也就是写前先写到
cache中,然后同步到内存。对于non-write-allocate,没有中间那个步骤,数据直接从source
数组对应的
cacheline同步到内存中。
3.寄存器只是cpu做运算使用的工具,通常需要先把内存中的内容搬到寄存器中,在寄存器中运算完了再写回内存(当然,它们中间就是上面的
cache)。
呵呵,lz问的这些不是基础不好,我觉得你问的深了。上面大概介绍了下过程,但实际上中间很多细节都没讲到,因为太多太多,打字累啊。我建议lz现在先对它有个感性认识就好了,需要的时候再阅读专门的资料深入学习。论坛只能让你知道个大概,不能让你知道细节。
分享到:
相关推荐
Java连接Cache数据库主要涉及到的是如何使用Java编程...以上就是关于"java连接cache数据库说明,数据库驱动,cache可视化工具"的主要知识点。理解并掌握这些内容,将有助于你在Java项目中成功地集成和操作Cache数据库。
### MIPS Cache指令详解 在深入探讨MIPS处理器的Cache指令之前,我们首先简要回顾一下MIPS架构的特点以及Cache在其中扮演的角色。MIPS(Microprocessor without Interlocked Pipeline Stages)是一种精简指令集...
文档中提到的“trace cache研究的几种变形说明”可能涵盖不同的优化策略,例如: - **动态Trace Cache**:根据程序运行情况动态调整大小和结构,以适应各种工作负载。 - **混合Trace Cache**:结合传统的指令缓存...
### 参数说明 #### 1. `string key` - **含义**:用于唯一标识缓存项的字符串键。 - **示例**:`"ds"`,这个字符串可以是任何有意义的名称,只要能够区分不同的缓存项即可。 #### 2. `object value` - **含义**:...
标题"jdbc连接cache的demo及jar包,自己备份.rar"指出这是一个关于使用JDBC(Java Database Connectivity)连接Cache数据库的示例项目,其中包含了必要的jar包,并且用户已经将其作为个人备份保存。这里的“Cache”...
赠送jar包:cache-api-1.1.1.jar; 赠送原API文档:cache-api-1.1.1-javadoc.jar; 赠送源代码:cache-api-1.1.1-sources.jar;...人性化翻译,文档中的代码和结构保持不变,注释和说明精准翻译,请放心使用。
- Driver模块设计说明:解释了控制机构的驱动模块如何控制Cache的操作,如读写信号的生成、命中/缺失的判断等。 这个实验旨在帮助学生掌握直接相联Cache的设计与实现,通过实际操作加深对Cache工作原理的理解,...
从提供的文件内容来看,我们可以提取以下关于Cache数据库的知识点: 1. Cache数据库基础概念:Cache是InterSystems公司开发的一个高性能的对象数据库,适合处理大量数据和复杂数据结构,通常用于医疗、金融等行业的...
在本文中,我们将讨论Cache的设计,特别是针对一级Cache的考虑点和优化策略。一级Cache因其较高的命中率,通常对CPU性能有显著影响。在流水线CPU架构中,数据和指令的访问并行处理是关键,因为它们分别在流水线的...
Cache 模拟器代码说明: 1. Cache 模拟器使用 newarray 二维数组模拟 Cache 2. 在直接映射和全相连映射中,newarray[index][0] 用来表示 Cache 中 index 对应记录的有效位,newarray[index][1] 代表 Cache 中 ...
DB Cache插件只缓存数据库,节省了空间,就像插件作者在说明这款插件是所说的:“你听说过WP-Cache或者WP Super Cache吧,它们可以加快数据空间的加载速度,那么,忘掉它们吧!DB Cache将更快的、并节省空间,CPU的...
压缩包中的“部署说明和代码.txt”可能包含了示例代码。通常,连接Cache数据库的C#代码如下: ```csharp using System.Data.Odbc; // 创建ODBC连接字符串 string connectionString = "Driver={InterSystems Cache ...
这个版本2.4.2的压缩包包含了ngx_cache_purge模块的所有源代码及相关文件,以便开发者在自己的Nginx环境中集成和使用。 Nginx是一款高性能、轻量级的Web服务器和反向代理服务器,广泛应用于互联网服务。其内置的...
二、设置说明 在 Supercache 的设置中,有多个参数需要注意: * Cache page size:缓存页大小,默认为 32K。大值会增加碎片,小值增加开销。推荐值为 64K。 * Cache size:缓存大小,默认为 128M,指定分配给 ...
此外,还可以通过查询`v$sysstat`视图中的统计数据来获取更多关于SQL解析的信息: ```sql SELECT name, value FROM v$sysstat WHERE name LIKE 'parsecount%'; ``` 如果发现`parsecount total`的值较高,那么...
《SuperCache5.0超级缓存:提升系统性能的秘密武器》 在当今信息化时代,计算机系统的性能优化成为了每个用户关注的焦点。SuperCache5.0超级缓存是一款针对这一需求而设计的专业软件,旨在通过优化硬盘读写速度,...
在实际使用`diskcache`时,开发者可以按照`README`中的说明安装库,然后导入并使用其提供的类和方法来创建和管理缓存。例如,可能有如`diskcache.Cache`这样的主要类,以及`get`、`set`、`delete`等操作方法。通过...
PrimoCache3.0.2+永久60天+免PE重置(x86.x64),亲测(win7 x86,x64 win10 x64,其他未测,理论可用),一键恢复60天试用状态,不用重启进PE这么麻烦。使用方法见文件中的说明文档,需要说明的是,程序运行需要...