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