diff options
author | Pierre Tardy <tardyp@gmail.com> | 2010-05-09 16:31:54 +0200 |
---|---|---|
committer | Pierre Tardy <tardyp@gmail.com> | 2010-05-09 16:31:54 +0200 |
commit | 23b825f23ea95a3946f4b886612493690f1ba088 (patch) | |
tree | 2aabeae734356040908ff86804bf8fa925fe24ad | |
parent | 32fc9c6e44387a8c70a031e6a2ce1bf0e4d409a6 (diff) |
timechart: Added some stats depending on selection
Signed-off-by: Pierre Tardy <tardyp@gmail.com>
-rwxr-xr-x | timechart.py | 38 | ||||
-rwxr-xr-x | timechart/timechart.py | 79 | ||||
-rwxr-xr-x | timechart/timechart_plot.py | 28 |
3 files changed, 103 insertions, 42 deletions
diff --git a/timechart.py b/timechart.py index 2714609..67a57a0 100755 --- a/timechart.py +++ b/timechart.py @@ -17,7 +17,7 @@ from enthought.pyface.action.api import StatusBarManager, ToolBarManager from enthought.pyface.action.api import Group as ActionGroup from enthought.pyface.api import SplitApplicationWindow, SplitPanel -from enthought.traits.ui.api import Item, Group, View,spring,HGroup +from enthought.traits.ui.api import Item, Group, View,spring,HGroup,TableEditor from enthought.traits.api import HasTraits,Button,Str from enthought.traits.ui.menu import OKButton @@ -83,7 +83,6 @@ class MainWindow(ApplicationWindow): # Create an action that exits the application. exit_action = Action(name='exit', on_perform=self.close) - switch_action = Action(name='switch_control', on_perform=self.switch) help_action = Action(name='About', on_perform = self.show_about) # Add a menu bar. @@ -99,21 +98,6 @@ class MainWindow(ApplicationWindow): return def open_file(self): self.status_bar_manager.message=open_file() - def switch(self): - if self.using_old: - self.using_old = False - self.plot = create_timechart_container(self.proj) - else: - self.using_old = True - self.plot = create_timechart_container_old(self.proj) - plotwindow = Window(parent=self.window,kind='panel',component = self.plot) - new = DockControl( name = 'Plot', - closeable = False, - control = plotwindow.control, - width=600, - style = 'horizontal' ) - self.sizer.GetContents().replace_control(self.plot_control,new) - self.plot_control = new def on_range_changed(self,r): time = r[1]-r[0] self.status_bar_manager.message = "total view: %d.%03d %03ds %d"%(time/1000000,(time/1000)%1000,time%1000,time) @@ -124,7 +108,7 @@ class MainWindow(ApplicationWindow): self.plot = create_timechart_container(self.proj) options_confview = self.plot.options.edit_traits(parent=window,kind='panel',scrollable=True) range_tools_confview = self.plot.range_tools.edit_traits(parent=window,kind='panel',scrollable=True) - #project_confview = self.plot.proj.edit_traits(parent=window,kind='panel',scrollable=True) + project_confview = self.plot.proj.edit_traits(parent=window,kind='panel',scrollable=True) plotwindow = Window(parent=window,kind='panel',component = self.plot) self.plot.index_range.on_trait_change(self.on_range_changed, "updated") @@ -143,12 +127,12 @@ class MainWindow(ApplicationWindow): closeable = False, control = range_tools_confview.control, style = 'horizontal' ), - # DockControl( name = 'Plot', - # closeable = False, - # control = project_confview.control, - # style = 'horizontal' ) ], - self.plot_control + self.plot_control, + DockControl( name = 'Plot', + closeable = False, + control = project_confview.control, + style = 'horizontal' ) ]) self.sizer = sizer window.SetSizer( sizer ) @@ -173,7 +157,7 @@ def open_file(): return rv # Application entry point. -prof=0 +prof=1 if __name__ == '__main__': # Create the GUI (this does NOT start the GUI event loop). gui = GUI() @@ -185,7 +169,11 @@ if __name__ == '__main__': fn = open_file() if not fn: sys.exit(1) - proj.load(fn) + if prof: + import cProfile + cProfile.run('proj.load(fn)','timechart_load.prof') + else: + proj.load(fn) # Create and open the main window. window = MainWindow(proj = proj,size=(1024,768),title="PyTimechart:%s"%(fn)) window.open() diff --git a/timechart/timechart.py b/timechart/timechart.py index 8d746b9..da182a7 100755 --- a/timechart/timechart.py +++ b/timechart/timechart.py @@ -5,8 +5,10 @@ from numpy import amin, amax, arange, searchsorted, sin, pi, linspace import numpy as np from enthought.traits.api import HasTraits, Instance, Str, Float,Delegate,\ DelegatesTo,Int,Enum,Color,List,Bool,CArray,Property, cached_property, String -from enthought.traits.ui.api import Group, HGroup, Item, View, spring, Handler,VGroup +from enthought.traits.ui.api import Group, HGroup, Item, View, spring, Handler,VGroup,TableEditor from enthought.enable.colors import ColorTrait +from enthought.traits.ui.table_column \ + import ObjectColumn, ExpressionColumn import cPickle import random @@ -62,6 +64,20 @@ class Timechart(HasTraits): @cached_property def _get_max_latency(self): return -1 + def get_partial_tables(self,start,end): + low_i = searchsorted(self.end_ts,start) + high_i = searchsorted(self.start_ts,end) + ends = self.end_ts[low_i:high_i].copy() + starts = self.start_ts[low_i:high_i].copy() + if len(starts)==0: + return np.array([]),np.array([]),[] + # take care of activities crossing the selection + if starts[0]<start: + starts[0] = start + if ends[-1]>end: + ends[-1] = end + types = self.types[low_i:high_i] + return starts,ends,types class Process(Timechart): name = Property(String) # overide TimeChart # start_ts=CArray # inherited from TimeChart @@ -69,10 +85,13 @@ class Process(Timechart): # values = CArray # inherited from TimeChart pid = Int ppid = Int + selection_time = Int(0) + selection_pc = Float(0) comm = String cpus = CArray comments = CArray has_comments = Bool(True) + show = Bool(True) project = None @cached_property def _get_name(self): @@ -102,8 +121,7 @@ class Process(Timechart): indices = np.nonzero((self.end_ts - self.start_ts) > self.max_latency)[0] return np.array(sorted(map(lambda i:self.start_ts[i], indices))) return [] - - + @cached_property def _get_bg_color(self): if self.max_latency >0 and max(self.end_ts - self.start_ts)>self.max_latency: @@ -118,15 +136,39 @@ class Process(Timechart): return (.3,1,.3,1) else: return (.9,.9,1,1) - -class TimechartProject(HasTraits): + +# The definition of the process TableEditor: +process_table_editor = TableEditor( + columns = [ + ObjectColumn( name = 'comm', width = 0.45 ,editable=False), + ObjectColumn( name = 'pid', width = 0.10 ,editable=False), + ObjectColumn( name = 'selection_time',label="stime", width = 0.20 ,editable=False), + ExpressionColumn( + label = 'stime%', + width = 0.20, + expression = "'%.2f' % (object.selection_pc)" ) + ], + deletable = False, + sort_model = False, + auto_size = False, + orientation = 'vertical', + show_toolbar = False + ) + +class TimechartProject(HasTraits): c_states = List(Timechart) p_states = List(Timechart) processes = List(Process) power_event = CArray num_cpu = Property(Int,depends_on='c_states') num_process = Property(Int,depends_on='process') + traits_view = View( + Item( 'processes', + show_label = False, + height=40, + editor = process_table_editor + )) @cached_property def _get_num_cpu(self): return len(self.c_states) @@ -137,7 +179,7 @@ class TimechartProject(HasTraits): c_states = [ Timechart(name="CCPU%d"%(i)) for i in xrange(num_cpu)] p_states = [ Timechart(name="FCPU%d"%(i)) for i in xrange(num_cpu)] processes = [ Process(comm="program#%d"%(i),pid=i,ppid=i-1) for i in xrange(num_process)] - + for i in xrange(num_cpu): c_states[i].random(length,6,100) p_states[i].random(length,1000,1000) @@ -151,6 +193,31 @@ class TimechartProject(HasTraits): return self.load_tmct(filename) else: return self.load_ftrace(filename) +######### stats part ########## + + def c_states_stats(self,start,end): + l = [] + for tc in self.c_states: # walk cstates per cpus + starts,ends,types = tc.get_partial_tables(start,end) + stats = {} + tot = 0 + for t in np.unique(types): + inds = np.where(types==t) + time = sum(ends[inds]-starts[inds]) + tot += time + stats[t] = time + stats[0] = (end-start)-tot + l.append(stats) + return l + def process_stats(self,start,end): + fact = 100./(end-start) + for tc in self.processes: + starts,ends,types = tc.get_partial_tables(start,end) + #@todo, need to take care of running vs waiting + inds = np.where(types==1) + tot = sum(ends[inds]-starts[inds]) + tc.selection_time = tot + tc.selection_pc = tot*fact ######### ftrace parsing part ########## diff --git a/timechart/timechart_plot.py b/timechart/timechart_plot.py index dcc1fcc..8d4ba3e 100755 --- a/timechart/timechart_plot.py +++ b/timechart/timechart_plot.py @@ -56,18 +56,17 @@ class TimeChartOptions(HasTraits): self.plot.invalidate()
def _auto_zoom_y_changed(self,val):
self.plot.value_range.high = self.plot.max_y+1
- self.plot.value_range.low = self.plot.min_y
+ self.plot.value_range.low = self.plot.min_y
self.plot.invalidate_draw()
self.plot.request_redraw()
+
class RangeSelectionTools(HasTraits):
time = Str
c_states = Str
- top_process = Str
zoom = Button()
traits_view = View(VGroup(
Item('time'),
- Item('c_states'),
- Item('top_process'),
+ Item('c_states',style="custom"),
Item('zoom'),
label='Selection Infos'
))
@@ -88,11 +87,19 @@ class RangeSelectionTools(HasTraits): self.plot.range_selection.deselect()
self.plot.invalidate_draw()
self.plot.request_redraw()
-
+
def _selection_updated_delayed(self):
- #@todo here we need to update c_states and top_process stats.
- self.c_states= "not yet implemented"
- self.top_process= "not yet implemented"
+ c_states_stats = self.plot.proj.c_states_stats(self.start,self.end)
+ tmp = ""
+ i=0
+ for cpu_stat in c_states_stats:
+ tmp+="cpu%d:\n"%(i)
+ i+=1
+ for cstate in sorted([i for i in cpu_stat.keys()]):
+ part = cpu_stat[cstate]
+ tmp += "C%d:%dus %02.f%%\n"%(cstate,part,part*100/(self.end-self.start))
+ self.c_states = tmp
+ self.plot.proj.process_stats(self.start,self.end)
self._timer.Stop()
pass
class TimeChartPlot(BarPlot):
@@ -360,7 +367,7 @@ def create_timechart_container(project): if len(tc.start_ts):
low = min(low,tc.start_ts[0])
high = max(high,tc.end_ts[-1])
-
+ project.process_stats(low,high)
# we have the same x_mapper/range for each plots
index_range = DataRange1D(low=low, high=high)
index_mapper = LinearMapper(range=index_range,domain_limit=(low,high))
@@ -386,7 +393,7 @@ def create_timechart_container(project): zoom = myZoomTool(component=plot, tool_mode="range", always_on=True,axis="index",drag_button=None)
plot.tools.append(zoom)
- plot.range_selection = RangeSelection(plot,resize_margin=1,left_button_selects=False)
+ plot.range_selection = RangeSelection(plot,resize_margin=1)
plot.tools.append(plot.range_selection)
plot.overlays.append(RangeSelectionOverlay(component=plot,axis="index",use_backbuffer=True))
@@ -394,5 +401,4 @@ def create_timechart_container(project): plot.underlays.append(axe)
plot.options.connect(plot)
plot.range_tools.connect(plot)
-
return plot
|