Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Performance 矩阵与repa相乘_Performance_Haskell_Matrix_Repa - Fatal编程技术网

Performance 矩阵与repa相乘

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个这

我正在用纯Haskell编写JPEG解码器(这是我学习
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毫秒”:

  • 对于每个矩阵,要计算矩阵中的单个结果元素,我们需要进行8次乘法和7次加法。对于一个非常悲观的范围,假设我们不做任何SIMD的事情。在我的CPU上,所有相关指令的交互吞吐量都是
    1
    ,因此它需要15个周期(当然,也有指令延迟,但这不应该是一个因素,特别是如果我们说要做很多次的话)
  • 要计算每个结果矩阵,我们需要计算64个结果元素,即64×15,或每个结果矩阵大约1000个循环
  • 我们需要计算大约一百万个矩阵,给出大约十亿个循环
  • 我的CPU运行频率为4 GHz(而且任务对缓存非常友好,因此不受内存限制),因此它应该占秒数的¼,因此最差估计为250毫秒
  • 现在,如果编译器足够聪明,它肯定会使用SIMD指令进行向量乘法和水平求和,将每个元素的15个周期减少到大约两个(当然,也有加载和打包部分,但是IDCT矩阵可以完全驻留在我的16个CPU中的8个XMM寄存器中,因此无需加载该寄存器,并且还有足够的指令级并行空间,因此在进行此估计时,我们可以忽略这一点).因此,这是大约8倍的速度,给出了250/8的乐观界限≈ 30毫秒
  • 考虑到以上所有因素,我有点目瞪口呆地看到下面的函数需要2秒钟。更有趣的是,它对元素是按行顺序还是按列顺序遍历完全不敏感:替换

    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矩阵,但这不会影响性能

    所以,我能做的不同