luc*_*ura 13 parallel-processing haskell fft
我有一个用于解决快速傅里叶变换的haskell代码,我想在其上应用数据并行性.但是,我使用的每个策略都会产生太多的火花,而且大多数都会溢出.
有没有人知道如何在以下算法上应用良好的数据并行策略:
-- radix 2 Cooley-Tukey FFT
fft::[Complex Float] -> [Complex Float]
fft [a] = [a]
fft as = interleave ls rs
where
(cs,ds) = bflyS as
ls = fft cs
rs = fft ds
interleave [] bs = bs
interleave (a:as) bs = a : interleave bs as
bflyS :: [Complex Float] -> ([Complex Float], [Complex Float])
bflyS as = (los,rts)
where
(ls,rs) = halve as
los = zipWith (+) ls rs
ros = zipWith (-) ls rs
rts = zipWith (*) ros [tw (length as) i | i <- [0..(length ros) - 1]]
halve as = splitAt n' as
where
n' = div (length as + 1) 2
-- twiddle factors
tw :: Int -> Int -> Complex Float
tw n k = cis (-2 * pi * fromIntegral k / fromIntegral n)
Run Code Online (Sandbox Code Playgroud)
PAR MONAD
leftaroundabout的答案帮助我了解了如何在代码上应用数据并行性.但是,我研究了par monad并尝试将任务并行性应用于它.问题是它的运行速度比原来的bflyS慢.我认为我开发的代码与我正在进行的相关工作相比,创建线程的成本很高.有谁知道如何以更好的方式使用par monad?
--New Task Parallelism bflyS
bflySTask :: [Complex Float] -> ([Complex Float], [Complex Float])
bflySTask as = runPar $ do
let (ls, rs) = halve as
v1<-new
v2<-new
let ros = DATA.zipWith (-) ls rs
let aux = DATA.map (tw n) [0..n-1]
fork $ put v1 (DATA.zipWith (+) ls rs)
fork $ put v2 (DATA.zipWith (*) ros aux)
los <- get v1
rts <- get v2
return (los, rts)
where
n = DATA.length as
Run Code Online (Sandbox Code Playgroud)
lef*_*out 12
首先:在我开始考虑并行性之前,有很多优化要做:
列出摇滚,但它们的非连续内存模型意味着它们不能允许遍历几乎与使用紧密数组所能实现的速度一样快Data.Vector,因为您不可避免地会遇到大量缓存未命中.实际上,我很少看到基于列表的算法从并行化中获得很多,因为它们受到内存的限制,而不是CPU的性能.
你的旋转因子一遍又一遍地计算,你可以通过这里的记忆显然获得很多.
你继续打电话length,但这是一个非常浪费的功能(O(n)可能是O(1)).使用一些可能处理长度的容器; 列表并不意味着(我们希望保持其无限的能力).
并行化本身将非常简单; 我会检查John L所建议的长度,确实我需要一个相当大的尺寸才能引发一个线程,至少类似于256:因为性能可能只在数千的大小时变得至关重要,这应该是基石有足够的线程来保持你的核心繁忙.
import Data.Vector.Unboxed as UBV
import Control.Parallel.Strategies
type ? = Complex Float
fft' :: UBV.Vector ? -> UBV.Vector ?
fft' a?s = interleave l?s r?s
where (l?s, r?s) = (fft l?s, fft r?s)
`using` if UBV.length a?s > 256 then parTuple2 else r0
(l?s, r?s) = byflyS a?s
Run Code Online (Sandbox Code Playgroud)