AI加速(八)

2023-11-05

大家好啊,我是董董灿。

前文回顾:

AI加速(一)| GPU为什么这么牛?

AI加速(二)| 计算机存储和计算的分离

AI加速(三)| 每条指令都是流水线的工人

AI加速(四)| 衣柜般的分层存储设计

AI加速(五)| 一个例子看懂流水——从指令到算法

AI加速(六)| 异构编程——性能不够,“外挂“来凑?

AI加速(七)| 存算一体——冰箱里面炒鸡蛋?

AI加速系列写了7篇文章了,基本都从硬件的角度介绍了程序加速的手段和方法。

其实现在想想,这个系列叫AI加速不是很恰当,因为很多加速方法并非仅仅在AI计算中会用到,在很多科学计算和程序设计中,都会用到。可以说是一些通用的计算机程序加速方法。

从这篇开始,会从软件以及AI本身的角度来介绍一些常用的AI加速方法。

循环展开

如果要我说一个最简单,最有效的,并且人人都能学会的程序优化方法,我估计会投票给Unrooling(译为:循环展开)。

循环展开,从名字就能看出来是什么意思:就是把一段循环代码展开来写。

听着简单,但具体怎么做呢?先举个简单的例子——

高斯年轻的时候,老师曾问他:从1加到100,结果是多少?高斯思考片刻后,给出了5050的答案,让老师大吃一惊。

这里也用这个例子,计算1到100的所有数的和。用C语言很容易写出下面的代码:这个写法很容易想出来:100个数相加,循环100次,每次累加一个数字,最终输出结果 sum = 5050。

#include "stdio.h"

int main() {
  int sum = 0;
  for (int i = 1; i <= 100; ++i) {
    sum = sum + i;
  }
  printf("sum = %d\n", sum);
  return 0;
}

这个写法很容易想出来:100个数相加,循环100次,每次累加一个数字,最终输出结果 sum = 5050。

那么,这段代码,如果用循环展开会怎么写呢?

#include "stdio.h"

int main() {
  int sum = 0;
  for (int i = 1; i <= 100; i+=4) {
    sum = sum + i;
    sum = sum + (i + 1);
    sum = sum + (i + 2);
    sum = sum + (i + 3);
  }
  printf("sum = %d\n", sum);
  return 0;
}

如上是循环展开的写法,我们把原来循环100次,每次循环加1个数的写法,写成了循环25次,每次循环加4个数。

从结果上看肯定是一致的,最终结果都是5050。但是两者的性能会有较大的差别。

性能验证

下面实际验证一下两种写法的性能。

为了更准确的获取到程序中数字累加的耗时,把100个数字的相加改为10000个数字相加。因为100个数字对于计算机来说太少了,两者的性能差别不大,不容易看出差别。

在我的笔记本上进行如下的测试,有以下代码,其中 gettimeofday函数用来获取时间戳。

#include "stdio.h"
#include <sys/time.h>
 
int main() {
  int sum = 0;
  struct timeval tv0, tv1;
  #if 0
  printf("do not use unrooling\n");
  gettimeofday(&tv0, NULL); 
  for (int i = 1; i <= 10000; ++i) {
    sum = sum + i;
  }
#else
  printf("use unrooling\n");
  gettimeofday(&tv0, NULL);
  for (int i = 1; i <= 10000; i+=4) {
    sum = sum + i;
    sum = sum + (i + 1);
    sum = sum + (i + 2);
    sum = sum + (i + 3);
  }
#endif
  gettimeofday(&tv1, NULL);
  printf("time = %ld\n", (tv1.tv_usec) - (tv0.tv_usec));
  printf("sum = %d\n", sum);
  return 0;
}

测试结果如下:

可以看到,使用循环展开后,10000个数的累加耗时为14微秒;不使用循环展开,10000个数的累加耗时为24微秒。

两者相差10us的耗时,大约相差40%的耗时!

这是很夸张的,要知道,在做程序性能优化时,如果能一次优化掉40%的耗时,几乎就算是一个很棒的优化手段了。(感兴趣的同学可以复制上面的代码实际测试一下)

为什么循环展开会有效呢

这和计算机的取指令以及缓存机制有关。

其性能加速的思想是:减少CPU读取指令的失败次数,也就是降低指令的Cache Miss

可能不太好理解,没关系,先看一个实际例子就懂了。

双11刚刚过去,你肯定买了不少的快递。假设你买了100件快递,并且这些快递已经放在了快递柜中一个个的小格子里了。

现在要去取快递,100件快递至少要开100次的快递柜门,才能把所有的快递取出来。

为什么这里说至少100次呢?因为很有可能因为某些原因一次不能成功开启快递柜的门,这些原因可能包括:

  • 走错快递柜

  • 输错取件码

  • 脑袋发蒙,快递没取出来又给关上了

