blob: 2a14b97697709624598d17e09bde3cde87b4aba7 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
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
|