Performance 矩阵与repa相乘
我正在用纯Haskell编写JPEG解码器(这是我学习Performance 矩阵与repa相乘,performance,haskell,matrix,repa,Performance,Haskell,Matrix,Repa,我正在用纯Haskell编写JPEG解码器(这是我学习repa的机会!),现在我正在研究IDCT(相当于将一组8×8矩阵乘以一个固定的8×8矩阵)。文章末尾的函数idctBlocks采用了Word16s的向量,以及blockCount(8×8块的计数)和compscont(请原谅我的术语,在每个块中,用YCbCr编码的图像的组件数量为3)并根据IDCT的结果产生一些值。然后向量的总大小为blockCount*compscont*8*8元素 现在,我还有一个(相当大的)测试图像,有大约320k个这
repa
的机会!),现在我正在研究IDCT(相当于将一组8×8矩阵乘以一个固定的8×8矩阵)。文章末尾的函数idctBlocks
采用了Word16
s的向量,以及blockCount
(8×8块的计数)和compscont
(请原谅我的术语,在每个块中,用YCbCr编码的图像的组件数量为3)并根据IDCT的结果产生一些值。然后向量的总大小为blockCount*compscont*8*8
元素
现在,我还有一个(相当大的)测试图像,有大约320k个这样的块,每个块有3个分量,总共有大约一百万个8×8矩阵。在没有任何太聪明的东西的情况下,对所有这些设备执行IDCT需要多长时间?我的餐巾纸背面计算显示“单芯时间约为30-250毫秒”:
1
,因此它需要15个周期(当然,也有指令延迟,但这不应该是一个因素,特别是如果我们说要做很多次的话)arrsicle=R.unsafeSlice-arr(sh:.x:.All)
idctSlice=R.unsafeSlice idctMat(任意:.y:.All)
与
arrsice=R.unsafeSlice-arr(sh:.All:.x)
idctSlice=R.unsafeSlice idctMat(任意:。所有:。y)
只是为了看看运行时是如何变化的,这表明运行时根本没有变化(我认为这本身就说明了某些事情是非常错误的)
哦,如果我删除了最后的R.sumals
(我在pre-repa时间中使用了它以确保所有内容都得到评估),并将其替换为,比如说,idct blockMats`R.deepSeqArray`0
,那么运行时间不会有任何显著的变化(好吧,它减少了约5%,但这并不重要)
最后,这里是模块:
{-#语言重载列表、类型运算符、灵活上下文、类型族}
{-#语言严格}
{-#选项-optlo-O3}
模块Data.Image.Jpeg.IDCT(idctBlocks,zigzag),其中
将限定的Data.Array.Repa作为R导入
将限定的Data.Array.Repa.Eval作为R导入
将符合条件的Data.Array.Repa.Unsafe导入为R
导入符合条件的数据.Vector.unbox为V
导入控制.Monad.Identity
导入Data.Array.Repa(数组,所有(..),任何(..),U,Z(..),(:)(..)
导入GHC.Word
V.向量整数
之字形=
[
0, 1, 5, 6, 14, 15, 27, 28,
2, 4, 7, 13, 16, 26, 29, 42,
3, 8, 12, 17, 25, 30, 41, 43,
9, 11, 18, 24, 31, 40, 44, 53,
10, 19, 23, 32, 39, 45, 52, 54,
20, 22, 33, 38, 46, 51, 55, 60,
21, 34, 37, 47, 50, 56, 59, 61,
35, 36, 48, 49, 57, 58, 62, 63
]
计算步骤::(R.Load R sh a,V.Unbox a)=>Array R sh a->Array U sh a
computeP=runIdentity.R.computeP
{-#内联计算步骤}
取消锯齿化::(Z:.Int:.Int:.Int)->(Z:.Int:.Int:.Int)
取消锯齿形(uuz:.b:.c:.p)=Z:.b:.c:(锯齿形'V.unsafeIndex`p)
{-#内联解之字形#-}
idctMat::阵列U R.DIM2浮点
idctMat=R.ComputeUnbox$R.transpose$R.fromFunction(Z:.8:.8)(\(\(\:.R:.c)->点R(c+1))
哪里
第0点=平方米$1/8
点rc=sqrt(2/8)*cos(pi*(2*c'-1)*r'/(2*8))
哪里
r'=积分r
c'=积分c
idct::R.源R浮点
=>阵列r r.DIM4浮点
->数组U R.DIM4浮点
idct arr=computeP$R.from函数dims f
哪里
dims=右范围arr
f(sh:.x:.y)=R.sumals(R.zipwhith(*)arrcslice idctSlice)
哪里
arrsicle=R.unsafeSlice arr(sh:.x:.All)
idctSlice=R.unsafeSlice idctMat(任意:.y:.All)
{-#内联idct}
idctBlocks::Int->Int->V.向量字16->Float
idctBlocks BLOCKSCONT COMPSCONT blocks=R.SUMALS$idct blockMats
哪里
flatExtent=Z:.块搜索:.块搜索:.块搜索:.64::R.DIM3
matExtent=Z:.blockScont:.compScont:.8:.8::R.DIM4
reparr=R.fromUnbexed flatExtent块
blockMats=R.map from Integral$R.Removate matExtent$R.ComputeUnbox$R.backpermute FlatExtension Unzigziggify reparr
{-#NOINLINE idctBlocks}
我的整个项目都有-O2-fllvm
,因此这些选项也适用于此文件。当然,我可能会因为转置而弄乱IDCT矩阵,但这不会影响性能
所以,我能做的不同