连着取100个快递,谁能说得准会发生什么事情呢?

但不管怎样,在这个场景下,你需要一件一件地将快递拿出来,但由于上面几个原因,如果运气不好,就会出现好几次打不开快递柜门的情况。

那有没有办法优化一下这个问题呢?

当然有,那就是让快递员把多个快递放在同一个快递格子里。

如上图,比如每4个快递放在一个快递格子里,这样打开一个格子,就一定能取出4个快递。那至少开25次的快递柜门,就能把所有的快递取出来。这很显然,比100次的效率要高不少。

说回循环展开,100个快递就需要做100次循环,每个快递的取出就是循环里的一条加法指令。

如果不做循环展开,那就需要一个快递一个快递的取(相当于从指令内存iCache中一条指令一条指令的取),并且很有可能取完这一条指令后,并不能成功的取到下一条指令,从而发生Cache Miss现象。

但如果我们做了循环展开,相当于把相邻的4条指令绑定了,CPU做一次循环,看到里面一定有四条相邻的指令,就像我们打开快递柜门,里面一定有四个快递一样。

CPU取完第一条指令后,能很快地取到第二条指令,从而很快地取到第三条第四条指令。

在取完4条指令后,才会有可能发生Cache Miss 现象。连着取四个快递之后Miss一次,和每取一个快递,就Miss一次,浪费的时间肯定是不一样的。

循环展开能有效地降低指令的Cache Miss 。这个方法对于程序加速很有效,并且实施起来也很简单,如果你有兴趣,不防在自己的项目中试一试。

但是需要说明的是:现在的编译器可能会对你的代码自动做循环展开优化,因此,如果你想试试效果,建议编译的时候不要打开任何优化选项。

好啦,循环展开就写到这,欢迎持续关注AI加速系列。


所有文章均为作者原创,免费阅读,欢迎关注。专栏地址 >>>>>>>

https://blog.csdn.net/dongtuoc/category_11895363.htmlhttps://blog.csdn.net/dongtuoc/category_11895363.html



v v v v v v

**本文为作者原创,请勿转载,转载请联系作者。**
**点击下方卡片,关注我的公众号,有最新的文章和项目动态。**

v v v v v v

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

