1#!/usr/bin/env python 2 3##################################################################### 4# xenmon is a front-end for xenbaked. 5# There is a curses interface for live monitoring. XenMon also allows 6# logging to a file. For options, run python xenmon.py -h 7# 8# Copyright (C) 2005,2006 by Hewlett Packard, Palo Alto and Fort Collins 9# Authors: Lucy Cherkasova, lucy.cherkasova@hp.com 10# Rob Gardner, rob.gardner@hp.com 11# Diwaker Gupta, diwaker.gupta@hp.com 12##################################################################### 13# This program is free software; you can redistribute it and/or modify 14# it under the terms of the GNU General Public License as published by 15# the Free Software Foundation; under version 2 of the License. 16# 17# This program is distributed in the hope that it will be useful, 18# but WITHOUT ANY WARRANTY; without even the implied warranty of 19# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20# GNU General Public License for more details. 21# 22# You should have received a copy of the GNU General Public License 23# along with this program; If not, see <http://www.gnu.org/licenses/>. 24##################################################################### 25 26import mmap 27import struct 28import os 29import time 30import optparse as _o 31import curses as _c 32import math 33import sys 34 35# constants 36NSAMPLES = 100 37NDOMAINS = 32 38IDLE_DOMAIN = -1 # idle domain's ID 39 40# the struct strings for qos_info 41ST_DOM_INFO = "6Q3i2H32s" 42ST_QDATA = "%dQ" % (6*NDOMAINS + 4) 43 44# size of mmaped file 45QOS_DATA_SIZE = struct.calcsize(ST_QDATA)*NSAMPLES + struct.calcsize(ST_DOM_INFO)*NDOMAINS + struct.calcsize("4i") 46 47# location of mmaped file, hard coded right now 48SHM_FILE = "/var/run/xenq-shm" 49 50# format strings 51TOTALS = 15*' ' + "%6.2f%%" + 35*' ' + "%6.2f%%" 52 53ALLOCATED = "Allocated" 54GOTTEN = "Gotten" 55BLOCKED = "Blocked" 56WAITED = "Waited" 57IOCOUNT = "I/O Count" 58EXCOUNT = "Exec Count" 59 60# globals 61dom_in_use = [] 62 63# our curses screen 64stdscr = None 65 66# parsed options 67options, args = None, None 68 69# the optparse module is quite smart 70# to see help, just run xenmon -h 71def setup_cmdline_parser(): 72 parser = _o.OptionParser() 73 parser.add_option("-l", "--live", dest="live", action="store_true", 74 default=True, help = "show the ncurses live monitoring frontend (default)") 75 parser.add_option("-n", "--notlive", dest="live", action="store_false", 76 default="True", help = "write to file instead of live monitoring") 77 parser.add_option("-p", "--prefix", dest="prefix", 78 default = "log", help="prefix to use for output files") 79 parser.add_option("-t", "--time", dest="duration", 80 action="store", type="int", default=10, 81 help="stop logging to file after this much time has elapsed (in seconds). set to 0 to keep logging indefinitely") 82 parser.add_option("-i", "--interval", dest="interval", 83 action="store", type="int", default=1000, 84 help="interval for logging (in ms)") 85 parser.add_option("--ms_per_sample", dest="mspersample", 86 action="store", type="int", default=100, 87 help = "determines how many ms worth of data goes in a sample") 88 parser.add_option("--cpu", dest="cpu", action="store", type="int", default=0, 89 help = "specifies which cpu to display data for") 90 91 parser.add_option("--allocated", dest="allocated", action="store_true", 92 default=False, help="Display allocated time for each domain") 93 parser.add_option("--noallocated", dest="allocated", action="store_false", 94 default=False, help="Don't display allocated time for each domain") 95 96 parser.add_option("--blocked", dest="blocked", action="store_true", 97 default=True, help="Display blocked time for each domain") 98 parser.add_option("--noblocked", dest="blocked", action="store_false", 99 default=True, help="Don't display blocked time for each domain") 100 101 parser.add_option("--waited", dest="waited", action="store_true", 102 default=True, help="Display waiting time for each domain") 103 parser.add_option("--nowaited", dest="waited", action="store_false", 104 default=True, help="Don't display waiting time for each domain") 105 106 parser.add_option("--excount", dest="excount", action="store_true", 107 default=False, help="Display execution count for each domain") 108 parser.add_option("--noexcount", dest="excount", action="store_false", 109 default=False, help="Don't display execution count for each domain") 110 parser.add_option("--iocount", dest="iocount", action="store_true", 111 default=False, help="Display I/O count for each domain") 112 parser.add_option("--noiocount", dest="iocount", action="store_false", 113 default=False, help="Don't display I/O count for each domain") 114 115 return parser 116 117# encapsulate information about a domain 118class DomainInfo: 119 def __init__(self): 120 self.allocated_sum = 0 121 self.gotten_sum = 0 122 self.blocked_sum = 0 123 self.waited_sum = 0 124 self.exec_count = 0; 125 self.iocount_sum = 0 126 self.ffp_samples = [] 127 128 def gotten_stats(self, passed): 129 total = float(self.gotten_sum) 130 per = 100*total/passed 131 exs = self.exec_count 132 if exs > 0: 133 avg = total/exs 134 else: 135 avg = 0 136 return [total/(float(passed)/10**9), per, avg] 137 138 def waited_stats(self, passed): 139 total = float(self.waited_sum) 140 per = 100*total/passed 141 exs = self.exec_count 142 if exs > 0: 143 avg = total/exs 144 else: 145 avg = 0 146 return [total/(float(passed)/10**9), per, avg] 147 148 def blocked_stats(self, passed): 149 total = float(self.blocked_sum) 150 per = 100*total/passed 151 ios = self.iocount_sum 152 if ios > 0: 153 avg = total/float(ios) 154 else: 155 avg = 0 156 return [total/(float(passed)/10**9), per, avg] 157 158 def allocated_stats(self, passed): 159 total = self.allocated_sum 160 exs = self.exec_count 161 if exs > 0: 162 return float(total)/exs 163 else: 164 return 0 165 166 def ec_stats(self, passed): 167 total = float(self.exec_count/(float(passed)/10**9)) 168 return total 169 170 def io_stats(self, passed): 171 total = float(self.iocount_sum) 172 exs = self.exec_count 173 if exs > 0: 174 avg = total/exs 175 else: 176 avg = 0 177 return [total/(float(passed)/10**9), avg] 178 179 def stats(self, passed): 180 return [self.gotten_stats(passed), self.allocated_stats(passed), self.blocked_stats(passed), 181 self.waited_stats(passed), self.ec_stats(passed), self.io_stats(passed)] 182 183# report values over desired interval 184def summarize(startat, endat, duration, samples): 185 dominfos = {} 186 for i in range(0, NDOMAINS): 187 dominfos[i] = DomainInfo() 188 189 passed = 1 # to prevent zero division 190 curid = startat 191 numbuckets = 0 192 lost_samples = [] 193 ffp_samples = [] 194 195 while passed < duration: 196 for i in range(0, NDOMAINS): 197 if dom_in_use[i]: 198 dominfos[i].gotten_sum += samples[curid][0*NDOMAINS + i] 199 dominfos[i].allocated_sum += samples[curid][1*NDOMAINS + i] 200 dominfos[i].waited_sum += samples[curid][2*NDOMAINS + i] 201 dominfos[i].blocked_sum += samples[curid][3*NDOMAINS + i] 202 dominfos[i].exec_count += samples[curid][4*NDOMAINS + i] 203 dominfos[i].iocount_sum += samples[curid][5*NDOMAINS + i] 204 205 passed += samples[curid][6*NDOMAINS] 206 lost_samples.append(samples[curid][6*NDOMAINS + 2]) 207 ffp_samples.append(samples[curid][6*NDOMAINS + 3]) 208 209 numbuckets += 1 210 211 if curid > 0: 212 curid -= 1 213 else: 214 curid = NSAMPLES - 1 215 if curid == endat: 216 break 217 218 lostinfo = [min(lost_samples), sum(lost_samples), max(lost_samples)] 219 ffpinfo = [min(ffp_samples), sum(ffp_samples), max(ffp_samples)] 220 221 ldoms = [] 222 for x in range(0, NDOMAINS): 223 if dom_in_use[x]: 224 ldoms.append(dominfos[x].stats(passed)) 225 else: 226 ldoms.append(0) 227 228 return [ldoms, lostinfo, ffpinfo] 229 230# scale microseconds to milliseconds or seconds as necessary 231def time_scale(ns): 232 if ns < 1000: 233 return "%4.2f ns" % float(ns) 234 elif ns < 1000*1000: 235 return "%4.2f us" % (float(ns)/10**3) 236 elif ns < 10**9: 237 return "%4.2f ms" % (float(ns)/10**6) 238 else: 239 return "%4.2f s" % (float(ns)/10**9) 240 241# paint message on curses screen, but detect screen size errors 242def display(scr, row, col, str, attr=0): 243 try: 244 scr.addstr(row, col, str, attr) 245 except: 246 scr.erase() 247 _c.nocbreak() 248 scr.keypad(0) 249 _c.echo() 250 _c.endwin() 251 print "Your terminal screen is not big enough; Please resize it." 252 print "row=%d, col=%d, str='%s'" % (row, col, str) 253 sys.exit(1) 254 255 256# diplay domain id 257def display_domain_id(scr, row, col, dom): 258 if dom == IDLE_DOMAIN: 259 display(scr, row, col-1, "Idle") 260 else: 261 display(scr, row, col, "%d" % dom) 262 263 264# the live monitoring code 265def show_livestats(cpu): 266 ncpu = 1 # number of cpu's on this platform 267 slen = 0 # size of shared data structure, incuding padding 268 cpu_1sec_usage = 0.0 269 cpu_10sec_usage = 0.0 270 heartbeat = 1 271 global dom_in_use, options 272 273 # mmap the (the first chunk of the) file 274 shmf = open(SHM_FILE, "r+") 275 shm = mmap.mmap(shmf.fileno(), QOS_DATA_SIZE) 276 277 # initialize curses 278 stdscr = _c.initscr() 279 _c.noecho() 280 _c.cbreak() 281 282 stdscr.keypad(1) 283 stdscr.timeout(1000) 284 [maxy, maxx] = stdscr.getmaxyx() 285 286 # display in a loop 287 while True: 288 289 cpuidx = 0 290 while cpuidx < ncpu: 291 292 # calculate offset in mmap file to start from 293 idx = cpuidx * slen 294 295 296 samples = [] 297 doms = [] 298 dom_in_use = [] 299 domain_id = [] 300 301 # read in data 302 for i in range(0, NSAMPLES): 303 len = struct.calcsize(ST_QDATA) 304 sample = struct.unpack(ST_QDATA, shm[idx:idx+len]) 305 samples.append(sample) 306 idx += len 307 308 for i in range(0, NDOMAINS): 309 len = struct.calcsize(ST_DOM_INFO) 310 dom = struct.unpack(ST_DOM_INFO, shm[idx:idx+len]) 311 doms.append(dom) 312# (last_update_time, start_time, runnable_start_time, blocked_start_time, 313# ns_since_boot, ns_oncpu_since_boot, runnable_at_last_update, 314# runnable, in_use, domid, junk, name) = dom 315# dom_in_use.append(in_use) 316 dom_in_use.append(dom[8]) 317 domid = dom[9] 318 if domid == 32767 : 319 domid = IDLE_DOMAIN 320 domain_id.append(domid) 321 idx += len 322# print "dom_in_use(cpu=%d): " % cpuidx, dom_in_use 323 324 325 len = struct.calcsize("4i") 326 oldncpu = ncpu 327 (next, ncpu, slen, freq) = struct.unpack("4i", shm[idx:idx+len]) 328 idx += len 329 330 # xenbaked tells us how many cpu's it's got, so re-do 331 # the mmap if necessary to get multiple cpu data 332 if oldncpu != ncpu: 333 shm = mmap.mmap(shmf.fileno(), ncpu*slen) 334 335 # if we've just calculated data for the cpu of interest, then 336 # stop examining mmap data and start displaying stuff 337 if cpuidx == cpu: 338 break 339 340 cpuidx = cpuidx + 1 341 342 # calculate starting and ending datapoints; never look at "next" since 343 # it represents live data that may be in transition. 344 startat = next - 1 345 if next + 10 < NSAMPLES: 346 endat = next + 10 347 else: 348 endat = 10 349 350 # get summary over desired interval 351 [h1, l1, f1] = summarize(startat, endat, 10**9, samples) 352 [h2, l2, f2] = summarize(startat, endat, 10 * 10**9, samples) 353 354 355 # the actual display code 356 row = 0 357 display(stdscr, row, 1, "CPU = %d" % cpu, _c.A_STANDOUT) 358 359 display(stdscr, row, 10, "%sLast 10 seconds (%3.2f%%)%sLast 1 second (%3.2f%%)" % (6*' ', cpu_10sec_usage, 30*' ', cpu_1sec_usage), _c.A_BOLD) 360 row +=1 361 display(stdscr, row, 1, "%s" % ((maxx-2)*'=')) 362 363 total_h1_cpu = 0 364 total_h2_cpu = 0 365 366 cpu_1sec_usage = 0.0 367 cpu_10sec_usage = 0.0 368 369 for dom in range(0, NDOMAINS): 370 if not dom_in_use[dom]: 371 continue 372 373 if h1[dom][0][1] > 0 or domain_id[dom] == IDLE_DOMAIN: 374 # display gotten 375 row += 1 376 col = 2 377 display_domain_id(stdscr, row, col, domain_id[dom]) 378 col += 4 379 display(stdscr, row, col, "%s" % time_scale(h2[dom][0][0])) 380 col += 12 381 display(stdscr, row, col, "%3.2f%%" % h2[dom][0][1]) 382 if dom != IDLE_DOMAIN: 383 cpu_10sec_usage += h2[dom][0][1] 384 col += 12 385 display(stdscr, row, col, "%s/ex" % time_scale(h2[dom][0][2])) 386 col += 18 387 display(stdscr, row, col, "%s" % time_scale(h1[dom][0][0])) 388 col += 12 389 display(stdscr, row, col, "%3.2f%%" % h1[dom][0][1], _c.A_STANDOUT) 390 col += 12 391 display(stdscr, row, col, "%s/ex" % time_scale(h1[dom][0][2])) 392 col += 18 393 display(stdscr, row, col, "Gotten") 394 395 if dom != IDLE_DOMAIN: 396 cpu_1sec_usage = cpu_1sec_usage + h1[dom][0][1] 397 398 # display allocated 399 if options.allocated: 400 row += 1 401 col = 2 402 display_domain_id(stdscr, row, col, domain_id[dom]) 403 col += 28 404 display(stdscr, row, col, "%s/ex" % time_scale(h2[dom][1])) 405 col += 42 406 display(stdscr, row, col, "%s/ex" % time_scale(h1[dom][1])) 407 col += 18 408 display(stdscr, row, col, "Allocated") 409 410 # display blocked 411 if options.blocked: 412 row += 1 413 col = 2 414 display_domain_id(stdscr, row, col, domain_id[dom]) 415 col += 4 416 display(stdscr, row, col, "%s" % time_scale(h2[dom][2][0])) 417 col += 12 418 display(stdscr, row, col, "%3.2f%%" % h2[dom][2][1]) 419 col += 12 420 display(stdscr, row, col, "%s/io" % time_scale(h2[dom][2][2])) 421 col += 18 422 display(stdscr, row, col, "%s" % time_scale(h1[dom][2][0])) 423 col += 12 424 display(stdscr, row, col, "%3.2f%%" % h1[dom][2][1]) 425 col += 12 426 display(stdscr, row, col, "%s/io" % time_scale(h1[dom][2][2])) 427 col += 18 428 display(stdscr, row, col, "Blocked") 429 430 # display waited 431 if options.waited: 432 row += 1 433 col = 2 434 display_domain_id(stdscr, row, col, domain_id[dom]) 435 col += 4 436 display(stdscr, row, col, "%s" % time_scale(h2[dom][3][0])) 437 col += 12 438 display(stdscr, row, col, "%3.2f%%" % h2[dom][3][1]) 439 col += 12 440 display(stdscr, row, col, "%s/ex" % time_scale(h2[dom][3][2])) 441 col += 18 442 display(stdscr, row, col, "%s" % time_scale(h1[dom][3][0])) 443 col += 12 444 display(stdscr, row, col, "%3.2f%%" % h1[dom][3][1]) 445 col += 12 446 display(stdscr, row, col, "%s/ex" % time_scale(h1[dom][3][2])) 447 col += 18 448 display(stdscr, row, col, "Waited") 449 450 # display ex count 451 if options.excount: 452 row += 1 453 col = 2 454 display_domain_id(stdscr, row, col, domain_id[dom]) 455 456 col += 28 457 display(stdscr, row, col, "%d/s" % h2[dom][4]) 458 col += 42 459 display(stdscr, row, col, "%d" % h1[dom][4]) 460 col += 18 461 display(stdscr, row, col, "Execution count") 462 463 # display io count 464 if options.iocount: 465 row += 1 466 col = 2 467 display_domain_id(stdscr, row, col, domain_id[dom]) 468 col += 4 469 display(stdscr, row, col, "%d/s" % h2[dom][5][0]) 470 col += 24 471 display(stdscr, row, col, "%d/ex" % h2[dom][5][1]) 472 col += 18 473 display(stdscr, row, col, "%d" % h1[dom][5][0]) 474 col += 24 475 display(stdscr, row, col, "%3.2f/ex" % h1[dom][5][1]) 476 col += 18 477 display(stdscr, row, col, "I/O Count") 478 479 #row += 1 480 #stdscr.hline(row, 1, '-', maxx - 2) 481 total_h1_cpu += h1[dom][0][1] 482 total_h2_cpu += h2[dom][0][1] 483 484 485 row += 1 486 star = heartbeat * '*' 487 heartbeat = 1 - heartbeat 488 display(stdscr, row, 1, star) 489 display(stdscr, row, 2, TOTALS % (total_h2_cpu, total_h1_cpu)) 490 row += 1 491# display(stdscr, row, 2, 492# "\tFFP: %d (Min: %d, Max: %d)\t\t\tFFP: %d (Min: %d, Max %d)" % 493# (math.ceil(f2[1]), f2[0], f2[2], math.ceil(f1[1]), f1[0], f1[2]), _c.A_BOLD) 494 495 if l1[1] > 1 : 496 row += 1 497 display(stdscr, row, 2, 498 "\tRecords lost: %d (Min: %d, Max: %d)\t\t\tRecords lost: %d (Min: %d, Max %d)" % 499 (math.ceil(l2[1]), l2[0], l2[2], math.ceil(l1[1]), l1[0], l1[2]), _c.A_BOLD) 500 501 # grab a char from tty input; exit if interrupt hit 502 try: 503 c = stdscr.getch() 504 except: 505 break 506 507 # q = quit 508 if c == ord('q'): 509 break 510 511 # c = cycle to a new cpu of interest 512 if c == ord('c'): 513 cpu = (cpu + 1) % ncpu 514 515 # n/p = cycle to the next/previous CPU 516 if c == ord('n'): 517 cpu = (cpu + 1) % ncpu 518 if c == ord('p'): 519 cpu = (cpu - 1) % ncpu 520 521 stdscr.erase() 522 523 _c.nocbreak() 524 stdscr.keypad(0) 525 _c.echo() 526 _c.endwin() 527 shm.close() 528 shmf.close() 529 530 531# simple functions to allow initialization of log files without actually 532# physically creating files that are never used; only on the first real 533# write does the file get created 534class Delayed(file): 535 def __init__(self, filename, mode): 536 self.filename = filename 537 self.saved_mode = mode 538 self.delay_data = "" 539 self.opened = 0 540 541 def delayed_write(self, str): 542 self.delay_data = str 543 544 def write(self, str): 545 if not self.opened: 546 self.file = open(self.filename, self.saved_mode) 547 self.opened = 1 548 self.file.write(self.delay_data) 549 self.file.write(str) 550 551 def rename(self, name): 552 self.filename = name 553 554 def flush(self): 555 if self.opened: 556 self.file.flush() 557 558 def close(self): 559 if self.opened: 560 self.file.close() 561 562 563def writelog(): 564 global options 565 global dom_in_use 566 567 ncpu = 1 # number of cpu's 568 slen = 0 # size of shared structure inc. padding 569 570 shmf = open(SHM_FILE, "r+") 571 shm = mmap.mmap(shmf.fileno(), QOS_DATA_SIZE) 572 573 interval = 0 574 curr = last = time.time() 575 outfiles = {} 576 for dom in range(0, NDOMAINS): 577 outfiles[dom] = Delayed("%s-dom%d.log" % (options.prefix, dom), 'w') 578 outfiles[dom].delayed_write("# passed cpu dom cpu(tot) cpu(%) cpu/ex allocated/ex blocked(tot) blocked(%) blocked/io waited(tot) waited(%) waited/ex ex/s io(tot) io/ex\n") 579 580 while options.duration == 0 or interval < (options.duration * 1000): 581 cpuidx = 0 582 while cpuidx < ncpu: 583 584 idx = cpuidx * slen # offset needed in mmap file 585 586 samples = [] 587 doms = [] 588 dom_in_use = [] 589 domain_id = [] 590 591 for i in range(0, NSAMPLES): 592 len = struct.calcsize(ST_QDATA) 593 sample = struct.unpack(ST_QDATA, shm[idx:idx+len]) 594 samples.append(sample) 595 idx += len 596 597 for i in range(0, NDOMAINS): 598 len = struct.calcsize(ST_DOM_INFO) 599 dom = struct.unpack(ST_DOM_INFO, shm[idx:idx+len]) 600# doms.append(dom) 601# (last_update_time, start_time, runnable_start_time, blocked_start_time, 602# ns_since_boot, ns_oncpu_since_boot, runnable_at_last_update, 603# runnable, in_use, domid, junk, name) = dom 604 dom_in_use.append(dom[8]) 605 domid = dom[9] 606 if domid == 32767: 607 domid = IDLE_DOMAIN 608 domain_id.append(domid) 609 if domid == IDLE_DOMAIN: 610 outfiles[i].rename("%s-idle.log" % options.prefix) 611 else: 612 outfiles[i].rename("%s-dom%d.log" % (options.prefix, domid)) 613 idx += len 614 615 len = struct.calcsize("4i") 616 oldncpu = ncpu 617 (next, ncpu, slen, freq) = struct.unpack("4i", shm[idx:idx+len]) 618 idx += len 619 620 if oldncpu != ncpu: 621 shm = mmap.mmap(shmf.fileno(), ncpu*slen) 622 623 startat = next - 1 624 if next + 10 < NSAMPLES: 625 endat = next + 10 626 else: 627 endat = 10 628 629 [h1,l1, f1] = summarize(startat, endat, options.interval * 10**6, samples) 630 for dom in range(0, NDOMAINS): 631 if not dom_in_use[dom]: 632 continue 633 if h1[dom][0][1] > 0 or dom == IDLE_DOMAIN: 634 outfiles[dom].write("%.3f %d %d %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f\n" % 635 (interval, cpuidx, domain_id[dom], 636 h1[dom][0][0], h1[dom][0][1], h1[dom][0][2], 637 h1[dom][1], 638 h1[dom][2][0], h1[dom][2][1], h1[dom][2][2], 639 h1[dom][3][0], h1[dom][3][1], h1[dom][3][2], 640 h1[dom][4], 641 h1[dom][5][0], h1[dom][5][1])) 642 outfiles[dom].flush() 643 curr = time.time() 644 interval += (curr - last) * 1000 645 last = curr 646 cpuidx = cpuidx + 1 647 time.sleep(options.interval / 1000.0) 648 649 for dom in range(0, NDOMAINS): 650 outfiles[dom].close() 651 652# start xenbaked 653def start_xenbaked(): 654 global options 655 global kill_cmd 656 global xenbaked_cmd 657 658 os.system(kill_cmd) 659 os.system(xenbaked_cmd + " --ms_per_sample=%d &" % 660 options.mspersample) 661 time.sleep(1) 662 663# stop xenbaked 664def stop_xenbaked(): 665 global stop_cmd 666 os.system(stop_cmd) 667 668def main(): 669 global options 670 global args 671 global domains 672 global stop_cmd 673 global kill_cmd 674 global xenbaked_cmd 675 676 if os.uname()[0] == "SunOS": 677 xenbaked_cmd = "/usr/lib/xenbaked" 678 stop_cmd = "/usr/bin/pkill -INT -z global xenbaked" 679 kill_cmd = "/usr/bin/pkill -KILL -z global xenbaked" 680 else: 681 # assumes that xenbaked is in your path 682 xenbaked_cmd = "xenbaked" 683 stop_cmd = "/usr/bin/pkill -INT xenbaked" 684 kill_cmd = "/usr/bin/pkill -KILL xenbaked" 685 686 parser = setup_cmdline_parser() 687 (options, args) = parser.parse_args() 688 689 if len(args): 690 parser.error("No parameter required") 691 if options.mspersample < 0: 692 parser.error("option --ms_per_sample: invalid negative value: '%d'" % 693 options.mspersample) 694 # If --ms_per_sample= is too large, no data may be logged. 695 if not options.live and options.duration != 0 and \ 696 options.mspersample > options.duration * 1000: 697 parser.error("option --ms_per_sample: too large (> %d ms)" % 698 (options.duration * 1000)) 699 700 start_xenbaked() 701 if options.live: 702 show_livestats(options.cpu) 703 else: 704 try: 705 writelog() 706 except: 707 print 'Quitting.' 708 stop_xenbaked() 709 710if __name__ == "__main__": 711 main() 712