[Dev] event profiling and profile tool
Mike Taylor
bear at code-bear.com
Thu Feb 10 16:35:35 PST 2005
That was a similar idea I was working thru to allow for a "Chandler
Startup" unit test - something that allowed us to test/time the startup
process. My thought was also to just script event names and then add a
basic hook that would inject them into the wx or cpia event queue
directly.
---
Bear
http://code-bear.com
PGP Fingerprint = 9996 719F 973D B11B E111 D770 9331 E822 40B3 CD29
On Feb 10, 2005, at 7:21 PM, Alec Flett wrote:
> Phillip J. Eby wrote:
>
>> At 10:32 AM 2/10/05 -0800, Ted Leung wrote:
>>
>>> It would also be good to coordinate your CLI with Phillip's code for
>>> profiling the unit tests...
>>
>>
>> Perhaps my tool should use 'events.prof' instead of 'profile.dat', or
>> vice versa. OTOH, if Alec's profile analysis tool accepts the
>> filename on the command line, then it's of no import. One could
>> simply run the unit tests and then run the analysis tool on
>> profile.dat to analyze the test results.
>>
> Ted and I were talking about this - one thing that would probably be
> really good to work out is a method of generating events to chandler
> itself - orthogonal to the unit tests, we probably need a way to
> simulate at least a few user actions to the full chandler app. Really,
> this could be as easy as:
> - having a bunch of event names with possible parameters (a few events
> take parameters) in a text file
> - a command line option for chandler to "execute" this script by just
> firing off the events listed in the file once the UI has appeared,
> wait a bit, then quit the app
>
> I think an important thing to know about the event profiling things
> are that they are based on CPIA events, which are application events -
> i.e. when someone selects a menu item, and so forth. We can simulate
> those pretty easily by just dispatching them to the toplevel view.
>
>
>> I'm certainly curious to see the profile navigation. I seem to
>> recall that somebody has written a nice GUI for analyzing Python
>> profiling results but I don't remember where I saw it. Personally I
>> haven't had reason to do much with profiler data besides sort the
>> data a couple different ways and display the top 10 or 20 routines by
>> time, cumulative time, or number of calls.
>>
> its pretty darn rudamentary (but it does take the filename on the
> command line) - it runs on the console and its basically stuff like
> "show callers of <functionName>" or "show stats sorted by <field>" -
> we probably want a GUI for doing more elaborate analisys, and I would
> gladly throw it away if you know of a better system out there for
> analyzing these files.
>
> I've attached the python file here and will try to get it checked in
> later (so you guys can hack on it :)
> Alec
>
> #!/usr/bin/env python
>
> import getopt, sys, os
> import hotshot, hotshot.stats
> import pstats
> import cStringIO
>
>
> options = { 'filename': None,
> 'order': 'time',
> 'limit': 20,
> 'output': None,
> 'pager': True }
>
> #
> # process_options - processes the options from the command line
> #
> def process_options():
> optlist, args = getopt.getopt(sys.argv[1:], "p:o:l:c:e:",
> ["profile=",
> "order=",
> "limit=",
> "callers-of=",
> "callees-of="])
>
>
> for opt, arg in optlist:
> if (opt == '-p'):
> options['filename'] = arg
>
> # need to check valid orders:
> # calls, cumulative, file, module, pcalls, line, name, nfl,
> stdname, time
> if (opt == '-o'):
> options['order'] = arg
>
> if (opt == '-l'):
> options['limit'] = int(arg)
>
> if (opt == '-c'):
> options['output'] = 'callers'
> options['data'] = arg
>
> if (opt == '-e'):
> options['output'] = 'callees'
> options['data'] = arg
>
> if args and not options['filename']:
> options['filename'] = args[0]
>
> if not options['order']:
> options['order'] = 'time'
>
> if not options['filename']:
> print "Filename required..."
> exit
>
> #
> # prompt_user - prompts the user for an action, and then sets the
> option
> # structure to match what they entered
> #
> def prompt_user():
> while True:
> try:
> print "c = callers | e = callees | s = stats | o = order |
> l = limit";
>
> line = sys.stdin.readline().strip()
>
> commandline = line.split(None)
> command = commandline[0]
> if len(commandline) > 1:
> data = commandline[1]
> else:
> data = None
>
> if command == 'q':
> return False
>
> if command == 'c':
> options['output'] = 'callers'
> options['data'] = data
>
> if command == 'e':
> options['output'] = 'callees'
> options['data'] = data
>
> if command == 's':
> options['output'] = 'stats'
> options['data'] = data
>
> if command == 'o':
> options['order'] = data
>
> break
>
> except:
> print "Unrecognized command"
>
> return True
>
> #
> # output_with_pager - borrowed from
> http://www.andreasen.org/misc/util.py
> #
> def output_with_pager(string):
> print string
>
> # this seems to be broken right now?
> less = os.popen('less -', 'w')
> #try:
> less.write(string)
> less.close()
> #except:
> pass
>
> #
> # show_profile - displays the profile to the user given the current
> options
> #
> def show_profile(stats):
> # stats.strip_dirs()
> stats.sort_stats(options['order'])
>
> # now capture the output
> out = cStringIO.StringIO()
> old_stdout = sys.stdout
> sys.stdout = out
>
> # Figure out the correct part of stats to call
> try:
> if options['output'] == 'callers':
> print " Callers of '" + options['data'] + "':"
> stats.print_callers(options['data'], options['limit'])
> elif options['output'] == 'callees':
> print " Functions that '" + options['data'] + "' call:"
> stats.print_callees(options['data'], options['limit'])
> else:
> # show stats
> print "Statistics: "
> stats.print_stats(options['limit'])
>
> except:
> print "Couldn't generate output. Possibly bad caller/callee
> pattern"
>
> # reset to defaults
> sys.stdout = old_stdout
> out.seek(0)
>
> parse_state = None;
>
> # keep track of where the 2nd column of functions start
> # we'll find this out from the header
> col2starts = 0
>
> result = "";
> for line in out:
>
> # funclist1: the first line of the function list
> if parse_state == 'funclist':
> function = line[0:col2starts].strip()
> subfunc = line[col2starts:].strip()
> if function:
> result += "\n" + function + "\n"
> result += " " + subfunc + "\n"
>
> # default parse_state, look for Function header
> elif line.startswith('Function'):
> if options['output'] == 'callers':
> col2starts = line.find('was called by')
>
> elif options['output'] == 'callees':
> col2starts = line.find('called')
>
> parse_state = 'funclist'
> else:
> result += line + "\n"
>
> # now spit out to less
> output_with_pager(result)
>
> #
> # main
> #
> def main():
>
> process_options()
>
> stats = hotshot.stats.load(options['filename'])
> while prompt_user():
> show_profile(stats)
>
>
> main()
> _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
>
> Open Source Applications Foundation "Dev" mailing list
> http://lists.osafoundation.org/mailman/listinfo/dev
-------------- next part --------------
A non-text attachment was scrubbed...
Name: PGP.sig
Type: application/pgp-signature
Size: 186 bytes
Desc: This is a digitally signed message part
Url : http://lists.osafoundation.org/pipermail/dev/attachments/20050210/4c5b3e01/PGP.bin
More information about the Dev
mailing list