diff options
| -rwxr-xr-x | gnuplot.py | 5 | ||||
| -rwxr-xr-x | oplot.py | 111 |
2 files changed, 108 insertions, 8 deletions
| @@ -63,7 +63,10 @@ class FileGraph(object): | |||
| 63 | using_txt = "%s:%s" % (self.xcol, self.ycol) | 63 | using_txt = "%s:%s" % (self.xcol, self.ycol) |
| 64 | style = self.style if self.style else default_style | 64 | style = self.style if self.style else default_style |
| 65 | style_txt = " with %s" % style if style else "" | 65 | style_txt = " with %s" % style if style else "" |
| 66 | title_txt = ' title "%s"' % self.title if self.title else "" | 66 | if self.title == 'notitle': |
| 67 | title_txt = ' notitle' | ||
| 68 | else: | ||
| 69 | title_txt = ' title "%s"' % self.title if self.title else "" | ||
| 67 | smooth_txt = ' smooth %s' % self.smooth if self.smooth else "" | 70 | smooth_txt = ' smooth %s' % self.smooth if self.smooth else "" |
| 68 | return "'%s' using %s%s%s%s" % \ | 71 | return "'%s' using %s%s%s%s" % \ |
| 69 | (self.fname, using_txt, title_txt, style_txt, smooth_txt) | 72 | (self.fname, using_txt, title_txt, style_txt, smooth_txt) |
| @@ -2,6 +2,7 @@ | |||
| 2 | import defapp | 2 | import defapp |
| 3 | 3 | ||
| 4 | from plot import decode | 4 | from plot import decode |
| 5 | from dplot import sched_name | ||
| 5 | from util import load_csv_file, load_binary_file, write_csv_file | 6 | from util import load_csv_file, load_binary_file, write_csv_file |
| 6 | from stats import iqr_cutoff | 7 | from stats import iqr_cutoff |
| 7 | 8 | ||
| @@ -59,6 +60,8 @@ options = [ | |||
| 59 | o(None, '--cycles', action='store', dest='cycles', type='int', | 60 | o(None, '--cycles', action='store', dest='cycles', type='int', |
| 60 | help='how many cycles per usec'), | 61 | help='how many cycles per usec'), |
| 61 | 62 | ||
| 63 | o(None, '--compare', action='store', dest='compare', | ||
| 64 | help='plot overhead comparison', choices=['max', 'avg']), | ||
| 62 | ] | 65 | ] |
| 63 | 66 | ||
| 64 | defaults = { | 67 | defaults = { |
| @@ -86,12 +89,14 @@ defaults = { | |||
| 86 | 'xmax' : None, | 89 | 'xmax' : None, |
| 87 | 'ymax' : None, | 90 | 'ymax' : None, |
| 88 | 'ylog' : False, | 91 | 'ylog' : False, |
| 92 | |||
| 93 | 'compare' : None, | ||
| 89 | } | 94 | } |
| 90 | 95 | ||
| 91 | 96 | ||
| 92 | TXT = { | 97 | TXT = { |
| 93 | 'RELEASE-LATENCY' : 'timer interrupt latency', | 98 | 'RELEASE-LATENCY' : 'event latency', |
| 94 | 'RELEASE' : 'job release overhead', | 99 | 'RELEASE' : 'release interrupt overhead', |
| 95 | 'SCHED' : 'scheduling overhead', | 100 | 'SCHED' : 'scheduling overhead', |
| 96 | 'SCHED2' : 'post-scheduling overhead', | 101 | 'SCHED2' : 'post-scheduling overhead', |
| 97 | 'CXS' : 'context-switch overhead', | 102 | 'CXS' : 'context-switch overhead', |
| @@ -291,7 +296,7 @@ class OverheadPlotter(defapp.App): | |||
| 291 | 296 | ||
| 292 | self.render(p) | 297 | self.render(p) |
| 293 | 298 | ||
| 294 | def prepare_trends(self, datafile, name, conf): | 299 | def prepare_trends(self, datafile, name, conf, want_avg_ymax=False): |
| 295 | data = load_csv_file(datafile) | 300 | data = load_csv_file(datafile) |
| 296 | if not self.options.per_proc and \ | 301 | if not self.options.per_proc and \ |
| 297 | 'host' in conf and conf['host'] in HOST_CPUS: | 302 | 'host' in conf and conf['host'] in HOST_CPUS: |
| @@ -312,7 +317,10 @@ class OverheadPlotter(defapp.App): | |||
| 312 | r[std_idx]] | 317 | r[std_idx]] |
| 313 | for r in data] | 318 | for r in data] |
| 314 | 319 | ||
| 315 | max_y = numpy.amax(data[:,wc_idx]) | 320 | if want_avg_ymax: |
| 321 | max_y = numpy.amax(data[:,avg_idx]) | ||
| 322 | else: | ||
| 323 | max_y = numpy.amax(data[:,wc_idx]) | ||
| 316 | 324 | ||
| 317 | return (self.write(rows, name), cpus, max_y) | 325 | return (self.write(rows, name), cpus, max_y) |
| 318 | 326 | ||
| @@ -363,6 +371,92 @@ class OverheadPlotter(defapp.App): | |||
| 363 | 371 | ||
| 364 | self.render(p) | 372 | self.render(p) |
| 365 | 373 | ||
| 374 | def plot_comparison(self, datafiles): | ||
| 375 | |||
| 376 | if self.options.compare == 'max': | ||
| 377 | stat = 'maximum' | ||
| 378 | want_avg_ymax = False | ||
| 379 | else: | ||
| 380 | stat = 'average' | ||
| 381 | want_avg_ymax = True | ||
| 382 | |||
| 383 | plots = [] | ||
| 384 | max_y = 0 | ||
| 385 | cpus = 0 | ||
| 386 | overheads = set() | ||
| 387 | |||
| 388 | for i, datafile in enumerate(datafiles): | ||
| 389 | self.out("[%d/%d] Processing %s ..." % (i + 1, len(datafiles), datafile)) | ||
| 390 | bname = basename(datafile) | ||
| 391 | name, ext = splitext(bname) | ||
| 392 | conf = decode(name) | ||
| 393 | overheads.add(conf['overhead']) | ||
| 394 | fname, _cpus, _max_y = self.prepare_trends(datafile, name, conf, want_avg_ymax) | ||
| 395 | max_y = max(max_y, _max_y) | ||
| 396 | cpus = max(cpus, _cpus) | ||
| 397 | plots.append((fname, conf)) | ||
| 398 | |||
| 399 | assert len(overheads) == 1 | ||
| 400 | overhead = overheads.pop() | ||
| 401 | |||
| 402 | |||
| 403 | schedulers = '_'.join([conf['scheduler'] for (_, conf) in plots]) | ||
| 404 | |||
| 405 | name = 'compare_%s-%s_%s' % (stat, overhead, schedulers) | ||
| 406 | |||
| 407 | p = self.make_plot(name) | ||
| 408 | |||
| 409 | p.title = "%s measured %s" \ | ||
| 410 | % (stat, TXT[overhead]) | ||
| 411 | |||
| 412 | p.ylabel = "overhead in microseconds" | ||
| 413 | if self.options.per_proc: | ||
| 414 | p.xlabel = "number of tasks per processor" | ||
| 415 | else: | ||
| 416 | p.xlabel = "number of tasks" | ||
| 417 | |||
| 418 | p.xticks = (0, max(cpus, 10)) | ||
| 419 | if self.options.xmax: | ||
| 420 | p.xrange = (0, self.options.xmax) | ||
| 421 | elif self.options.per_proc: | ||
| 422 | p.xrange = (0.5, 20.5) | ||
| 423 | p.xticks = (0, 1) | ||
| 424 | else: | ||
| 425 | p.xrange = (0, ceil(cpus * 20 / 100.0) * 100) | ||
| 426 | |||
| 427 | if self.options.ymax: | ||
| 428 | p.yrange = (0, self.options.ymax) | ||
| 429 | else: | ||
| 430 | p.yrange = (0, (ceil(max_y / 10.0)) * 10) | ||
| 431 | |||
| 432 | for (fname, conf) in plots: | ||
| 433 | name = sched_name(conf['scheduler']) | ||
| 434 | if self.options.compare == 'max': | ||
| 435 | p.curves += [ | ||
| 436 | curve(fname, xcol=1, ycol=2, title=name)] | ||
| 437 | else: | ||
| 438 | p.curves += [ | ||
| 439 | curve(fname, xcol=1, ycol=3, title=name)] | ||
| 440 | # curve(fname, xcol=1, ycol=3, error=4, title='notitle')] | ||
| 441 | |||
| 442 | #### Styling. | ||
| 443 | |||
| 444 | marker = 'lines' | ||
| 445 | if len(p.curves) > 2: | ||
| 446 | p.curves[2].style = marker + " ls 4" | ||
| 447 | |||
| 448 | if len(p.curves) > 3: | ||
| 449 | p.curves[3].style = marker + " ls 6" | ||
| 450 | |||
| 451 | p.font_size = '7' | ||
| 452 | p.size = ('6in', '2.50in') | ||
| 453 | p.monochrome = True #False | ||
| 454 | p.dashed_lines = True #True | ||
| 455 | p.key = 'top left' | ||
| 456 | p.default_style = marker + ' lw 1' | ||
| 457 | p.pointsize = 2 | ||
| 458 | |||
| 459 | self.render(p) | ||
| 366 | 460 | ||
| 367 | def plot_file(self, datafile): | 461 | def plot_file(self, datafile): |
| 368 | bname = basename(datafile) | 462 | bname = basename(datafile) |
| @@ -390,9 +484,12 @@ class OverheadPlotter(defapp.App): | |||
| 390 | if self.options.outlier_file: | 484 | if self.options.outlier_file: |
| 391 | self.options.outliers = load_outliers(self.options.outlier_file) | 485 | self.options.outliers = load_outliers(self.options.outlier_file) |
| 392 | 486 | ||
| 393 | for i, datafile in enumerate(self.args): | 487 | if not self.options.compare is None: |
| 394 | self.out("[%d/%d] Processing %s ..." % (i + 1, len(self.args), datafile)) | 488 | self.plot_comparison(self.args) |
| 395 | self.plot_file(datafile) | 489 | else: |
| 490 | for i, datafile in enumerate(self.args): | ||
| 491 | self.out("[%d/%d] Processing %s ..." % (i + 1, len(self.args), datafile)) | ||
| 492 | self.plot_file(datafile) | ||
| 396 | 493 | ||
| 397 | if __name__ == "__main__": | 494 | if __name__ == "__main__": |
| 398 | OverheadPlotter().launch() | 495 | OverheadPlotter().launch() |
