/Client/Benchmark.hs

http://github.com/ChristopheF/OpenCLTestFramework · Haskell · 624 lines · 369 code · 140 blank · 115 comment · 7 complexity · c929015d221a2d8420711012801681d5 MD5 · raw file

  1. {-# LANGUAGE EmptyDataDecls,FlexibleInstances, TypeSynonymInstances, TypeSynonymInstances, ExistentialQuantification, CPP #-}
  2. -----------------------------------------------------------------------------
  3. -- |
  4. -- Module : Benchmark
  5. -- Copyright : (c)2011, Texas Instruments France
  6. -- License : BSD-style (see the file LICENSE)
  7. --
  8. -- Maintainer : c-favergeon-borgialli@ti.com
  9. -- Stability : provisional
  10. -- Portability : portable
  11. --
  12. -- Benchmark module to create and control the OpenCL kernels on the board
  13. module Benchmark(
  14. -- * Benchmark types
  15. ArrayLength(..)
  16. -- ** Type of a generic Benchmark
  17. , Benchmark
  18. -- ** Type of kernel arguments
  19. , Float4(..)
  20. , CLFloat(..)
  21. , CLFloat4(..)
  22. , CLInt(..)
  23. , CLIntArray(..)
  24. , CLFloatArray(..)
  25. , CLFloat4Array(..)
  26. , CLIntArrayOO(..)
  27. , CLFloatArrayOO(..)
  28. , CLFloat4ArrayOO(..)
  29. -- ** Tag for a kernel argument
  30. , In
  31. , InOut
  32. -- * Benchmark control
  33. -- ** Rounding control
  34. , gpuRoundingMode
  35. -- ** For connection to the server and control of the test to run
  36. , Options(..)
  37. , defaultOptions
  38. -- ** NDRange specification
  39. , WorkSize
  40. , OneD
  41. , TwoD
  42. , ThreeD
  43. , NDRange
  44. , size1D
  45. , size2D
  46. , size3D
  47. , ndRange
  48. , simpleNDRange
  49. , defaultLocalWs
  50. -- ** Benchmark results
  51. , BenchResult(..)
  52. , DataResults(..)
  53. , DataResult(..)
  54. , TimingResult(..)
  55. -- * Benchmark functions
  56. -- ** Benchmark creations
  57. , bench
  58. , clFloatArrayOO
  59. , clFloat4ArrayOO
  60. , clIntArrayOO
  61. , clConstIntArray
  62. , clConstFloatArray
  63. , clConstFloat4Array
  64. -- ** Benchmark control
  65. , endSimu
  66. , onBoard
  67. , onBoardOnlyTiming
  68. , onBoardOnlyData
  69. , Clocks(..)
  70. , defaultClocks
  71. #ifdef OMAP4
  72. , CPUClock(..)
  73. , MemClock(..)
  74. , GPUClock(..)
  75. #endif
  76. -- ** Benchmark results
  77. , fromFloatResult
  78. , fromFloat4Result
  79. , fromIntResult
  80. ) where
  81. import System.IO
  82. import Network.Socket
  83. import Data.Int
  84. import Data.List(intercalate)
  85. import Test.QuickCheck.Monadic(run)
  86. import Rounding
  87. import Text.Printf
  88. -- -----------------------------------------------------------------------------
  89. -- Benchmark options
  90. -- | Options controling a benchmark
  91. data Options = Options
  92. { port :: String -- ^ The IP port
  93. , addr :: String -- ^ The server IP address
  94. , validation :: Bool -- ^ True is validation tests must be executed
  95. , performance :: Bool -- ^ True if performance tests must be executed
  96. , roundingMode :: RoundingMode -- ^ Rounding mode used by the GPU
  97. } deriving Show
  98. -- | Default values for the options
  99. defaultOptions = Options
  100. { port = "2000"
  101. , addr = "128.247.79.158"
  102. , validation = False
  103. , performance = True
  104. , roundingMode = TowardZero
  105. }
  106. class Dimension s
  107. instance Dimension OneD
  108. instance Dimension TwoD
  109. instance Dimension ThreeD
  110. -- | Phantom type to constraint a list to one element
  111. data OneD
  112. -- | Phantom type to constraint a list to two elements
  113. data TwoD
  114. -- | Phantom type to constraint a list to three elements
  115. data ThreeD
  116. -- | Index space dimension with a constrained dimension s
  117. data WorkSize s = WorkSize [Int]
  118. deriving(Eq)
  119. -- | NDRange : the global and local worksize are constrained to have the same dimension
  120. data NDRange s = NDRange (WorkSize s) (WorkSize s)
  121. -- | Force the rounding mode
  122. gpuRoundingMode :: Options -> IO ()
  123. gpuRoundingMode opts = setRoundingMode (roundingMode opts)
  124. a `isMultipleOf` b = a `rem` b == 0
  125. class DetailedShow a where
  126. detailedShow :: a -> String
  127. instance DetailedShow Int32 where
  128. detailedShow a = printf "%d" a
  129. instance DetailedShow Float where
  130. detailedShow a = printf "%.20f" a
  131. instance DetailedShow Float4 where
  132. detailedShow (x,y,z,t) = printf "(%.20f,%.20f,%.20f,%.20f)" x y z t
  133. instance DetailedShow [Float] where
  134. detailedShow l = ("[" ++) . ((intercalate "," (map detailedShow l)) ++) . ("]" ++) $ ""
  135. instance DetailedShow [Float4] where
  136. detailedShow l = ("[" ++) . ((intercalate "," (map detailedShow l)) ++) . ("]" ++) $ ""
  137. -- | Create the NDRange from the global and local worksize
  138. ndRange :: WorkSize s -> WorkSize s -> Maybe (NDRange s)
  139. ndRange a@(WorkSize la) b@(WorkSize lb) = if all (uncurry isMultipleOf) (zip la lb) then Just (NDRange a b) else Nothing
  140. -- | Creatre an ND range with a worksize of 1 in each dimension
  141. simpleNDRange :: WorkSize s -> NDRange s
  142. simpleNDRange w = NDRange w (defaultLocalWs w)
  143. instance (Show (NDRange OneD)) where
  144. show (NDRange wa wb) = show wa ++ " " ++ show wb
  145. instance (Show (NDRange TwoD)) where
  146. show (NDRange wa wb) = show wa ++ " " ++ show wb
  147. instance (Show (NDRange ThreeD)) where
  148. show (NDRange wa wb) = show wa ++ " " ++ show wb
  149. #ifdef OMAP4
  150. data Clocks = Clocks {
  151. cpuClock :: CPUClock
  152. , memClock :: MemClock
  153. , gpuClock :: GPUClock
  154. } deriving(Eq)
  155. {-
  156. WARNING : Those clock values DO NOT reflect the capabilities of the
  157. OMAP4 platform and OMAP derivatives. To know the maximum clock values for each
  158. OMAP4 derivative, please refer to the official Texas Instruments documentation.
  159. -}
  160. data CPUClock = CPU_1008MHz | CPU_800MHz deriving(Eq,Enum,Show)
  161. data MemClock = MEM_400MHz | MEM_200MHz deriving(Eq,Enum,Show)
  162. data GPUClock = GPU_307MHz | GPU_192MHz deriving(Eq,Enum,Show)
  163. defaultClocks = Clocks CPU_1008MHz MEM_400MHz GPU_307MHz
  164. instance Show Clocks where
  165. show (Clocks a b c) = "(" ++ show (fromEnum a) ++ "," ++ show (fromEnum b) ++ "," ++ show (fromEnum c) ++ ")"
  166. #else
  167. data Clocks = Clocks
  168. defaultClocks = Clocks
  169. instance Show Clocks where
  170. show _ = "(0,0,0)"
  171. #endif
  172. -- | Create a 1D worksize
  173. size1D :: Int -> WorkSize OneD
  174. size1D a = WorkSize [a]
  175. -- | Create a 2D worksize
  176. size2D :: Int -> Int -> WorkSize TwoD
  177. size2D a b = WorkSize [a,b]
  178. -- | Create a 3D worksize
  179. size3D :: Int -> Int -> Int -> WorkSize ThreeD
  180. size3D a b c = WorkSize [a,b,c]
  181. -- | Create the standard worksize with a size of 1 in each dimension and
  182. -- with a number of number given by the argument worksize
  183. defaultLocalWs :: WorkSize s -> WorkSize s
  184. defaultLocalWs (WorkSize l) = WorkSize $ replicate (length l) 1
  185. instance Show (WorkSize OneD) where
  186. show (WorkSize (a:_)) = show a
  187. show _ = error "Wrong number of elements for the worksize dimension"
  188. instance Show (WorkSize TwoD) where
  189. show (WorkSize (a:b:_)) = "(" ++ show a ++ "," ++ show b ++ ")"
  190. show _ = error "Wrong number of elements for the worksize dimension"
  191. instance Show (WorkSize ThreeD) where
  192. show (WorkSize (a:b:c:_)) = "(" ++ show a ++ "," ++ show b ++ "," ++ show c ++ ")"
  193. show _ = error "Wrong number of elements for the worksize dimension"
  194. -- | Data transfer mode for an argument
  195. data Mode a = Input a -- ^ The argument is an input
  196. | InputOutput a -- ^ The argument is used as an input/output
  197. deriving(Eq,Show)
  198. -- | Internal type for the argument
  199. -- used to generate the commands for the server
  200. data OCLARG = OCLInt (Mode Int32)
  201. | OCLFloat (Mode Float)
  202. | OCLFloat4 (Mode Float4)
  203. | OCLIntList (Mode [Int32])
  204. | OCLFloatList (Mode [Float])
  205. | OCLFloat4List (Mode [Float4])
  206. | OCLConstantIntList (Mode (ArrayLength,Int32))
  207. | OCLConstantFloatList (Mode (ArrayLength,Float))
  208. | OCLConstantFloat4List (Mode (ArrayLength,Float))
  209. | OCLIntListOO ArrayLength
  210. | OCLFloatListOO ArrayLength
  211. | OCLFloat4ListOO ArrayLength
  212. | OCLEnd
  213. | OCLCommand String
  214. deriving(Eq, Show)
  215. type ArrayLength = Int32
  216. -- | Create an output only float array
  217. clFloatArrayOO x = CLFloatArrayOO (fromIntegral x)
  218. -- | Create an output only float4 array
  219. clFloat4ArrayOO x = CLFloat4ArrayOO (fromIntegral x)
  220. -- | Create an output only int array
  221. clIntArrayOO x = CLIntArrayOO (fromIntegral x)
  222. -- | Create a constan int array
  223. clConstIntArray i f = CLConstIntArray (fromIntegral i) f
  224. -- | Create a constant float array
  225. clConstFloatArray i f = CLConstFloatArray (fromIntegral i) f
  226. -- | Create a constant float4 array
  227. clConstFloat4Array i f = CLConstFloat4Array (fromIntegral i) f
  228. -- | OpenCL Float value. 's' is used to identify if it is an input or an input /output
  229. data CLFloat s = CLFloat Float deriving(Eq,Show)
  230. -- | OpenCL Float value. 's' is used to identify if it is an input or an input /output
  231. data CLFloat4 s = CLFloat4 Float4 deriving(Eq,Show)
  232. -- | OpenCL int value. Warning : is is encoded as an Haskell Int which may be bigger
  233. data CLInt s = CLInt Int32 deriving(Eq,Show)
  234. -- | OpenCL array of int
  235. data CLIntArray s = CLIntArray [Int32]
  236. | CLConstIntArray ArrayLength Int32 -- ^ Constant data generator used by the board to generate the data
  237. deriving(Eq,Show)
  238. -- | OpenCL array of float
  239. data CLFloatArray s = CLFloatArray [Float] -- ^ The data is generated from the host
  240. | CLConstFloatArray ArrayLength Float -- ^ Constant data generator used by the board to generate the data
  241. deriving(Eq,Show)
  242. -- | A Float4 type
  243. type Float4 = (Float,Float,Float,Float)
  244. -- | OpenCL array of float4
  245. data CLFloat4Array s = CLFloat4Array [Float4] -- ^ The data is generated from the host
  246. | CLConstFloat4Array ArrayLength Float -- ^ Constant data generator used by the board to generate the data
  247. deriving(Eq,Show)
  248. -- | Output only OpenCL array of ints. The host is not transferring any data before running the kernel.
  249. -- The board is allocating the memory required to contain the output.
  250. data CLIntArrayOO = CLIntArrayOO ArrayLength deriving(Eq,Show)
  251. -- | Output only OpenCL array of float. The host is not transferring any data before running the kernel.
  252. -- The board is allocating the memory required to contain the output.
  253. data CLFloatArrayOO = CLFloatArrayOO ArrayLength deriving(Eq,Show)
  254. -- | Output only OpenCL array of float4. The host is not transferring any data before running the kernel.
  255. -- The board is allocating the memory required to contain the output.
  256. data CLFloat4ArrayOO = CLFloat4ArrayOO ArrayLength deriving(Eq,Show)
  257. -- | Used to tag an argument as input only
  258. data In
  259. -- | Used to tag an argument as input/output
  260. data InOut
  261. -- | Generate the part of the server command corresponding to a given argument type
  262. generateMsgElement (OCLInt (Input a)) = "IN INT:" ++ (show a) ++ ";"
  263. generateMsgElement (OCLInt (InputOutput a)) = "BOTH INT:" ++ (show a) ++ ";"
  264. generateMsgElement (OCLFloat (Input a)) = "IN FLOAT:" ++ (detailedShow a) ++ ";"
  265. generateMsgElement (OCLFloat (InputOutput a)) = "BOTH FLOAT:" ++ (detailedShow a) ++ ";"
  266. generateMsgElement (OCLFloat4 (Input a)) = "IN FLOAT4:" ++ (detailedShow a) ++ ";"
  267. generateMsgElement (OCLFloat4 (InputOutput a)) = "BOTH FLOAT4:" ++ (detailedShow a) ++ ";"
  268. generateMsgElement (OCLIntList (Input a)) = "IN INTLIST:" ++ (show a) ++ ";"
  269. generateMsgElement (OCLIntList (InputOutput a)) = "BOTH INTLIST:" ++ (show a) ++ ";"
  270. generateMsgElement (OCLIntListOO n) = "OUT INTLIST " ++ (show n) ++ ";"
  271. generateMsgElement (OCLFloatList (Input a)) = "IN FLOATLIST:" ++ (detailedShow a) ++ ";"
  272. generateMsgElement (OCLFloatList (InputOutput a)) = "BOTH FLOATLIST:" ++ (detailedShow a) ++ ";"
  273. generateMsgElement (OCLFloat4List (Input a)) = "IN FLOAT4LIST:" ++ (detailedShow a) ++ ";"
  274. generateMsgElement (OCLFloat4List (InputOutput a)) = "BOTH FLOAT4LIST:" ++ (detailedShow a) ++ ";"
  275. generateMsgElement (OCLConstantIntList (Input (nb,v))) = "IN INTLIST: CONSTARRAY " ++ (show nb) ++ " " ++ detailedShow v ++ ";"
  276. generateMsgElement (OCLConstantIntList (InputOutput (nb,v))) = "BOTH INTLIST: CONSTARRAY " ++ (show nb) ++ " " ++ detailedShow v ++ ";"
  277. generateMsgElement (OCLConstantFloatList (Input (nb,v))) = "IN FLOATLIST: CONSTARRAY " ++ (show nb) ++ " " ++ detailedShow v ++ ";"
  278. generateMsgElement (OCLConstantFloatList (InputOutput (nb,v))) = "BOTH FLOATLIST: CONSTARRAY " ++ (show nb) ++ " " ++ detailedShow v ++ ";"
  279. generateMsgElement (OCLConstantFloat4List (Input (nb,v))) = "IN FLOAT4LIST: CONSTARRAY " ++ (show nb) ++ " " ++ detailedShow v ++ ";"
  280. generateMsgElement (OCLConstantFloat4List (InputOutput (nb,v))) = "BOTH FLOAT4LIST: CONSTARRAY " ++ (show nb) ++ " " ++ detailedShow v ++ ";"
  281. generateMsgElement (OCLFloatListOO n) = "OUT FLOATLIST " ++ (show n) ++ ";"
  282. generateMsgElement (OCLFloat4ListOO n) = "OUT FLOAT4LIST " ++ (show n) ++ ";"
  283. generateMsgElement OCLEnd = "ENDMESSAGE"
  284. generateMsgElement (OCLCommand s) = s
  285. -- | Generate the final server command using the kernel name, global work size and kind of
  286. -- output wanted : data only or with data
  287. benchCommand s clock nb ignore | ignore = OCLCommand $ "KERNEL " ++ (show s) ++ " " ++ show clock ++ " " ++ (show nb) ++ " IGNORE ;"
  288. | otherwise = OCLCommand $ "KERNEL " ++ (show s) ++ " " ++ show clock ++ " " ++ (show nb) ++ ";"
  289. -- | Data type to described the wanted output from the server
  290. data ResultMode = TimingOnly -- ^ The server is only returning the timing
  291. | AllData -- ^ The server is also returning the data
  292. deriving(Eq,Show)
  293. -- | Generate a Benchmark
  294. bench :: Benchmark r
  295. => String -- ^ Kernel name
  296. -> r
  297. bench s = generateCmd s []
  298. -- | Each type which can be used as an argument of a kernel is an instance of this class
  299. class BenchmarkArg a where
  300. toOCLARG :: String -> a -> OCLARG
  301. instance BenchmarkArg Float where
  302. toOCLARG _ a = OCLFloat (Input a)
  303. instance BenchmarkArg Float4 where
  304. toOCLARG _ a = OCLFloat4 (Input a)
  305. instance BenchmarkArg Int32 where
  306. toOCLARG _ a = OCLInt (Input a)
  307. instance BenchmarkArg Int where
  308. toOCLARG _ a = OCLInt (Input . fromIntegral $ a)
  309. instance BenchmarkArg (CLFloat In) where
  310. toOCLARG _ (CLFloat a) = OCLFloat (Input a)
  311. instance BenchmarkArg (CLFloat InOut) where
  312. toOCLARG _ (CLFloat a) = OCLFloat (InputOutput a)
  313. instance BenchmarkArg (CLFloat4 In) where
  314. toOCLARG _ (CLFloat4 a) = OCLFloat4 (Input a)
  315. instance BenchmarkArg (CLFloat4 InOut) where
  316. toOCLARG _ (CLFloat4 a) = OCLFloat4 (InputOutput a)
  317. instance BenchmarkArg (CLInt In) where
  318. toOCLARG _ (CLInt a) = OCLInt (Input a)
  319. instance BenchmarkArg (CLInt InOut) where
  320. toOCLARG _ (CLInt a) = OCLInt (InputOutput a)
  321. instance BenchmarkArg (CLIntArray In) where
  322. toOCLARG _ (CLIntArray a) = OCLIntList (Input a)
  323. toOCLARG _ (CLConstIntArray nb v) = OCLConstantIntList (Input (nb,v))
  324. instance BenchmarkArg (CLIntArray InOut) where
  325. toOCLARG _ (CLIntArray a) = OCLIntList (InputOutput a)
  326. toOCLARG _ (CLConstIntArray nb v) = OCLConstantIntList (Input (nb,v))
  327. instance BenchmarkArg (CLFloatArray In) where
  328. toOCLARG _ (CLFloatArray a) = OCLFloatList (Input a)
  329. toOCLARG _ (CLConstFloatArray nb v) = OCLConstantFloatList (Input (nb,v))
  330. instance BenchmarkArg (CLFloatArray InOut) where
  331. toOCLARG _ (CLFloatArray a) = OCLFloatList (InputOutput a)
  332. toOCLARG _ (CLConstFloatArray nb v) = OCLConstantFloatList (InputOutput (nb,v))
  333. instance BenchmarkArg (CLFloat4Array In) where
  334. toOCLARG _ (CLFloat4Array a) = OCLFloat4List (Input a)
  335. toOCLARG _ (CLConstFloat4Array nb v) = OCLConstantFloat4List (Input (nb,v))
  336. instance BenchmarkArg (CLFloat4Array InOut) where
  337. toOCLARG _ (CLFloat4Array a) = OCLFloat4List (InputOutput a)
  338. toOCLARG _ (CLConstFloat4Array nb v) = OCLConstantFloat4List (InputOutput (nb,v))
  339. instance BenchmarkArg (CLIntArrayOO) where
  340. toOCLARG _ (CLIntArrayOO n) = OCLIntListOO n
  341. instance BenchmarkArg (CLFloatArrayOO) where
  342. toOCLARG _ (CLFloatArrayOO n) = OCLFloatListOO n
  343. instance BenchmarkArg (CLFloat4ArrayOO) where
  344. toOCLARG _ (CLFloat4ArrayOO n) = OCLFloat4ListOO n
  345. instance BenchmarkArg [Float] where
  346. toOCLARG _ a = OCLFloatList (Input a)
  347. instance BenchmarkArg [Float4] where
  348. toOCLARG _ a = OCLFloat4List (Input a)
  349. instance BenchmarkArg (Clocks, NDRange OneD,ResultMode) where
  350. toOCLARG c (clocks,nb,TimingOnly) = benchCommand c clocks nb True
  351. toOCLARG c (clocks,nb,_) = benchCommand c clocks nb False
  352. instance BenchmarkArg (Clocks, NDRange TwoD,ResultMode) where
  353. toOCLARG c (clocks,nb,TimingOnly) = benchCommand c clocks nb True
  354. toOCLARG c (clocks,nb,_) = benchCommand c clocks nb False
  355. instance BenchmarkArg (Clocks, NDRange ThreeD,ResultMode) where
  356. toOCLARG c (clocks,nb,TimingOnly) = benchCommand c clocks nb True
  357. toOCLARG c (clocks,nb,_) = benchCommand c clocks nb False
  358. -- | Magic class used to implement a function with a varying number
  359. -- of argument using different types.
  360. class Benchmark r where
  361. generateCmd :: String -> [OCLARG] -> r
  362. -- | String is of benchmark kind since we want to be able to generate
  363. -- a string of command from a Benchmark
  364. instance Benchmark String where
  365. generateCmd s (kernel:args) = let cmds = kernel:reverse (OCLEnd:args)
  366. in
  367. concatMap generateMsgElement cmds
  368. -- | A benchmark taking one argument is equivalent to a new argument command for the server
  369. -- plus a benchmark without this argument
  370. instance (BenchmarkArg a,Benchmark r) => Benchmark (a -> r) where
  371. generateCmd c args = \a -> generateCmd c (toOCLARG c a:args)
  372. -- | Send command to the server and read the timing and data returned by the server
  373. onBoard :: Options -> Clocks -> NDRange s -> ((Clocks, NDRange s, ResultMode) -> String) -> IO BenchResult
  374. onBoard opts clocks global_ws a = runCmd opts $ \h -> executeBench h (a (clocks,global_ws,AllData))
  375. -- | Send command to the server and read the timing returned by the server.
  376. -- The server is not returning any data to minimize the communication costs.
  377. onBoardOnlyTiming :: Options -> Clocks -> NDRange s -> ((Clocks, NDRange s, ResultMode) -> String) -> IO TimingResult
  378. onBoardOnlyTiming opts clocks global_ws a = do
  379. BenchResult (t,_) <- runCmd opts $ \h -> executeBench h (a (clocks,global_ws,TimingOnly))
  380. return t
  381. -- | Send command to the server and read the data returned by the server.
  382. -- Timing data are just dropped and not returned. But timing data (small) are nevertheless returned from
  383. -- the server
  384. onBoardOnlyData :: Options -> NDRange s -> ((Clocks,NDRange s, ResultMode) -> String) -> IO DataResults
  385. onBoardOnlyData opts global_ws a = do
  386. BenchResult (_,v) <- runCmd opts $ \h -> executeBench h (a (defaultClocks, global_ws,AllData))
  387. return v
  388. -- | Send the end of simulation command
  389. endSimu :: Options -> IO ()
  390. endSimu opts = runCmd opts $ \h -> do
  391. hPutStrLn h $ "END"
  392. hFlush h
  393. -- | Send a command to the server socket
  394. runCmd :: Options -> (Handle -> IO a) -> IO a
  395. runCmd opts a = do
  396. addrinfos <- getAddrInfo Nothing (Just (addr opts)) (Just (port opts))
  397. let serveraddr = head addrinfos
  398. sock <- socket (addrFamily serveraddr) Stream defaultProtocol
  399. setSocketOption sock KeepAlive 1
  400. connect sock (addrAddress serveraddr)
  401. -- Make a Handle out of it for convenience
  402. h <- socketToHandle sock ReadWriteMode
  403. hSetBuffering h (BlockBuffering Nothing)
  404. r <- a h
  405. hClose h
  406. return r
  407. data DataResult = FloatResult [Float] | Float4Result [Float4] | IntResult [Int32] deriving(Eq,Show)
  408. -- | Extract the float result
  409. fromFloatResult :: DataResult -> [Float]
  410. fromFloatResult (FloatResult l) = l
  411. fromFloatResult _ = error "Can't get a float result"
  412. -- | Extract the float4 result
  413. fromFloat4Result :: DataResult -> [Float4]
  414. fromFloat4Result (Float4Result l) = l
  415. fromFloat4Result _ = error "Can't get a float result"
  416. -- | Extract the int result
  417. fromIntResult :: DataResult -> [Int32]
  418. fromIntResult (IntResult l) = l
  419. fromIntResult _ = error "Can't get a int result"
  420. -- | Result of a benchmark : timing and list of OpenCL arrays
  421. newtype BenchResult = BenchResult (TimingResult,DataResults) deriving(Eq,Show)
  422. -- | Data only result : list of OpenCL arrays
  423. type DataResults = [DataResult]
  424. type CLBufferCreationTime = Double
  425. type CLBufferWriteTime = Double
  426. type CLExecutionTime = Double
  427. type CLReadingResultTime = Double
  428. -- | Timing only result
  429. -- Creation time, execution time, result time and execution time measured by the HLOS (see DESIGN doc)
  430. type TimingResult = (CLBufferCreationTime,CLBufferWriteTime,CLExecutionTime,CLReadingResultTime)
  431. -- | Write the command to the server socket and read the results
  432. executeBench :: Handle -> String -> IO BenchResult
  433. executeBench h command = do
  434. --putStrLn command
  435. hPutStrLn h command
  436. hFlush h
  437. getResult h
  438. --return $ BenchResult ((0.0,0.0,0.0),[[1.0]])
  439. {-
  440. Reading result
  441. -}
  442. -- | Read an array of float
  443. getArray h l = do
  444. nb <- hGetLine h
  445. if (nb == ".")
  446. then
  447. return (reverse l)
  448. else
  449. getArray h (read nb:l)
  450. -- | Read a result from the socket.
  451. -- * is end of result transmissions
  452. -- t is timing result
  453. -- rl is array of float
  454. readResult h t l = do
  455. c <- hGetLine h
  456. case c of
  457. "*" -> return $ BenchResult (t,l)
  458. "t" -> do
  459. c <- hGetLine h
  460. w <- hGetLine h
  461. e <- hGetLine h
  462. r <- hGetLine h
  463. let createTime = read c :: Double
  464. writeTime = read w :: Double
  465. executeTime = read e :: Double
  466. readTime = read r :: Double
  467. readResult h (createTime,writeTime,executeTime,readTime) l
  468. "rl" -> do
  469. nl <- getArray h [] :: IO [Float]
  470. readResult h t (FloatResult nl:l)
  471. "zl" -> do
  472. nl <- getArray h [] :: IO [Float4]
  473. readResult h t (Float4Result nl:l)
  474. "nl" -> do
  475. nl <- getArray h [] :: IO [Int32]
  476. readResult h t (IntResult nl:l)
  477. _ -> return $ BenchResult (t,reverse l)
  478. -- | Parse a result from the socket
  479. getResult :: Handle -> IO BenchResult
  480. getResult h = readResult h (0.0,0.0,0.0,0.0) []