aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPierre Tardy <tardyp@gmail.com>2010-05-09 16:31:54 +0200
committerPierre Tardy <tardyp@gmail.com>2010-05-09 16:31:54 +0200
commit23b825f23ea95a3946f4b886612493690f1ba088 (patch)
tree2aabeae734356040908ff86804bf8fa925fe24ad
parent32fc9c6e44387a8c70a031e6a2ce1bf0e4d409a6 (diff)
timechart: Added some stats depending on selection
Signed-off-by: Pierre Tardy <tardyp@gmail.com>
-rwxr-xr-xtimechart.py38
-rwxr-xr-xtimechart/timechart.py79
-rwxr-xr-xtimechart/timechart_plot.py28
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