CSAPP Lab4- PerfLab

news2024/11/27 18:25:41

代码优化 

typedef struct { 
    unsigned short red; /* R value */ 
    unsigned short green; /* G value */ 
    unsigned short blue; /* B value */ 
} pixel

图像用一维数组表示,第(i,j)个像素表示为I[RIDX(i,j,n)],n为图像的维数

#define RIDX(i,j,n) ((i)*(n)+(j))

旋转操作

void naive_rotate(int dim, pixel *src, pixel *dst) { 
    int i, j; 
    for(i=0; i < dim; i++) 
    for(j=0; j < dim; j++) 
        dst[RIDX(dim-1-j,i,dim)] = src[RIDX(i,j,dim)]; 
    return; 
} 

目标:使用代码优化技术使旋转操作运行的更快

平滑操作

void naive_smooth(int dim, pixel *src, pixel *dst) { 
    int i, j; 
    for(i=0; i < dim; i++) 
    for(j=0; j < dim; j++) 
        dst[RIDX(i,j,dim)] = avg(dim, i, j, src); /* Smooth the (i,j)thpixel */ 
    return; 
} 

目标:使用代码优化技术使平滑操作运行的更快

性能评判方法

CPE or Cycles per Element

如果一个函数使用C个周期去执行一个大小为N*N的图像,那么CPE=C/(N*N),因此CPE越小越好

如何定义函数

在kernel.c中有rotate的实现方法,我们需要添加自己的rotate实现,函数名自己命名,然后通过

void register_rotate_functions() { 
    add_rotate_function(&rotate, rotate_descr); 
    add_rotate_function(&my_rotate,my_rotate_descr);
} 

把自己实现的函数注册进去

编码规则

只能用ANSI C,不能用嵌入式汇编

不能修改测量时间的机制(CPE)

只能修改kernels.c,可以定义宏,全局变量,函数


旋转

在旋转过程中,源图像(src)的每一列被逆序复制到目标图像(dst)的每一行。因此,源图像的左上角(src[0])被复制到目标图像的左下角(dst[0]),源图像的第二列的顶部(src[dim])被复制到目标图像的第二行的底部(dst[1]),以此类推。

这是通过以下步骤完成的:

  1. 初始时,dst指针被移动到目标图像的底部(dst += (dim * dim - dim))。

  2. 然后,开始两层循环。外层循环按32像素的步长遍历源图像的列(i);内层循环遍历每列的所有像素(j)。

  3. 在内层循环中,源图像的每一列(src[i])被逆序复制到目标图像的对应行(dst[j])。这是通过将src的当前元素复制到dst的当前元素,然后递增src指针(src++)并递减dst指针(dst -= dim)实现的。这样,dst指针总是指向目标图像的上一行,而src指针总是指向源图像的下一列。

  4. 在外层循环的每次迭代结束时,src和dst指针都被调整,以便在下一次迭代中处理源图像的下一组32列和目标图像的下一组32行。

因此,这段代码实现了将源图像旋转90度并复制到目标图像的功能。

/*
 * rotate - Your current working version of rotate
 * IMPORTANT: This is the version you will be graded on
 */
