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