home *** CD-ROM | disk | FTP | other *** search
- ############################################################################
- #
- # File: memsum.icn
- #
- # Subject: Program to summarize Icon memory management
- #
- # Author: Ralph E. Griswold
- #
- # Date: April 17, 1990
- #
- ###########################################################################
- #
- # This program is a filter for Icon allocation history files (see IPD113).
- # It tabulates the number of allocations by type and the total amount of
- # storage (in bytes) by type.
- #
- # It takes an Icon allocation history file from standard input and writes to
- # standard output.
- #
- # The command-line options are:
- #
- # -t produce tab-separated output for use in spreadsheets (the
- # default is a formatted report)
- #
- # -d produce debugging output
- #
- # -g produce garbage-collection details (formatted report only)
- #
- # -z list types with zero allocation (the default is to not list
- # them)
- #
- # Some assumptions are made about where newlines occur -- specifically
- # that verification commands are on single lines and that refresh and
- # garbage collection data are on multiple lines.
- #
- ############################################################################
- #
- # Links: numbers, options
- #
- ############################################################################
-
- link numbers, options
-
- global cmds, highlights, lastlen, alloccnt, alloctot, collections
- global mmunits, diagnose, namemap, zeroes, gdetail
-
- procedure main(args)
- local line, region, s, skip, opts, prefix
-
- opts := options(args,"dgtz")
- diagnose := if \opts["d"] then write else 1
- gdetail := if \opts["g"] then 1
- display := if \opts["t"] then spread else report
- zeroes := if \opts["z"] then 1
-
- cmds := 'cefihLlRrSsTtux"XAF' # command characters
- highlights := '%$Y' # highlight commands
- mmunits := 4 # default; reset if different
- namemap := table("*** undefined ***")
- namemap["b"] := "large integer"
- namemap["c"] := "cset"
- namemap["e"] := "table-element tv"
- namemap["f"] := "file"
- namemap["h"] := "hash block"
- namemap["i"] := "large integer"
- namemap["L"] := "list header"
- namemap["l"] := "list element"
- namemap["R"] := "record"
- namemap["r"] := "real number"
- namemap["S"] := "set header"
- namemap["s"] := "set element"
- namemap["T"] := "table header"
- namemap["t"] := "table element"
- namemap["u"] := "substring tv"
- namemap["x"] := "refresh block"
- namemap["\""] := "string"
- namemap["X"] := "co-expression"
- namemap["A"] := "alien block"
- namemap["F"] := "free space"
-
- lastlen := table() # last size
- alloccnt := table(0) # count of allocations
- alloctot := table(0) # total allocation
- collections := list(4,0) # garbage collection counts
-
- every alloccnt[!cmds] := 0
- every alloctot[!cmds] := 0
-
- cmds ++:= highlights
-
- while line := read() do # input from allocation history file
- line ? {
- if prefix := tab(upto('{=#;!<>')) then {
- case move(1) of {
- !"=#;!>": next
- "{": { # refresh sequence
- collections[prefix] +:= 1
- while line := read() | stop("**** premature eof") do
- line ? if upto('#!') then break next
- }
- "<": {
- mmunits := integer(prefix) # covers old case with no value
- while line := read() | stop("**** premature eof") do
- line ? if upto('#>') then break next
- }
- }
- }
- else { # process allocation
- while move(process(tab(upto(cmds) + 1)))
- }
- }
-
- display()
-
- end
-
- # Display a table of allocation data
- #
- procedure report()
- local name, cnt, cnttotal, i, tot, totalcoll, tottotal
-
- static col1, col2, gutter # column widths
-
- initial {
- col1 := 16 # name field
- col2 := 10 # number field
- gutter := repl(" ",6)
- }
-
- write(, # write column headings
- "\n",
- left("type",col1),
- right("number",col2),
- gutter,
- right("bytes",col2),
- gutter,
- right("average",col2),
- gutter,
- right("% bytes",col2),
- "\n"
- )
-
- alloccnt := sort(alloccnt,3) # get the data
- alloctot := sort(alloctot,3)
-
- cnttotal := 0
- tottotal := 0
-
- every i := 2 to *alloccnt by 2 do {
- cnttotal +:= alloccnt[i]
- tottotal +:= alloctot[i]
- }
-
- while name := get(alloccnt) do {
- if ((cnt := get(alloccnt)) = 0) & /zeroes then { # skip zero entries
- get(alloctot) # remove unused values
- get(alloctot)
- next # get next group
- }
- write( # write the data
- left(namemap[name],col1), # name
- right(cnt,col2), # number of allocations
- gutter,
- get(alloctot) & right(tot := get(alloctot),col2), # space allocated
- gutter,
- fix(tot,cnt,col2) | repl(" ",col2),
- gutter,
- fix(100.0 * tot,tottotal,col2) | repl(" ",col2)
- )
- }
-
- write( # write totals
- "\n",
- left("total:",col1),
- right(cnttotal,col2),
- gutter,
- right(tottotal,col2),
- gutter,
- fix(tottotal,cnttotal,col2) | repl(" ",col2)
- )
-
- totalcoll := 0 # garbage collections
- every totalcoll +:= !collections
- write("\n",left("collections:",col1),right(totalcoll,col2))
- if totalcoll > 0 then {
- write(left(" static region:",col1),right(collections[1],col2))
- write(left(" string region:",col1),right(collections[2],col2))
- write(left(" block region:",col1),right(collections[3],col2))
- write(left(" no region:",col1),right(collections[4],col2))
- }
-
- return
- end
-
- # Produce tab-separated output for a spreadsheet. The first column
- # is the type name, the second column is the number of allocations,
- # and the third column is the total number of bytes allocated for that
- # type.
- #
- procedure spread()
- local name, number, total
-
- alloccnt := sort(alloccnt,3) # get the data
- alloctot := sort(alloctot,3)
-
- write("type\tnumber\ttotal bytes") # label row
- while name := namemap[get(alloccnt)] do {
- number := get(alloccnt)
- get(alloctot)
- total := get(alloctot)
- if (number = 0) & /zeroes then next
- write(name,"\t",number,"\t",total)
- }
-
- return
- end
-
- # Process data
- #
- procedure process(s)
- local cmd, len
-
- s ? {
- tab(upto('+') + 1) # skip address
- len := tab(many(&digits)) | &null
- cmd := move(1)
-
- if cmd == !highlights then return 2 else {
- # if given len is nonstring, scale
- if cmd ~== "\"" then \len *:= mmunits
- alloccnt[cmd] +:= 1
- (/len := lastlen[cmd]) | (lastlen[cmd] := len)
- diagnose(&errout,"cmd=",cmd,", len=",len)
- alloctot[cmd] +:= len
- return 0
- }
- }
- end
-