char rotate_descr[] = "rotate: Current working version";
void rotate(int dim, pixel *src, pixel *dst)
{
    // naive_rotate(dim, src, dst);
    int i, j;
    dst += (dim * dim - dim); // dst指针被移动到目标图像的底部
    for (i = 0; i < dim; i += 32)
    {
        for (j = 0; j < dim; j++)
        {
            dst[0] = src[0];
            dst[1] = src[dim];
            dst[2] = src[2 * dim];
            dst[3] = src[3 * dim];
            dst[4] = src[4 * dim];
            dst[5] = src[5 * dim];
            dst[6] = src[6 * dim];
            dst[7] = src[7 * dim];
            dst[8] = src[8 * dim];
            dst[9] = src[9 * dim];
            dst[10] = src[10 * dim];
            dst[11] = src[11 * dim];
            dst[12] = src[12 * dim];
            dst[13] = src[13 * dim];
            dst[14] = src[14 * dim];
            dst[15] = src[15 * dim];
            dst[16] = src[16 * dim];
            dst[17] = src[17 * dim];
            dst[18] = src[18 * dim];
            dst[19] = src[19 * dim];
            dst[20] = src[20 * dim];
            dst[21] = src[21 * dim];
            dst[22] = src[22 * dim];
            dst[23] = src[23 * dim];
            dst[24] = src[24 * dim];
            dst[25] = src[25 * dim];
            dst[26] = src[26 * dim];
            dst[27] = src[27 * dim];
            dst[28] = src[28 * dim];
            dst[29] = src[29 * dim];
            dst[30] = src[30 * dim];
            dst[31] = src[31 * dim];
            src++;      // src指针指向源图像的下一列
            dst -= dim; // dst指针指向目标图像的上一行
        }
        // 源图像的下一组32列
        src += 31 * dim;
        // 目标图像的下一组32行
        dst += dim * dim + 32;
    }
}

平滑

smooth函数的目标是通过对每个像素及其邻近像素的平均值来“平滑”图像,因为它降低了像素与像素之间颜色的突变,使得图像的颜色变得更为均匀。其中涉及到处理图像边界(角落和边缘)的特殊情况,因为这些像素的邻近像素较少。对于图像的其他部分,smooth会计算每个像素及其8个邻居的平均值,并将该平均值分配给输出图像的相应像素。

/*
 * smooth - Your current working version of smooth.
 * IMPORTANT: This is the version you will be graded on
 */
