ia64/xen-unstable

annotate tools/xenmon/xenmon.py @ 16510:7bee812a0397

Fix xenmon.py to work on Solaris

The xenmon.py script does not work on Solaris because of (1) its
assumption that xenbaked is in the users path and, (2) the use of the
killall command. Changed xenmon.py to use pkill instead and provided
the path to xenbaked on Solaris.

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