AI加速(八) 的相关文章

  • 为什么数组不可赋值? [复制]

    这个问题在这里已经有答案了 据我所知 C 标准禁止使用数组作为可修改的左值 即在赋值的左侧 int lhs 4 rhs 4 0 1 2 3 lhs rhs illegal 现在 我一直想知道为什么会这样 我可以看到上面的语句 以及写入数组的
  • 用于轻松动态反射的 C# 库

    是否有任何库 例如开源项目等 可以更轻松地使用复杂的反射 例如动态创建对象或类 检查实例等 Thanks 有一个LinFu http www codeproject com KB cs LinFuPart1 aspx可用的库除了反射之外还可
  • 从 Apache Kafka 中的主题删除消息

    所以我是 Apache Kafka 的新手 我正在尝试创建一个简单的应用程序 以便我可以更好地理解 API 我知道这个问题在这里被问了很多 但是如何清除存储在主题上的消息 记录 我看到的大多数答案都说要更改消息保留时间或删除并重新创建主题
  • C# While 循环与 For 循环?

    在 C 中 一个问题已经困扰我一段时间了 它的 While 和 For 循环之间的实际主要区别是什么 它只是纯粹的可读性吗 在 for 循环中本质上可以做的所有事情都可以在 while 循环中完成 只是在不同的地方 举这些例子 int nu
  • 获取进程的所有 DLL

    我想获取为给定进程加载的所有 dll 的列表 我目前正在使用 NET框架4 0 我知道有一个bug https connect microsoft com VisualStudio feedback details 546430 syste
  • 关于 FirstOrDefault 或 SingleOrDefault

    FirstOrDefault 或 SingleOrDefault 将返回什么类型的数据 假设我的查询返回 3 条记录 例如 empid ename salary 1 joy 1500 2 rob 4500 3 jen 6500 所以如果我们
  • 使用 c# 中的 c++ ref 中的引用从 C# 调用 C++ 代码错误

    所以在我的 c dll 文件中我得到了以下函数 DLL void GetUserPass char userName char passWord userName ceva passWord altceva 现在我想从 c 调用它 但它给了
  • 使用 OpenSSL 库在 C++ 中生成 SHA 哈希值

    如何使用以下命令生成 SHA1 或 SHA2 哈希值OpenSSL https openssl org图书馆 我搜索了谷歌 找不到任何函数或示例代码 从命令行来看 很简单 printf compute sha1 openssl sha1 您
  • 为什么这段代码不会产生编译错误?

    template
  • 在unity3D中显示数学方程

    我想使用它的 GUI 系统统一显示数学方程 有办法吗 我正在使用 C 语言在 Unity 中进行编程 如果我还可以使用 C 代码显示数学符号 这对我来说会很有用 谢谢 自 2016 年起 您可以使用TEXDraw https assetst
  • 我可以使用本机系统窗口作为父窗口使 JDialog 成为模式吗?

    我有一个 JDialog 窗口 我需要使其成为模态窗口 但父窗口不是 Java 窗口 而是本机 Windows 操作系统窗口 是否可以 不 你不能 您甚至无法不仅引用本机窗口 甚至无法引用运行在其他 JVM 中的 java 应用程序创建的窗
  • 使用 Swift 在 iOS 和 Android 之间共享核心代码

    我想要的是 使用 Swift 在 Android 和 iOS 之间共享非 UI 代码 问题 Android 具有 NDK 支持 允许您使用 Java 本机接口 JNI 运行 C 和 C 代码 不是 Objective C 我是一名Java程
  • vs2010 c++ 通过debug查看指针内容

    我正在使用 Vs2010 c 处理 2D 数组 我从一维指针开始 并使用操作 如下 class CMatrix void clear public int nRows int nCols short MyMat CMatrix CMatri
  • AllowUserToAddRows 不适用于 DataGridView 上的 List<> 数据源

    我有一个DataGridView与DataSource set to List
  • 使用客户端 hello 消息进行 TLS 协议检测

    我需要检测网络流量中的 https 数据包 到目前为止 我将所有 443 标记为 https 但我不想再在这种情况下使用端口信息 检查客户端问候消息是否足够 Check 22 and version info 0300 0301 or 03
  • 如何获取数字列的确切类型,包括。规模和精度?

    有没有办法知道列中列的确切类型DataTable 现在我正在这样做 DataTable st dataReader GetSchemaTable foreach DataColumn col in st Columns var type c
  • 如何从项目文件夹中的 jlabel 上设置图像?

    我正在尝试制作一个 Java 桌面应用程序 我想设置一个图像JLabel 我正在使用 NetBeans 从我的项目文件夹中 我的目录结构是 F gt MARKET src lib src defaultpackage demo java i
  • 无法以联觉方式绘制像素、Pi 数

    我想将 pi 数字的每个数字打印为彩色像素 因此 我得到一个带有 pi 数字的输入 然后将其解析为一个列表 每个节点包含一个数字 我知道 稍后我将使用一个数组 但我从来没有把它画到屏幕上 有人能帮我看看我错在哪里吗 import java
  • 创建进程的多个子进程并维护所有 PID 的共享数组

    我已经分叉了几次 并用 C 创建了一堆子进程 我想将它们所有的 PID 存储在一个共享数组中 PID 的顺序并不重要 例如 我创建了 32 个进程 我想要一个 32 个整数长的数组来存储每个 PID 并且每个进程都可以访问 最好的方法是什么
  • 应用程序中 GC 长时间暂停

    我当前运行的应用程序需要最大堆大小为 16GB 目前我使用以下标志来处理垃圾收集 XX UseParNewGC XX UseConcMarkSweepGC XX CMSInitiatingOccupancyFraction 50 XX Di

