Build the Cassava Benchmark Suite
masterTo compile the benchmark suite, use the following command:
cabal build allrepository·master·Indexed 42 days ago
https://github.com/haskell-hvr/cassavaA high-performance CSV parsing and encoding library for Haskell that balances RFC4180 compliance with flexibility. It provides functions like `decode` for headerless files and `decodeByName` for files with headers, emphasizing performance and a minimal dependency footprint.
To compile the benchmark suite, use the following command:
cabal build allTo build the provided examples using the in-tree version of cassava, ensure you have cabal-install version 2.0 or later installed. Navigate to the examples/ directory and run the build command.
$ cabal new-buildThe benchmark suite includes a generator script Generate.hs to create randomized CSV files containing integer, double, and string columns. Using a seed ensures that benchmarks are reproducible.
Usage:
cabal run Generate.hs -- <rows> <columns> <seed>
# Generate wide CSV (5000 rows, 500 columns, seed 42)
cabal run Generate.hs -- 5000 500 42
# Generate long CSV (1000000 rows, 10 columns, seed 42)
cabal run Generate.hs -- 1000000 10 42To avoid running the full suite, you can filter for specific benchmark groups using the -m (match) flag within --benchmark-options. This is useful for isolating specific scenarios like positional decoding or wide/long CSV performance.
# Run only positional decode benchmarks
cabal bench benchmark-iut --benchmark-options="-m prefix positional/decode"
# Run only wide benchmarks
cabal bench benchmark-iut --benchmark-options="-m prefix wide"
# Run only long benchmarks
cabal bench benchmark-iut --benchmark-options="-m prefix long"The suite provides two distinct benchmark targets to compare the local implementation against the official Hackage version:
benchmark-iut: Benchmarks the local cassava implementation (the implementation under test).benchmark-ref: Benchmarks the reference cassava version from Hackage.Use cabal bench to execute them.
# Run implementation-under-test benchmarks
cabal bench benchmark-iut
# Run reference benchmarks
cabal bench benchmark-refYou can export benchmark results to HTML files using the --benchmark-options flag to pass the --output argument to the underlying benchmarking engine.
cabal bench benchmark-iut --benchmark-options="--output=report-iut.html"
cabal bench benchmark-ref --benchmark-options="--output=report-ref.html"To parse a CSV file that does not contain a header row, use the decode function from Data.Csv. You must specify the header option (e.g., NoHeader) and provide the lazy ByteString data. The function returns either an error string or a Vector of records. For simple tuple-based records, you can use type annotations to guide the parser.
{-# LANGUAGE ScopedTypeVariables #-}
import qualified Data.ByteString.Lazy as BL
import Data.Csv
import qualified Data.Vector as V
main :: IO ()
main = do
csvData <- BL.readFile "salaries.csv"
case decode NoHeader csvData of
Left err -> putStrLn err
Right v -> V.forM_ v $ \ (name, salary :: Int) ->
putStrLn $ name ++ " earns " ++ show salary ++ " dollars"To parse a CSV file that includes a header row, use the decodeByName function. This requires your data type to implement the FromNamedRecord typeclass. You define how to map CSV column names to your data structure using the .: operator within the parseNamedRecord method. decodeByName returns a tuple containing the header and a Vector of the parsed records.
{-# LANGUAGE OverloadedStrings #-}
import Control.Applicative
import qualified Data.ByteString.Lazy as BL
import Data.Csv
import qualified Data.Vector as V
data Person = Person
{ name :: !String
, salary :: !Int
}
instance FromNamedRecord Person where
parseNamedRecord r = Person <$> r .: "name" <*> r .: "salary"
main :: IO ()
main = do
csvData <- BL.readFile "salaries.csv"
case decodeByName csvData of
Left err -> putStrLn err
Right (_, v) -> V.forM_ v $ \ p ->
putStrLn $ name p ++ " earns " ++ show (salary p) ++ " dollars"The following CSV files are used as standard inputs for the benchmark suite:
| File | Description |
|---|---|
presidents.csv | US Presidents data without header (positional parsing) |
presidents_with_header.csv | US Presidents data with header (named parsing) |
random_r5000_c500_s42.csv | Wide CSV: 5,000 rows × 500 columns |
random_r1000000_c10_s42.csv | Long CSV: 1,000,000 rows × 10 columns |