|
1 # |
|
2 # Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). |
|
3 # All rights reserved. |
|
4 # This component and the accompanying materials are made available |
|
5 # under the terms of the License "Eclipse Public License v1.0" |
|
6 # which accompanies this distribution, and is available |
|
7 # at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 # |
|
9 # Initial Contributors: |
|
10 # Nokia Corporation - initial contribution. |
|
11 # |
|
12 # Contributors: |
|
13 # |
|
14 # Description: |
|
15 # Annofile class |
|
16 # |
|
17 |
|
18 import xml.sax |
|
19 import os |
|
20 |
|
21 class Annofile(xml.sax.handler.ContentHandler): |
|
22 """A class to represent an emake anno file""" |
|
23 |
|
24 def __init__(self, name, maxagents=30): |
|
25 self.name = name |
|
26 self.overallAggregateTime = 0 |
|
27 self.inJob = False |
|
28 self.inMetricDuration = False |
|
29 self.jobType = '' |
|
30 self.nodes = set() |
|
31 self.maxagents = maxagents |
|
32 |
|
33 parser = xml.sax.make_parser() |
|
34 parser.setContentHandler(self) |
|
35 try: |
|
36 parser.parse(open(name)) |
|
37 except xml.sax._exceptions.SAXParseException, e: |
|
38 print "Error:\n" + str(e) |
|
39 print "Ignore that file, parsing continues..." |
|
40 |
|
41 |
|
42 def startElement(self, name, attrs): |
|
43 if name == 'build': |
|
44 # attrs.get() returns unicode type |
|
45 self.cm = attrs.get('cm', '') |
|
46 |
|
47 elif name == 'job': |
|
48 self.inJob = True |
|
49 self.jobType = attrs.get('type', '') |
|
50 |
|
51 elif name == 'timing': |
|
52 # Find agent number |
|
53 node = attrs.get('node') |
|
54 if node not in self.nodes: |
|
55 self.nodes.add(node) |
|
56 |
|
57 # Calculate aggregate build time |
|
58 # This is the sum of time spending on each node |
|
59 # Ideally it equals the build time if there is |
|
60 # only one node |
|
61 time = float(attrs.get('completed')) \ |
|
62 - float(attrs.get('invoked')) |
|
63 self.overallAggregateTime += time |
|
64 |
|
65 # Calculate parse time |
|
66 if self.inJob and self.jobType == 'parse': |
|
67 self.parseTime = time |
|
68 |
|
69 elif name == 'metric': |
|
70 if attrs.get('name') == 'duration': |
|
71 self.inMetricDuration = True |
|
72 |
|
73 |
|
74 def endElement(self, name): |
|
75 if name == 'job': |
|
76 self.inJob = False |
|
77 elif name == 'metric': |
|
78 if self.inMetricDuration: |
|
79 self.inMetricDuration = False |
|
80 |
|
81 # Parse to the end of XML file |
|
82 elif name == 'build': |
|
83 self.doFinal() |
|
84 |
|
85 def characters(self, ch): |
|
86 if self.inMetricDuration: |
|
87 self.duration = ch |
|
88 |
|
89 |
|
90 # Get class attributes |
|
91 |
|
92 def getParseTime(self): |
|
93 """Get the time that emake spends on |
|
94 parsing all makefiles |
|
95 """ |
|
96 return self.parseTime |
|
97 |
|
98 def getOverallDuration(self): |
|
99 """Get the overall build duration""" |
|
100 return float(self.duration) |
|
101 |
|
102 def getClusterManager(self): |
|
103 return self.cm |
|
104 |
|
105 def getAggregateTime(self): |
|
106 """This is the sum of time spending on each node. |
|
107 Ideally it equals the build time if there is |
|
108 only one node |
|
109 """ |
|
110 return self.overallAggregateTime |
|
111 |
|
112 # Calculate two efficiencies: |
|
113 # first includes makefile parse time; second doesn't |
|
114 def getEfficiency(self): |
|
115 """100% means all nodes are busy from start to finish. |
|
116 """ |
|
117 at = self.getAggregateTime() |
|
118 num = self.maxagents |
|
119 d = self.getOverallDuration() |
|
120 |
|
121 idealDuration = at / num |
|
122 if d != 0: |
|
123 efficiency = round(idealDuration / d, 3) |
|
124 else: |
|
125 efficiency = 0 |
|
126 |
|
127 # This is efficiency WITHOUT counting makefile |
|
128 # parsing time. Tempararily still useful. |
|
129 pt = self.getParseTime() |
|
130 idealD_wo = (at - pt) / num |
|
131 if d != pt: |
|
132 e_wo = round(idealD_wo / (d - pt), 3) |
|
133 else: |
|
134 e_wo = 0 |
|
135 |
|
136 #return str(efficiency * 100) + '%', str(e_wo * 100) + '%' |
|
137 return efficiency, e_wo |
|
138 |
|
139 def doFinal(self): |
|
140 report = open('anno_report.xml', 'a') |
|
141 report.write("<annofile name='%s'>\n" % self.name) |
|
142 report.write("<metric name='agentNumber' value='%s'/>\n" % len(self.nodes)) |
|
143 report.write("<metric name='makefileParseTime' value='%s'/>\n" \ |
|
144 % self.getParseTime()) |
|
145 report.write("<metric name='duration' value='%s'/>\n" \ |
|
146 % self.getOverallDuration()) |
|
147 report.write("<metric name='aggregateTime' value='%s'/>\n" \ |
|
148 % self.getAggregateTime()) |
|
149 report.write("<metric name='efficiency' value='%f'/>\n" \ |
|
150 % self.getEfficiency()[0]) |
|
151 report.write("<metric name='efficiencyNoMakefile' value='%f'/>\n" \ |
|
152 % self.getEfficiency()[1]) |
|
153 report.write("</annofile>\n") |
|
154 report.close() |
|
155 |
|
156 def __str__(self): |
|
157 s = " <metric name='agentcount' value='%d' />\n" % len(self.nodes) + \ |
|
158 " <metric name='maxagents' value='%d' />\n" % self.maxagents + \ |
|
159 " <metric name='parsetimesecs' value='%s' />\n" % self.getParseTime() + \ |
|
160 " <metric name='overallduration' value='%s' />\n" % self.getOverallDuration() + \ |
|
161 " <metric name='aggregatetime' value='%s' />\n" % self.getAggregateTime() + \ |
|
162 " <metric name='efficiency' value='%s' />\n" % self.getEfficiency()[0] + \ |
|
163 " <metric name='efficiency_nomake' value='%s' />\n" % self.getEfficiency()[1] |
|
164 |
|
165 return s |
|
166 |
|
167 |
|
168 |
|
169 if __name__ == '__main__': |
|
170 |
|
171 # Work around annoying DOCTYPE error by |
|
172 # creating a dummy DTD file |
|
173 if not os.path.exists('build.dtd'): |
|
174 dummy = open('build.dtd', 'w') |
|
175 dummy.close() |
|
176 |
|
177 ################## Edit this basepath ################ |
|
178 basepath = '92_7952_201022_logs\\output\\logs' |
|
179 ###################################################### |
|
180 |
|
181 # Find out all the annofiles |
|
182 annofiles = [] |
|
183 for dirpath, dirs, files in os.walk(basepath): |
|
184 for f in files: |
|
185 if f.endswith('.anno') or f.endswith('.anno.xml'): |
|
186 annofiles.append(dirpath + '\\' + f) |
|
187 |
|
188 #print annofiles # debug |
|
189 |
|
190 # Parse all the annofiles and generate report |
|
191 # Write XML header |
|
192 report = open('anno_report.xml', 'w') |
|
193 report.write('<?xml version="1.0" encoding="ISO-8859-1"?>\n') |
|
194 report.write("<report>\n") |
|
195 report.close() |
|
196 # Parse each annofile |
|
197 #num = 0 # debug |
|
198 parser = xml.sax.make_parser() |
|
199 for afilename in annofiles: |
|
200 parser.setContentHandler(Annofile(afilename)) |
|
201 try: |
|
202 parser.parse(open(afilename)) |
|
203 except xml.sax._exceptions.SAXParseException, e: |
|
204 print "Error:\n" + str(e) |
|
205 print "Ignore that file, parsing continues..." |
|
206 |
|
207 #num += 1 # <debug> only process num annofiles |
|
208 #if num == 3: |
|
209 # break |
|
210 |
|
211 # Write XML footer |
|
212 report = open('anno_report.xml', 'a') |
|
213 report.write("</report>") |
|
214 report.close() |
|
215 |