[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] The new userland monitoring tool, XenMon.



# HG changeset patch
# User kaf24@xxxxxxxxxxxxxxxxxxxx
# Node ID 394390f6ff853783161ef1a88705b192b7369e71
# Parent  e580f80518881f2642703230dfdfa21bfdb21ff4
The new userland monitoring tool, XenMon.
Signed-off-by: Rob Gardner <rob.gardner@xxxxxx>

diff -r e580f8051888 -r 394390f6ff85 tools/Makefile
--- a/tools/Makefile    Tue Nov 15 13:59:59 2005
+++ b/tools/Makefile    Tue Nov 15 14:09:58 2005
@@ -11,6 +11,7 @@
 SUBDIRS += firmware
 SUBDIRS += security
 SUBDIRS += console
+SUBDIRS += xenmon
 ifeq ($(VTPM_TOOLS),y)
 SUBDIRS += vtpm_manager
 SUBDIRS += vtpm
diff -r e580f8051888 -r 394390f6ff85 tools/xentrace/setsize.c
--- a/tools/xentrace/setsize.c  Tue Nov 15 13:59:59 2005
+++ b/tools/xentrace/setsize.c  Tue Nov 15 14:09:58 2005
@@ -9,9 +9,9 @@
   int xc_handle = xc_interface_open();
   
   if (xc_tbuf_get_size(xc_handle, &size) != 0) {
-    perror("Failure to get tbuf info from Xen. Guess size is 0.");
-    printf("This may mean that tracing is not compiled into xen.\n");
-    exit(1);
+    perror("Failure to get tbuf info from Xen. Guess size is 0");
+    printf("This may mean that tracing is not enabled in xen.\n");
+    //    exit(1);
   }
   else
     printf("Current tbuf size: 0x%x\n", size);
@@ -25,9 +25,10 @@
     perror("set_size Hypercall failure");
     exit(1);
   }
+  printf("set_size succeeded.\n");
   
   if (xc_tbuf_get_size(xc_handle, &size) != 0)
-    perror("Failure to get tbuf info from Xen. Guess size is 0.");
+    perror("Failure to get tbuf info from Xen. Tracing must be enabled first");
   else
     printf("New tbuf size: 0x%x\n", size);
   
