matlab 多重循环在最外层加断点_循环优化之循环分块(loop tiling)

fa771447eedaa125211a7fc26effdccc.png

引言

编译器里的循环优化有两个重要的目标,一是提高局部性,二是提高并行性,loop tiling是提高数据局部性最重要的优化之一,是传统编译器和深度编译器考虑的重中之重,我们今天来看看如何做loop tiling(循环分块)(aka cache blocking)。

loop tiling的basic idea很简单,就是一个cache line现在被用过以后,后面什么时候还会被用,但是按循环默认的执行方式,可能到下次再被用到的时候已经被evict了。于是我们就把循环怎么重排一下,使得一个cache line在被evict之前就被再次使用。

在该文中我们讨论一个简单的tiling方法,以及通过计算cache miss来估算tiling的作用。

例程一

我们从一个简单的例子看起,为了更好的可读性,我们使用Fortran语法(column major):

DO I = 1, NDO J = 1, MA(I) = A(I) + B(J)  END DO
END DO

首先我们分析一下该循环的重用模式(reuse pattern),可以看到A(I)在每一轮J循环中被重用、B(J)在每一轮I循环中会被重用。当前由于I是外层循环,所以当B(J)在J层循环中的跨度太大时(无法fit in the cache),则在被下一次I重用时数据已被清出缓存。譬如我们假设M和N是很大的数(大数组),所以对于每一轮I循环,等到B(M)被访问时,B(1)、B(2)等已经被清出缓存了。

分析完了重用模式,我们现在计算cache miss。假设每个cache line能容纳b个数组元素,associativity是fully associative,则可计算出A的cache miss次数是N/b,B的cache miss次数是N*M/b。

现在我们来看看什么是tiling,以及如何通过做tiling减少cache miss。

我们先考虑tile J层循环,将B的访问模式变成如下,令tile size为T,T一般是b的倍数,也足够小,可以认为N,M >> b,T,T的取值应该使得当B(T)被访问时B(1)也依然还在缓存中:

I=1: B(1), B(2), B(3) ... B(T)
I=2: B(1), B(2), B(3) ... B(T)
I=3: B(1), B(2), B(3) ... B(T)
...
I=N: B(1), B(2), B(3) ... B(T)I=1: B(T+1), B(T+2), B(T+3) ... B(2T)
I=2: B(T+1), B(T+2), B(T+3) ... B(2T)
I=3: B(T+1), B(T+2), B(T+3) ... B(2T)
...
I=N: B(T+1), B(T+2), B(T+3) ... B(2T)
小灯泡:tile的本质当总的数据量无法fit in cache的时候,把数据分成一个一个tile,让每一个tile的数据fit in the cache。所以tiling一般从最内层循环开始(tile外层循环的话一个tile就包括整个内层循环,这样的tile太大)。

此时循环变成:

DO J = 1, M, TDO I = 1, NDO jj = J, min(J+T-1, M)A(I) = A(I) + B(jj)END DOEND DO
END DO

注意当我们tile J层循环的时候,tile以后J层循环就跑到了外层(loop interchange),这样又会影响A的缓存命中率。该变换又称为strip-mine-and-interchange。我们可以计算此时A的cache miss次数是(M/T) * (N/b),B的cache miss次数是T/b * M/T = M/b(每一轮J层循环miss一次),所以总共的cache miss是MN/(bT) + M/b,tile之前是N/b+N*M/b。所以在M和N的大小也相当的情况下做tiling大约能将cache miss缩小T倍。

思考题1:为什么分块以后还要交换循环I和J?循环交换是否总是可行的?

那要是我们选择tile I层循环呢?我们看看会发生什么。要tile I层循环首先将I、J循环调换:

DO J = 1, MDO I = 1, NA(I) = A(I) + B(J)  END DO
END DO

依然假设tile size=T,访问模式将变为:

J=1: A(1) B(1), A(2) B(1), A(3) B(1) ... A(T) B(1)
J=2: A(1) B(2), A(2) B(2), A(3) B(2) ... A(T) B(2)
...
J=M: A(1) B(M), A(2) B(M), A(3) B(M) ... A(T) B(M)J=1: A(T+1) B(1), A(T+2) B(1), A(T+3) B(1) ... A(2T) B(1)
J=2: A(T+1) B(2), A(T+2) B(2), A(T+3) B(2) ... A(2T) B(2)
...
J=M:A(T+1) B(M), A(T+2) B(M), A(T+3) B(M) ... A(2T) B(M)
...

此时循环变成:

DO I = 1, N, TDO J = 1, MDO ii = I, min(I+T-1, N)A(ii) = A(ii) + B(J)END DOEND DO
END DO

此时A的cache miss次数是T/b * N/T,B的cache miss次数是M/b*(N/T),加起来就是(MN)/(bT)+N/b,而tile J层循环得到的cache miss是(MN)* (bT)+M/b,所以对于该循环到底应该tile I层循环还是J层循环更好其实取决于M和N的相当大小。

思考题2:是否可以既tile I层循环也tile J层循环?如果可以,这样做是否具有更好的局部性?

例程二

DO J = 1, MDO I = 1, ND(I) = D(I) + B(I, J)END DO
END DO
注:fortran是column major layout,B(I, J)是访问二维数组,相当于C语言中的B[I][J]。不管是column major还是row major不影响tiling的原理。
注:对于多维数组我们在计算cache miss时假设数据的存储是连续的。

该循环的cache miss是M*N/b + M*N/b(D和B的miss都是M*N/b)。

还是用之前的strip-mine-and-interchange方法来tile内层循环I:

DO I = 1, N, TDO J = 1, MDO ii = I, min(I+T-1, N)D(ii) = D(ii) + B(ii, J)END DOEND DO
END DO

tiling loop I 之后的cache miss是N/T * T/b + T/b * M * N/T(J层循环每一轮一开始都会miss B)= N/b + NM/b。

再考虑tile J层循环(需要首先调换I、J层循环):

DO J = 1, M, TDO I = 1, NDO jj = J, min(J+T-1, M)D(I) = D(I) + B(I, jj)END DOEND DO
END DO

此时的cache miss是N/b * M/T + T*(N/b)*M/T = NM/(bT) + MN/b。跟tiling I循环相比,由于M一般远大于T,所以会有更高的cache miss。造成这个区别的本质原因在于D(I)在J层的重用没有被exploited。

例程三

我们再来看一个更有趣的例子:矩阵转置。

DO J = 1, NDO I = 1, NA(I, J) = B(J, I)ENDDO
ENDDO

这个例子之所以有趣是因为,无论是否做交换I、J循环(交换是合法的),cache miss都是N*N/b + N*N。下面是交换I、J循环后的情况:

DO I = 1, NDO J = 1, NA(I, J) = B(J, I)ENDDO
ENDDO

如果I是内层循环,则A的miss是N*N/b,而B每次都是miss,所以一共miss N*N次。如果J是内层循环,则是A每次都是miss,而B miss N*N/b次。不管哪种情况,都有一个没有achieve locality。

那有什么办法让A和B都能achieve locality吗?答案是可以,请看如下的tiling:

DO I = 1, N, TDO J = 1, N, TDO ii = I, min(I+T-1, N)DO jj = J, min(J+T-1, N)A(ii, jj) = B(jj, ii)ENDDOENDDOENDDO
ENDDO

这里的精髓在于tiling不仅可以利用temporal locality,也能用上spatial locality。对于A(ii, jj),虽然最内层循环是jj(没有locality),但是当内层循环jj完了以后开始下一轮ii的时候,因为tiling使得A(ii, jj)、A(ii, jj+1)依然会在缓存,于是这时的A(ii+1, jj)、A(ii+1, jj+1)等就能命中缓存(spatial locality)。

下面是各层cache miss的breakdown(外层的cache miss包含了内层的):

loop/cache missesAB
jjTT/b
iiT * T/bT/b * T
JT * T/b * N/T = NT/bT/b * T * N/T = NT/b
INT/b * N/T = N*N/bNT/b * N/T = N*N/b

总结

循环分块的本质是在外层循环挖掘内层的temporal和spatial reuse。基本的方法是strip-mine-and-interchange。以下是takeaway:

  • 循环分块是什么?如何做?
  • 对于不同的循环层分块有什么不同的结果?
  • 如何计算cache miss?

想了解更复杂的循环如何做tiling(譬如经典的矩阵乘法)以及tiling的合法性请看本系列第二讲:

https://zhuanlan.zhihu.com/p/301905385​zhuanlan.zhihu.com

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

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

相关文章

artifacts屏蔽java文件输出_Java 是什么?

Java 是一种通用型的计算机编程语言,基于类实现了面向对象的编程范式,通过虚拟机实现了强大的跨平台能力。用 Java 写的代码,既可以在 Windows 操作系统上面运行,也可以在 UNIX、Linux、MacOS 等操作系统上面运行。 Java 代码会被…

ftp同一主机的多个子进程使用同一个套接字_linux进程通信方式对比

管道:速度慢,容量有限(64kB,ulimit -a可以查询的pipe size 指的是一次性写入的大小限制),只有父子进程能通讯 半双工的(即数据只能在一个方向上流动)----(匿名管道)int pipe(int fd[2]); // 返回值:若成功返回0&#x…

ios开发中计算代码运算时间_理解Unity中的优化(二):内存

内存:内存消耗是一个关键的性能指标,尤其是在内存资源有限的平台上,比如低端移动设备。内存消耗分析:在Unity中诊断内存问题,Unity介绍了一款开元的可视化内存分析工具——MemoryProfiler,地址:…

虚拟桌面分屏_桌面中的灭霸 三星C49HG90 32:9超带鱼屏体验

本文作者:dpgisdpg前言参加一起Show桌面活动,顺便搞定之前未做的三星C49HG90DMC显示器开箱作业。搭建一套美如画的桌面,工程堪比“复仇者联盟”,不但需要足够的财力来买装备,还得会构图和互相搭配,打个比方…

easyswoole数据库连接池_EasySwoole使用Mysqli

EasySwoole使用Mysqli羡仙. • 2019 年 05 月 06 日我为什么要写这些东西呢!因为好多的文档他并不是我所想的能复制粘贴就直接用了!还要改!有的地方写的还不全.复制过来就报错!!而我希望我之前学过的东西在以后用的时候能tm直接复制粘贴去使用…

rhce考试试题以及答案_搞懂这套五年级数学上册期末考试试题(含答案),考试不担心...

快要期末考试了,今天海老师以北师大版五年级数学上册期末考试的一份试题为例,分析一下六年级数学上册期末考试题型。先看看试卷(答案文后另附):总的来说这份试卷难度适中,主要以面积计算(梯形、正方形、长方形、组合图形)、分数的…

idea的总部_雷普索尔- YPF总部

雷普索尔- YPF总部Repsol-YPF is located in the up-and-coming district of Puerto Madero in Buenos Aires. The design originally called for a three-story parking garage at the intersection of Macacha Gemes and Juana Manso streets. Balmori Associates buried the…

fetch用英语解释_fetch的意思在线翻译,解释fetch中文英文含义,短语词组,音标读音,例句,词源,同义词【澳典网ODict.Net】...

fetch 1fetch的音标和读音:DJ音标发音: [fetʃ]KK音标发音: [fɛtʃ]fetch的词性:v.(动词)fetched, fetching, fetchesfetch的词性:v.tr.(及物动词)1. To come or go after and take or bring b…

添加中文数据出现问号_怪物猎人世界绚辉龙和冥赤龙的出现时间规律一览

估计在七月上旬煌黑龙出现前,所有的活动任务都不会消失,唯一在变的元素就是绚辉龙和冥赤龙这两条特殊的古龙。绚辉龙和冥赤龙目前看来是交替出现的,也就是说有绚辉龙的日子就不会有冥赤龙,每条龙分别驻场两周。如无意外的话&#…

python中strip是什么意思啊_python中的strip是什么意思

