aboutsummaryrefslogtreecommitdiffstats
path: root/pm_data_analysis/pm_data_analyzer.py
diff options
context:
space:
mode:
Diffstat (limited to 'pm_data_analysis/pm_data_analyzer.py')
-rwxr-xr-xpm_data_analysis/pm_data_analyzer.py246
1 files changed, 151 insertions, 95 deletions
diff --git a/pm_data_analysis/pm_data_analyzer.py b/pm_data_analysis/pm_data_analyzer.py
index 63baa27..cc6e0a5 100755
--- a/pm_data_analysis/pm_data_analyzer.py
+++ b/pm_data_analysis/pm_data_analyzer.py
@@ -102,7 +102,8 @@ class Overhead:
102class Analyzer(defapp.App): 102class Analyzer(defapp.App):
103 def __init__(self): 103 def __init__(self):
104 defapp.App.__init__(self, options, defaults, no_std_opts=True) 104 defapp.App.__init__(self, options, defaults, no_std_opts=True)
105 self.min_sample_wss = {} 105 self.last_conf = {}
106 self.valid_ovds_list = {}
106 self.lsamples = {} 107 self.lsamples = {}
107 if self.options.npreempt: 108 if self.options.npreempt:
108 self.lsamples['preemption'] = self.options.npreempt 109 self.lsamples['preemption'] = self.options.npreempt
@@ -115,33 +116,38 @@ class Analyzer(defapp.App):
115 116
116 # read previously saved overhead data 117 # read previously saved overhead data
117 def read_valid_data(self, filename): 118 def read_valid_data(self, filename):
119 valid_ovds = Overhead()
118 nf = filename + '_preemption.vbin' 120 nf = filename + '_preemption.vbin'
119 if self.options.debug: 121 if self.options.debug:
120 print "Reading '%s'" % nf 122 print "Reading '%s'" % nf
121 self.valid_ovds.add(pms.unpickl_it(nf), 'preemtion') 123 valid_ovds.add(pms.unpickl_it(nf), 'preemtion')
122 124
123 nf = filename + '_onchip.vbin' 125 nf = filename + '_onchip.vbin'
124 if self.options.debug: 126 if self.options.debug:
125 print "Reading '%s'" % nf 127 print "Reading '%s'" % nf
126 self.valid_ovds.add(pms.unpickl_it(nf), 'onchip') 128 valid_ovds.add(pms.unpickl_it(nf), 'onchip')
127 129
128 nf = filename + '_offchip.vbin' 130 nf = filename + '_offchip.vbin'
129 if debug: 131 if self.options.debug:
130 print "Reading '%s'" % nf 132 print "Reading '%s'" % nf
131 self.valid_ovds.add(pms.unpickl_it(nf), 'offchip') 133 valid_ovds.add(pms.unpickl_it(nf), 'offchip')
132 134
133 if self.options.coresL2 != 0: 135 if self.options.coresL2 != 0:
134 nf = filename + '_l2cache.vbin' 136 nf = filename + '_l2cache.vbin'
135 if self.options.debug: 137 if self.options.debug:
136 print "Reading '%s'" % nf 138 print "Reading '%s'" % nf
137 self.valid_ovds.add(pms.unpickl_it(nf), 'l2cache') 139 valid_ovds.add(pms.unpickl_it(nf), 'l2cache')
140 return valid_ovds
138 141
139 def process_raw_data(self, datafile, conf): 142 def process_raw_data(self, datafile, conf):
140 coresL2 = self.options.coresL2 143 coresL2 = self.options.coresL2
141 pcpu = self.options.pcpu 144 pcpu = self.options.pcpu
142 # initialize pmmodule 145 # initialize pmmodule
143 pm.load(datafile, coresL2, pcpu, int(conf['wss']), int(conf['tss'])) 146 pm.load(datafile, coresL2, pcpu, int(conf['wss']), int(conf['tss']))
147 # raw overheads
144 ovds = Overhead() 148 ovds = Overhead()
149 # valid overheads
150 valid_ovds = Overhead()
145 # get overheads 151 # get overheads
146 ovds.add(pm.getPreemption(), 'preemption') 152 ovds.add(pm.getPreemption(), 'preemption')
147 ovds.add(pm.getOnChipMigration(), 'onchip') 153 ovds.add(pm.getOnChipMigration(), 'onchip')
@@ -161,10 +167,10 @@ class Analyzer(defapp.App):
161 # just add overheads, "forget" preemption length 167 # just add overheads, "forget" preemption length
162 # FIXME: is really needed? 168 # FIXME: is really needed?
163 # valid_ovds.add(sd.remOutliers(i[0][:,0]), i[1]) 169 # valid_ovds.add(sd.remOutliers(i[0][:,0]), i[1])
164 self.valid_ovds.add(i[0][:,0], i[1]) 170 valid_ovds.add(i[0][:,0], i[1])
165 else: 171 else:
166 print "Warning: no valid data collected..." 172 print "Warning: no valid data collected..."
167 self.valid_ovds.add([], i[1]) 173 valid_ovds.add([], i[1])
168 174
169 if self.options.debug: 175 if self.options.debug:
170 # check outliers removals 176 # check outliers removals
@@ -172,36 +178,36 @@ class Analyzer(defapp.App):
172 for i in ovds: 178 for i in ovds:
173 print "samples(%(0)s) = %(1)d" % {"0":i[1], "1":len(i[0])} 179 print "samples(%(0)s) = %(1)d" % {"0":i[1], "1":len(i[0])}
174 print "After outliers removal" 180 print "After outliers removal"
175 for i in self.valid_ovds: 181 for i in valid_ovds:
176 print "samples(%(0)s) = %(1)d" % {"0":i[1], "1":len(i[0])} 182 print "samples(%(0)s) = %(1)d" % {"0":i[1], "1":len(i[0])}
177 183
178 count_sample = {} 184 count_sample = {}
179 if self.options.autocap or self.options.verbose: 185 if self.options.autocap or self.options.verbose:
180 for i in self.valid_ovds: 186 for i in valid_ovds:
181 if self.options.verbose: 187 if self.options.verbose:
182 print "samples(%(0)s) = %(1)d" % {"0":i[1], "1":len(i[0])} 188 print "samples(%(0)s) = %(1)d" % {"0":i[1], "1":len(i[0])}
183 count_sample[i[1]] = len(i[0]) 189 count_sample[i[1]] = len(i[0])
184 190
185 if self.options.autocap: 191 if self.options.autocap:
186 if conf['wss'] in self.min_sample_wss: 192 if 'min' in self.valid_ovds_list:
187 # it is normally sufficient to check num samples for 193 # it is normally sufficient to check num samples for
188 # preemptions to get tss with min num samples in wss 194 # preemptions to get tss with min num samples in wss
189 if self.min_sample_wss[conf['wss']]['preemption'] > \ 195 if self.valid_ovds_list['min']['preemption'] > \
190 count_sample['preemption']: 196 count_sample['preemption']:
191 self.min_sample_wss[conf['wss']] = {'tss':conf['tss'], 197 self.valid_ovds_list['min'] = {
198 'preemption':count_sample['preemption'],
199 'onchip':count_sample['onchip'],
200 'offchip':count_sample['offchip'],
201 'l2cache':count_sample['l2cache']}
202 else:
203 self.valid_ovds_list['min'] = {
192 'preemption':count_sample['preemption'], 204 'preemption':count_sample['preemption'],
193 'onchip':count_sample['onchip'], 205 'onchip':count_sample['onchip'],
194 'offchip':count_sample['offchip'], 206 'offchip':count_sample['offchip'],
195 'l2cache':count_sample['l2cache']} 207 'l2cache':count_sample['l2cache']}
196 else:
197 self.min_sample_wss[conf['wss']] = {'tss':conf['tss'],
198 'preemption':count_sample['preemption'],
199 'onchip':count_sample['onchip'],
200 'offchip':count_sample['offchip'],
201 'l2cache':count_sample['l2cache']}
202 208
203 # serialize valid overheads 209 # serialize valid overheads
204 for i in self.valid_ovds: 210 for i in valid_ovds:
205 dname = dirname(datafile) 211 dname = dirname(datafile)
206 fname, ext = splitext(basename(datafile)) 212 fname, ext = splitext(basename(datafile))
207 213
@@ -209,6 +215,7 @@ class Analyzer(defapp.App):
209 pms.pickl_it(i[0], curf) 215 pms.pickl_it(i[0], curf)
210 216
211 del ovds 217 del ovds
218 return valid_ovds
212 219
213 # The output is one csv WSS file per ovhd type, "tss, max_ovd, avg_ovd" 220 # The output is one csv WSS file per ovhd type, "tss, max_ovd, avg_ovd"
214 # Filename output format: 221 # Filename output format:
@@ -216,100 +223,149 @@ class Analyzer(defapp.App):
216 # ovd: preemption, onchip, offchip, l2cache 223 # ovd: preemption, onchip, offchip, l2cache
217 224
218 def analyze_data(self, dname, conf): 225 def analyze_data(self, dname, conf):
219
220 csvbname = dname + '/pm_plugin=' + conf['plugin'] + \ 226 csvbname = dname + '/pm_plugin=' + conf['plugin'] + \
221 '_dist=uni_light_wss=' + conf['wss'] 227 '_dist=uni_light_wss=' + conf['wss']
222 if self.options.verbose:
223 print "(WSS = %(0)s, TSS = %(1)s)" % {"0":conf['wss'], \
224 "1":conf['tss']}
225 228
226 for i in self.valid_ovds: 229 for tss,vohs in self.valid_ovds_list.iteritems():
227 csvfname = csvbname + '_ovd=' + i[1] + '.csv' 230 if tss == 'min':
228 if self.options.debug: 231 # do not analyze fake 'min' tss
229 print "Saving csv '%s'" % csvfname 232 continue
230 233
231 csvf = open(csvfname, 'a') 234 if self.options.verbose:
232 csvlist = [conf['tss']] 235 print "\n(WSS = %(0)s, TSS = %(1)s)" % {"0":conf['wss'], \
233 236 "1":tss}
234 # data (valid_ovds already have only overheads, not length) 237
235 # vector = i[0][:,0] 238 for i in vohs:
236 # 239 csvfname = csvbname + '_ovd=' + i[1] + '.csv'
237 # Check if we need to limit the number of samples 240 if self.options.debug:
238 # that we use in the computation of max and avg. 241 print "Saving csv '%s'" % csvfname
239 # Statistically, this is more sound than other choices 242
240 if i[1] in self.lsamples: 243 csvf = open(csvfname, 'a')
241 if self.lsamples[i[1]] > 0: 244 csvlist = [tss]
242 nsamples = min(self.lsamples[i[1]], len(i[0])) 245
246 # data (valid_ovds already have only overheads, not length)
247 # vector = i[0][:,0]
248 #
249 # Check if we need to limit the number of samples
250 # that we use in the computation of max and avg.
251 # Statistically, this is more sound than other choices
252 if i[1] in self.lsamples:
253 if self.lsamples[i[1]] > 0:
254 nsamples = min(self.lsamples[i[1]], len(i[0]))
255 if self.options.verbose:
256 print "Computing %(0)s stat only on %(1)d samples" % \
257 {"0":i[1],
258 "1":nsamples}
259 vector = i[0][0:nsamples]
260 elif self.options.autocap: # we can also autocompute the cap
261 nsamples = self.valid_ovds_list['min'][i[1]]
243 if self.options.verbose: 262 if self.options.verbose:
244 print "Computing %(0)s stat only on %(1)d samples" % \ 263 print "Computing %(0)s stat only on %(1)d samples" % \
245 {"0":i[1], 264 {"0":i[1], "1":nsamples}
246 "1":nsamples}
247 vector = i[0][0:nsamples] 265 vector = i[0][0:nsamples]
248 elif self.options.autocap: # we can also autocompute the cap 266 else:
249 nsamples = self.min_sample_wss[conf['wss']][i[1]] 267 vector = i[0]
250 if self.options.verbose:
251 print "Computing %(0)s stat only on %(1)d samples" % \
252 {"0":i[1], "1":nsamples}
253 vector = i[0][0:nsamples]
254 else:
255 vector = i[0]
256
257 if vector != []:
258 # FIXME if after disabling prefetching there are
259 # still negative value, they shouldn't be considered
260 max_vec = np.max(vector)
261 avg_vec = np.average(vector)
262 else:
263 max_vec = 0
264 avg_vec = 0
265
266 if self.options.cpufreq == 0:
267 max_vec_str = "%5.5f" % max_vec
268 avg_vec_str = "%5.5f" % avg_vec
269 else:
270 max_vec_str = "%5.5f" % (max_vec / self.options.cpufreq)
271 avg_vec_str = "%5.5f" % (avg_vec / self.options.cpufreq)
272 268
273 csvlist.append(max_vec_str) 269 if vector != []:
274 csvlist.append(avg_vec_str) 270 # FIXME if after disabling prefetching there are
275 pms.csv_it(csvf, csvlist) 271 # still negative value, they shouldn't be considered
276 csvf.close() 272 max_vec = np.max(vector)
273 avg_vec = np.average(vector)
274 else:
275 max_vec = 0
276 avg_vec = 0
277 277
278 if self.options.verbose:
279 if self.options.cpufreq == 0: 278 if self.options.cpufreq == 0:
280 print i[1] + " overheads (ticks)" 279 max_vec_str = "%5.5f" % max_vec
281 print "Max = %5.5f" % max_vec 280 avg_vec_str = "%5.5f" % avg_vec
282 print "Avg = %5.5f" % avg_vec
283 else: 281 else:
284 print i[1] + " overheads (us)" 282 max_vec_str = "%5.5f" % (max_vec / self.options.cpufreq)
285 print "Max = %5.5f" % (max_vec / self.options.cpufreq) 283 avg_vec_str = "%5.5f" % (avg_vec / self.options.cpufreq)
286 print "Avg = %5.5f" % (avg_vec / self.options.cpufreq) 284
287 285 csvlist.append(max_vec_str)
288 def process_datafile(self, datafile): 286 csvlist.append(avg_vec_str)
289 dname = dirname(datafile) 287 pms.csv_it(csvf, csvlist)
290 bname = basename(datafile) 288 csvf.close()
291 fname, ext = splitext(bname) 289
292 if ext != '.raw': 290 if self.options.verbose:
293 self.err("Warning: '%s' doesn't look like a .raw file" 291 if self.options.cpufreq == 0:
294 % bname) 292 print i[1] + " overheads (ticks)"
293 print "Max = %5.5f" % max_vec
294 print "Avg = %5.5f" % avg_vec
295 else:
296 print i[1] + " overheads (us)"
297 print "Max = %5.5f" % (max_vec / self.options.cpufreq)
298 print "Avg = %5.5f" % (avg_vec / self.options.cpufreq)
299
300 def process_datafile(self, datafile, dname, fname, conf):
295 if self.options.verbose: 301 if self.options.verbose:
296 print "\nProcessing: " + fname 302 print "\nProcessing: " + fname
297 conf = decode(fname)
298
299 self.valid_ovds = Overhead()
300 if self.options.read_valid: 303 if self.options.read_valid:
301 # .vbin output should be in same directory as input filename 304 # .vbin output should be in same directory as input filename
302 readf = dname + '/' + fname 305 readf = dname + '/' + fname
303 self.read_valid_data(readf) 306 self.valid_ovds_list[conf['tss']] = self.read_valid_data(readf)
304 else: 307 else:
305 self.process_raw_data(datafile, conf) 308 self.valid_ovds_list[conf['tss']] = \
306 309 self.process_raw_data(datafile, conf)
307 self.analyze_data(dname, conf)
308 del self.valid_ovds
309 310
310 def default(self, _): 311 def default(self, _):
312 # TODO: to support this combination we should store also the min
313 # number of samples in the .vbin file
314 if self.options.read_valid and self.options.autocap:
315 self.err("Read stored values + autocap not currently supported")
316 return None
317
311 for datafile in self.args: 318 for datafile in self.args:
312 self.process_datafile(datafile) 319 dname = dirname(datafile)
320 bname = basename(datafile)
321 fname, ext = splitext(bname)
322 if ext != '.raw':
323 self.err("Warning: '%s' doesn't look like a .raw file"
324 % bname)
325
326 conf = decode(fname)
327
328 if datafile == self.args[-1]:
329 # manage single file / last of list
330 if ('wss' in self.last_conf) and (conf['wss'] != \
331 self.last_conf['wss']):
332 # we have already analyzed at least one file,
333 # this is the first file of a new set of WSS,
334 # and it is also the last file of the list
335 self.analyze_data(dname, self.last_conf)
336 # delete previously used dictionary
337 del self.valid_ovds_list
338 # reinit dictionary
339 self.valid_ovds_list = {}
340 # analyze this file
341 self.process_datafile(datafile, dname, fname, conf)
342 self.analyze_data(dname, conf)
343 del self.valid_ovds_list
344 else:
345 # just the end of a list of wss files or 1 single file
346 self.process_datafile(datafile, dname, fname, conf)
347 if self.args[0] == self.args[-1]:
348 self.analyze_data(dname, conf)
349 else:
350 self.analyze_data(dname, self.last_conf)
351 del self.valid_ovds_list
352 else:
353 # assume WSS are anayzed in order (all 1024s, all 256s, etc.)
354 if ('wss' in self.last_conf) and (conf['wss'] != \
355 self.last_conf['wss']):
356 # we have already analyzed at least one file,
357 # this is the first file of a new set of WSS,
358 # analyze tss for previous wss
359 self.analyze_data(dname, self.last_conf)
360 # delete previously used dictionary
361 del self.valid_ovds_list
362 # reinit dictionary
363 self.valid_ovds_list = {}
364
365 # add tss to valid ovds list for this wss
366 self.process_datafile(datafile, dname, fname, conf)
367 # save previously analyzed configuration
368 self.last_conf = conf
313 369
314if __name__ == "__main__": 370if __name__ == "__main__":
315 Analyzer().launch() 371 Analyzer().launch()