diff options
author | Michalis Pardalos <m.pardalos@gmail.com> | 2021-03-10 10:40:16 +0000 |
---|---|---|
committer | Michalis Pardalos <m.pardalos@gmail.com> | 2021-03-29 17:29:40 +0100 |
commit | 5c36514942b335f42044ab41d0433e952f979f24 (patch) | |
tree | 8c654035a854b30daa35e3d96b38ed4e7430aa4d | |
parent | 8f05f94ea8f3827a914b6fdbc5f2d2acc6acd61a (diff) | |
download | vericert-5c36514942b335f42044ab41d0433e952f979f24.tar.gz vericert-5c36514942b335f42044ab41d0433e952f979f24.zip |
Add a script to count calls in benchmarks
-rwxr-xr-x | benchmarks/count-calls | 89 |
1 files changed, 89 insertions, 0 deletions
diff --git a/benchmarks/count-calls b/benchmarks/count-calls new file mode 100755 index 0000000..2a14b97 --- /dev/null +++ b/benchmarks/count-calls @@ -0,0 +1,89 @@ +#!/usr/bin/env nix-shell +#! nix-shell -p "haskellPackages.ghcWithPackages (pkgs: with pkgs; [ turtle parsec text ])" -i runghc + +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE BlockArguments #-} +{-# LANGUAGE NamedFieldPuns #-} +{-# LANGUAGE RecordWildCards #-} + +import Turtle +import Text.Parsec as P +import qualified Data.Text as T +import Data.List (group) +import Debug.Trace + +args = argPath "benchmark" "The benchmark directory to check" + +data ParserState = ParserState { + macroNames :: [String], + functionCalls :: [String] +} + +addMacroName :: String -> ParserState -> ParserState +addMacroName macroName ParserState{macroNames, ..} = ParserState {macroNames = macroName:macroNames, ..} + +addFunctionCall :: String -> ParserState -> ParserState +addFunctionCall functionCall ParserState{functionCalls, ..} = ParserState {functionCalls = functionCall:functionCalls, ..} + +cParser :: Parsec T.Text ParserState [T.Text] +cParser = do + P.manyTill + (betweenFuncs >> parserTrace "interesting" >> (try macroDef P.<|> funcBody)) + (try endOfFile) + map T.pack . functionCalls <$> getState + where + betweenFuncs = do + traceM "betweenFuncs" + manyTill P.anyChar $ lookAhead (P.oneOf "#{") + + funcBody :: Parsec T.Text ParserState () + funcBody = do + parserTrace "funcBody" + P.char '{' + void (P.char '}') P.<|> (call >> funcBody) P.<|> (P.anyChar >> funcBody) + + macroDef :: Parsec T.Text ParserState () + macroDef = do + parserTrace "macroDef" + P.char '#' + traceM "macroDef #" + P.many (P.char ' ') + traceM "macroDef spaces" + macroName <- P.many P.alphaNum + traceM ("macroDef " ++ macroName) + modifyState (addMacroName macroName) + + endOfFile = P.many P.space >> P.eof + + call = do + identifier <- many1 idChar + inParens <- P.between (P.char '(') (P.char ')') inParensP + guard (identifier `notElem` ["for", "while"]) + modifyState (addFunctionCall identifier) + pure identifier + + -- handle balanced parens inside calls + inParensP = P.option "" do + t1 <- P.many (P.noneOf "()") + t2 <- P.option "" $ P.between (P.char '(') (P.char ')') inParensP + t3 <- P.many (P.noneOf "()") + return (t1 ++ t2 ++ t3) + idChar = label (P.alphaNum P.<|> P.oneOf "_-") "identifier" + +main = sh do + benchmarkDir <- options "count-calls" args + + printf "benchmark,totalCalls,repeatedCalls\n" + benchmarkName <- fromText . lineToText <$> input (benchmarkDir </> "benchmark-list-master") + let filePath = benchmarkDir </> benchmarkName <.> "c" + + fileContents <- strict $ input filePath + printf (fp%"\n") benchmarkName + + case runParser cParser (ParserState [] []) "file" fileContents of + Left err -> error $ show err + Right calls -> + let + callCount = length calls + repeatedCalls = calls & group & map length & sum + in printf (fp%","%d%","%d%"\n") (basename filePath) callCount repeatedCalls |