diff options
author | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-03-26 13:55:47 -0400 |
---|---|---|
committer | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-03-26 13:55:47 -0400 |
commit | baee00899b87c09e2cfb08dc59cdf5862c7f9255 (patch) | |
tree | 7bf8d2070619ade1947f49c259f497e920f779ae /pm_data_analysis/pm_data_analyzer.py | |
parent | 0955215f93b077978f58e337c54114518710c062 (diff) |
Fix autocomputation of cap on data samples
Diffstat (limited to 'pm_data_analysis/pm_data_analyzer.py')
-rwxr-xr-x | pm_data_analysis/pm_data_analyzer.py | 246 |
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: | |||
102 | class Analyzer(defapp.App): | 102 | class 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 | ||
314 | if __name__ == "__main__": | 370 | if __name__ == "__main__": |
315 | Analyzer().launch() | 371 | Analyzer().launch() |