随机推荐

  • GDB忽略SIGPWR和SIGCPU这两个信号

    用GDB 调试Java程序 陈皓 http blog csdn net haoel 背景 想要使用GDB调试程序 就需要用GNU的编译器编译程序 如 用GCC编译的C C 的程序 才能用GDB调试 对于Java程序也是一样的 如果想要用GD
  • 【嵌入式】7段数码管电路原理

    电路原理说明 中间的是F 小数点是G 上面的对应具体管 下面的代表各个大管 两两对应 上面4个为一个字节 有两个字节 下面直接为一个字节 要让某个数字亮起必须满足两个逻辑条件 对应的 LED SEL 必须为 0 低电频 代表对应笔画的 LE
  • 无符号整形和有符号整形的比较

    对无符号整形比较的错误认知 整形数据存储形式 进制的转换 原码 反码 补码 转换原理 代码演示 总结 整形数据存储形式 在计算机内存里 整数以补码形式存储 正数的补码即原码 进制的转换 原码 反码 补码 正数的原码 正数的反码 正数的补码
  • 从进程中操作WPF窗体的显示隐藏

    一 问题描述 如何在一个进程中 打开另一个进程中的wpf已经隐藏的窗体 二 解决方案 1 在WPF进程中 获取该窗体的句柄 并保存到某个文件 这个文件可以是内存映射文件 也可以是普通的xml文件 在WPF的MainWindow中 添加 pr
  • Manjaro 根据连接速度排序配置源地址

    一 引言 使用 Manjaro 已经有一段时间了 一开始按照某一篇博客手动配置了国内源 最近公司搬了新的办公室 发现升级系统时出现连接不到更新服务器的问题 sudo pacman Syu 一定是源访问出现了问题 那么怎么办呢 二 解决 通过
  • (Leetcode) 寻找数组的中心索引- Python实现

    题目 给定一个整数类型的数组 nums 请编写一个能够返回数组 中心索引 的方法 我们是这样定义数组中心索引的 数组中心索引的左侧所有元素相加的和等于右侧所有元素相加的和 如果数组不存在中心索引 那么我们应该返回 1 如果数组有多个中心索引
  • Vue项目优化——通过 externals 加载外部 CDN 资源

    1 发现项目中存在的问题 为了直观地发现项目中存在的问题 我们可以在打包时生成报告 我们可以通过VueCli可视化的UI面板运行bulid直接查看报告 而在报告中我们发现了有这么一个文件 体积比较大 这样可能会造成我们较长时间的请求 2 那
  • JAV学习Object类

    Obj类 首先我们要认识到 Object类是我们所有类的顶层父类 所有类都是直接或者间接的继承自他 我们可以将它new出来也就是格式 Object obj new Object 我们罗列出来objct类的常用方法然后再一一介绍 方法名 ob
  • Flowable的基本使用 (4常用BPMN图配置)

    Flowable的基本使用 4常用BPMN图配置 上面几篇博客我们已经介绍了BPMN是什么 有什么节点 节点直接的关系与作用 这一篇我们画几个标准一些的BPMN图 一字长蛇阵 流程只要审核了就到下个节点 不审核就一直卡住 节点都配置了权限信
  • 媒介盒子「AI一键生成文章」功能上线,连新闻稿都不用自己写了~

    媒介盒子 AI一键生成文章 功能上线 发软文再也不用担心没有软文稿了 媒介盒子 AI一键生成文章 功能专为有软文发稿需求 但没有软文稿件的用户量身定做 媒介盒子作为国内首屈一指的专业软文发稿平台 在以往合作的客户中 经常有人反馈 我们公司没
  • python--argparse之action用法

    argparse之action用法 action关键字默认状态有两种 store true和store false 若输入命令时 不指定其参数 则store true显示为False store false显示为True 下面举个例子来直观
  • C++加密库 Crypto++

    lcrypto algorithm type name authenticated encryption schemes GCM CCM EAX high speed stream ciphers Panama Sosemanuk Sals
  • python从Excel表格中读取数据

    使用python从Excel表格中读取数据 需要安装xlrd库 pip3 install xlrd 或者 pip install xlrd 之后就可以在 py文件中导入该模块了 import xlrd
  • 用ppt图表分析人口数据

    2022年7月11日是世界人口日 联合国经济和社会事务部 经社部 在这一天发布了 世界人口展望2022 联合国每两年或三年发布一次 世界人口展望 的版本 上一个版本是2019版 世界人口展望2022 预测2022年11月15日 世界人口将达
  • 爆料称字节跳动实习生删库

    本文转载自IT之家 6 月 24 日消息 脉脉用户 程序员 白胜 在社交媒体称 字节跳动一名实习生删除了公司所有 lite 模型 在脉脉上引发关注 这名用户随后在回复中称 实习生直接 delete 父目录 还加了 skip trash li
  • 算法题记录【华为od】查找单入口空闲区域

    题目描述 思路分析 来源 华为OD真题学习 查找单入口空闲区域 100 大为童鞋的博客 CSDN博客 总体思路是遍历数组 查找符合要求的点即可 注意点一 单入口区域只能存在一个入口 用count判断是否只存在一个入口 注意点二 目标点上下左
  • 【云原生学习】PromQL学习以及Node Exporter常用查询语句

    文章目录 PromQL学习以及Node Exporter常用查询语句 一 PromQL学习 1 1 表达式数据类型 1 1 1 Instant vector selectors 1 1 2 区间vector selectors 1 2 符合
  • pythonpandas数据输出_[Python]pandas用法-数据系列,pythonpandas,使用,Series

    pandas数据Series 目录 默认数字索引 import pandas as pd import numpy as np from pandas import Series from pandas import DataFrame o
  • 软件工程知识-软件测试

    1 软件测试是发现软件错误 缺陷 的主要手段 从是否关系软件内部结构和具体实现的角度对软件测试进行分类 2 静态测试 以检查为主 桌前检查 代码走查 代码审查 动态测试 实际运行程序 分白盒测试 黑盒测试 灰盒测试 白盒测试 结构测试 用于
  • AI加速(八)

    大家好啊 我是董董灿 前文回顾 AI加速 一 GPU为什么这么牛 AI加速 二 计算机存储和计算的分离 AI加速 三 每条指令都是流水线的工人 AI加速 四 衣柜般的分层存储设计 AI加速 五 一个例子看懂流水 从指令到算法 AI加速 六