char smooth_descr[] = "smooth: Current working version";
void smooth(int dim, pixel *src, pixel *dst)
{
    // naive_smooth(dim, src, dst);
    int i, j, myJ;

    // 处理四个角
    dst[0].red = (src[0].red + src[1].red + src[dim].red + src[dim + 1].red) >> 2;
    dst[0].blue = (src[0].blue + src[1].blue + src[dim].blue + src[dim + 1].blue) >> 2;
    dst[0].green = (src[0].green + src[1].green + src[dim].green + src[dim + 1].green) >> 2;

    i = dim * 2 - 1;
    dst[dim - 1].red = (src[dim - 2].red + src[dim - 1].red + src[i - 1].red + src[i].red) >> 2;
    dst[dim - 1].blue = (src[dim - 2].blue + src[dim - 1].blue + src[i - 1].blue + src[i].blue) >> 2;
    dst[dim - 1].green = (src[dim - 2].green + src[dim - 1].green + src[i - 1].green + src[i].green) >> 2;

    j = dim * (dim - 1);
    i = dim * (dim - 2);
    dst[j].red = (src[j].red + src[j + 1].red + src[i].red + src[i + 1].red) >> 2;
    dst[j].blue = (src[j].blue + src[j + 1].blue + src[i].blue + src[i + 1].blue) >> 2;
    dst[j].green = (src[j].green + src[j + 1].green + src[i].green + src[i + 1].green) >> 2;

    j = dim * dim - 1;
    i = dim * (dim - 1) - 1;
    dst[j].red = (src[j - 1].red + src[j].red + src[i - 1].red + src[i].red) >> 2;
    dst[j].blue = (src[j - 1].blue + src[j].blue + src[i - 1].blue + src[i].blue) >> 2;
    dst[j].green = (src[j - 1].green + src[j].green + src[i - 1].green + src[i].green) >> 2;

    // 处理四个边
    // 上
    i = dim - 1;
    for (j = 1; j < i; j++)
    {
        dst[j].red = (src[j].red + src[j - 1].red + src[j + 1].red + src[j + dim].red + src[j + 1 + dim].red + src[j - 1 + dim].red) / 6;
        dst[j].green = (src[j].green + src[j - 1].green + src[j + 1].green + src[j + dim].green + src[j + 1 + dim].green + src[j - 1 + dim].green) / 6;
        dst[j].blue = (src[j].blue + src[j - 1].blue + src[j + 1].blue + src[j + dim].blue + src[j + 1 + dim].blue + src[j - 1 + dim].blue) / 6;
    }

    // 下
    i = dim * dim - 1;
    for (j = i - dim + 2; j < i; j++)
    {
        dst[j].red = (src[j].red + src[j - 1].red + src[j + 1].red + src[j - dim].red + src[j + 1 - dim].red + src[j - 1 - dim].red) / 6;
        dst[j].green = (src[j].green + src[j - 1].green + src[j + 1].green + src[j - dim].green + src[j + 1 - dim].green + src[j - 1 - dim].green) / 6;
        dst[j].blue = (src[j].blue + src[j - 1].blue + src[j + 1].blue + src[j - dim].blue + src[j + 1 - dim].blue + src[j - 1 - dim].blue) / 6;
    }

    // 右
    for (j = dim + dim - 1; j < dim * dim - 1; j += dim)
    {
        dst[j].red = (src[j].red + src[j - 1].red + src[j - dim].red + src[j + dim].red + src[j - dim - 1].red + src[j - 1 + dim].red) / 6;
        dst[j].green = (src[j].green + src[j - 1].green + src[j - dim].green + src[j + dim].green + src[j - dim - 1].green + src[j - 1 + dim].green) / 6;
        dst[j].blue = (src[j].blue + src[j - 1].blue + src[j - dim].blue + src[j + dim].blue + src[j - dim - 1].blue + src[j - 1 + dim].blue) / 6;
    }

    // 左
    i = i - (dim - 1);
    for (j = dim; j < i; j += dim)
    {
        dst[j].red = (src[j].red + src[j - dim].red + src[j + 1].red + src[j + dim].red + src[j + 1 + dim].red + src[j - dim + 1].red) / 6;
        dst[j].green = (src[j].green + src[j - dim].green + src[j + 1].green + src[j + dim].green + src[j + 1 + dim].green + src[j - dim + 1].green) / 6;
        dst[j].blue = (src[j].blue + src[j - dim].blue + src[j + 1].blue + src[j + dim].blue + src[j + 1 + dim].blue + src[j - dim + 1].blue) / 6;
    }

    // 处理中间部分
    myJ = dim;  // 第二行的第一个元素

    for (i = 1; i < dim - 1; i++)
    {
        for (j = 1; j < dim - 1; j++)
        {
            myJ++;
            dst[myJ].red = (src[myJ - 1].red + src[myJ].red + src[myJ + 1].red + src[myJ - dim - 1].red + src[myJ - dim].red + src[myJ - dim + 1].red + src[myJ + dim - 1].red + src[myJ + dim].red + src[myJ + dim + 1].red) / 9;
            dst[myJ].green = (src[myJ - 1].green + src[myJ].green + src[myJ + 1].green + src[myJ - dim - 1].green + src[myJ - dim].green + src[myJ - dim + 1].green + src[myJ + dim - 1].green + src[myJ + dim].green + src[myJ + dim + 1].green) / 9;
            dst[myJ].blue = (src[myJ - 1].blue + src[myJ].blue + src[myJ + 1].blue + src[myJ - dim - 1].blue + src[myJ - dim].blue + src[myJ - dim + 1].blue + src[myJ + dim - 1].blue + src[myJ + dim].blue + src[myJ + dim + 1].blue) / 9;
        }

        // 跳过这一行的最后一个像素和下一行的第一个像素
        myJ += 2;
    }
}

运行时要将kernels.c文件中的以下三处修改为自己的信息

然后依次执行

make driver
./driver

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/551169.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Datacom-HCIE 02(10月26日更新)--含解析