Python中strip() 方法用于移除字符串头尾指定的字符(默认为空格或换行符)或字符序列。注意:该方法只能删除开头或是结尾的字符,不能删除中间部分的字符。它的函数原型:string.strip(s[, chars]),它返回的是字符串的副本&#xff0…

只可顺守不可逆取书法_闲章不“闲”

点击图片,学习春秋国画教程!闲章由秦汉时期刻有吉祥文字的印章演变而来,宋元以后风气颇盛,名谓“闲章”,其实不“闲”。到了近代,闲章便发展成为中国书画艺术不可或缺的部分。闲章的内容十分广泛&#xff0…

.net core orm框架_轻量级高性能PHP框架ycroute

YCRoute目录框架介绍运行环境代码结构路由配置过滤验签控制层加载器模型层数据交互dao层(可选)Redis缓存操作数据库操作配置加载公共类加载公共函数日志模块视图层RPC 介绍 - 像调用本地函数一样调用远程函数RPC ServerRPC ClientRPC 并行调用附录 - Core_Model 中的辅助极速开…

python子图之间的距离_python与图论的桥梁——igraph

之前收集到一个关于纽约市全年出租车的数据集,于是想到,我们是不是可以用这个数据集来研究一下纽约市中各个社区之间的关联度?为了研究这个问题,就需要使用python来建立一些图论模型。igraph是python/R等语言中常用的建立图模型的…

jmeter web监听结果_jmeter使用总结

1 jmeter简介Apache JMeter是Apache组织开发的基于Java的压力测试工具。用于对软件做压力测试,它最初被设计用于Web应用测试,但后来扩展到其他测试领域。 可以用于测试静态和动态资源,例如静态文件、CGI 脚本、Java 对象、数据库、FTP 服务器…

金蝶报表制作_BI报表不光好看,更好用,为什么很多人却还不知道?

要在短时间内对海量数据实现有效的数据整理清洗,快速理清数据情况,掌握数据信息,可太为难一般的数据分析报表了。但既然大数据时代给了这样的数据分析难题,自然也会给出一个有效的解决方法——BI报表。但很奇怪,明明BI…

vue可以直接进行运算么_Vue实现计算器功能

直接上代码,目前程序没有校验小数点输入是否正确情况。v-model"result"clearable>789/456*1230.-export default {name: Calculator,data () {return {result: }},methods: {sendMessage (message) {this.$message({message: message,type: warning})}…

恒驰机器人_2545台机器人,1分钟造1辆车,恒大许家印的智能造车工厂首次曝光...

车企「造车」的势头只增不减。前有奔驰造车,后有特斯拉、小鹏、蔚来等新势力造车。 在「造车」界最近迎来一位「新秀」。凭借中国最大房地产开发商的名号跨界造车。在「造车」这件事情上高举高打,从自建工厂到连发六款新车,以投入千亿的势头打…

零窗口探测怎么抓包_Linux服务器下的HTTP抓包分析

说到抓包分析,最简单的办法莫过于在客户端直接安装一个Wireshark或者Fiddler了,但是有时候由于客户端开发人员(可能是第三方)知识欠缺或者其它一些原因,无法顺利的在客户端进行抓包分析,这种情况下怎么办呢…

三维重建 几何方法 深度学习_基于深度学习的三维重建算法:MVSNet、RMVSNet、PointMVSNet、Cascade系列...

欢迎关注微信公众号“3D视觉学习笔记”,分享博士期间3D视觉学习收获MVSNet:香港科技大学的权龙教授团队的MVSNet(2018年ECCV)开启了用深度做多视图三维重建的先河。2019年,2020年又有多篇改进:RMVSNet(CVPR2019),Point…

easypoi list中的map导出_如何优雅的导出 Excel

作者:你在我家门口来源:https://juejin.im/post/5c6b6b126fb9a04a0c2f024f前言公司项目最近有一个需要:报表导出。整个系统下来,起码超过一百张报表需要导出。这个时候如何优雅的实现报表导出,释放生产力就显得很重要了…