计算机系统(2) 实验五 Cache实验

简介: 计算机系统(2) 实验五 Cache实验

一、实验目标:


了解Cache对系统性能的影响


二、实验环境:


个人电脑(Intel CPU)

Fedora 13 Linux 操作系统


三、实验内容与步骤


编译并运行程序A,记录相关数据。

不改变矩阵大小时,编译并运行程序B,记录相关数据。

改变矩阵大小,重复1和2两步。

通过以上的实验现象,分析出现这种现象的原因。

程序A:

#include <sys/time.h> 
#include <unistd.h> 
#include <stdlib.h>
#include <stdio.h> 
int main(int argc,char *argv[]) 
{
    float *a,*b,*c, temp;
    long int i, j, k, size, m;
    struct timeval time1,time2; 
    if(argc<2) { 
        printf("\n\tUsage:%s <Row of square matrix>\n",argv[0]); 
        exit(-1); 
    } //if
    size = atoi(argv[1]);
    m = size*size; 
    a = (float*)malloc(sizeof(float)*m); 
    b = (float*)malloc(sizeof(float)*m); 
    c = (float*)malloc(sizeof(float)*m); 
    for(i=0;i<size;i++) { 
        for(j=0;j<size;j++) { 
            a[i*size+j] = (float)(rand()%1000/100.0); 
            b[i*size+j] = (float)(rand()%1000/100.0); 
        } 
    }
    gettimeofday(&time1,NULL);
    for(i=0;i<size;i++) { 
        for(j=0;j<size;j++)  {
            c[i*size+j] = 0; 
            for (k=0;k<size;k++) 
                c[i*size+j] += a[i*size+k]*b[k*size+j];
        }
    }
    gettimeofday(&time2,NULL); 
    time2.tv_sec-=time1.tv_sec; 
    time2.tv_usec-=time1.tv_usec; 
    if (time2.tv_usec<0L) { 
        time2.tv_usec+=1000000L; 
        time2.tv_sec-=1; 
    } 
    printf("Executiontime=%ld.%06ld seconds\n",time2.tv_sec,time2.tv_usec); 
    return(0); 
}//main

程序B:

#include <sys/time.h> 
#include <unistd.h> 
#include <stdlib.h>
#include <stdio.h> 
int main(int argc,char *argv[]) 
{
    float *a,*b,*c, temp;
    long int i, j, k, size, m;
    struct timeval time1,time2; 
    if(argc<2) { 
        printf("\n\tUsage:%s <Row of square matrix>\n",argv[0]); 
        exit(-1); 
    } //if
    size = atoi(argv[1]);
    m = size*size; 
    a = (float*)malloc(sizeof(float)*m); 
    b = (float*)malloc(sizeof(float)*m); 
    c = (float*)malloc(sizeof(float)*m); 
    for(i=0;i<size;i++) { 
        for(j=0;j<size;j++) { 
            a[i*size+j] = (float)(rand()%1000/100.0); 
            c[i*size+j] = (float)(rand()%1000/100.0); 
        } 
    }
    gettimeofday(&time1,NULL);
    for(i=0;i<size;i++) {
        for(j=0;j<size;j++) {
            b[i*size+j] = c[j*size+i];
        }
    }
    for(i=0;i<size;i++) { 
        for(j=0;j<size;j++)  {
            c[i*size+j] = 0; 
            for (k=0;k<size;k++) 
                c[i*size+j] += a[i*size+k]*b[j*size+k];
        }
    }
    gettimeofday(&time2,NULL); 
    time2.tv_sec-=time1.tv_sec; 
    time2.tv_usec-=time1.tv_usec; 
    if (time2.tv_usec<0L) { 
        time2.tv_usec+=1000000L; 
        time2.tv_sec-=1; 
    } 
    printf("Executiontime=%ld.%06ld seconds\n",time2.tv_sec,time2.tv_usec); 
    return(0); 
}//main

四、实验结果及分析


  1. 用C语言实现矩阵(方阵)乘积一般算法(程序A),填写下表:


ef7561f975ea4eb3858e33bb06e01647.png

分析:


c14903d5ad344064958058c3281b4f47.png

aaafa666ce4c4b15bdbdcbf061d5676c.png

通过对代码进行分析,可以发现,代码中对数组中的每个元素进行的是以列为顺序的访问(行优先)


      for(i=0;i<size;i++) { 
          for(j=0;j<size;j++)  {
              c[i*size+j] = 0; 
              for (k=0;k<size;k++) 
                  c[i*size+j] += a[i*size+k]*b[k*size+j];
          }
    }

这有很差的空间局部性,也不能够高效借助Cache完成数据传递,效率很低。


程序B是基于Cache的矩阵(方阵)乘积优化算法,填写下表:


419f3d084f3b4b84bfc6a91be165cb88.png

分析:

d00174c306b045fc9bd61c041a77a8ba.png

612cd408a2ea45399f1dc5c71db72541.png


