Verified Commit 72e7c4e7 authored by Camil Staps's avatar Camil Staps 🚀

Add profile2callgrind tool

parent 2c5c2eb8
......@@ -2,3 +2,4 @@
*.o
profile2html
profile2callgrind
module profile2callgrind
import StdEnv
import StdMaybe
import Data.Error
import Data.Func
import qualified Data.Set
import System.CommandLine
import System.FilePath
import System.Options
from Text import class Text(concat,join), instance Text String
import PGCL
:: Options =
{ input :: !FilePath
, output :: !FilePath
, min_cumulative_ticks :: !Int
, exclude :: !'Data.Set'.Set String
}
defaultOptions =
{ input = ""
, output = ""
, min_cumulative_ticks = 0
, exclude = 'Data.Set'.newSet
}
Start w
# ([prog:args],w) = getCommandLine w
# args = parseOptions option_description args defaultOptions
| isError args
= exit (join "\n" [usage prog,"":fromError args]) w
# args = fromOk args
| size args.input==0
= exit "Specify an input file" w
# args & output = if (size args.output==0)
(addExtension args.input "html")
args.output
# (ok,input,w) = fopen args.input FReadData w
| not ok
= exit "Could not open input file" w
# (profile,input) = read_profile input
# (_,w) = fclose input w
| isError profile
= exit ("Could not parse input: "+++fromError profile) w
# profile = prepare args.min_cumulative_ticks args.exclude (fromOk profile)
# costs = compute_aggregate_costs profile
# calls = compute_call_matrix profile
# (ok,f,w) = fopen args.output FWriteText w
| not ok
= exit "Could not open output file" w
# f = write_profile costs calls profile f
# (_,w) = fclose f w
= w
where
usage prog = concat
[ "Usage: "
, prog
, " [options] INPUT"
]
option_description =
WithHelp True $ Options
[ Shorthand "-o" "--output" $ Option "--output"
(\op opts -> Ok {opts & output=op})
"OUTPUT"
"The output file"
, Shorthand "-e" "--exclude" $ Option "--exclude"
(\e opts -> Ok {opts & exclude='Data.Set'.insert e opts.exclude})
"MODULE:FUNCTION"
"A function to exclude (may be specified multiple times)"
, Option "--min-ticks"
(\t opts -> case toInt t of
0
| t=="0"
-> Ok {opts & min_cumulative_ticks=0}
-> Error [concat ["--min-ticks: invalid integer '",t,"'"]]
t
-> Ok {opts & min_cumulative_ticks=t})
"N"
"Only include cost centres with at least N ticks (cumulatively)"
, Operand
False
(\ip opts
| size opts.input==0
-> Just (Ok {opts & input=ip})
-> Nothing)
"INPUT"
"The input file"
]
exit err w
# (_,w) = fclose (stderr <<< err <<< '\n') w
= setReturnCode -1 w
:: Call =
{ call_count :: !Int
, call_ticks :: !Int
, call_words :: !Int
}
compute_call_matrix :: !Profile -> .{#.{#Call}}
compute_call_matrix {cost_centres,profile}
# calls =
{ createArray
(size cost_centres)
{call_count=0,call_ticks=0,call_words=0}
\\ _ <- [1..size cost_centres]
}
= aggregate_calls profile calls
where
aggregate_calls :: !ProfileStack !*{#*{#Call}} -> *{#*{#Call}}
aggregate_calls {cost_centre,children} calls
# calls = foldr
(\c calls
# (call,calls) = calls![cost_centre,c.cost_centre]
# call
& call_count = call.call_count + c.scalls + c.lcalls + c.ccalls
, call_ticks = call.call_ticks + c.cumulative_ticks
, call_words = call.call_words + c.cumulative_words
-> {calls & [cost_centre,c.cost_centre]=call})
calls
children
# calls = foldr aggregate_calls calls children
= calls
:: Costs =
{ costs_ticks :: !Int
, costs_words :: !Int
}
compute_aggregate_costs :: !Profile -> .{#Costs}
compute_aggregate_costs {cost_centres,profile}
# costs = createArray (size cost_centres) {costs_ticks=0,costs_words=0}
= aggregate_costs profile costs
where
aggregate_costs :: !ProfileStack !*{#Costs} -> *{#Costs}
aggregate_costs p costs
# (this,costs) = costs![p.cost_centre]
# this
& costs_ticks = this.costs_ticks + p.ticks
, costs_words = this.costs_words + p.words
# costs & [p.cost_centre] = this
# costs = foldr aggregate_costs costs p.children
= costs
write_profile :: !{#Costs} !{#{#Call}} !Profile !*File -> *File
write_profile costs calls p f
# f = f <<< "# callgrind format\n"
# f = f <<< "events: Cycles Words\n"
# f = write_cost_centres (size p.cost_centres-1) costs calls p.cost_centres p.modules f
= f
write_cost_centres :: !Int !{#Costs} !{#{#Call}} !{#CostCentre} !{#String} !*File -> *File
write_cost_centres -1 _ _ _ _ f = f
write_cost_centres i costs calls ccs mods f
# f = f <<< "fl=" <<< mods.[ccs.[i].cc_module] <<< "\n"
# f = f <<< "fn=" <<< ccs.[i].cc_name <<< "\n"
# f = f <<< "0 " <<< costs.[i].costs_ticks <<< " " <<< costs.[i].costs_words <<< "\n"
# f = write_calls (size ccs-1) calls.[i] f
= write_cost_centres (i-1) costs calls ccs mods f
where
write_calls -1 _ f = f
write_calls i calls f
# f = case calls.[i] of
{call_count=0}
= f
{call_count,call_ticks,call_words}
# f = f <<< "cfi=" <<< mods.[ccs.[i].cc_module] <<< "\n"
# f = f <<< "cfn=" <<< ccs.[i].cc_name <<< "\n"
# f = f <<< "calls=" <<< call_count <<< " 0\n"
# f = f <<< "0 " <<< call_ticks <<< " " <<< call_words <<< "\n"
= f
= write_calls (i-1) calls f
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment