summaryrefslogtreecommitdiff
path: root/util/stats/profile.py
diff options
context:
space:
mode:
Diffstat (limited to 'util/stats/profile.py')
-rw-r--r--util/stats/profile.py146
1 files changed, 146 insertions, 0 deletions
diff --git a/util/stats/profile.py b/util/stats/profile.py
new file mode 100644
index 000000000..65a03e9aa
--- /dev/null
+++ b/util/stats/profile.py
@@ -0,0 +1,146 @@
+# Copyright (c) 2005 The Regents of The University of Michigan
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+from orderdict import orderdict
+import output
+
+class ProfileData(object):
+ def __init__(self):
+ self.data = {}
+ self.total = {}
+ self.runs = orderdict()
+ self.runlist = []
+
+ def addvalue(self, run, cpu, symbol, value):
+ value = float(value)
+ self.data[run, cpu, symbol] = self.getvalue(run, cpu, symbol) + value
+ self.total[run, cpu] = self.gettotal(run, cpu) + value
+ if run not in self.runs:
+ self.runs[run] = orderdict()
+
+ if cpu not in self.runs[run]:
+ self.runs[run][cpu] = {}
+
+ if symbol not in self.runs[run][cpu]:
+ self.runs[run][cpu][symbol] = 0
+
+ self.runs[run][cpu][symbol] += value
+
+ def getvalue(self, run, cpu, symbol):
+ return self.data.get((run, cpu, symbol), 0)
+
+ def gettotal(self, run, cpu):
+ return self.total.get((run, cpu), 0)
+
+class Profile(object):
+ default_order = ['ste', 'hte', 'htd', 'ocm', 'occ', 'ocp']
+
+ # This list controls the order of values in stacked bar data output
+ default_categories = [ 'interrupt',
+ 'driver',
+ 'stack',
+ 'bufmgt',
+ 'copy',
+ 'user',
+ 'other',
+ 'idle']
+
+ def __init__(self, run_order=[], categories=[], stacknames=[]):
+ if not run_order:
+ run_order = Profile.default_order
+ if not categories:
+ categories = Profile.default_categories
+
+ self.run_order = run_order
+ self.categories = categories
+ self.rcategories = []
+ self.rcategories.extend(categories)
+ self.rcategories.reverse()
+ self.stacknames = stacknames
+ self.prof = ProfileData()
+ self.categorize = True
+ self.showidle = True
+ self.maxsymlen = 0
+
+ def category(self, symbol):
+ from categories import categories, categories_re
+ if categories.has_key(symbol):
+ return categories[symbol]
+ for regexp, cat in categories_re:
+ if regexp.match(symbol):
+ return cat
+ return 'other'
+
+ # Parse input file and put the results in the given run and cpu
+ def parsefile(self, run, cpu, filename):
+ fd = file(filename)
+
+ for line in fd:
+ (symbol, count) = line.split()
+ if symbol == "0x0":
+ continue
+ count = int(count)
+
+ if self.categorize:
+ symbol = self.category(symbol)
+ if symbol == 'idle' and not self.showidle:
+ continue
+
+ if symbol not in self.categories:
+ symbol = 'other'
+
+ self.maxsymlen = max(self.maxsymlen, len(symbol))
+ self.prof.addvalue(run, cpu, symbol, count)
+
+ fd.close()
+
+ # Read in files
+ def inputdir(self, directory):
+ import os, os.path, re
+ from os.path import expanduser, join as joinpath
+
+ directory = expanduser(directory)
+ label_ex = re.compile(r'm5prof\.(.*)')
+ for root,dirs,files in os.walk(directory):
+ for name in files:
+ match = label_ex.match(name)
+ if not match:
+ continue
+
+ filename = joinpath(root, name)
+ prefix = os.path.commonprefix([root, directory])
+ dirname = root[len(prefix)+1:]
+ self.parsefile(dirname, match.group(1), filename)
+
+ def get(self, job, stat):
+ if job.system is None:
+ raise AttributeError, 'The job must have a system set'
+
+ cpu = '%s.full0' % job.system
+ values = []
+ for cat in self.categories:
+ values.append(self.prof.getvalue(job.name, cpu, cat))
+ return values