@@ -456,6 +456,105 @@ def plot_file(filename, index=0, timestamps=True, children=True, options=None):
456456 return mprofile
457457
458458
459+ def flame_plotter (filename , index = 0 , timestamps = True , children = True , options = None ):
460+ try :
461+ import pylab as pl
462+ except ImportError as e :
463+ print ("matplotlib is needed for plotting." )
464+ print (e )
465+ sys .exit (1 )
466+ import numpy as np # pylab requires numpy anyway
467+ mprofile = read_mprofile_file (filename )
468+
469+ if len (mprofile ['timestamp' ]) == 0 :
470+ print ('** No memory usage values have been found in the profile '
471+ 'file.**\n File path: {0}\n '
472+ 'File may be empty or invalid.\n '
473+ 'It can be deleted with "mprof rm {0}"' .format (
474+ mprofile ['filename' ]))
475+ sys .exit (0 )
476+
477+ # Merge function timestamps and memory usage together
478+ ts = mprofile ['func_timestamp' ]
479+ t = mprofile ['timestamp' ]
480+ mem = mprofile ['mem_usage' ]
481+ chld = mprofile ['children' ]
482+
483+ if len (ts ) > 0 :
484+ for values in ts .values ():
485+ for v in values :
486+ t .extend (v [:2 ])
487+ mem .extend (v [2 :4 ])
488+
489+ mem = np .asarray (mem )
490+ t = np .asarray (t )
491+ ind = t .argsort ()
492+ mem = mem [ind ]
493+ t = t [ind ]
494+
495+ # Plot curves
496+ global_start = float (t [0 ])
497+ t = t - global_start
498+
499+ max_mem = mem .max ()
500+ max_mem_ind = mem .argmax ()
501+
502+ all_colors = ("c" , "y" , "g" , "r" , "b" )
503+ mem_line_colors = ("k" , "b" , "r" , "g" , "c" , "y" , "m" )
504+ mem_line_label = time .strftime ("%d / %m / %Y - start at %H:%M:%S" ,
505+ time .localtime (global_start )) \
506+ + ".{0:03d}" .format (int (round (math .modf (global_start )[0 ] * 1000 )))
507+
508+ pl .plot (t , mem , "+-" + mem_line_colors [index % len (mem_line_colors )],
509+ label = mem_line_label )
510+
511+ bottom , top = pl .ylim ()
512+ bottom += 0.001
513+ top -= 0.001
514+
515+ # plot children, if any
516+ if len (chld ) > 0 and children :
517+ cmpoint = (0 ,0 ) # maximal child memory
518+
519+ for idx , (proc , data ) in enumerate (chld .items ()):
520+ # Create the numpy arrays from the series data
521+ cts = np .asarray ([item [1 ] for item in data ]) - global_start
522+ cmem = np .asarray ([item [0 ] for item in data ])
523+
524+ # Plot the line to the figure
525+ pl .plot (cts , cmem , "+-" + mem_line_colors [(idx + 1 ) % len (mem_line_colors )],
526+ label = "child {}" .format (proc ))
527+
528+ # Detect the maximal child memory point
529+ cmax_mem = cmem .max ()
530+ if cmax_mem > cmpoint [1 ]:
531+ cmpoint = (cts [cmem .argmax ()], cmax_mem )
532+
533+ # Add the marker lines for the maximal child memory usage
534+ pl .vlines (cmpoint [0 ], pl .ylim ()[0 ]+ 0.001 , pl .ylim ()[1 ] - 0.001 , 'r' , '--' )
535+ pl .hlines (cmpoint [1 ], pl .xlim ()[0 ]+ 0.001 , pl .xlim ()[1 ] - 0.001 , 'r' , '--' )
536+
537+ # plot timestamps, if any
538+ if len (ts ) > 0 and timestamps :
539+ func_num = 0
540+ f_labels = function_labels (ts .keys ())
541+ for f , exec_ts in ts .items ():
542+ for execution in exec_ts :
543+ add_brackets (execution [:2 ], execution [2 :], xshift = global_start ,
544+ color = all_colors [func_num % len (all_colors )],
545+ label = f_labels [f ]
546+ + " %.3fs" % (execution [1 ] - execution [0 ]), options = options )
547+ func_num += 1
548+
549+ if timestamps :
550+ pl .hlines (max_mem ,
551+ pl .xlim ()[0 ] + 0.001 , pl .xlim ()[1 ] - 0.001 ,
552+ colors = "r" , linestyles = "--" )
553+ pl .vlines (t [max_mem_ind ], bottom , top ,
554+ colors = "r" , linestyles = "--" )
555+ return mprofile
556+
557+
459558def function_labels (dotted_function_names ):
460559 state = {}
461560
@@ -507,6 +606,8 @@ def xlim_type(value):
507606 help = "Save plot to file instead of displaying it." )
508607 parser .add_argument ("--window" , "-w" , dest = "xlim" , type = xlim_type ,
509608 help = "Plot a time-subset of the data. E.g. to plot between 0 and 20.5 seconds: --window 0,20.5" )
609+ parser .add_argument ("--flame" , "-f" , dest = "flame_mode" , action = "store_true" ,
610+ help = "Plot the timestamps as a flame-graph instead of the default brackets" )
510611 parser .add_argument ("--backend" ,
511612 help = "Specify the Matplotlib backend to use" )
512613 parser .add_argument ("profiles" , nargs = "*" ,
@@ -561,8 +662,11 @@ def xlim_type(value):
561662 timestamps = False
562663 else :
563664 timestamps = True
665+ plotter = plot_file
666+ if args .flame_mode :
667+ plotter = flame_plotter
564668 for n , filename in enumerate (filenames ):
565- mprofile = plot_file (filename , index = n , timestamps = timestamps , options = args )
669+ mprofile = plotter (filename , index = n , timestamps = timestamps , options = args )
566670 pl .xlabel ("time (in seconds)" )
567671 pl .ylabel ("memory used (in MiB)" )
568672
0 commit comments