通过对代码进行分析,可以发现,代码中对数组中的每个元素进行的是以行为顺序的访问(列优先)

      for(i=0;i<size;i++) { 
          for(j=0;j<size;j++)  {
              c[i*size+j] = 0; 
              for (k=0;k<size;k++) 
                  c[i*size+j] += a[i*size+k]*b[j*size+k];
          }
      }

即按顺序对数组元素进行访问,有比较好的空间局部性,比较高效的借助了Cache进行数据传递。因此效率比较高。


  1. 优化后的加速比(speedup)


d89c6470673446b8805ec4effc800a99.png

加速比定义:加速比=优化前系统耗时/优化后系统耗时;

所谓加速比,就是优化前的耗时与优化后耗时的比值。加速比越高,表明优化效果越明显。

分析:


cdefab6aec15436e95ceae726f49f94c.png

可以看到,加速比随着数据量的增大而增大,即数据越多,利用Cache进行优化得越明显。这说明,Cache对大数据量下的优化效果比小数据量下好。


五、实验总结与体会


       通过本次实验,我借助两份代码,借助矩阵乘法对C语言程序运行中Cache对程序运行的影响进行了探究。可以看到,Cache对大数据下的程序运行有比较明显的优化效果。这说明具有良好空间局部性的代码运行起来往往较快,在实际编程中,我们也要尽量写出具有空间局部性的代码,以缩短程序运行时间。

相关文章
|
存储 编译器 C语言
【深入理解函数栈帧:探索函数调用的内部机制】
【深入理解函数栈帧:探索函数调用的内部机制】
281 0
|
存储 算法 大数据
算法设计与分析 实验三 回溯法求解地图填色问题(下)
算法设计与分析 实验三 回溯法求解地图填色问题
1093 0
算法设计与分析 实验三 回溯法求解地图填色问题(下)
|
9月前
|
Ubuntu Linux Shell
(已解决)Linux环境—bash: wget: command not found; Docker pull报错Error response from daemon: Get https://registry-1.docker.io/v2/: net/http: request canceled
(已成功解决)Linux环境报错—bash: wget: command not found;常见Linux发行版本,Linux中yum、rpm、apt-get、wget的区别;Docker pull报错Error response from daemon: Get https://registry-1.docker.io/v2/: net/http: request canceled
4489 69
(已解决)Linux环境—bash: wget: command not found; Docker pull报错Error response from daemon: Get https://registry-1.docker.io/v2/: net/http: request canceled
|
9月前
|
存储 设计模式 算法
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。行为型模式分为类行为模式和对象行为模式,前者采用继承机制来在类间分派行为,后者采用组合或聚合在对象间分配行为。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象行为模式比类行为模式具有更大的灵活性。 行为型模式分为: • 模板方法模式 • 策略模式 • 命令模式 • 职责链模式 • 状态模式 • 观察者模式 • 中介者模式 • 迭代器模式 • 访问者模式 • 备忘录模式 • 解释器模式
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
|
Ubuntu 网络协议 数据安全/隐私保护
【Ubuntu】sudo apt-get update 无法解析域名(亲测有效)
在Ubuntu 18.04系统中,用户在执行sudo apt-get update时遇到“无法解析域名‘ip’”的错误。经分析,问题源于之前设置的网络代理配置未完全清除。解决方案是找到并重命名/etc/apt/apt.conf.d下的proxy.conf文件,使其不再生效。操作后,sudo apt-get update命令恢复正常,问题得到完美解决。
3434 4
【Ubuntu】sudo apt-get update 无法解析域名(亲测有效)
|
设计模式 XML 存储
【二】设计模式~~~创建型模式~~~工厂方法模式(Java)
文章详细介绍了工厂方法模式(Factory Method Pattern),这是一种创建型设计模式,用于将对象的创建过程委托给多个工厂子类中的某一个,以实现对象创建的封装和扩展性。文章通过日志记录器的实例,展示了工厂方法模式的结构、角色、时序图、代码实现、优点、缺点以及适用环境,并探讨了如何通过配置文件和Java反射机制实现工厂的动态创建。
【二】设计模式~~~创建型模式~~~工厂方法模式(Java)
|
NoSQL Linux C语言
Linux gdb调试的时候没有对应的c调试信息库怎么办?
Linux gdb调试的时候没有对应的c调试信息库怎么办?
168 1
|
JavaScript Java 测试技术
基于SpringBoot+Vue+uniapp的儿童阅读系统的详细设计和实现(源码+lw+部署文档+讲解等)
基于SpringBoot+Vue+uniapp的儿童阅读系统的详细设计和实现(源码+lw+部署文档+讲解等)
105 0
回调函数在异步编程中的作用与实现方式
回调函数在异步编程中的作用与实现方式
|
Web App开发 前端开发
css小技巧——鼠标悬浮时切换图片
css小技巧——鼠标悬浮时切换图片
541 0