单选题 1.[试题编号&#xff1a;189785] &#xff08;单选题&#xff09;如图所示&#xff0c;VTEP1上在BD20域内开启了ARP广播抑制功能&#xff0c;并且VTEP1通过 BGP EVPN路由学习到了PC2的ARP信息&#xff0c;则PC1发送的针对PC2的ARP请求&#xff0c;VIEP1在转发给VIEP2时…

sqli-labs Less-11,12

less-11(基于错误的POST型单引号字符型注入) sqlmap 1.使用bp抓包 2.保存为1.txt在本地&#xff0c;使用sqlmap查询数据库 sqlmap.py -r "C:\Users\wy199\Desktop\1.txt" --dbs 3.查询当前数据库的所有表 sqlmap.py -r "C:\Users\wy199\Desktop\1.txt"…

正点原子ALPHA开发板核心资源分析

目录 正点原子ALPHA开发板核心资源分析I.MX6ULL实物图对比SOC 主控芯片&#xff08;MCIMX6Y2CVM08AB&#xff09;NAND FLASHEMMCDDR3L 正点原子ALPHA开发板核心资源分析 I.MX6ULL实物图对比 I.MX6ULL NAND BTB 接口核心板资源图与 I.MX6ULL EMMC BTB 接口核心板资源图如上图&a…

安装ElasticSearch之前的准备工作jdk的安装

一.windows 下载jdk的软件 (1).进入jdk1.8官网 (2).根据电脑是32位还是64位按需下载 (3).点击下载之后就会跳转到Oracle账号登录界面 没有 Oracle账号的注册一下就可以了 下载好的jdk如下: 双击下一步下一步安装jdk 默认安装就可以了 配置环境变量 (1).电脑左下方设置选项 (2).…

UFT软件的安装与注意事项

安装包下载 UFT软件的安装包网上也有许多&#xff0c;这里我分享下我使用的--->UFT安装包 下载完成解压后进行安装。 要注意关闭杀毒软件&#xff0c;否则安装过程中某些组件可能会安装不上。 部分电脑在安装过程中出现以下提示&#xff0c;可以点击确定 然后我们查看桌面上…

学习open62541 --- [77] 修改String类型变量的注意点

对于String类型的节点&#xff0c;其值的类型是UA_String&#xff0c;在这篇文章中我们解释了UA_String的生成方法。 当我们修改String类型节点的值时&#xff0c;会事先准备一个UA_String变量&#xff0c;这时就会遇到一个选择&#xff1a;是否需要动态分配内存&#xff0c;即…

一种基于数值的横向相互作用

( A, B )---144*30*2---( 1, 0 )( 0, 1 ) 让网络的输入有144个节点&#xff0c;训练集AB各由12张二值化的图片组成&#xff0c;让A中每行有1个1&#xff0c;B中全是0&#xff0c;排列组合A &#xff0c;统计迭代次数的顺序。 前面实验已经表明对于A中每行只有1个1&#xff0c;…

虚幻or现实?堆区、栈区真实存在吗?是操作系统在骗你罢了...

文章目录 &#x1f490;专栏导读&#x1f490;文章导读&#x1f427;引例 &#x1f426;进程地址空间&#x1f426;虚拟地址与物理内存的联系&#x1f514;回答引例中的问题&#x1f513;写时拷贝 &#x1f426;虚拟地址存在的意义&#x1f513;malloc的本质 &#x1f490;专栏…

Lift, Splat, Shoot 论文学习

1. 解决了什么问题&#xff1f; LSS 在工业界具有非常重要的地位。自从 Tesla AI Day 上提出了 BEV 感知后&#xff0c;不少公司都进行了 BEV 工程化的探索。当前 BEV 下的感知方法大致分为两类&#xff1a; 自下而上&#xff1a;利用 transformer 的 query 机制&#xff0c;…

软考 软件设计师上午题设计模式概念类

设计模式分类 创建型设计模式 简单工厂模式 不符合开闭原则&#xff0c;因此没有列入23类模式里 对扩展开放对修改关闭 工厂方法模式 说穿了&#xff1a;系统开放一个接口&#xff08;拓展开放&#xff09;、不提供修改的接口&#xff08;修改关闭&#xff09;&#xff0c;…

基于html+css的图展示83

准备项目 项目开发工具 Visual Studio Code 1.44.2 版本: 1.44.2 提交: ff915844119ce9485abfe8aa9076ec76b5300ddd 日期: 2020-04-16T16:36:23.138Z Electron: 7.1.11 Chrome: 78.0.3904.130 Node.js: 12.8.1 V8: 7.8.279.23-electron.0 OS: Windows_NT x64 10.0.19044 项目…

使用贝壳物联控制led灯

1、完成esp8266 01S的固件刷机 1.1 使用刷机软件刷原生固件 esp8266 01S要使用标准固件1M&#xff08;主要是01S是8M&#xff09; 1.2 刷机接线方式 ttl直接连esp8266 接线&#xff1a; tts esp8266 3v3 ---》面包板高----》3.3 tx--------------…

BEVFormer 论文学习

1. 解决了什么问题&#xff1f; 3D 视觉感知任务&#xff0c;包括基于多相机图像的 3D 目标检测和分割&#xff0c;对于自动驾驶系统非常重要。与基于 LiDAR 的方法相比&#xff0c;基于相机图像的方法能够检测到更远距离的目标&#xff0c;识别交通信号灯、交通标识等信息。有…

[CTF/网络安全] 攻防世界 command_execution 解题详析

[CTF/网络安全] 攻防世界 command_execution 解题详析 ping命令ping命令的应用格式ping命令执行漏洞 ls命令cat命令姿势ping本地回环地址ping目录ping文件夹ping文件 Tips总结 题目描述&#xff1a;小宁写了个ping功能,但没有写waf,X老师告诉她这是非常危险的&#xff0c;你知道…

图【无向图】的创建与遍历

树&#xff1a;无回路 图&#xff1a;有回路 代码在最下面 邻接矩阵&#xff1a;重点&#xff1a;矩阵 &#xff08;一&#xff09;图的创建 存储方式 如图&#xff1a; 代码截图分析&#xff1a;顶点用一维数组存&#xff0c;边用两个点之间的值为0或1来表…

异地研发团队都使用哪些研发协同工具?盘点7类最主流的研发管理协同软件

产品研发场景下好用的协同办公软件有哪些&#xff1f;分享7类研发过程中主流的协同办公软件&#xff0c;比如项目管理协作与问题跟踪工具PingCode、代码托管与版本控制平台github、持续集成与持续部署&#xff08;CI/CD&#xff09;工具jinkens、文档协作与知识管理工具conflue…

【力扣周赛】第346场周赛

【力扣周赛】第346场周赛 6439. 删除子串后的字符串最小长度题目描述解题思路 6454. 字典序最小回文串题目描述解题思路 6441. 求一个整数的惩罚数题目描述解题思路 6439. 删除子串后的字符串最小长度 题目描述 描述&#xff1a;给你一个仅由 大写 英文字符组成的字符串 s 。…

Gradle ——Gradle安装与配置

目录 一、简介 二、功能和特点 三、安装 参考&#xff1a; Gradle_百度百科 Gradle 学习 ----Gradle 入门_你若不离不弃&#xff0c;我必生死相依的博客-CSDN博客 还有硬石科技的开源wifiAPP程序,没找到他们的码仓 一、简介 Gradle是一个基于Apache Ant和Apache Maven概念…

BPMN2.0 -条件序列流和默认序列流

序列流是流程中两个元素或者活动的连接器。在流程执行过程中访问一个元素之后,将继续执行素有的序列流,默认是并行的。传出的序列流将创建独立的并行执行路径。 顺序流需要有流程唯一的id,并引用存在的源与目标元素。 <sequenceFlow id="flow1" sourceRef=&qu…

vxe-table 对合并列的理解

行列对应关系 删除数据&#xff0c;只对一条数据进行分析 合并列代码&#xff08;_rowspan移除不影响&#xff0c;但是函数会eslint报红&#xff0c;正常运行&#xff09; 合并之后&#xff0c;从第一列开始&#xff0c;内容整体右移动&#xff0c;标题内容不对应 解决内容右移…