packages feed

NGLess-1.4.0: Execs/Bench.hs

{- Copyright 2016-2019
 - Licence: MIT -}
import Criterion.Main


import qualified Data.Vector as V
import qualified Data.Conduit.List as CL
import qualified Data.Conduit.Binary as CB
import           Data.Conduit.Algorithms.Async (conduitPossiblyCompressedFile)
import qualified Data.Conduit.Combinators as CC
import qualified Data.Conduit as C
import qualified Data.ByteString as B
import qualified Data.Text as T
import           Data.Conduit ((.|))
import           Control.DeepSeq (NFData)

import Control.Monad.Trans.Resource (runResourceT)

import BuiltinFunctions (builtinModule)
import NGLess (NGLessIO, testNGLessIO)


import Interpretation.Count (performCount
                            , MMMethod(..)
                            , loadFunctionalMap
                            , CountOpts(..)
                            , AnnotationMode(..)
                            , StrandMode(..)
                            , annotationRule
                            , AnnotationIntersectionMode(..)
                            , Annotator(..)
                            , NMode(..))
import Interpretation.Substrim (substrim)
import StandardModules.Parallel (pasteCounts)
import Interpret (interpret)
import FileOrStream (FileOrStream(..))
import Parse (parsengless)
import Language (Script(..))
import Data.Sam (readSamLine, readSamGroupsC', samStatsC)
import Data.FastQ (FastQEncoding(..), ShortRead(..), fqDecodeVector)
import Utils.Conduit (linesC, ByteLine(..), linesVC)
import Transform (transform)
import NGLess.NGLEnvironment (NGLVersion(..), setupTestEnvironment, setModulesForTestingPurposesOnlyDoNotUseOtherwise)

nfNGLessIO :: (NFData a) => NGLessIO a -> Benchmarkable
nfNGLessIO = nfIO . testNGLessIO

nfNGLessScript :: T.Text -> Benchmarkable
nfNGLessScript sc = case parsengless "bench" False sc of
    Left err -> error (show err)
    Right expr -> nfNGLessIO $ interpret [] . nglBody $ expr

nfNGLessScriptWithTransform :: T.Text -> Benchmarkable
nfNGLessScriptWithTransform code = case parsengless "bench" False code of
    Left err -> error (show err)
    Right sc -> nfNGLessIO $ do
        let mods = [builtinModule (NGLVersion 1 4)]
        setModulesForTestingPurposesOnlyDoNotUseOtherwise mods
        sc' <- transform mods sc
        interpret mods (nglBody sc')


nfRIO = nfIO . runResourceT
countRights = loop (0 :: Int)
    where
        loop !i = C.await >>= \case
            Nothing -> return i
            Just (Right !_) -> loop (i+1)
            Just (Left !_) -> loop i

rightOrDie (Right r) = r
rightOrDie err = error $ "Expected Right, got: " ++ show err
exampleSR :: ShortRead
exampleSR = V.head . rightOrDie . fqDecodeVector 0 SangerEncoding $ V.fromList
                [ByteLine "@SRR867735.1 HW-ST997:253:C16APACXX:7:1101:2971:1948/1"
                ,ByteLine "NCCGCTGCTCGGGATCAAGACATACCGCGGGGGGAGGGGAGCGGGACCAC"
                ,ByteLine "+"
                ,ByteLine "#11ABDD6DFBDFHEGHDDGFFFHE?@GEEGA##################"]


count= loop (0 :: Int)
    where
        loop !i = C.await >>= \case
            Nothing -> return i
            Just _ -> loop (i+1)

basicCountOpts = CountOpts
        { optFeatures = []
        , optSubFeatures = Nothing
        , optIntersectMode = annotationRule IntersectStrict
        , optAnnotationMode = AnnotateSeqName
        , optStrandMode = SMBoth
        , optMinCount = 0.0
        , optMMMethod = MMDist1
        , optDelim = "\t"
        , optNormMode = NMRaw
        , optIncludeMinus1 = True
        }

main = setupTestEnvironment >> defaultMain [
    bgroup "sam-stats"
        [ bench "sample" $ nfNGLessIO (C.runConduit (CB.sourceFile "test_samples/sample.sam" .| linesVC 4096 .| samStatsC))
        ]
    ,bgroup "fastq"
        [ bench "fastqStats" $ nfNGLessIO (C.runConduit (conduitPossiblyCompressedFile "test_samples/sample.fq.gz" .| linesC .| count))
        , bench "preprocess" $ nfNGLessScript                          "p = fastq('test_samples/sample.fq.gz')\npreprocess(p) using |r|:\n  r = substrim(r, min_quality=26)\n  if len(r) < 45:\n    discard"
        , bench "preprocess-transformed" $ nfNGLessScriptWithTransform "p = fastq('test_samples/sample.fq.gz')\npreprocess(p) using |r|:\n  r = substrim(r, min_quality=26)\n  if len(r) < 45:\n    discard"
        , bench "preprocess-pair" $ nfNGLessScript
                "p = paired('test_samples/sample.fq.gz', 'test_samples/sample.fq.gz')\npreprocess(p) using |r|:\n  r = substrim(r, min_quality=26)\n"
        , bench "preprocess-pair-transformed" $ nfNGLessScriptWithTransform
                "p = paired('test_samples/sample.fq.gz', 'test_samples/sample.fq.gz')\npreprocess(p) using |r|:\n  r = substrim(r, min_quality=26)\n"
        , bench "preprocess-pair-nop" $ nfNGLessScriptWithTransform
                "p = paired('test_samples/sample.fq.gz', 'test_samples/sample.fq.gz')\npreprocess(p) using |r|:\n  r = r\n"
        , bench "substrim" $ nf (substrim 30) exampleSR
        ]
    ,bgroup "conduit"
        [ bench "raw"      $ nfNGLessIO (C.runConduit (conduitPossiblyCompressedFile "test_samples/sample.sam.gz" .| CB.lines .| (CC.conduitVector 1024 :: C.ConduitT B.ByteString (V.Vector B.ByteString) NGLessIO ()) .| count))
        , bench "linesC"   $ nfNGLessIO (C.runConduit (conduitPossiblyCompressedFile "test_samples/sample.sam.gz" .| linesC .| (CC.conduitVector 1024 :: C.ConduitT ByteLine (V.Vector ByteLine) NGLessIO ()) .| count))
        , bench "linesVC"  $ nfNGLessIO (C.runConduit (conduitPossiblyCompressedFile "test_samples/sample.sam.gz" .| (linesVC 1024 :: C.ConduitT B.ByteString (V.Vector ByteLine) NGLessIO ()) .| count))
        ]
    ,bgroup "parse-sam"
        [ bench "readSamLine" $ nfRIO (C.runConduit (CB.sourceFile "test_samples/sample.sam" .| CB.lines .| CL.map readSamLine .| countRights))
        , bench "samGroups" $ nfNGLessIO (C.runConduit (CB.sourceFile "test_samples/sample.sam" .| linesVC 2048 .| readSamGroupsC' 1 True .| count))
        ]
    ,bgroup "count"
        [ bench "load-map"      $ nfNGLessIO (loadFunctionalMap "test_samples/functional.map" ["KEGG_ko", "eggNOG_OG"])
        , bench "annotate-seqname" . nfNGLessIO $ performCount (File "test_samples/sample.sam") "testing" [SeqNameAnnotator Nothing] basicCountOpts
        , bench "annotate-functionalmap" . nfNGLessIO $ do
                    amap <- loadFunctionalMap "test_samples/functional.map" ["KEGG_ko", "eggNOG_OG"]
                    performCount (File "test_samples/sample.sam") "testing" amap basicCountOpts
        ]
    ,bgroup "parallel"
        [ bench "paste-sparse"   $ nfNGLessIO (pasteCounts [] False ["sample" | _ <- [(0 :: Int)..127]]
                                                                ["test_samples/merge/sp_sample_"++show i | i <- [(0 :: Int)..127]])
        , bench "paste-dense"    $ nfNGLessIO (pasteCounts [] True ["sample" | _ <- [(0 :: Int)..127]]
                                                                ["test_samples/merge/sample_"++show i | i <- [(0 :: Int)..127]])
        ]
    ]