profile.py revision 1881:fc205a7edd58
1# Copyright (c) 2005 The Regents of The University of Michigan
2# All rights reserved.
3#
4# Redistribution and use in source and binary forms, with or without
5# modification, are permitted provided that the following conditions are
6# met: redistributions of source code must retain the above copyright
7# notice, this list of conditions and the following disclaimer;
8# redistributions in binary form must reproduce the above copyright
9# notice, this list of conditions and the following disclaimer in the
10# documentation and/or other materials provided with the distribution;
11# neither the name of the copyright holders nor the names of its
12# contributors may be used to endorse or promote products derived from
13# this software without specific prior written permission.
14#
15# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
27from orderdict import orderdict
28import output
29
30class ProfileData(object):
31    def __init__(self):
32        self.data = {}
33        self.total = {}
34        self.runs = orderdict()
35        self.runlist = []
36
37    def addvalue(self, run, cpu, symbol, value):
38        value = float(value)
39        self.data[run, cpu, symbol] = self.getvalue(run, cpu, symbol) + value
40        self.total[run, cpu] = self.gettotal(run, cpu) + value
41        if run not in self.runs:
42            self.runs[run] = orderdict()
43
44        if cpu not in self.runs[run]:
45            self.runs[run][cpu] = {}
46
47        if symbol not in self.runs[run][cpu]:
48            self.runs[run][cpu][symbol] = 0
49
50        self.runs[run][cpu][symbol] += value
51
52    def getvalue(self, run, cpu, symbol):
53        return self.data.get((run, cpu, symbol), 0)
54
55    def gettotal(self, run, cpu):
56        return self.total.get((run, cpu), 0)
57
58class Profile(object):
59    default_order = ['ste', 'hte', 'htd', 'ocm', 'occ', 'ocp']
60
61    # This list controls the order of values in stacked bar data output
62    default_categories = [ 'interrupt',
63                           'driver',
64                           'stack',
65                           'bufmgt',
66                           'copy',
67                           'user',
68                           'other',
69                           'idle']
70
71    def __init__(self, run_order=[], categories=[], stacknames=[]):
72        if not run_order:
73            run_order = Profile.default_order
74        if not categories:
75            categories = Profile.default_categories
76
77        self.run_order = run_order
78        self.categories = categories
79        self.rcategories = []
80        self.rcategories.extend(categories)
81        self.rcategories.reverse()
82        self.stacknames = stacknames
83        self.prof = ProfileData()
84        self.categorize = True
85        self.showidle = True
86        self.maxsymlen = 0
87
88    def category(self, symbol):
89        from categories import categories, categories_re
90        if categories.has_key(symbol):
91            return categories[symbol]
92        for regexp, cat in categories_re:
93            if regexp.match(symbol):
94                return cat
95        return 'other'
96
97    # Parse input file and put the results in the given run and cpu
98    def parsefile(self, run, cpu, filename):
99        fd = file(filename)
100
101        for line in fd:
102            (symbol, count) = line.split()
103            if symbol == "0x0":
104                continue
105            count = int(count)
106
107            if self.categorize:
108                symbol = self.category(symbol)
109                if symbol == 'idle' and not self.showidle:
110                    continue
111
112                if symbol not in self.categories:
113                    symbol = 'other'
114
115            self.maxsymlen = max(self.maxsymlen, len(symbol))
116            self.prof.addvalue(run, cpu, symbol, count)
117
118        fd.close()
119
120    # Read in files
121    def inputdir(self, directory):
122        import os, os.path, re
123        from os.path import expanduser, join as joinpath
124
125        directory = expanduser(directory)
126        label_ex = re.compile(r'm5prof\.(.*)')
127        for root,dirs,files in os.walk(directory):
128            for name in files:
129                match = label_ex.match(name)
130                if not match:
131                    continue
132
133                filename = joinpath(root, name)
134                prefix = os.path.commonprefix([root, directory])
135                dirname = root[len(prefix)+1:]
136                self.parsefile(dirname, match.group(1), filename)
137
138    def get(self, job, stat):
139        if job.system is None:
140            raise AttributeError, 'The job must have a system set'
141
142        cpu =  '%s.full0' % job.system
143        values = []
144        for cat in self.categories:
145            values.append(self.prof.getvalue(job.name, cpu, cat))
146        return values
147