diff -r e580f8051888 -r 394390f6ff85 tools/xenmon/COPYING
--- /dev/null   Tue Nov 15 13:59:59 2005
+++ b/tools/xenmon/COPYING      Tue Nov 15 14:09:58 2005
@@ -0,0 +1,340 @@
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                   GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                           NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+
+           How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff -r e580f8051888 -r 394390f6ff85 tools/xenmon/Makefile
--- /dev/null   Tue Nov 15 13:59:59 2005
+++ b/tools/xenmon/Makefile     Tue Nov 15 14:09:58 2005
@@ -0,0 +1,51 @@
+# Copyright (C) HP Labs, Palo Alto and Fort Collins, 2005
+# Author: Diwaker Gupta <diwaker.gupta@xxxxxx>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; under version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+INSTALL         = install
+INSTALL_PROG    = $(INSTALL) -m0755
+INSTALL_DIR     = $(INSTALL) -d -m0755
+INSTALL_DATA    = $(INSTALL) -m064
+
+prefix=/usr/local
+mandir=$(prefix)/share/man
+man1dir=$(mandir)/man1
+sbindir=$(prefix)/sbin
+
+XEN_ROOT=../..
+include $(XEN_ROOT)/tools/Rules.mk
+
+CFLAGS += -Wall -Werror -g
+CFLAGS  += -I $(XEN_XC)
+CFLAGS  += -I $(XEN_LIBXC)
+LDFLAGS += -L $(XEN_LIBXC)
+
+BIN = setmask xenbaked
+SCRIPTS = xenmon.py
+
+all: build
+
+build: $(BIN)
+
+install: xenbaked setmask
+       [ -d $(DESTDIR)$(sbindir) ] || $(INSTALL_DIR) $(DESTDIR)$(sbindir)
+       $(INSTALL_PROG) xenbaked $(DESTDIR)$(sbindir)/xenbaked
+       $(INSTALL_PROG) setmask  $(DESTDIR)$(sbindir)/setmask
+       $(INSTALL_PROG) xenmon.py  $(DESTDIR)$(sbindir)/xenmon.py
+
+clean:
+       rm -f $(BIN)
+
+
+%: %.c Makefile
+       $(CC) $(CFLAGS) $(LDFLAGS) -lxenctrl -o $@ $<
+
+
diff -r e580f8051888 -r 394390f6ff85 tools/xenmon/README
--- /dev/null   Tue Nov 15 13:59:59 2005
+++ b/tools/xenmon/README       Tue Nov 15 14:09:58 2005
@@ -0,0 +1,104 @@
+Xen Performance Monitor
+-----------------------
+
+The xenmon tools make use of the existing xen tracing feature to provide fine
+grained reporting of various domain related metrics. It should be stressed that
+the xenmon.py script included here is just an example of the data that may be
+displayed. The xenbake demon keeps a large amount of history in a shared memory
+area that may be accessed by tools such as xenmon.
+
+For each domain, xenmon reports various metrics. One part of the display is a
+group of metrics that have been accumulated over the last second, while another
+part of the display shows data measured over 10 seconds. Other measurement
+intervals are possible, but we have just chosen 1s and 10s as an example.
+
+
+Execution Count
+---------------
+ o The number of times that a domain was scheduled to run (ie, dispatched) over
+ the measurement interval
+
+
+CPU usage
+---------
+ o Total time used over the measurement interval
+ o Usage expressed as a percentage of the measurement interval
+ o Average cpu time used during each execution of the domain
+
+
+Waiting time
+------------
+This is how much time the domain spent waiting to run, or put another way, the
+amount of time the domain spent in the "runnable" state (or on the run queue)
+but not actually running. Xenmon displays:
+
+ o Total time waiting over the measurement interval
+ o Wait time expressed as a percentage of the measurement interval
+ o Average waiting time for each execution of the domain
+
+Blocked time
+------------
+This is how much time the domain spent blocked (or sleeping); Put another way,
+the amount of time the domain spent not needing/wanting the cpu because it was
+waiting for some event (ie, I/O). Xenmon reports:
+
+ o Total time blocked over the measurement interval
+ o Blocked time expressed as a percentage of the measurement interval
+ o Blocked time per I/O (see I/O count below)
+
+Allocation time
+---------------
+This is how much cpu time was allocated to the domain by the scheduler; This is
+distinct from cpu usage since the "time slice" given to a domain is frequently
+cut short for one reason or another, ie, the domain requests I/O and blocks.
+Xenmon reports:
+
+ o Average allocation time per execution (ie, time slice)
+ o Min and Max allocation times
+
+I/O Count
+---------
+This is a rough measure of I/O requested by the domain. The number of page
+exchanges (or page "flips") between the domain and dom0 are counted. The
+number of pages exchanged may not accurately reflect the number of bytes
+transferred to/from a domain due to partial pages being used by the network
+protocols, etc. But it does give a good sense of the magnitude of I/O being
+requested by a domain. Xenmon reports:
+
+ o Total number of page exchanges during the measurement interval
+ o Average number of page exchanges per execution of the domain
+
+
+Usage Notes and issues
+----------------------
+ - Start xenmon by simply running xenmon.py; The xenbake demon is started and
+   stopped automatically by xenmon.
+ - To see the various options for xenmon, run xenmon -h. Ditto for xenbaked.
+ - xenmon also has an option (-n) to output log data to a file instead of the
+   curses interface.
+ - NDOMAINS is defined to be 32, but can be changed by recompiling xenbaked
+ - Xenmon.py appears to create 1-2% cpu overhead; Part of this is just the
+   overhead of the python interpreter. Part of it may be the number of trace
+   records being generated. The number of trace records generated can be
+   limited by setting the trace mask (with a dom0 Op), which controls which
+   events cause a trace record to be emitted.
+ - To exit xenmon, type 'q'
+ - To cycle the display to other physical cpu's, type 'c'
+
+Future Work
+-----------
+o RPC interface to allow external entities to programmatically access 
processed data
+o I/O Count batching to reduce number of trace records generated
+
+Case Study
+----------
+We have written a case study which demonstrates some of the usefulness of
+this tool and the metrics reported. It is available at:
+http://www.hpl.hp.com/techreports/2005/HPL-2005-187.html
+
+Authors
+-------
+Diwaker Gupta   <diwaker.gupta@xxxxxx>
+Rob Gardner     <rob.gardner@xxxxxx>
+Lucy Cherkasova <lucy.cherkasova.hp.com>
+
diff -r e580f8051888 -r 394390f6ff85 tools/xenmon/setmask.c
--- /dev/null   Tue Nov 15 13:59:59 2005
+++ b/tools/xenmon/setmask.c    Tue Nov 15 14:09:58 2005
@@ -0,0 +1,90 @@
+/******************************************************************************
+ * tools/xenmon/setmask.c
+ * 
+ * Simple utility for getting/setting the event mask
+ *
+ * Copyright (C) 2005 by Hewlett-Packard, Palo Alto and Fort Collins
+ *
+ * Authors: Lucy Cherkasova, lucy.cherkasova.hp.com
+ *          Rob Gardner, rob.gardner@xxxxxx
+ *          Diwaker Gupta, diwaker.gupta@xxxxxx
+ * Date:   August, 2005
+ * 
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; under version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <getopt.h>
+#include <xenctrl.h>
+#include <xen/xen.h>
+typedef struct { int counter; } atomic_t;
+#include <xen/trace.h>
+
+#define XENMON (TRC_SCHED_DOM_ADD | TRC_SCHED_DOM_REM | 
TRC_SCHED_SWITCH_INFPREV | TRC_SCHED_SWITCH_INFNEXT | TRC_SCHED_BLOCK | 
TRC_SCHED_SLEEP | TRC_SCHED_WAKE | TRC_MEM_PAGE_GRANT_TRANSFER)
+
+int main(int argc, char * argv[])
+{
+
+    dom0_op_t op; 
+    int ret;
+
+    int xc_handle = xc_interface_open();
+    op.cmd = DOM0_TBUFCONTROL;
+    op.interface_version = DOM0_INTERFACE_VERSION;
+    op.u.tbufcontrol.op  = DOM0_TBUF_GET_INFO;
+    ret = xc_dom0_op(xc_handle, &op);
+    if ( ret != 0 )
+    {
+        perror("Failure to get event mask from Xen");
+        exit(1);
+    }
+    else
+    {
+        printf("Current event mask: 0x%.8x\n", op.u.tbufcontrol.evt_mask);
+    }
+
+    op.cmd = DOM0_TBUFCONTROL;
+    op.interface_version = DOM0_INTERFACE_VERSION;
+    op.u.tbufcontrol.op  = DOM0_TBUF_SET_EVT_MASK;
+    op.u.tbufcontrol.evt_mask = XENMON;
+
+    ret = xc_dom0_op(xc_handle, &op);
+    printf("Setting mask to 0x%.8x\n", op.u.tbufcontrol.evt_mask);
+    if ( ret != 0 )
+    {
+        perror("Failure to get scheduler ID from Xen");
+        exit(1);
+    }
+
+    op.cmd = DOM0_TBUFCONTROL;
+    op.interface_version = DOM0_INTERFACE_VERSION;
+    op.u.tbufcontrol.op  = DOM0_TBUF_GET_INFO;
+    ret = xc_dom0_op(xc_handle, &op);
+    if ( ret != 0 )
+    {
+        perror("Failure to get event mask from Xen");
+        exit(1);
+    }
+    else
+    {
+        printf("Current event mask: 0x%.8x\n", op.u.tbufcontrol.evt_mask);
+    }
+    xc_interface_close(xc_handle);
+    return 0;
+}
diff -r e580f8051888 -r 394390f6ff85 tools/xenmon/xenbaked.c
--- /dev/null   Tue Nov 15 13:59:59 2005
+++ b/tools/xenmon/xenbaked.c   Tue Nov 15 14:09:58 2005
@@ -0,0 +1,1029 @@
+/******************************************************************************
+ * tools/xenbaked.c
+ *
+ * Tool for collecting raw trace buffer data from Xen and 
+ *  performing some accumulation operations and other processing
+ *  on it.
+ *
+ * Copyright (C) 2004 by Intel Research Cambridge
+ * Copyright (C) 2005 by Hewlett Packard, Palo Alto and Fort Collins
+ *
+ * Authors: Diwaker Gupta, diwaker.gupta@xxxxxx
+ *          Rob Gardner, rob.gardner@xxxxxx
+ *          Lucy Cherkasova, lucy.cherkasova.hp.com
+ * Much code based on xentrace, authored by Mark Williamson, 
mark.a.williamson@xxxxxxxxx
+ * Date:   November, 2005
+ * 
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; under version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <time.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <argp.h>
+#include <signal.h>
+#include <xenctrl.h>
+#include <xen/xen.h>
+#include <string.h>
+
+#include "xc_private.h"
+typedef struct { int counter; } atomic_t;
+#define _atomic_read(v)                ((v).counter)
+
+#include <xen/trace.h>
+#include "xenbaked.h"
+
+extern FILE *stderr;
+
+/***** Compile time configuration of defaults ********************************/
+
+/* when we've got more records than this waiting, we log it to the output */
+#define NEW_DATA_THRESH 1
+
+/* sleep for this long (milliseconds) between checking the trace buffers */
+#define POLL_SLEEP_MILLIS 100
+
+/* Size of time period represented by each sample */
+#define MS_PER_SAMPLE 100
+
+/* CPU Frequency */
+#define MHZ
+#define CPU_FREQ 2660 MHZ
+
+/***** The code **************************************************************/
+
+typedef struct settings_st {
+    char *outfile;
+    struct timespec poll_sleep;
+    unsigned long new_data_thresh;
+    unsigned long ms_per_sample;
+    double cpu_freq;
+} settings_t;
+
+settings_t opts;
+
+int interrupted = 0; /* gets set if we get a SIGHUP */
+int rec_count = 0;
+time_t start_time;
+int dom0_flips = 0;
+
+_new_qos_data *new_qos;
+_new_qos_data **cpu_qos_data;
+
+
+#define ID(X) ((X>NDOMAINS-1)?(NDOMAINS-1):X)
+
+// array of currently running domains, indexed by cpu
+int *running = NULL;
+
+// number of cpu's on this platform
+int NCPU = 0;
+
+
+void init_current(int ncpu)
+{
+  running = calloc(ncpu, sizeof(int));
+  NCPU = ncpu;
+  printf("Initialized with %d %s\n", ncpu, (ncpu == 1) ? "cpu" : "cpu's");
+}
+
+int is_current(int domain, int cpu)
+{
+  //  int i;
+  
+  //  for (i=0; i<NCPU; i++)
+    if (running[cpu] == domain)
+      return 1;
+  return 0;
+}
+
+
+// return the domain that's currently running on the given cpu
+int current(int cpu)
+{
+  return running[cpu];
+}
+
+void set_current(int cpu, int domain)
+{
+  running[cpu] = domain;
+}
+
+
+
+void close_handler(int signal)
+{
+    interrupted = 1;
+}
+
+#if 0
+void dump_record(int cpu, struct t_rec *x)
+{
+    printf("record: cpu=%x, tsc=%lx, event=%x, d1=%lx\n", 
+            cpu, x->cycles, x->event, x->data[0]);
+}
+#endif
+
+/**
+ * millis_to_timespec - convert a time in milliseconds to a struct timespec
+ * @millis:             time interval in milliseconds
+ */
+struct timespec millis_to_timespec(unsigned long millis)
+{
+    struct timespec spec;
+
+    spec.tv_sec = millis / 1000;
+    spec.tv_nsec = (millis % 1000) * 1000;
+
+    return spec;
+}
+
+
+typedef struct 
+{
+    int event_count;
+    int event_id;
+    char *text;
+} stat_map_t;
+
+stat_map_t stat_map[] = {
+    { 0,       0,          "Other" },
+    { 0, TRC_SCHED_DOM_ADD, "Add Domain" },
+    { 0, TRC_SCHED_DOM_REM, "Remove Domain" },
+    { 0, TRC_SCHED_SLEEP, "Sleep" },
+    { 0, TRC_SCHED_WAKE,  "Wake" },
+    { 0, TRC_SCHED_BLOCK,  "Block" },
+    { 0, TRC_SCHED_SWITCH,  "Switch" },
+    { 0, TRC_SCHED_S_TIMER_FN, "Timer Func"},
+    { 0, TRC_SCHED_SWITCH_INFPREV,  "Switch Prev" },
+    { 0, TRC_SCHED_SWITCH_INFNEXT,  "Switch Next" },
+    { 0, TRC_MEM_PAGE_GRANT_MAP,  "Page Map" },
+    { 0, TRC_MEM_PAGE_GRANT_UNMAP,  "Page Unmap" },
+    { 0, TRC_MEM_PAGE_GRANT_TRANSFER,  "Page Transfer" },
+    { 0,      0,                0  }
+};
+
+
+void check_gotten_sum(void)
+{
+#if 0
+    uint64_t sum, ns;
+    extern uint64_t total_ns_gotten(uint64_t*);
+    double percent;
+    int i;
+
+    for (i=0; i<NCPU; i++) {
+      new_qos = cpu_qos_data[i];
+      ns = billion;
+      sum = total_ns_gotten(&ns);
+
+      printf("[cpu%d] ns_gotten over all domains = %lldns, over %lldns\n",
+             i, sum, ns);
+      percent = (double) sum;
+      percent = (100.0*percent) / (double)ns;
+      printf(" ==> ns_gotten = %7.3f%%\n", percent);
+    }
+#endif
+}
+
+
+
+void dump_stats(void) 
+{
+    stat_map_t *smt = stat_map;
+    time_t end_time, run_time;
+
+    time(&end_time);
+
+    run_time = end_time - start_time;
+
+    printf("Event counts:\n");
+    while (smt->text != NULL) {
+        printf("%08d\t%s\n", smt->event_count, smt->text);
+        smt++;
+    }
+
+    printf("processed %d total records in %d seconds (%ld per second)\n",
+            rec_count, (int)run_time, rec_count/run_time);
+
+    check_gotten_sum();
+}
+
+void log_event(int event_id) 
+{
+    stat_map_t *smt = stat_map;
+
+    //  printf("event_id = 0x%x\n", event_id);
+
+    while (smt->text != NULL) {
+        if (smt->event_id == event_id) {
+            smt->event_count++;
+            return;
+        }
+        smt++;
+    }
+    if (smt->text == NULL)
+        stat_map[0].event_count++;     // other
+}
+
+
+
+/**
+ * get_tbufs - get pointer to and size of the trace buffers
+ * @mfn:  location to store mfn of the trace buffers to
+ * @size: location to store the size of a trace buffer to
+ *
+ * Gets the machine address of the trace pointer area and the size of the
+ * per CPU buffers.
+ */
+void get_tbufs(unsigned long *mfn, unsigned long *size)
+{
+    int ret;
+    dom0_op_t op;                        /* dom0 op we'll build             */
+    int xc_handle = xc_interface_open(); /* for accessing control interface */
+
+    op.cmd = DOM0_TBUFCONTROL;
+    op.interface_version = DOM0_INTERFACE_VERSION;
+    op.u.tbufcontrol.op  = DOM0_TBUF_GET_INFO;
+
+    ret = do_dom0_op(xc_handle, &op);
+
+    xc_interface_close(xc_handle);
+
+    if ( ret != 0 )
+    {
+        PERROR("Failure to get trace buffer pointer from Xen");
+        exit(EXIT_FAILURE);
+    }
+
+    *mfn  = op.u.tbufcontrol.buffer_mfn;
+    *size = op.u.tbufcontrol.size;
+}
+
+/**
+ * map_tbufs - memory map Xen trace buffers into user space
+ * @tbufs_mfn: mfn of the trace buffers
+ * @num:       number of trace buffers to map
+ * @size:      size of each trace buffer
+ *
+ * Maps the Xen trace buffers them into process address space.
+ */
+struct t_buf *map_tbufs(unsigned long tbufs_mfn, unsigned int num,
+                        unsigned long size)
+{
+    int xc_handle;                  /* file descriptor for /proc/xen/privcmd */
+    struct t_buf *tbufs_mapped;
+
+    xc_handle = xc_interface_open();
+
+    if ( xc_handle < 0 ) 
+    {
+        PERROR("Open /proc/xen/privcmd when mapping trace buffers\n");
+        exit(EXIT_FAILURE);
+    }
+
+    tbufs_mapped = xc_map_foreign_range(xc_handle, 0 /* Dom 0 ID */,
+                                        size * num, PROT_READ | PROT_WRITE,
+                                        tbufs_mfn);
+
+    xc_interface_close(xc_handle);
+
+    if ( tbufs_mapped == 0 ) 
+    {
+        PERROR("Failed to mmap trace buffers");
+        exit(EXIT_FAILURE);
+    }
+
+    return tbufs_mapped;
+}
+
+/**
+ * init_bufs_ptrs - initialises an array of pointers to the trace buffers
+ * @bufs_mapped:    the userspace address where the trace buffers are mapped
+ * @num:            number of trace buffers
+ * @size:           trace buffer size
+ *
+ * Initialises an array of pointers to individual trace buffers within the
+ * mapped region containing all trace buffers.
+ */
+struct t_buf **init_bufs_ptrs(void *bufs_mapped, unsigned int num,
+        unsigned long size)
+{
+    int i;
+    struct t_buf **user_ptrs;
+
+    user_ptrs = (struct t_buf **)calloc(num, sizeof(struct t_buf *));
+    if ( user_ptrs == NULL )
+    {
+        PERROR( "Failed to allocate memory for buffer pointers\n");
+        exit(EXIT_FAILURE);
+    }
+
+    /* initialise pointers to the trace buffers - given the size of a trace
+     * buffer and the value of bufs_maped, we can easily calculate these */
+    for ( i = 0; i<num; i++ )
+        user_ptrs[i] = (struct t_buf *)((unsigned long)bufs_mapped + size * i);
+
+    return user_ptrs;
+}
+
+
+/**
+ * init_rec_ptrs - initialises data area pointers to locations in user space
+ * @tbufs_mfn:     base mfn of the trace buffer area
+ * @tbufs_mapped:  user virtual address of base of trace buffer area
+ * @meta:          array of user-space pointers to struct t_buf's of metadata
+ * @num:           number of trace buffers
+ *
+ * Initialises data area pointers to the locations that data areas have been
+ * mapped in user space.  Note that the trace buffer metadata contains machine
+ * pointers - the array returned allows more convenient access to them.
+ */
+struct t_rec **init_rec_ptrs(struct t_buf **meta, unsigned int num)
+{
+    int i;
+    struct t_rec **data;
+    
+    data = calloc(num, sizeof(struct t_rec *));
+    if ( data == NULL )
+    {
+        PERROR("Failed to allocate memory for data pointers\n");
+        exit(EXIT_FAILURE);
+    }
+
+    for ( i = 0; i < num; i++ )
+        data[i] = (struct t_rec *)(meta[i] + 1);
+
+    return data;
+}
+
+
+
+/**
+ * get_num_cpus - get the number of logical CPUs
+ */
+unsigned int get_num_cpus()
+{
+    dom0_op_t op;
+    int xc_handle = xc_interface_open();
+    int ret;
+
+    op.cmd = DOM0_PHYSINFO;
+    op.interface_version = DOM0_INTERFACE_VERSION;
+
+    ret = xc_dom0_op(xc_handle, &op);
+
+    if ( ret != 0 )
+    {
+        PERROR("Failure to get logical CPU count from Xen");
+        exit(EXIT_FAILURE);
+    }
+
+    xc_interface_close(xc_handle);
+    opts.cpu_freq = (double)op.u.physinfo.cpu_khz/1000.0;
+
+    return (op.u.physinfo.threads_per_core *
+            op.u.physinfo.cores_per_socket *
+            op.u.physinfo.sockets_per_node *
+            op.u.physinfo.nr_nodes);
+}
+
+
+/**
+ * monitor_tbufs - monitor the contents of tbufs
+ */
+int monitor_tbufs()
+{
+    int i;
+    extern void process_record(int, struct t_rec *);
+    extern void alloc_qos_data(int ncpu);
+
+    void *tbufs_mapped;          /* pointer to where the tbufs are mapped    */
+    struct t_buf **meta;         /* pointers to the trace buffer metadata    */
+    struct t_rec **data;         /* pointers to the trace buffer data areas
+                                  * where they are mapped into user space.   */
+    unsigned long tbufs_mfn;     /* mfn of the tbufs                         */
+    unsigned int  num;           /* number of trace buffers / logical CPUS   */
+    unsigned long size;          /* size of a single trace buffer            */
+
+    int size_in_recs;
+
+    /* get number of logical CPUs (and therefore number of trace buffers) */
+    num = get_num_cpus();
+
+    init_current(num);
+    alloc_qos_data(num);
+
+    printf("CPU Frequency = %7.2f\n", opts.cpu_freq);
+    
+    /* setup access to trace buffers */
+    get_tbufs(&tbufs_mfn, &size);
+
+    //    printf("from dom0op: %ld, t_buf: %d, t_rec: %d\n",
+    //            size, sizeof(struct t_buf), sizeof(struct t_rec));
+
+    tbufs_mapped = map_tbufs(tbufs_mfn, num, size);
+
+    size_in_recs = (size - sizeof(struct t_buf)) / sizeof(struct t_rec);
+    //    fprintf(stderr, "size_in_recs = %d\n", size_in_recs);
+
+    /* build arrays of convenience ptrs */
+    meta  = init_bufs_ptrs (tbufs_mapped, num, size);
+    data  = init_rec_ptrs(meta, num);
+
+    /* now, scan buffers for events */
+    while ( !interrupted )
+    {
+        for ( i = 0; ( i < num ) && !interrupted; i++ )
+            while ( meta[i]->cons != meta[i]->prod )
+            {
+                rmb(); /* read prod, then read item. */
+                process_record(i, data[i] + meta[i]->cons % size_in_recs);
+                mb(); /* read item, then update cons. */
+                meta[i]->cons++;
+            }
+
+        nanosleep(&opts.poll_sleep, NULL);
+    }
+
+    /* cleanup */
+    free(meta);
+    free(data);
+    /* don't need to munmap - cleanup is automatic */
+
+    return 0;
+}
+
+
+/******************************************************************************
+ * Various declarations / definitions GNU argp needs to do its work
+ *****************************************************************************/
+
+
+/* command parser for GNU argp - see GNU docs for more info */
+error_t cmd_parser(int key, char *arg, struct argp_state *state)
+{
+    settings_t *setup = (settings_t *)state->input;
+
+    switch ( key )
+    {
+        case 't': /* set new records threshold for logging */
+            {
+                char *inval;
+                setup->new_data_thresh = strtol(arg, &inval, 0);
+                if ( inval == arg )
+                    argp_usage(state);
+            }
+            break;
+
+        case 's': /* set sleep time (given in milliseconds) */
+            {
+                char *inval;
+                setup->poll_sleep = millis_to_timespec(strtol(arg, &inval, 0));
+                if ( inval == arg )
+                    argp_usage(state);
+            }
+            break;
+
+        case 'm': /* set ms_per_sample */
+            {
+                char *inval;
+                setup->ms_per_sample = strtol(arg, &inval, 0);
+                if ( inval == arg )
+                    argp_usage(state);
+            }
+            break;
+
+        case ARGP_KEY_ARG:
+            {
+                if ( state->arg_num == 0 )
+                    setup->outfile = arg;
+                else
+                    argp_usage(state);
+            }
+            break;
+
+        default:
+            return ARGP_ERR_UNKNOWN;
+    }
+
+    return 0;
+}
+
+#define SHARED_MEM_FILE "/tmp/xenq-shm"
+void alloc_qos_data(int ncpu)
+{
+    int i, n, pgsize, off=0;
+    char *dummy;
+    int qos_fd;
+    void advance_next_datapoint(uint64_t);
+
+    cpu_qos_data = (_new_qos_data **) calloc(ncpu, sizeof(_new_qos_data *));
+
+
+    qos_fd = open(SHARED_MEM_FILE, O_RDWR|O_CREAT|O_TRUNC, 0777);
+    if (qos_fd < 0) {
+        PERROR(SHARED_MEM_FILE);
+        exit(2);
+    }
+    pgsize = getpagesize();
+    dummy = malloc(pgsize);
+
+    for (n=0; n<ncpu; n++) {
+
+      for (i=0; i<sizeof(_new_qos_data); i=i+pgsize)
+        write(qos_fd, dummy, pgsize);
+
+      new_qos = (_new_qos_data *) mmap(0, sizeof(_new_qos_data), 
PROT_READ|PROT_WRITE, 
+                                      MAP_SHARED, qos_fd, off);
+      off += i;
+      if (new_qos == NULL) {
+        PERROR("mmap");
+        exit(3);
+      }
+      //  printf("new_qos = %p\n", new_qos);
+      memset(new_qos, 0, sizeof(_new_qos_data));
+      new_qos->next_datapoint = 0;
+      advance_next_datapoint(0);
+      new_qos->structlen = i;
+      new_qos->ncpu = ncpu;
+      //      printf("structlen = 0x%x\n", i);
+      cpu_qos_data[n] = new_qos;
+    }
+    free(dummy);
+    new_qos = NULL;
+}
+
+
+#define xstr(x) str(x)
+#define str(x) #x
+
+const struct argp_option cmd_opts[] =
+{
+    { .name = "log-thresh", .key='t', .arg="l",
+        .doc =
+            "Set number, l, of new records required to trigger a write to 
output "
+            "(default " xstr(NEW_DATA_THRESH) ")." },
+
+    { .name = "poll-sleep", .key='s', .arg="p",
+        .doc = 
+            "Set sleep time, p, in milliseconds between polling the trace 
buffer "
+            "for new data (default " xstr(POLL_SLEEP_MILLIS) ")." },
+
+    { .name = "ms_per_sample", .key='m', .arg="MS",
+        .doc = 
+            "Specify the number of milliseconds per sample "
+            " (default " xstr(MS_PER_SAMPLE) ")." },
+
+    {0}
+};
+
+const struct argp parser_def =
+{
+    .options = cmd_opts,
+    .parser = cmd_parser,
+    //    .args_doc = "[output file]",
+    .doc =
+        "Tool to capture and partially process Xen trace buffer data"
+        "\v"
+        "This tool is used to capture trace buffer data from Xen.  The data is 
"
+        "saved in a shared memory structure to be further processed by xenmon."
+};
+
+
+const char *argp_program_version     = "xenbaked v1.3";
+const char *argp_program_bug_address = "<rob.gardner@xxxxxx>";
+
+
+int main(int argc, char **argv)
+{
+    int ret;
+    struct sigaction act;
+
+    time(&start_time);
+    opts.outfile = 0;
+    opts.poll_sleep = millis_to_timespec(POLL_SLEEP_MILLIS);
+    opts.new_data_thresh = NEW_DATA_THRESH;
+    opts.ms_per_sample = MS_PER_SAMPLE;
+    opts.cpu_freq = CPU_FREQ;
+
+    argp_parse(&parser_def, argc, argv, 0, 0, &opts);
+    fprintf(stderr, "ms_per_sample = %ld\n", opts.ms_per_sample);
+
+
+    /* ensure that if we get a signal, we'll do cleanup, then exit */
+    act.sa_handler = close_handler;
+    act.sa_flags = 0;
+    sigemptyset(&act.sa_mask);
+    sigaction(SIGHUP,  &act, NULL);
+    sigaction(SIGTERM, &act, NULL);
+    sigaction(SIGINT,  &act, NULL);
+
+    ret = monitor_tbufs();
+
+    dump_stats();
+    msync(new_qos, sizeof(_new_qos_data), MS_SYNC);
+
+    return ret;
+}
+
+int domain_runnable(int domid)
+{
+    return new_qos->domain_info[ID(domid)].runnable;
+}
+
+
+void update_blocked_time(int domid, uint64_t now)
+{
+    uint64_t t_blocked;
+    int id = ID(domid);
+
+    if (new_qos->domain_info[id].blocked_start_time != 0) {
+        if (now >= new_qos->domain_info[id].blocked_start_time)
+            t_blocked = now - new_qos->domain_info[id].blocked_start_time;
+        else
+            t_blocked = now + (~0ULL - 
new_qos->domain_info[id].blocked_start_time);
+        new_qos->qdata[new_qos->next_datapoint].ns_blocked[id] += t_blocked;
+    }
+
+    if (domain_runnable(id))
+        new_qos->domain_info[id].blocked_start_time = 0;
+    else
+        new_qos->domain_info[id].blocked_start_time = now;
+}
+
+
+// advance to next datapoint for all domains
+void advance_next_datapoint(uint64_t now)
+{
+    int new, old, didx;
+
+    old = new_qos->next_datapoint;
+    new = QOS_INCR(old);
+    new_qos->next_datapoint = new;
+    // memset(&new_qos->qdata[new], 0, sizeof(uint64_t)*(2+5*NDOMAINS));
+    for (didx = 0; didx < NDOMAINS; didx++) {
+        new_qos->qdata[new].ns_gotten[didx] = 0;
+        new_qos->qdata[new].ns_allocated[didx] = 0;
+        new_qos->qdata[new].ns_waiting[didx] = 0;
+        new_qos->qdata[new].ns_blocked[didx] = 0;
+        new_qos->qdata[new].switchin_count[didx] = 0;
+        new_qos->qdata[new].io_count[didx] = 0;
+    }
+    new_qos->qdata[new].ns_passed = 0;
+    new_qos->qdata[new].lost_records = 0;
+    new_qos->qdata[new].flip_free_periods = 0;
+
+    new_qos->qdata[new].timestamp = now;
+}
+
+
+
+void qos_update_thread(int cpu, int domid, uint64_t now)
+{
+    int n, id;
+    uint64_t last_update_time, start;
+    int64_t time_since_update, run_time = 0;
+
+    id = ID(domid);
+
+    n = new_qos->next_datapoint;
+    last_update_time = new_qos->domain_info[id].last_update_time;
+
+    time_since_update = now - last_update_time;
+
+    if (time_since_update < 0) {
+      // what happened here? either a timestamp wraparound, or more likely,
+      // a slight inconsistency among timestamps from various cpu's
+      if (-time_since_update < billion) {
+       // fairly small difference, let's just adjust 'now' to be a little
+       // beyond last_update_time
+       time_since_update = -time_since_update;
+      }
+      else if ( ((~0ULL - last_update_time) < billion) && (now < billion) ) {
+       // difference is huge, must be a wraparound
+       // last_update time should be "near" ~0ULL,
+       // and now should be "near" 0
+       time_since_update = now + (~0ULL - last_update_time);
+       printf("time wraparound\n");
+      }
+      else {
+       // none of the above, may be an out of order record
+       // no good solution, just ignore and update again later
+       return;
+      }
+    }
+       
+    new_qos->domain_info[id].last_update_time = now;
+
+    if (new_qos->domain_info[id].runnable_at_last_update && is_current(domid, 
cpu)) {
+        start = new_qos->domain_info[id].start_time;
+        if (start > now) {             // wrapped around
+            run_time = now + (~0ULL - start);
+           printf("warning: start > now\n");
+        }
+        else
+            run_time = now - start;
+       //      if (run_time < 0)       // should not happen
+       //        printf("warning: run_time < 0; start = %lld now= %lld\n", 
start, now);
+        new_qos->domain_info[id].ns_oncpu_since_boot += run_time;
+        new_qos->domain_info[id].start_time = now;
+        new_qos->domain_info[id].ns_since_boot += time_since_update;
+#if 1
+       new_qos->qdata[n].ns_gotten[id] += run_time;
+       if (domid == 0 && cpu == 1)
+         printf("adding run time for dom0 on cpu1\r\n");
+#endif
+    }
+
+    new_qos->domain_info[id].runnable_at_last_update = domain_runnable(domid);
+
+    update_blocked_time(domid, now);
+
+    // how much time passed since this datapoint was updated?
+    if (now >= new_qos->qdata[n].timestamp) {
+        // all is right with the world, time is increasing
+        new_qos->qdata[n].ns_passed += (now - new_qos->qdata[n].timestamp);
+    }
+    else {
+        // time wrapped around
+        //new_qos->qdata[n].ns_passed += (now + (~0LL - 
new_qos->qdata[n].timestamp));
+        //    printf("why timewrap?\r\n");
+    }
+    new_qos->qdata[n].timestamp = now;
+}
+
+
+// called by dump routines to update all structures
+void qos_update_all(uint64_t now, int cpu)
+{
+    int i;
+
+    for (i=0; i<NDOMAINS; i++)
+        if (new_qos->domain_info[i].in_use)
+            qos_update_thread(cpu, i, now);
+}
+
+
+void qos_update_thread_stats(int cpu, int domid, uint64_t now)
+{
+    if (new_qos->qdata[new_qos->next_datapoint].ns_passed > 
(million*opts.ms_per_sample)) {
+        qos_update_all(now, cpu);
+        advance_next_datapoint(now);
+        return;
+    }
+    qos_update_thread(cpu, domid, now);
+}
+
+
+void qos_init_domain(int cpu, int domid, uint64_t now)
+{
+    int i, id;
+
+    id = ID(domid);
+
+    if (new_qos->domain_info[id].in_use)
+        return;
+
+
+    memset(&new_qos->domain_info[id], 0, sizeof(_domain_info));
+    new_qos->domain_info[id].last_update_time = now;
+    //  runnable_start_time[id] = 0;
+    new_qos->domain_info[id].runnable_start_time = 0; // invalidate
+    new_qos->domain_info[id].in_use = 1;
+    new_qos->domain_info[id].blocked_start_time = 0;
+    new_qos->domain_info[id].id = id;
+    if (domid == IDLE_DOMAIN_ID)
+        sprintf(new_qos->domain_info[id].name, "Idle Task%d", cpu);
+    else
+        sprintf(new_qos->domain_info[id].name, "Domain#%d", domid);
+
+    for (i=0; i<NSAMPLES; i++) {
+        new_qos->qdata[i].ns_gotten[id] = 0;
+        new_qos->qdata[i].ns_allocated[id] = 0;
+        new_qos->qdata[i].ns_waiting[id] = 0;
+        new_qos->qdata[i].ns_blocked[id] = 0;
+        new_qos->qdata[i].switchin_count[id] = 0;
+        new_qos->qdata[i].io_count[id] = 0;
+    }
+}
+
+
+// called when a new thread gets the cpu
+void qos_switch_in(int cpu, int domid, uint64_t now, unsigned long ns_alloc, 
unsigned long ns_waited)
+{
+    int id = ID(domid);
+
+    new_qos->domain_info[id].runnable = 1;
+    update_blocked_time(domid, now);
+    new_qos->domain_info[id].blocked_start_time = 0; // invalidate
+    new_qos->domain_info[id].runnable_start_time = 0; // invalidate
+    //runnable_start_time[id] = 0;
+
+    new_qos->domain_info[id].start_time = now;
+    new_qos->qdata[new_qos->next_datapoint].switchin_count[id]++;
+    new_qos->qdata[new_qos->next_datapoint].ns_allocated[id] += ns_alloc;
+    new_qos->qdata[new_qos->next_datapoint].ns_waiting[id] += ns_waited;
+    qos_update_thread_stats(cpu, domid, now);
+    set_current(cpu, id);
+
+    // count up page flips for dom0 execution
+    if (id == 0)
+      dom0_flips = 0;
+}
+
+// called when the current thread is taken off the cpu
+void qos_switch_out(int cpu, int domid, uint64_t now, unsigned long gotten)
+{
+    int id = ID(domid);
+    int n;
+
+    if (!is_current(id, cpu)) {
+        //    printf("switching out domain %d but it is not current. 
gotten=%ld\r\n", id, gotten);
+    }
+
+    if (gotten == 0) {
+        printf("gotten==0 in qos_switchout(domid=%d)\n", domid);
+    }
+
+    if (gotten < 100) {
+        printf("gotten<100ns in qos_switchout(domid=%d)\n", domid);
+    }
+
+
+    n = new_qos->next_datapoint;
+#if 0
+    new_qos->qdata[n].ns_gotten[id] += gotten;
+    if (gotten > new_qos->qdata[n].ns_passed)
+      printf("inconsistency #257, diff = %lld\n",
+           gotten - new_qos->qdata[n].ns_passed );
+#endif
+    new_qos->domain_info[id].ns_oncpu_since_boot += gotten;
+    new_qos->domain_info[id].runnable_start_time = now;
+    //  runnable_start_time[id] = now;
+    qos_update_thread_stats(cpu, id, now);
+
+    // process dom0 page flips
+    if (id == 0)
+      if (dom0_flips == 0)
+       new_qos->qdata[n].flip_free_periods++;
+}
+
+// called when domain is put to sleep, may also be called
+// when thread is already asleep
+void qos_state_sleeping(int cpu, int domid, uint64_t now) 
+{
+    int id = ID(domid);
+
+    if (!domain_runnable(id))  // double call?
+        return;
+
+    new_qos->domain_info[id].runnable = 0;
+    new_qos->domain_info[id].blocked_start_time = now;
+    new_qos->domain_info[id].runnable_start_time = 0; // invalidate
+    //  runnable_start_time[id] = 0; // invalidate
+    qos_update_thread_stats(cpu, domid, now);
+}
+
+
+
+void qos_kill_thread(int domid)
+{
+    new_qos->domain_info[ID(domid)].in_use = 0;
+}
+
+
+// called when thread becomes runnable, may also be called
+// when thread is already runnable
+void qos_state_runnable(int cpu, int domid, uint64_t now)
+{
+    int id = ID(domid);
+
+    if (domain_runnable(id))   // double call?
+        return;
+    new_qos->domain_info[id].runnable = 1;
+    update_blocked_time(domid, now);
+
+    qos_update_thread_stats(cpu, domid, now);
+
+    new_qos->domain_info[id].blocked_start_time = 0; /* invalidate */
+    new_qos->domain_info[id].runnable_start_time = now;
+    //  runnable_start_time[id] = now;
+}
+
+
+void qos_count_packets(domid_t domid, uint64_t now)
+{
+  int i, id = ID(domid);
+  _new_qos_data *cpu_data;
+
+  for (i=0; i<NCPU; i++) {
+    cpu_data = cpu_qos_data[i];
+    if (cpu_data->domain_info[id].in_use) {
+      cpu_data->qdata[cpu_data->next_datapoint].io_count[id]++;
+    }
+  }
+
+  new_qos->qdata[new_qos->next_datapoint].io_count[0]++;
+  dom0_flips++;
+}
+
+
+int domain_ok(int cpu, int domid, uint64_t now)
+{
+    if (domid == IDLE_DOMAIN_ID)
+        domid = NDOMAINS-1;
+    if (domid < 0 || domid >= NDOMAINS) {
+        printf("bad domain id: %d\n", domid);
+        return 0;
+    }
+    if (new_qos->domain_info[domid].in_use == 0)
+        qos_init_domain(cpu, domid, now);
+    return 1;
+}
+
+
+void process_record(int cpu, struct t_rec *r)
+{
+  uint64_t now;
+
+
+  new_qos = cpu_qos_data[cpu];
+
+  rec_count++;
+
+  now = ((double)r->cycles) / (opts.cpu_freq / 1000.0);
+
+  log_event(r->event);
+
+  switch (r->event) {
+
+  case TRC_SCHED_SWITCH_INFPREV:
+    // domain data[0] just switched out and received data[1] ns of cpu time
+    if (domain_ok(cpu, r->data[0], now))
+      qos_switch_out(cpu, r->data[0], now, r->data[1]);
+    //    printf("ns_gotten %ld\n", r->data[1]);
+    break;
+    
+  case TRC_SCHED_SWITCH_INFNEXT:
+    // domain data[0] just switched in and
+    // waited data[1] ns, and was allocated data[2] ns of cpu time
+    if (domain_ok(cpu, r->data[0], now))
+      qos_switch_in(cpu, r->data[0], now, r->data[2], r->data[1]);
+    break;
+    
+  case TRC_SCHED_DOM_ADD:
+    if (domain_ok(cpu, r->data[0], now))
+      qos_init_domain(cpu, r->data[0],  now);
+    break;
+    
+  case TRC_SCHED_DOM_REM:
+    if (domain_ok(cpu, r->data[0], now))
+      qos_kill_thread(r->data[0]);
+    break;
+    
+  case TRC_SCHED_SLEEP:
+    if (domain_ok(cpu, r->data[0], now))
+      qos_state_sleeping(cpu, r->data[0], now);
+    break;
+    
+  case TRC_SCHED_WAKE:
+    if (domain_ok(cpu, r->data[0], now))
+      qos_state_runnable(cpu, r->data[0], now);
+    break;
+    
+  case TRC_SCHED_BLOCK:
+    if (domain_ok(cpu, r->data[0], now))
+      qos_state_sleeping(cpu, r->data[0], now);
+    break;
+    
+  case TRC_MEM_PAGE_GRANT_TRANSFER:
+    if (domain_ok(cpu, r->data[0], now))
+      qos_count_packets(r->data[0], now);
+    break;
+    
+  default:
+    break;
+  }
+  new_qos = NULL;
+}
+
+
+
diff -r e580f8051888 -r 394390f6ff85 tools/xenmon/xenbaked.h
--- /dev/null   Tue Nov 15 13:59:59 2005
+++ b/tools/xenmon/xenbaked.h   Tue Nov 15 14:09:58 2005
@@ -0,0 +1,101 @@
+/******************************************************************************
+ * tools/xenbaked.h
+ *
+ * Header file for xenbaked
+ *
+ * Copyright (C) 2005 by Hewlett Packard, Palo Alto and Fort Collins
+ *
+ * Authors: Diwaker Gupta, diwaker.gupta@xxxxxx
+ *          Rob Gardner, rob.gardner@xxxxxx
+ *          Lucy Cherkasova, lucy.cherkasova.hp.com
+ * 
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; under version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __QOS_H__
+#define __QOS_H__
+
+///// qos stuff
+#define million 1000000LL
+#define billion 1000000000LL
+
+#define QOS_ADD(N,A) ((N+A)<(NSAMPLES-1) ? (N+A) : A)
+#define QOS_INCR(N) ((N<(NSAMPLES-2)) ? (N+1) : 0)
+#define QOS_DECR(N) ((N==0) ? (NSAMPLES-1) : (N-1))
+
+#define MAX_NAME_SIZE 32
+#define IDLE_DOMAIN_ID 32767
+
+/* Number of domains we can keep track of in memory */
+#define NDOMAINS 32
+
+/* Number of data points to keep */
+#define NSAMPLES 100
+
+
+// per domain stuff
+typedef struct 
+{
+  uint64_t last_update_time;
+  uint64_t start_time;         // when the thread started running
+  uint64_t runnable_start_time;        // when the thread became runnable
+  uint64_t blocked_start_time; // when the thread became blocked
+  uint64_t ns_since_boot;              // time gone by since boot
+  uint64_t ns_oncpu_since_boot;        // total cpu time used by thread since 
boot
+  //  uint64_t ns_runnable_since_boot;
+  int runnable_at_last_update; // true if the thread was runnable last time we 
checked.
+  int runnable;                        // true if thread is runnable right now
+  // tells us something about what happened during the 
+  // sample period that we are analysing right now
+  int in_use;                  // 
+  domid_t  id;
+  char     name[MAX_NAME_SIZE];
+} _domain_info;
+
+
+
+typedef struct 
+{
+  struct 
+  {
+// data point:
+//   stuff that is recorded once for each measurement interval
+    uint64_t ns_gotten[NDOMAINS];              // ns used in the last sample 
period
+    uint64_t ns_allocated[NDOMAINS];           // ns allocated by scheduler
+    uint64_t ns_waiting[NDOMAINS];             // ns spent waiting to execute, 
ie, time from
+                                        // becoming runnable until actually 
running
+    uint64_t ns_blocked[NDOMAINS];             // ns spent blocked
+    uint64_t switchin_count[NDOMAINS]; // number of executions of the domain   
+    uint64_t io_count[NDOMAINS];
+    uint64_t ns_passed;              // ns gone by on the wall clock, ie, the 
sample period
+    uint64_t timestamp;
+    uint64_t lost_records;             // # of lost trace records this time 
period
+    uint64_t flip_free_periods;        // # of executions of dom0 in which no 
page flips happened
+  } qdata[NSAMPLES];
+  
+  _domain_info domain_info[NDOMAINS];
+  
+  // control information
+  int next_datapoint;
+  int ncpu;
+  int structlen;
+
+  // parameters
+  int measurement_frequency;   // for example
+  
+} _new_qos_data;
+
+
+
+#endif
diff -r e580f8051888 -r 394390f6ff85 tools/xenmon/xenmon.py
--- /dev/null   Tue Nov 15 13:59:59 2005
+++ b/tools/xenmon/xenmon.py    Tue Nov 15 14:09:58 2005
@@ -0,0 +1,578 @@
+#!/usr/bin/env python
+
+#####################################################################
+# xenmon is a front-end for xenbaked.
+# There is a curses interface for live monitoring. XenMon also allows
+# logging to a file. For options, run python xenmon.py -h
+#
+# Copyright (C) 2005 by Hewlett Packard, Palo Alto and Fort Collins
+# Authors: Lucy Cherkasova, lucy.cherkasova@xxxxxx
+#          Rob Gardner, rob.gardner@xxxxxx
+#          Diwaker Gupta, diwaker.gupta@xxxxxx
+#####################################################################
+#   This program is free software; you can redistribute it and/or modify
+#   it under the terms of the GNU General Public License as published by
+#   the Free Software Foundation; under version 2 of the License.
+# 
+#   This program is distributed in the hope that it will be useful,
+#   but WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#   GNU General Public License for more details.
+# 
+#   You should have received a copy of the GNU General Public License
+#   along with this program; if not, write to the Free Software
+#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#####################################################################
+
+import mmap
+import struct
+import os
+import time
+import optparse as _o
+import curses as _c
+import math
+import sys
+
+# constants
+NSAMPLES = 100
+NDOMAINS = 32
+
+# the struct strings for qos_info
+ST_DOM_INFO = "6Q4i32s"
+ST_QDATA = "%dQ" % (6*NDOMAINS + 4)
+
+# size of mmaped file
+QOS_DATA_SIZE = struct.calcsize(ST_QDATA)*NSAMPLES + 
struct.calcsize(ST_DOM_INFO)*NDOMAINS + struct.calcsize("4i")
+
+# location of mmaped file, hard coded right now
+SHM_FILE = "/tmp/xenq-shm"
+
+# format strings
+TOTALS = 15*' ' + "%6.2f%%" + 35*' ' + "%6.2f%%"
+
+ALLOCATED = "Allocated"
+GOTTEN = "Gotten"
+BLOCKED = "Blocked"
+WAITED = "Waited"
+IOCOUNT = "I/O Count"
+EXCOUNT = "Exec Count"
+
+# globals
+# our curses screen
+stdscr = None
+
+# parsed options
+options, args = None, None
+
+# the optparse module is quite smart
+# to see help, just run xenmon -h
+def setup_cmdline_parser():
+    parser = _o.OptionParser()
+    parser.add_option("-l", "--live", dest="live", action="store_true",
+                      default=True, help = "show the ncurses live monitoring 
frontend (default)")
+    parser.add_option("-n", "--notlive", dest="live", action="store_false",
+                      default="True", help = "write to file instead of live 
monitoring")
+    parser.add_option("-p", "--prefix", dest="prefix",
+                      default = "log", help="prefix to use for output files")
+    parser.add_option("-t", "--time", dest="duration",
+            action="store", type="int", default=10, 
+            help="stop logging to file after this much time has elapsed (in 
seconds). set to 0 to keep logging indefinitely")
+    parser.add_option("-i", "--interval", dest="interval",
+            action="store", type="int", default=1000,
+            help="interval for logging (in ms)")
+    parser.add_option("--ms_per_sample", dest="mspersample",
+            action="store", type="int", default=100,
+            help = "determines how many ms worth of data goes in a sample")
+    return parser
+
+# encapsulate information about a domain
+class DomainInfo:
+    def __init__(self):
+        self.allocated_samples = []
+        self.gotten_samples = []
+        self.blocked_samples = []
+        self.waited_samples = []
+        self.execcount_samples = []
+        self.iocount_samples = []
+        self.ffp_samples = []
+
+    def gotten_stats(self, passed):
+        total = float(sum(self.gotten_samples))
+        per = 100*total/passed
+        exs = sum(self.execcount_samples)
+        if exs > 0:
+            avg = total/exs
+        else:
+            avg = 0
+        return [total/(float(passed)/10**9), per, avg]
+
+    def waited_stats(self, passed):
+        total = float(sum(self.waited_samples))
+        per = 100*total/passed
+        exs = sum(self.execcount_samples)
+        if exs > 0:
+            avg = total/exs
+        else:
+            avg = 0
+        return [total/(float(passed)/10**9), per, avg]
+
+    def blocked_stats(self, passed):
+        total = float(sum(self.blocked_samples))
+        per = 100*total/passed
+        ios = sum(self.iocount_samples)
+        if ios > 0:
+            avg = total/float(ios)
+        else:
+            avg = 0
+        return [total/(float(passed)/10**9), per, avg]
+
+    def allocated_stats(self, passed):
+        total = sum(self.allocated_samples)
+        exs = sum(self.execcount_samples)
+        if exs > 0:
+            return float(total)/exs
+        else:
+            return 0
+
+    def ec_stats(self, passed):
+        total = float(sum(self.execcount_samples))/(float(passed)/10**9)
+        return total
+
+    def io_stats(self, passed):
+        total = float(sum(self.iocount_samples))
+        exs = sum(self.execcount_samples)
+        if exs > 0:
+            avg = total/exs
+        else:
+            avg = 0
+        return [total/(float(passed)/10**9), avg]
+
+    def stats(self, passed):
+        return [self.gotten_stats(passed), self.allocated_stats(passed), 
self.blocked_stats(passed), 
+                self.waited_stats(passed), self.ec_stats(passed), 
self.io_stats(passed)]
+
+# report values over desired interval
+def summarize(startat, endat, duration, samples):
+    dominfos = {}
+    for i in range(0, NDOMAINS):
+        dominfos[i] = DomainInfo()
+        
+    passed = 1              # to prevent zero division
+    curid = startat
+    numbuckets = 0
+    lost_samples = []
+    ffp_samples = []
+    
+    while passed < duration:
+        for i in range(0, NDOMAINS):
+            dominfos[i].gotten_samples.append(samples[curid][0*NDOMAINS + i])
+            dominfos[i].allocated_samples.append(samples[curid][1*NDOMAINS + 
i])
+            dominfos[i].waited_samples.append(samples[curid][2*NDOMAINS + i])
+            dominfos[i].blocked_samples.append(samples[curid][3*NDOMAINS + i])
+            dominfos[i].execcount_samples.append(samples[curid][4*NDOMAINS + 
i])
+            dominfos[i].iocount_samples.append(samples[curid][5*NDOMAINS + i])
+    
+        passed += samples[curid][6*NDOMAINS]
+        lost_samples.append(samples[curid][6*NDOMAINS + 2])
+        ffp_samples.append(samples[curid][6*NDOMAINS + 3])
+
+        numbuckets += 1
+
+        if curid > 0:
+            curid -= 1
+        else:
+            curid = NSAMPLES - 1
+        if curid == endat:
+            break
+
+    lostinfo = [min(lost_samples), sum(lost_samples), max(lost_samples)]
+    ffpinfo = [min(ffp_samples), sum(ffp_samples), max(ffp_samples)]
+    ldoms = map(lambda x: dominfos[x].stats(passed), range(0, NDOMAINS))
+
+    return [ldoms, lostinfo, ffpinfo]
+
+# scale microseconds to milliseconds or seconds as necessary
+def time_scale(ns):
+    if ns < 1000:
+        return "%4.2f ns" % float(ns)
+    elif ns < 1000*1000:
+        return "%4.2f us" % (float(ns)/10**3)
+    elif ns < 10**9:
+           return "%4.2f ms" % (float(ns)/10**6)
+    else:
+        return "%4.2f s" % (float(ns)/10**9)
+
+# paint message on curses screen, but detect screen size errors
+def display(scr, row, col, str, attr=0):
+    try:
+        scr.addstr(row, col, str, attr)
+    except:
+        scr.erase()
+        _c.nocbreak()
+        scr.keypad(0)
+        _c.echo()
+        _c.endwin()
+        print "Your terminal screen is not big enough; Please resize it."
+        print "row=%d, col=%d, str='%s'" % (row, col, str)
+        sys.exit(1)
+
+
+# the live monitoring code
+def show_livestats():
+    cpu = 0          # cpu of interest to display data for
+    ncpu = 1         # number of cpu's on this platform
+    slen = 0         # size of shared data structure, incuding padding
+    
+    # mmap the (the first chunk of the) file
+    shmf = open(SHM_FILE, "r+")
+    shm = mmap.mmap(shmf.fileno(), QOS_DATA_SIZE)
+
+    samples = []
+    doms = []
+
+    # initialize curses
+    stdscr = _c.initscr()
+    _c.noecho()
+    _c.cbreak()
+
+    stdscr.keypad(1)
+    stdscr.timeout(1000)
+    [maxy, maxx] = stdscr.getmaxyx()
+
+    
+
+    # display in a loop
+    while True:
+
+        for cpuidx in range(0, ncpu):
+
+            # calculate offset in mmap file to start from
+            idx = cpuidx * slen
+
+
+            samples = []
+            doms = []
+
+            # read in data
+            for i in range(0, NSAMPLES):
+                len = struct.calcsize(ST_QDATA)
+                sample = struct.unpack(ST_QDATA, shm[idx:idx+len])
+                samples.append(sample)
+                idx += len
+
+            for i in range(0, NDOMAINS):
+                len = struct.calcsize(ST_DOM_INFO)
+                dom = struct.unpack(ST_DOM_INFO, shm[idx:idx+len])
+                doms.append(dom)
+                idx += len
+
+            len = struct.calcsize("4i")
+            oldncpu = ncpu
+            (next, ncpu, slen, freq) = struct.unpack("4i", shm[idx:idx+len])
+            idx += len
+
+            # xenbaked tells us how many cpu's it's got, so re-do
+            # the mmap if necessary to get multiple cpu data
+            if oldncpu != ncpu:
+                shm = mmap.mmap(shmf.fileno(), ncpu*slen)
+
+            # if we've just calculated data for the cpu of interest, then
+            # stop examining mmap data and start displaying stuff
+            if cpuidx == cpu:
+                break
+
+        # calculate starting and ending datapoints; never look at "next" since
+        # it represents live data that may be in transition. 
+        startat = next - 1
+        if next + 10 < NSAMPLES:
+            endat = next + 10
+        else:
+            endat = 10
+
+        # get summary over desired interval
+        [h1, l1, f1] = summarize(startat, endat, 10**9, samples)
+        [h2, l2, f2] = summarize(startat, endat, 10 * 10**9, samples)
+
+        # the actual display code
+        row = 0
+        display(stdscr, row, 1, "CPU = %d" % cpu, _c.A_STANDOUT)
+
+        display(stdscr, row, 10, "%sLast 10 seconds%sLast 1 second" % (6*' ', 
30*' '), _c.A_BOLD)
+        row +=1
+        display(stdscr, row, 1, "%s" % ((maxx-2)*'='))
+
+        total_h1_cpu = 0
+        total_h2_cpu = 0
+
+        for dom in range(0, NDOMAINS):
+            if h1[dom][0][1] > 0 or dom == NDOMAINS - 1:
+                # display gotten
+                row += 1 
+                col = 2
+                display(stdscr, row, col, "%d" % dom)
+                col += 4
+                display(stdscr, row, col, "%s" % time_scale(h2[dom][0][0]))
+                col += 12
+                display(stdscr, row, col, "%3.2f%%" % h2[dom][0][1])
+                col += 12
+                display(stdscr, row, col, "%s/ex" % time_scale(h2[dom][0][2]))
+                col += 18
+                display(stdscr, row, col, "%s" % time_scale(h1[dom][0][0]))
+                col += 12
+                display(stdscr, row, col, "%3.2f%%" % h1[dom][0][1])
+                col += 12
+                display(stdscr, row, col, "%s/ex" % time_scale(h1[dom][0][2]))
+                col += 18
+                display(stdscr, row, col, "Gotten")
+    
+                # display allocated
+                row += 1
+                col = 2
+                display(stdscr, row, col, "%d" % dom)
+                col += 28
+                display(stdscr, row, col, "%s/ex" % time_scale(h2[dom][1]))
+                col += 42
+                display(stdscr, row, col, "%s/ex" % time_scale(h1[dom][1]))
+                col += 18
+                display(stdscr, row, col, "Allocated")
+
+                # display blocked
+                row += 1
+                col = 2
+                display(stdscr, row, col, "%d" % dom)
+                col += 4
+                display(stdscr, row, col, "%s" % time_scale(h2[dom][2][0]))
+                col += 12
+                display(stdscr, row, col, "%3.2f%%" % h2[dom][2][1])
+                col += 12
+                display(stdscr, row, col, "%s/io" % time_scale(h2[dom][2][2]))
+                col += 18
+                display(stdscr, row, col, "%s" % time_scale(h1[dom][2][0]))
+                col += 12
+                display(stdscr, row, col, "%3.2f%%" % h1[dom][2][1])
+                col += 12
+                display(stdscr, row, col, "%s/io" % time_scale(h1[dom][2][2]))
+                col += 18
+                display(stdscr, row, col, "Blocked")
+
+                # display waited
+                row += 1
+                col = 2
+                display(stdscr, row, col, "%d" % dom)
+                col += 4
+                display(stdscr, row, col, "%s" % time_scale(h2[dom][3][0]))
+                col += 12
+                display(stdscr, row, col, "%3.2f%%" % h2[dom][3][1])
+                col += 12
+                display(stdscr, row, col, "%s/ex" % time_scale(h2[dom][3][2]))
+                col += 18
+                display(stdscr, row, col, "%s" % time_scale(h1[dom][3][0]))
+                col += 12
+                display(stdscr, row, col, "%3.2f%%" % h1[dom][3][1])
+                col += 12
+                display(stdscr, row, col, "%s/ex" % time_scale(h1[dom][3][2]))
+                col += 18
+                display(stdscr, row, col, "Waited")
+
+                # display ex count
+                row += 1
+                col = 2
+                display(stdscr, row, col, "%d" % dom)
+
+                col += 28
+                display(stdscr, row, col, "%d/s" % h2[dom][4])
+                col += 42
+                display(stdscr, row, col, "%d" % h1[dom][4])
+                col += 18
+                display(stdscr, row, col, "Execution count")
+
+                # display io count
+                row += 1
+                col = 2
+                display(stdscr, row, col, "%d" % dom)
+                col += 4
+                display(stdscr, row, col, "%d/s" % h2[dom][5][0])
+                col += 24
+                display(stdscr, row, col, "%d/ex" % h2[dom][5][1])
+                col += 18
+                display(stdscr, row, col, "%d" % h1[dom][5][0])
+                col += 24
+                display(stdscr, row, col, "%3.2f/ex" % h1[dom][5][1])
+                col += 18
+                display(stdscr, row, col, "I/O Count")
+
+            #row += 1
+            #stdscr.hline(row, 1, '-', maxx - 2)
+            total_h1_cpu += h1[dom][0][1]
+            total_h2_cpu += h2[dom][0][1]
+
+
+        row += 1
+        display(stdscr, row, 2, TOTALS % (total_h2_cpu, total_h1_cpu))
+        row += 1
+#        display(stdscr, row, 2, 
+#                "\tFFP: %d (Min: %d, Max: %d)\t\t\tFFP: %d (Min: %d, Max %d)" 
% 
+#                (math.ceil(f2[1]), f2[0], f2[2], math.ceil(f1[1]), f1[0], 
f1[2]), _c.A_BOLD)
+
+        if l1[1] > 1 :
+            row += 1
+            display(stdscr, row, 2, 
+                    "\tRecords lost: %d (Min: %d, Max: %d)\t\t\tRecords lost: 
%d (Min: %d, Max %d)" % 
+                    (math.ceil(l2[1]), l2[0], l2[2], math.ceil(l1[1]), l1[0], 
l1[2]), _c.A_BOLD)
+
+        # grab a char from tty input; exit if interrupt hit
+        try:
+            c = stdscr.getch()
+        except:
+            break
+        
+        # q = quit
+        if c == ord('q'):
+            break
+    
+        # c = cycle to a new cpu of interest
+        if c == ord('c'):
+            cpu = (cpu + 1) % ncpu
+
+        stdscr.erase()
+
+    _c.nocbreak()
+    stdscr.keypad(0)
+    _c.echo()
+    _c.endwin()
+    shm.close()
+    shmf.close()
+
+
+# simple functions to allow initialization of log files without actually
+# physically creating files that are never used; only on the first real
+# write does the file get created
+class Delayed(file):
+    def __init__(self, filename, mode):
+       self.filename = filename
+       self.saved_mode = mode
+       self.delay_data = ""
+       self.opened = 0
+
+    def delayed_write(self, str):
+       self.delay_data = str
+
+    def write(self, str):
+       if not self.opened:
+           self.file = open(self.filename, self.saved_mode)
+           self.opened = 1
+            self.file.write(self.delay_data)
+       self.file.write(str)
+
+    def flush(self):
+        if  self.opened:
+            self.file.flush()
+
+    def close(self):
+        if  self.opened:
+            self.file.close()
+            
+
+def writelog():
+    global options
+
+    ncpu = 1        # number of cpu's
+    slen = 0        # size of shared structure inc. padding
+
+    shmf = open(SHM_FILE, "r+")
+    shm = mmap.mmap(shmf.fileno(), QOS_DATA_SIZE)
+
+    interval = 0
+    outfiles = {}
+    for dom in range(0, NDOMAINS):
+        outfiles[dom] = Delayed("%s-dom%d.log" % (options.prefix, dom), 'w')
+        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")
+
+    while options.duration == 0 or interval < (options.duration * 1000):
+        for cpuidx in range(0, ncpu):
+            idx = cpuidx * slen      # offset needed in mmap file
+
+
+            samples = []
+            doms = []
+
+            for i in range(0, NSAMPLES):
+                len = struct.calcsize(ST_QDATA)
+                sample = struct.unpack(ST_QDATA, shm[idx:idx+len])
+                samples.append(sample)
+                idx += len
+
+            for i in range(0, NDOMAINS):
+                len = struct.calcsize(ST_DOM_INFO)
+                dom = struct.unpack(ST_DOM_INFO, shm[idx:idx+len])
+                doms.append(dom)
+                idx += len
+
+            len = struct.calcsize("4i")
+            oldncpu = ncpu
+            (next, ncpu, slen, freq) = struct.unpack("4i", shm[idx:idx+len])
+            idx += len
+
+            if oldncpu != ncpu:
+                shm = mmap.mmap(shmf.fileno(), ncpu*slen)
+
+            startat = next - 1
+            if next + 10 < NSAMPLES:
+                endat = next + 10
+            else:
+                endat = 10
+
+            [h1,l1, f1] = summarize(startat, endat, options.interval * 10**6, 
samples)
+            for dom in range(0, NDOMAINS):
+                if h1[dom][0][1] > 0 or dom == NDOMAINS - 1:
+                    outfiles[dom].write("%.3f %d %d %.3f %.3f %.3f %.3f %.3f 
%.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f\n" %
+                                     (interval, cpuidx, dom,
+                                     h1[dom][0][0], h1[dom][0][1], 
h1[dom][0][2],
+                                     h1[dom][1],
+                                     h1[dom][2][0], h1[dom][2][1], 
h1[dom][2][2],
+                                     h1[dom][3][0], h1[dom][3][1], 
h1[dom][3][2],
+                                     h1[dom][4], 
+                                     h1[dom][5][0], h1[dom][5][1]))
+                    outfiles[dom].flush()
+
+        interval += options.interval
+        time.sleep(1)
+
+    for dom in range(0, NDOMAINS):
+        outfiles[dom].close()
+
+# start xenbaked
+def start_xenbaked():
+    global options
+    global args
+    
+    os.system("killall -9 xenbaked")
+    # assumes that xenbaked is in your path
+    os.system("xenbaked --ms_per_sample=%d &" %
+              options.mspersample)
+    time.sleep(1)
+
+# stop xenbaked
+def stop_xenbaked():
+    os.system("killall -s INT xenbaked")
+
+def main():
+    global options
+    global args
+    global domains
+
+    parser = setup_cmdline_parser()
+    (options, args) = parser.parse_args()
+    
+    start_xenbaked()
+    if options.live:
+        show_livestats()
+    else:
+        try:
+            writelog()
+        except:
+            print 'Quitting.'
+    stop_xenbaked()
+
+if __name__ == "__main__":
+    main()

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.