ia64/xen-unstable

changeset 7819:394390f6ff85

The new userland monitoring tool, XenMon.
Signed-off-by: Rob Gardner <rob.gardner@hp.com>
author kaf24@firebug.cl.cam.ac.uk
date Tue Nov 15 15:09:58 2005 +0100 (2005-11-15)
parents e580f8051888
children e60d8a3ad96e
files tools/Makefile tools/xenmon/COPYING tools/xenmon/Makefile tools/xenmon/README tools/xenmon/setmask.c tools/xenmon/xenbaked.c tools/xenmon/xenbaked.h tools/xenmon/xenmon.py tools/xentrace/setsize.c
line diff
     1.1 --- a/tools/Makefile	Tue Nov 15 14:59:59 2005 +0100
     1.2 +++ b/tools/Makefile	Tue Nov 15 15:09:58 2005 +0100
     1.3 @@ -11,6 +11,7 @@ SUBDIRS += xcutils
     1.4  SUBDIRS += firmware
     1.5  SUBDIRS += security
     1.6  SUBDIRS += console
     1.7 +SUBDIRS += xenmon
     1.8  ifeq ($(VTPM_TOOLS),y)
     1.9  SUBDIRS += vtpm_manager
    1.10  SUBDIRS += vtpm
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/tools/xenmon/COPYING	Tue Nov 15 15:09:58 2005 +0100
     2.3 @@ -0,0 +1,340 @@
     2.4 +		    GNU GENERAL PUBLIC LICENSE
     2.5 +		       Version 2, June 1991
     2.6 +
     2.7 + Copyright (C) 1989, 1991 Free Software Foundation, Inc.
     2.8 +                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
     2.9 + Everyone is permitted to copy and distribute verbatim copies
    2.10 + of this license document, but changing it is not allowed.
    2.11 +
    2.12 +			    Preamble
    2.13 +
    2.14 +  The licenses for most software are designed to take away your
    2.15 +freedom to share and change it.  By contrast, the GNU General Public
    2.16 +License is intended to guarantee your freedom to share and change free
    2.17 +software--to make sure the software is free for all its users.  This
    2.18 +General Public License applies to most of the Free Software
    2.19 +Foundation's software and to any other program whose authors commit to
    2.20 +using it.  (Some other Free Software Foundation software is covered by
    2.21 +the GNU Library General Public License instead.)  You can apply it to
    2.22 +your programs, too.
    2.23 +
    2.24 +  When we speak of free software, we are referring to freedom, not
    2.25 +price.  Our General Public Licenses are designed to make sure that you
    2.26 +have the freedom to distribute copies of free software (and charge for
    2.27 +this service if you wish), that you receive source code or can get it
    2.28 +if you want it, that you can change the software or use pieces of it
    2.29 +in new free programs; and that you know you can do these things.
    2.30 +
    2.31 +  To protect your rights, we need to make restrictions that forbid
    2.32 +anyone to deny you these rights or to ask you to surrender the rights.
    2.33 +These restrictions translate to certain responsibilities for you if you
    2.34 +distribute copies of the software, or if you modify it.
    2.35 +
    2.36 +  For example, if you distribute copies of such a program, whether
    2.37 +gratis or for a fee, you must give the recipients all the rights that
    2.38 +you have.  You must make sure that they, too, receive or can get the
    2.39 +source code.  And you must show them these terms so they know their
    2.40 +rights.
    2.41 +
    2.42 +  We protect your rights with two steps: (1) copyright the software, and
    2.43 +(2) offer you this license which gives you legal permission to copy,
    2.44 +distribute and/or modify the software.
    2.45 +
    2.46 +  Also, for each author's protection and ours, we want to make certain
    2.47 +that everyone understands that there is no warranty for this free
    2.48 +software.  If the software is modified by someone else and passed on, we
    2.49 +want its recipients to know that what they have is not the original, so
    2.50 +that any problems introduced by others will not reflect on the original
    2.51 +authors' reputations.
    2.52 +
    2.53 +  Finally, any free program is threatened constantly by software
    2.54 +patents.  We wish to avoid the danger that redistributors of a free
    2.55 +program will individually obtain patent licenses, in effect making the
    2.56 +program proprietary.  To prevent this, we have made it clear that any
    2.57 +patent must be licensed for everyone's free use or not licensed at all.
    2.58 +
    2.59 +  The precise terms and conditions for copying, distribution and
    2.60 +modification follow.
    2.61 +
    2.62 +		    GNU GENERAL PUBLIC LICENSE
    2.63 +   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
    2.64 +
    2.65 +  0. This License applies to any program or other work which contains
    2.66 +a notice placed by the copyright holder saying it may be distributed
    2.67 +under the terms of this General Public License.  The "Program", below,
    2.68 +refers to any such program or work, and a "work based on the Program"
    2.69 +means either the Program or any derivative work under copyright law:
    2.70 +that is to say, a work containing the Program or a portion of it,
    2.71 +either verbatim or with modifications and/or translated into another
    2.72 +language.  (Hereinafter, translation is included without limitation in
    2.73 +the term "modification".)  Each licensee is addressed as "you".
    2.74 +
    2.75 +Activities other than copying, distribution and modification are not
    2.76 +covered by this License; they are outside its scope.  The act of
    2.77 +running the Program is not restricted, and the output from the Program
    2.78 +is covered only if its contents constitute a work based on the
    2.79 +Program (independent of having been made by running the Program).
    2.80 +Whether that is true depends on what the Program does.
    2.81 +
    2.82 +  1. You may copy and distribute verbatim copies of the Program's
    2.83 +source code as you receive it, in any medium, provided that you
    2.84 +conspicuously and appropriately publish on each copy an appropriate
    2.85 +copyright notice and disclaimer of warranty; keep intact all the
    2.86 +notices that refer to this License and to the absence of any warranty;
    2.87 +and give any other recipients of the Program a copy of this License
    2.88 +along with the Program.
    2.89 +
    2.90 +You may charge a fee for the physical act of transferring a copy, and
    2.91 +you may at your option offer warranty protection in exchange for a fee.
    2.92 +
    2.93 +  2. You may modify your copy or copies of the Program or any portion
    2.94 +of it, thus forming a work based on the Program, and copy and
    2.95 +distribute such modifications or work under the terms of Section 1
    2.96 +above, provided that you also meet all of these conditions:
    2.97 +
    2.98 +    a) You must cause the modified files to carry prominent notices
    2.99 +    stating that you changed the files and the date of any change.
   2.100 +
   2.101 +    b) You must cause any work that you distribute or publish, that in
   2.102 +    whole or in part contains or is derived from the Program or any
   2.103 +    part thereof, to be licensed as a whole at no charge to all third
   2.104 +    parties under the terms of this License.
   2.105 +
   2.106 +    c) If the modified program normally reads commands interactively
   2.107 +    when run, you must cause it, when started running for such
   2.108 +    interactive use in the most ordinary way, to print or display an
   2.109 +    announcement including an appropriate copyright notice and a
   2.110 +    notice that there is no warranty (or else, saying that you provide
   2.111 +    a warranty) and that users may redistribute the program under
   2.112 +    these conditions, and telling the user how to view a copy of this
   2.113 +    License.  (Exception: if the Program itself is interactive but
   2.114 +    does not normally print such an announcement, your work based on
   2.115 +    the Program is not required to print an announcement.)
   2.116 +
   2.117 +These requirements apply to the modified work as a whole.  If
   2.118 +identifiable sections of that work are not derived from the Program,
   2.119 +and can be reasonably considered independent and separate works in
   2.120 +themselves, then this License, and its terms, do not apply to those
   2.121 +sections when you distribute them as separate works.  But when you
   2.122 +distribute the same sections as part of a whole which is a work based
   2.123 +on the Program, the distribution of the whole must be on the terms of
   2.124 +this License, whose permissions for other licensees extend to the
   2.125 +entire whole, and thus to each and every part regardless of who wrote it.
   2.126 +
   2.127 +Thus, it is not the intent of this section to claim rights or contest
   2.128 +your rights to work written entirely by you; rather, the intent is to
   2.129 +exercise the right to control the distribution of derivative or
   2.130 +collective works based on the Program.
   2.131 +
   2.132 +In addition, mere aggregation of another work not based on the Program
   2.133 +with the Program (or with a work based on the Program) on a volume of
   2.134 +a storage or distribution medium does not bring the other work under
   2.135 +the scope of this License.
   2.136 +
   2.137 +  3. You may copy and distribute the Program (or a work based on it,
   2.138 +under Section 2) in object code or executable form under the terms of
   2.139 +Sections 1 and 2 above provided that you also do one of the following:
   2.140 +
   2.141 +    a) Accompany it with the complete corresponding machine-readable
   2.142 +    source code, which must be distributed under the terms of Sections
   2.143 +    1 and 2 above on a medium customarily used for software interchange; or,
   2.144 +
   2.145 +    b) Accompany it with a written offer, valid for at least three
   2.146 +    years, to give any third party, for a charge no more than your
   2.147 +    cost of physically performing source distribution, a complete
   2.148 +    machine-readable copy of the corresponding source code, to be
   2.149 +    distributed under the terms of Sections 1 and 2 above on a medium
   2.150 +    customarily used for software interchange; or,
   2.151 +
   2.152 +    c) Accompany it with the information you received as to the offer
   2.153 +    to distribute corresponding source code.  (This alternative is
   2.154 +    allowed only for noncommercial distribution and only if you
   2.155 +    received the program in object code or executable form with such
   2.156 +    an offer, in accord with Subsection b above.)
   2.157 +
   2.158 +The source code for a work means the preferred form of the work for
   2.159 +making modifications to it.  For an executable work, complete source
   2.160 +code means all the source code for all modules it contains, plus any
   2.161 +associated interface definition files, plus the scripts used to
   2.162 +control compilation and installation of the executable.  However, as a
   2.163 +special exception, the source code distributed need not include
   2.164 +anything that is normally distributed (in either source or binary
   2.165 +form) with the major components (compiler, kernel, and so on) of the
   2.166 +operating system on which the executable runs, unless that component
   2.167 +itself accompanies the executable.
   2.168 +
   2.169 +If distribution of executable or object code is made by offering
   2.170 +access to copy from a designated place, then offering equivalent
   2.171 +access to copy the source code from the same place counts as
   2.172 +distribution of the source code, even though third parties are not
   2.173 +compelled to copy the source along with the object code.
   2.174 +
   2.175 +  4. You may not copy, modify, sublicense, or distribute the Program
   2.176 +except as expressly provided under this License.  Any attempt
   2.177 +otherwise to copy, modify, sublicense or distribute the Program is
   2.178 +void, and will automatically terminate your rights under this License.
   2.179 +However, parties who have received copies, or rights, from you under
   2.180 +this License will not have their licenses terminated so long as such
   2.181 +parties remain in full compliance.
   2.182 +
   2.183 +  5. You are not required to accept this License, since you have not
   2.184 +signed it.  However, nothing else grants you permission to modify or
   2.185 +distribute the Program or its derivative works.  These actions are
   2.186 +prohibited by law if you do not accept this License.  Therefore, by
   2.187 +modifying or distributing the Program (or any work based on the
   2.188 +Program), you indicate your acceptance of this License to do so, and
   2.189 +all its terms and conditions for copying, distributing or modifying
   2.190 +the Program or works based on it.
   2.191 +
   2.192 +  6. Each time you redistribute the Program (or any work based on the
   2.193 +Program), the recipient automatically receives a license from the
   2.194 +original licensor to copy, distribute or modify the Program subject to
   2.195 +these terms and conditions.  You may not impose any further
   2.196 +restrictions on the recipients' exercise of the rights granted herein.
   2.197 +You are not responsible for enforcing compliance by third parties to
   2.198 +this License.
   2.199 +
   2.200 +  7. If, as a consequence of a court judgment or allegation of patent
   2.201 +infringement or for any other reason (not limited to patent issues),
   2.202 +conditions are imposed on you (whether by court order, agreement or
   2.203 +otherwise) that contradict the conditions of this License, they do not
   2.204 +excuse you from the conditions of this License.  If you cannot
   2.205 +distribute so as to satisfy simultaneously your obligations under this
   2.206 +License and any other pertinent obligations, then as a consequence you
   2.207 +may not distribute the Program at all.  For example, if a patent
   2.208 +license would not permit royalty-free redistribution of the Program by
   2.209 +all those who receive copies directly or indirectly through you, then
   2.210 +the only way you could satisfy both it and this License would be to
   2.211 +refrain entirely from distribution of the Program.
   2.212 +
   2.213 +If any portion of this section is held invalid or unenforceable under
   2.214 +any particular circumstance, the balance of the section is intended to
   2.215 +apply and the section as a whole is intended to apply in other
   2.216 +circumstances.
   2.217 +
   2.218 +It is not the purpose of this section to induce you to infringe any
   2.219 +patents or other property right claims or to contest validity of any
   2.220 +such claims; this section has the sole purpose of protecting the
   2.221 +integrity of the free software distribution system, which is
   2.222 +implemented by public license practices.  Many people have made
   2.223 +generous contributions to the wide range of software distributed
   2.224 +through that system in reliance on consistent application of that
   2.225 +system; it is up to the author/donor to decide if he or she is willing
   2.226 +to distribute software through any other system and a licensee cannot
   2.227 +impose that choice.
   2.228 +
   2.229 +This section is intended to make thoroughly clear what is believed to
   2.230 +be a consequence of the rest of this License.
   2.231 +
   2.232 +  8. If the distribution and/or use of the Program is restricted in
   2.233 +certain countries either by patents or by copyrighted interfaces, the
   2.234 +original copyright holder who places the Program under this License
   2.235 +may add an explicit geographical distribution limitation excluding
   2.236 +those countries, so that distribution is permitted only in or among
   2.237 +countries not thus excluded.  In such case, this License incorporates
   2.238 +the limitation as if written in the body of this License.
   2.239 +
   2.240 +  9. The Free Software Foundation may publish revised and/or new versions
   2.241 +of the General Public License from time to time.  Such new versions will
   2.242 +be similar in spirit to the present version, but may differ in detail to
   2.243 +address new problems or concerns.
   2.244 +
   2.245 +Each version is given a distinguishing version number.  If the Program
   2.246 +specifies a version number of this License which applies to it and "any
   2.247 +later version", you have the option of following the terms and conditions
   2.248 +either of that version or of any later version published by the Free
   2.249 +Software Foundation.  If the Program does not specify a version number of
   2.250 +this License, you may choose any version ever published by the Free Software
   2.251 +Foundation.
   2.252 +
   2.253 +  10. If you wish to incorporate parts of the Program into other free
   2.254 +programs whose distribution conditions are different, write to the author
   2.255 +to ask for permission.  For software which is copyrighted by the Free
   2.256 +Software Foundation, write to the Free Software Foundation; we sometimes
   2.257 +make exceptions for this.  Our decision will be guided by the two goals
   2.258 +of preserving the free status of all derivatives of our free software and
   2.259 +of promoting the sharing and reuse of software generally.
   2.260 +
   2.261 +			    NO WARRANTY
   2.262 +
   2.263 +  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
   2.264 +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
   2.265 +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
   2.266 +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
   2.267 +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
   2.268 +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
   2.269 +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
   2.270 +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
   2.271 +REPAIR OR CORRECTION.
   2.272 +
   2.273 +  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
   2.274 +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
   2.275 +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
   2.276 +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
   2.277 +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
   2.278 +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
   2.279 +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
   2.280 +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
   2.281 +POSSIBILITY OF SUCH DAMAGES.
   2.282 +
   2.283 +		     END OF TERMS AND CONDITIONS
   2.284 +
   2.285 +	    How to Apply These Terms to Your New Programs
   2.286 +
   2.287 +  If you develop a new program, and you want it to be of the greatest
   2.288 +possible use to the public, the best way to achieve this is to make it
   2.289 +free software which everyone can redistribute and change under these terms.
   2.290 +
   2.291 +  To do so, attach the following notices to the program.  It is safest
   2.292 +to attach them to the start of each source file to most effectively
   2.293 +convey the exclusion of warranty; and each file should have at least
   2.294 +the "copyright" line and a pointer to where the full notice is found.
   2.295 +
   2.296 +    <one line to give the program's name and a brief idea of what it does.>
   2.297 +    Copyright (C) <year>  <name of author>
   2.298 +
   2.299 +    This program is free software; you can redistribute it and/or modify
   2.300 +    it under the terms of the GNU General Public License as published by
   2.301 +    the Free Software Foundation; either version 2 of the License, or
   2.302 +    (at your option) any later version.
   2.303 +
   2.304 +    This program is distributed in the hope that it will be useful,
   2.305 +    but WITHOUT ANY WARRANTY; without even the implied warranty of
   2.306 +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   2.307 +    GNU General Public License for more details.
   2.308 +
   2.309 +    You should have received a copy of the GNU General Public License
   2.310 +    along with this program; if not, write to the Free Software
   2.311 +    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   2.312 +
   2.313 +
   2.314 +Also add information on how to contact you by electronic and paper mail.
   2.315 +
   2.316 +If the program is interactive, make it output a short notice like this
   2.317 +when it starts in an interactive mode:
   2.318 +
   2.319 +    Gnomovision version 69, Copyright (C) year name of author
   2.320 +    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
   2.321 +    This is free software, and you are welcome to redistribute it
   2.322 +    under certain conditions; type `show c' for details.
   2.323 +
   2.324 +The hypothetical commands `show w' and `show c' should show the appropriate
   2.325 +parts of the General Public License.  Of course, the commands you use may
   2.326 +be called something other than `show w' and `show c'; they could even be
   2.327 +mouse-clicks or menu items--whatever suits your program.
   2.328 +
   2.329 +You should also get your employer (if you work as a programmer) or your
   2.330 +school, if any, to sign a "copyright disclaimer" for the program, if
   2.331 +necessary.  Here is a sample; alter the names:
   2.332 +
   2.333 +  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
   2.334 +  `Gnomovision' (which makes passes at compilers) written by James Hacker.
   2.335 +
   2.336 +  <signature of Ty Coon>, 1 April 1989
   2.337 +  Ty Coon, President of Vice
   2.338 +
   2.339 +This General Public License does not permit incorporating your program into
   2.340 +proprietary programs.  If your program is a subroutine library, you may
   2.341 +consider it more useful to permit linking proprietary applications with the
   2.342 +library.  If this is what you want to do, use the GNU Library General
   2.343 +Public License instead of this License.
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/tools/xenmon/Makefile	Tue Nov 15 15:09:58 2005 +0100
     3.3 @@ -0,0 +1,51 @@
     3.4 +# Copyright (C) HP Labs, Palo Alto and Fort Collins, 2005
     3.5 +# Author: Diwaker Gupta <diwaker.gupta@hp.com>
     3.6 +#
     3.7 +# This program is free software; you can redistribute it and/or modify
     3.8 +# it under the terms of the GNU General Public License as published by
     3.9 +# the Free Software Foundation; under version 2 of the License.
    3.10 +#
    3.11 +# This program is distributed in the hope that it will be useful,
    3.12 +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    3.13 +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    3.14 +# GNU General Public License for more details.
    3.15 +
    3.16 +INSTALL         = install
    3.17 +INSTALL_PROG    = $(INSTALL) -m0755
    3.18 +INSTALL_DIR     = $(INSTALL) -d -m0755
    3.19 +INSTALL_DATA    = $(INSTALL) -m064
    3.20 +
    3.21 +prefix=/usr/local
    3.22 +mandir=$(prefix)/share/man
    3.23 +man1dir=$(mandir)/man1
    3.24 +sbindir=$(prefix)/sbin
    3.25 +
    3.26 +XEN_ROOT=../..
    3.27 +include $(XEN_ROOT)/tools/Rules.mk
    3.28 +
    3.29 +CFLAGS += -Wall -Werror -g
    3.30 +CFLAGS  += -I $(XEN_XC)
    3.31 +CFLAGS  += -I $(XEN_LIBXC)
    3.32 +LDFLAGS += -L $(XEN_LIBXC)
    3.33 +
    3.34 +BIN = setmask xenbaked
    3.35 +SCRIPTS = xenmon.py
    3.36 +
    3.37 +all: build
    3.38 +
    3.39 +build: $(BIN)
    3.40 +
    3.41 +install: xenbaked setmask
    3.42 +	[ -d $(DESTDIR)$(sbindir) ] || $(INSTALL_DIR) $(DESTDIR)$(sbindir)
    3.43 +	$(INSTALL_PROG) xenbaked $(DESTDIR)$(sbindir)/xenbaked
    3.44 +	$(INSTALL_PROG) setmask  $(DESTDIR)$(sbindir)/setmask
    3.45 +	$(INSTALL_PROG) xenmon.py  $(DESTDIR)$(sbindir)/xenmon.py
    3.46 +
    3.47 +clean:
    3.48 +	rm -f $(BIN)
    3.49 +
    3.50 +
    3.51 +%: %.c Makefile
    3.52 +	$(CC) $(CFLAGS) $(LDFLAGS) -lxenctrl -o $@ $<
    3.53 +
    3.54 +
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/tools/xenmon/README	Tue Nov 15 15:09:58 2005 +0100
     4.3 @@ -0,0 +1,104 @@
     4.4 +Xen Performance Monitor
     4.5 +-----------------------
     4.6 +
     4.7 +The xenmon tools make use of the existing xen tracing feature to provide fine
     4.8 +grained reporting of various domain related metrics. It should be stressed that
     4.9 +the xenmon.py script included here is just an example of the data that may be
    4.10 +displayed. The xenbake demon keeps a large amount of history in a shared memory
    4.11 +area that may be accessed by tools such as xenmon.
    4.12 +
    4.13 +For each domain, xenmon reports various metrics. One part of the display is a
    4.14 +group of metrics that have been accumulated over the last second, while another
    4.15 +part of the display shows data measured over 10 seconds. Other measurement
    4.16 +intervals are possible, but we have just chosen 1s and 10s as an example.
    4.17 +
    4.18 +
    4.19 +Execution Count
    4.20 +---------------
    4.21 + o The number of times that a domain was scheduled to run (ie, dispatched) over
    4.22 + the measurement interval
    4.23 +
    4.24 +
    4.25 +CPU usage
    4.26 +---------
    4.27 + o Total time used over the measurement interval
    4.28 + o Usage expressed as a percentage of the measurement interval
    4.29 + o Average cpu time used during each execution of the domain
    4.30 +
    4.31 +
    4.32 +Waiting time
    4.33 +------------
    4.34 +This is how much time the domain spent waiting to run, or put another way, the
    4.35 +amount of time the domain spent in the "runnable" state (or on the run queue)
    4.36 +but not actually running. Xenmon displays:
    4.37 +
    4.38 + o Total time waiting over the measurement interval
    4.39 + o Wait time expressed as a percentage of the measurement interval
    4.40 + o Average waiting time for each execution of the domain
    4.41 +
    4.42 +Blocked time
    4.43 +------------
    4.44 +This is how much time the domain spent blocked (or sleeping); Put another way,
    4.45 +the amount of time the domain spent not needing/wanting the cpu because it was
    4.46 +waiting for some event (ie, I/O). Xenmon reports:
    4.47 +
    4.48 + o Total time blocked over the measurement interval
    4.49 + o Blocked time expressed as a percentage of the measurement interval
    4.50 + o Blocked time per I/O (see I/O count below)
    4.51 +
    4.52 +Allocation time
    4.53 +---------------
    4.54 +This is how much cpu time was allocated to the domain by the scheduler; This is
    4.55 +distinct from cpu usage since the "time slice" given to a domain is frequently
    4.56 +cut short for one reason or another, ie, the domain requests I/O and blocks.
    4.57 +Xenmon reports:
    4.58 +
    4.59 + o Average allocation time per execution (ie, time slice)
    4.60 + o Min and Max allocation times
    4.61 +
    4.62 +I/O Count
    4.63 +---------
    4.64 +This is a rough measure of I/O requested by the domain. The number of page
    4.65 +exchanges (or page "flips") between the domain and dom0 are counted. The
    4.66 +number of pages exchanged may not accurately reflect the number of bytes
    4.67 +transferred to/from a domain due to partial pages being used by the network
    4.68 +protocols, etc. But it does give a good sense of the magnitude of I/O being
    4.69 +requested by a domain. Xenmon reports:
    4.70 +
    4.71 + o Total number of page exchanges during the measurement interval
    4.72 + o Average number of page exchanges per execution of the domain
    4.73 +
    4.74 +
    4.75 +Usage Notes and issues
    4.76 +----------------------
    4.77 + - Start xenmon by simply running xenmon.py; The xenbake demon is started and
    4.78 +   stopped automatically by xenmon.
    4.79 + - To see the various options for xenmon, run xenmon -h. Ditto for xenbaked.
    4.80 + - xenmon also has an option (-n) to output log data to a file instead of the
    4.81 +   curses interface.
    4.82 + - NDOMAINS is defined to be 32, but can be changed by recompiling xenbaked
    4.83 + - Xenmon.py appears to create 1-2% cpu overhead; Part of this is just the
    4.84 +   overhead of the python interpreter. Part of it may be the number of trace
    4.85 +   records being generated. The number of trace records generated can be
    4.86 +   limited by setting the trace mask (with a dom0 Op), which controls which
    4.87 +   events cause a trace record to be emitted.
    4.88 + - To exit xenmon, type 'q'
    4.89 + - To cycle the display to other physical cpu's, type 'c'
    4.90 +
    4.91 +Future Work
    4.92 +-----------
    4.93 +o RPC interface to allow external entities to programmatically access processed data
    4.94 +o I/O Count batching to reduce number of trace records generated
    4.95 +
    4.96 +Case Study
    4.97 +----------
    4.98 +We have written a case study which demonstrates some of the usefulness of
    4.99 +this tool and the metrics reported. It is available at:
   4.100 +http://www.hpl.hp.com/techreports/2005/HPL-2005-187.html
   4.101 +
   4.102 +Authors
   4.103 +-------
   4.104 +Diwaker Gupta   <diwaker.gupta@hp.com>
   4.105 +Rob Gardner     <rob.gardner@hp.com>
   4.106 +Lucy Cherkasova <lucy.cherkasova.hp.com>
   4.107 +
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/tools/xenmon/setmask.c	Tue Nov 15 15:09:58 2005 +0100
     5.3 @@ -0,0 +1,90 @@
     5.4 +/******************************************************************************
     5.5 + * tools/xenmon/setmask.c
     5.6 + * 
     5.7 + * Simple utility for getting/setting the event mask
     5.8 + *
     5.9 + * Copyright (C) 2005 by Hewlett-Packard, Palo Alto and Fort Collins
    5.10 + *
    5.11 + * Authors: Lucy Cherkasova, lucy.cherkasova.hp.com
    5.12 + *          Rob Gardner, rob.gardner@hp.com
    5.13 + *          Diwaker Gupta, diwaker.gupta@hp.com
    5.14 + * Date:   August, 2005
    5.15 + * 
    5.16 + *  This program is free software; you can redistribute it and/or modify
    5.17 + *  it under the terms of the GNU General Public License as published by
    5.18 + *  the Free Software Foundation; under version 2 of the License.
    5.19 + *
    5.20 + *  This program is distributed in the hope that it will be useful,
    5.21 + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
    5.22 + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    5.23 + *  GNU General Public License for more details.
    5.24 + *
    5.25 + *  You should have received a copy of the GNU General Public License
    5.26 + *  along with this program; if not, write to the Free Software
    5.27 + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    5.28 + */
    5.29 +
    5.30 +#include <stdlib.h>
    5.31 +#include <stdio.h>
    5.32 +#include <sys/types.h>
    5.33 +#include <fcntl.h>
    5.34 +#include <unistd.h>
    5.35 +#include <errno.h>
    5.36 +#include <getopt.h>
    5.37 +#include <xenctrl.h>
    5.38 +#include <xen/xen.h>
    5.39 +typedef struct { int counter; } atomic_t;
    5.40 +#include <xen/trace.h>
    5.41 +
    5.42 +#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)
    5.43 +
    5.44 +int main(int argc, char * argv[])
    5.45 +{
    5.46 +
    5.47 +    dom0_op_t op; 
    5.48 +    int ret;
    5.49 +
    5.50 +    int xc_handle = xc_interface_open();
    5.51 +    op.cmd = DOM0_TBUFCONTROL;
    5.52 +    op.interface_version = DOM0_INTERFACE_VERSION;
    5.53 +    op.u.tbufcontrol.op  = DOM0_TBUF_GET_INFO;
    5.54 +    ret = xc_dom0_op(xc_handle, &op);
    5.55 +    if ( ret != 0 )
    5.56 +    {
    5.57 +        perror("Failure to get event mask from Xen");
    5.58 +        exit(1);
    5.59 +    }
    5.60 +    else
    5.61 +    {
    5.62 +        printf("Current event mask: 0x%.8x\n", op.u.tbufcontrol.evt_mask);
    5.63 +    }
    5.64 +
    5.65 +    op.cmd = DOM0_TBUFCONTROL;
    5.66 +    op.interface_version = DOM0_INTERFACE_VERSION;
    5.67 +    op.u.tbufcontrol.op  = DOM0_TBUF_SET_EVT_MASK;
    5.68 +    op.u.tbufcontrol.evt_mask = XENMON;
    5.69 +
    5.70 +    ret = xc_dom0_op(xc_handle, &op);
    5.71 +    printf("Setting mask to 0x%.8x\n", op.u.tbufcontrol.evt_mask);
    5.72 +    if ( ret != 0 )
    5.73 +    {
    5.74 +        perror("Failure to get scheduler ID from Xen");
    5.75 +        exit(1);
    5.76 +    }
    5.77 +
    5.78 +    op.cmd = DOM0_TBUFCONTROL;
    5.79 +    op.interface_version = DOM0_INTERFACE_VERSION;
    5.80 +    op.u.tbufcontrol.op  = DOM0_TBUF_GET_INFO;
    5.81 +    ret = xc_dom0_op(xc_handle, &op);
    5.82 +    if ( ret != 0 )
    5.83 +    {
    5.84 +        perror("Failure to get event mask from Xen");
    5.85 +        exit(1);
    5.86 +    }
    5.87 +    else
    5.88 +    {
    5.89 +        printf("Current event mask: 0x%.8x\n", op.u.tbufcontrol.evt_mask);
    5.90 +    }
    5.91 +    xc_interface_close(xc_handle);
    5.92 +    return 0;
    5.93 +}
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/tools/xenmon/xenbaked.c	Tue Nov 15 15:09:58 2005 +0100
     6.3 @@ -0,0 +1,1029 @@
     6.4 +/******************************************************************************
     6.5 + * tools/xenbaked.c
     6.6 + *
     6.7 + * Tool for collecting raw trace buffer data from Xen and 
     6.8 + *  performing some accumulation operations and other processing
     6.9 + *  on it.
    6.10 + *
    6.11 + * Copyright (C) 2004 by Intel Research Cambridge
    6.12 + * Copyright (C) 2005 by Hewlett Packard, Palo Alto and Fort Collins
    6.13 + *
    6.14 + * Authors: Diwaker Gupta, diwaker.gupta@hp.com
    6.15 + *          Rob Gardner, rob.gardner@hp.com
    6.16 + *          Lucy Cherkasova, lucy.cherkasova.hp.com
    6.17 + * Much code based on xentrace, authored by Mark Williamson, mark.a.williamson@intel.com
    6.18 + * Date:   November, 2005
    6.19 + * 
    6.20 + *  This program is free software; you can redistribute it and/or modify
    6.21 + *  it under the terms of the GNU General Public License as published by
    6.22 + *  the Free Software Foundation; under version 2 of the License.
    6.23 + *
    6.24 + *  This program is distributed in the hope that it will be useful,
    6.25 + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
    6.26 + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    6.27 + *  GNU General Public License for more details.
    6.28 + *
    6.29 + *  You should have received a copy of the GNU General Public License
    6.30 + *  along with this program; if not, write to the Free Software
    6.31 + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    6.32 + */
    6.33 +
    6.34 +#include <time.h>
    6.35 +#include <stdlib.h>
    6.36 +#include <stdio.h>
    6.37 +#include <sys/mman.h>
    6.38 +#include <sys/stat.h>
    6.39 +#include <sys/types.h>
    6.40 +#include <fcntl.h>
    6.41 +#include <unistd.h>
    6.42 +#include <errno.h>
    6.43 +#include <argp.h>
    6.44 +#include <signal.h>
    6.45 +#include <xenctrl.h>
    6.46 +#include <xen/xen.h>
    6.47 +#include <string.h>
    6.48 +
    6.49 +#include "xc_private.h"
    6.50 +typedef struct { int counter; } atomic_t;
    6.51 +#define _atomic_read(v)		((v).counter)
    6.52 +
    6.53 +#include <xen/trace.h>
    6.54 +#include "xenbaked.h"
    6.55 +
    6.56 +extern FILE *stderr;
    6.57 +
    6.58 +/***** Compile time configuration of defaults ********************************/
    6.59 +
    6.60 +/* when we've got more records than this waiting, we log it to the output */
    6.61 +#define NEW_DATA_THRESH 1
    6.62 +
    6.63 +/* sleep for this long (milliseconds) between checking the trace buffers */
    6.64 +#define POLL_SLEEP_MILLIS 100
    6.65 +
    6.66 +/* Size of time period represented by each sample */
    6.67 +#define MS_PER_SAMPLE 100
    6.68 +
    6.69 +/* CPU Frequency */
    6.70 +#define MHZ
    6.71 +#define CPU_FREQ 2660 MHZ
    6.72 +
    6.73 +/***** The code **************************************************************/
    6.74 +
    6.75 +typedef struct settings_st {
    6.76 +    char *outfile;
    6.77 +    struct timespec poll_sleep;
    6.78 +    unsigned long new_data_thresh;
    6.79 +    unsigned long ms_per_sample;
    6.80 +    double cpu_freq;
    6.81 +} settings_t;
    6.82 +
    6.83 +settings_t opts;
    6.84 +
    6.85 +int interrupted = 0; /* gets set if we get a SIGHUP */
    6.86 +int rec_count = 0;
    6.87 +time_t start_time;
    6.88 +int dom0_flips = 0;
    6.89 +
    6.90 +_new_qos_data *new_qos;
    6.91 +_new_qos_data **cpu_qos_data;
    6.92 +
    6.93 +
    6.94 +#define ID(X) ((X>NDOMAINS-1)?(NDOMAINS-1):X)
    6.95 +
    6.96 +// array of currently running domains, indexed by cpu
    6.97 +int *running = NULL;
    6.98 +
    6.99 +// number of cpu's on this platform
   6.100 +int NCPU = 0;
   6.101 +
   6.102 +
   6.103 +void init_current(int ncpu)
   6.104 +{
   6.105 +  running = calloc(ncpu, sizeof(int));
   6.106 +  NCPU = ncpu;
   6.107 +  printf("Initialized with %d %s\n", ncpu, (ncpu == 1) ? "cpu" : "cpu's");
   6.108 +}
   6.109 +
   6.110 +int is_current(int domain, int cpu)
   6.111 +{
   6.112 +  //  int i;
   6.113 +  
   6.114 +  //  for (i=0; i<NCPU; i++)
   6.115 +    if (running[cpu] == domain)
   6.116 +      return 1;
   6.117 +  return 0;
   6.118 +}
   6.119 +
   6.120 +
   6.121 +// return the domain that's currently running on the given cpu
   6.122 +int current(int cpu)
   6.123 +{
   6.124 +  return running[cpu];
   6.125 +}
   6.126 +
   6.127 +void set_current(int cpu, int domain)
   6.128 +{
   6.129 +  running[cpu] = domain;
   6.130 +}
   6.131 +
   6.132 +
   6.133 +
   6.134 +void close_handler(int signal)
   6.135 +{
   6.136 +    interrupted = 1;
   6.137 +}
   6.138 +
   6.139 +#if 0
   6.140 +void dump_record(int cpu, struct t_rec *x)
   6.141 +{
   6.142 +    printf("record: cpu=%x, tsc=%lx, event=%x, d1=%lx\n", 
   6.143 +            cpu, x->cycles, x->event, x->data[0]);
   6.144 +}
   6.145 +#endif
   6.146 +
   6.147 +/**
   6.148 + * millis_to_timespec - convert a time in milliseconds to a struct timespec
   6.149 + * @millis:             time interval in milliseconds
   6.150 + */
   6.151 +struct timespec millis_to_timespec(unsigned long millis)
   6.152 +{
   6.153 +    struct timespec spec;
   6.154 +
   6.155 +    spec.tv_sec = millis / 1000;
   6.156 +    spec.tv_nsec = (millis % 1000) * 1000;
   6.157 +
   6.158 +    return spec;
   6.159 +}
   6.160 +
   6.161 +
   6.162 +typedef struct 
   6.163 +{
   6.164 +    int event_count;
   6.165 +    int event_id;
   6.166 +    char *text;
   6.167 +} stat_map_t;
   6.168 +
   6.169 +stat_map_t stat_map[] = {
   6.170 +    { 0,       0, 	    "Other" },
   6.171 +    { 0, TRC_SCHED_DOM_ADD, "Add Domain" },
   6.172 +    { 0, TRC_SCHED_DOM_REM, "Remove Domain" },
   6.173 +    { 0, TRC_SCHED_SLEEP, "Sleep" },
   6.174 +    { 0, TRC_SCHED_WAKE,  "Wake" },
   6.175 +    { 0, TRC_SCHED_BLOCK,  "Block" },
   6.176 +    { 0, TRC_SCHED_SWITCH,  "Switch" },
   6.177 +    { 0, TRC_SCHED_S_TIMER_FN, "Timer Func"},
   6.178 +    { 0, TRC_SCHED_SWITCH_INFPREV,  "Switch Prev" },
   6.179 +    { 0, TRC_SCHED_SWITCH_INFNEXT,  "Switch Next" },
   6.180 +    { 0, TRC_MEM_PAGE_GRANT_MAP,  "Page Map" },
   6.181 +    { 0, TRC_MEM_PAGE_GRANT_UNMAP,  "Page Unmap" },
   6.182 +    { 0, TRC_MEM_PAGE_GRANT_TRANSFER,  "Page Transfer" },
   6.183 +    { 0,      0, 		 0  }
   6.184 +};
   6.185 +
   6.186 +
   6.187 +void check_gotten_sum(void)
   6.188 +{
   6.189 +#if 0
   6.190 +    uint64_t sum, ns;
   6.191 +    extern uint64_t total_ns_gotten(uint64_t*);
   6.192 +    double percent;
   6.193 +    int i;
   6.194 +
   6.195 +    for (i=0; i<NCPU; i++) {
   6.196 +      new_qos = cpu_qos_data[i];
   6.197 +      ns = billion;
   6.198 +      sum = total_ns_gotten(&ns);
   6.199 +
   6.200 +      printf("[cpu%d] ns_gotten over all domains = %lldns, over %lldns\n",
   6.201 +	      i, sum, ns);
   6.202 +      percent = (double) sum;
   6.203 +      percent = (100.0*percent) / (double)ns;
   6.204 +      printf(" ==> ns_gotten = %7.3f%%\n", percent);
   6.205 +    }
   6.206 +#endif
   6.207 +}
   6.208 +
   6.209 +
   6.210 +
   6.211 +void dump_stats(void) 
   6.212 +{
   6.213 +    stat_map_t *smt = stat_map;
   6.214 +    time_t end_time, run_time;
   6.215 +
   6.216 +    time(&end_time);
   6.217 +
   6.218 +    run_time = end_time - start_time;
   6.219 +
   6.220 +    printf("Event counts:\n");
   6.221 +    while (smt->text != NULL) {
   6.222 +        printf("%08d\t%s\n", smt->event_count, smt->text);
   6.223 +        smt++;
   6.224 +    }
   6.225 +
   6.226 +    printf("processed %d total records in %d seconds (%ld per second)\n",
   6.227 +            rec_count, (int)run_time, rec_count/run_time);
   6.228 +
   6.229 +    check_gotten_sum();
   6.230 +}
   6.231 +
   6.232 +void log_event(int event_id) 
   6.233 +{
   6.234 +    stat_map_t *smt = stat_map;
   6.235 +
   6.236 +    //  printf("event_id = 0x%x\n", event_id);
   6.237 +
   6.238 +    while (smt->text != NULL) {
   6.239 +        if (smt->event_id == event_id) {
   6.240 +            smt->event_count++;
   6.241 +            return;
   6.242 +        }
   6.243 +        smt++;
   6.244 +    }
   6.245 +    if (smt->text == NULL)
   6.246 +        stat_map[0].event_count++;	// other
   6.247 +}
   6.248 +
   6.249 +
   6.250 +
   6.251 +/**
   6.252 + * get_tbufs - get pointer to and size of the trace buffers
   6.253 + * @mfn:  location to store mfn of the trace buffers to
   6.254 + * @size: location to store the size of a trace buffer to
   6.255 + *
   6.256 + * Gets the machine address of the trace pointer area and the size of the
   6.257 + * per CPU buffers.
   6.258 + */
   6.259 +void get_tbufs(unsigned long *mfn, unsigned long *size)
   6.260 +{
   6.261 +    int ret;
   6.262 +    dom0_op_t op;                        /* dom0 op we'll build             */
   6.263 +    int xc_handle = xc_interface_open(); /* for accessing control interface */
   6.264 +
   6.265 +    op.cmd = DOM0_TBUFCONTROL;
   6.266 +    op.interface_version = DOM0_INTERFACE_VERSION;
   6.267 +    op.u.tbufcontrol.op  = DOM0_TBUF_GET_INFO;
   6.268 +
   6.269 +    ret = do_dom0_op(xc_handle, &op);
   6.270 +
   6.271 +    xc_interface_close(xc_handle);
   6.272 +
   6.273 +    if ( ret != 0 )
   6.274 +    {
   6.275 +        PERROR("Failure to get trace buffer pointer from Xen");
   6.276 +        exit(EXIT_FAILURE);
   6.277 +    }
   6.278 +
   6.279 +    *mfn  = op.u.tbufcontrol.buffer_mfn;
   6.280 +    *size = op.u.tbufcontrol.size;
   6.281 +}
   6.282 +
   6.283 +/**
   6.284 + * map_tbufs - memory map Xen trace buffers into user space
   6.285 + * @tbufs_mfn: mfn of the trace buffers
   6.286 + * @num:       number of trace buffers to map
   6.287 + * @size:      size of each trace buffer
   6.288 + *
   6.289 + * Maps the Xen trace buffers them into process address space.
   6.290 + */
   6.291 +struct t_buf *map_tbufs(unsigned long tbufs_mfn, unsigned int num,
   6.292 +                        unsigned long size)
   6.293 +{
   6.294 +    int xc_handle;                  /* file descriptor for /proc/xen/privcmd */
   6.295 +    struct t_buf *tbufs_mapped;
   6.296 +
   6.297 +    xc_handle = xc_interface_open();
   6.298 +
   6.299 +    if ( xc_handle < 0 ) 
   6.300 +    {
   6.301 +        PERROR("Open /proc/xen/privcmd when mapping trace buffers\n");
   6.302 +        exit(EXIT_FAILURE);
   6.303 +    }
   6.304 +
   6.305 +    tbufs_mapped = xc_map_foreign_range(xc_handle, 0 /* Dom 0 ID */,
   6.306 +                                        size * num, PROT_READ | PROT_WRITE,
   6.307 +                                        tbufs_mfn);
   6.308 +
   6.309 +    xc_interface_close(xc_handle);
   6.310 +
   6.311 +    if ( tbufs_mapped == 0 ) 
   6.312 +    {
   6.313 +        PERROR("Failed to mmap trace buffers");
   6.314 +        exit(EXIT_FAILURE);
   6.315 +    }
   6.316 +
   6.317 +    return tbufs_mapped;
   6.318 +}
   6.319 +
   6.320 +/**
   6.321 + * init_bufs_ptrs - initialises an array of pointers to the trace buffers
   6.322 + * @bufs_mapped:    the userspace address where the trace buffers are mapped
   6.323 + * @num:            number of trace buffers
   6.324 + * @size:           trace buffer size
   6.325 + *
   6.326 + * Initialises an array of pointers to individual trace buffers within the
   6.327 + * mapped region containing all trace buffers.
   6.328 + */
   6.329 +struct t_buf **init_bufs_ptrs(void *bufs_mapped, unsigned int num,
   6.330 +        unsigned long size)
   6.331 +{
   6.332 +    int i;
   6.333 +    struct t_buf **user_ptrs;
   6.334 +
   6.335 +    user_ptrs = (struct t_buf **)calloc(num, sizeof(struct t_buf *));
   6.336 +    if ( user_ptrs == NULL )
   6.337 +    {
   6.338 +        PERROR( "Failed to allocate memory for buffer pointers\n");
   6.339 +        exit(EXIT_FAILURE);
   6.340 +    }
   6.341 +
   6.342 +    /* initialise pointers to the trace buffers - given the size of a trace
   6.343 +     * buffer and the value of bufs_maped, we can easily calculate these */
   6.344 +    for ( i = 0; i<num; i++ )
   6.345 +        user_ptrs[i] = (struct t_buf *)((unsigned long)bufs_mapped + size * i);
   6.346 +
   6.347 +    return user_ptrs;
   6.348 +}
   6.349 +
   6.350 +
   6.351 +/**
   6.352 + * init_rec_ptrs - initialises data area pointers to locations in user space
   6.353 + * @tbufs_mfn:     base mfn of the trace buffer area
   6.354 + * @tbufs_mapped:  user virtual address of base of trace buffer area
   6.355 + * @meta:          array of user-space pointers to struct t_buf's of metadata
   6.356 + * @num:           number of trace buffers
   6.357 + *
   6.358 + * Initialises data area pointers to the locations that data areas have been
   6.359 + * mapped in user space.  Note that the trace buffer metadata contains machine
   6.360 + * pointers - the array returned allows more convenient access to them.
   6.361 + */
   6.362 +struct t_rec **init_rec_ptrs(struct t_buf **meta, unsigned int num)
   6.363 +{
   6.364 +    int i;
   6.365 +    struct t_rec **data;
   6.366 +    
   6.367 +    data = calloc(num, sizeof(struct t_rec *));
   6.368 +    if ( data == NULL )
   6.369 +    {
   6.370 +        PERROR("Failed to allocate memory for data pointers\n");
   6.371 +        exit(EXIT_FAILURE);
   6.372 +    }
   6.373 +
   6.374 +    for ( i = 0; i < num; i++ )
   6.375 +        data[i] = (struct t_rec *)(meta[i] + 1);
   6.376 +
   6.377 +    return data;
   6.378 +}
   6.379 +
   6.380 +
   6.381 +
   6.382 +/**
   6.383 + * get_num_cpus - get the number of logical CPUs
   6.384 + */
   6.385 +unsigned int get_num_cpus()
   6.386 +{
   6.387 +    dom0_op_t op;
   6.388 +    int xc_handle = xc_interface_open();
   6.389 +    int ret;
   6.390 +
   6.391 +    op.cmd = DOM0_PHYSINFO;
   6.392 +    op.interface_version = DOM0_INTERFACE_VERSION;
   6.393 +
   6.394 +    ret = xc_dom0_op(xc_handle, &op);
   6.395 +
   6.396 +    if ( ret != 0 )
   6.397 +    {
   6.398 +        PERROR("Failure to get logical CPU count from Xen");
   6.399 +        exit(EXIT_FAILURE);
   6.400 +    }
   6.401 +
   6.402 +    xc_interface_close(xc_handle);
   6.403 +    opts.cpu_freq = (double)op.u.physinfo.cpu_khz/1000.0;
   6.404 +
   6.405 +    return (op.u.physinfo.threads_per_core *
   6.406 +            op.u.physinfo.cores_per_socket *
   6.407 +            op.u.physinfo.sockets_per_node *
   6.408 +            op.u.physinfo.nr_nodes);
   6.409 +}
   6.410 +
   6.411 +
   6.412 +/**
   6.413 + * monitor_tbufs - monitor the contents of tbufs
   6.414 + */
   6.415 +int monitor_tbufs()
   6.416 +{
   6.417 +    int i;
   6.418 +    extern void process_record(int, struct t_rec *);
   6.419 +    extern void alloc_qos_data(int ncpu);
   6.420 +
   6.421 +    void *tbufs_mapped;          /* pointer to where the tbufs are mapped    */
   6.422 +    struct t_buf **meta;         /* pointers to the trace buffer metadata    */
   6.423 +    struct t_rec **data;         /* pointers to the trace buffer data areas
   6.424 +                                  * where they are mapped into user space.   */
   6.425 +    unsigned long tbufs_mfn;     /* mfn of the tbufs                         */
   6.426 +    unsigned int  num;           /* number of trace buffers / logical CPUS   */
   6.427 +    unsigned long size;          /* size of a single trace buffer            */
   6.428 +
   6.429 +    int size_in_recs;
   6.430 +
   6.431 +    /* get number of logical CPUs (and therefore number of trace buffers) */
   6.432 +    num = get_num_cpus();
   6.433 +
   6.434 +    init_current(num);
   6.435 +    alloc_qos_data(num);
   6.436 +
   6.437 +    printf("CPU Frequency = %7.2f\n", opts.cpu_freq);
   6.438 +    
   6.439 +    /* setup access to trace buffers */
   6.440 +    get_tbufs(&tbufs_mfn, &size);
   6.441 +
   6.442 +    //    printf("from dom0op: %ld, t_buf: %d, t_rec: %d\n",
   6.443 +    //            size, sizeof(struct t_buf), sizeof(struct t_rec));
   6.444 +
   6.445 +    tbufs_mapped = map_tbufs(tbufs_mfn, num, size);
   6.446 +
   6.447 +    size_in_recs = (size - sizeof(struct t_buf)) / sizeof(struct t_rec);
   6.448 +    //    fprintf(stderr, "size_in_recs = %d\n", size_in_recs);
   6.449 +
   6.450 +    /* build arrays of convenience ptrs */
   6.451 +    meta  = init_bufs_ptrs (tbufs_mapped, num, size);
   6.452 +    data  = init_rec_ptrs(meta, num);
   6.453 +
   6.454 +    /* now, scan buffers for events */
   6.455 +    while ( !interrupted )
   6.456 +    {
   6.457 +        for ( i = 0; ( i < num ) && !interrupted; i++ )
   6.458 +            while ( meta[i]->cons != meta[i]->prod )
   6.459 +            {
   6.460 +                rmb(); /* read prod, then read item. */
   6.461 +                process_record(i, data[i] + meta[i]->cons % size_in_recs);
   6.462 +                mb(); /* read item, then update cons. */
   6.463 +                meta[i]->cons++;
   6.464 +            }
   6.465 +
   6.466 +        nanosleep(&opts.poll_sleep, NULL);
   6.467 +    }
   6.468 +
   6.469 +    /* cleanup */
   6.470 +    free(meta);
   6.471 +    free(data);
   6.472 +    /* don't need to munmap - cleanup is automatic */
   6.473 +
   6.474 +    return 0;
   6.475 +}
   6.476 +
   6.477 +
   6.478 +/******************************************************************************
   6.479 + * Various declarations / definitions GNU argp needs to do its work
   6.480 + *****************************************************************************/
   6.481 +
   6.482 +
   6.483 +/* command parser for GNU argp - see GNU docs for more info */
   6.484 +error_t cmd_parser(int key, char *arg, struct argp_state *state)
   6.485 +{
   6.486 +    settings_t *setup = (settings_t *)state->input;
   6.487 +
   6.488 +    switch ( key )
   6.489 +    {
   6.490 +        case 't': /* set new records threshold for logging */
   6.491 +            {
   6.492 +                char *inval;
   6.493 +                setup->new_data_thresh = strtol(arg, &inval, 0);
   6.494 +                if ( inval == arg )
   6.495 +                    argp_usage(state);
   6.496 +            }
   6.497 +            break;
   6.498 +
   6.499 +        case 's': /* set sleep time (given in milliseconds) */
   6.500 +            {
   6.501 +                char *inval;
   6.502 +                setup->poll_sleep = millis_to_timespec(strtol(arg, &inval, 0));
   6.503 +                if ( inval == arg )
   6.504 +                    argp_usage(state);
   6.505 +            }
   6.506 +            break;
   6.507 +
   6.508 +        case 'm': /* set ms_per_sample */
   6.509 +            {
   6.510 +                char *inval;
   6.511 +                setup->ms_per_sample = strtol(arg, &inval, 0);
   6.512 +                if ( inval == arg )
   6.513 +                    argp_usage(state);
   6.514 +            }
   6.515 +            break;
   6.516 +
   6.517 +        case ARGP_KEY_ARG:
   6.518 +            {
   6.519 +                if ( state->arg_num == 0 )
   6.520 +                    setup->outfile = arg;
   6.521 +                else
   6.522 +                    argp_usage(state);
   6.523 +            }
   6.524 +            break;
   6.525 +
   6.526 +        default:
   6.527 +            return ARGP_ERR_UNKNOWN;
   6.528 +    }
   6.529 +
   6.530 +    return 0;
   6.531 +}
   6.532 +
   6.533 +#define SHARED_MEM_FILE "/tmp/xenq-shm"
   6.534 +void alloc_qos_data(int ncpu)
   6.535 +{
   6.536 +    int i, n, pgsize, off=0;
   6.537 +    char *dummy;
   6.538 +    int qos_fd;
   6.539 +    void advance_next_datapoint(uint64_t);
   6.540 +
   6.541 +    cpu_qos_data = (_new_qos_data **) calloc(ncpu, sizeof(_new_qos_data *));
   6.542 +
   6.543 +
   6.544 +    qos_fd = open(SHARED_MEM_FILE, O_RDWR|O_CREAT|O_TRUNC, 0777);
   6.545 +    if (qos_fd < 0) {
   6.546 +        PERROR(SHARED_MEM_FILE);
   6.547 +        exit(2);
   6.548 +    }
   6.549 +    pgsize = getpagesize();
   6.550 +    dummy = malloc(pgsize);
   6.551 +
   6.552 +    for (n=0; n<ncpu; n++) {
   6.553 +
   6.554 +      for (i=0; i<sizeof(_new_qos_data); i=i+pgsize)
   6.555 +        write(qos_fd, dummy, pgsize);
   6.556 +
   6.557 +      new_qos = (_new_qos_data *) mmap(0, sizeof(_new_qos_data), PROT_READ|PROT_WRITE, 
   6.558 +				       MAP_SHARED, qos_fd, off);
   6.559 +      off += i;
   6.560 +      if (new_qos == NULL) {
   6.561 +        PERROR("mmap");
   6.562 +        exit(3);
   6.563 +      }
   6.564 +      //  printf("new_qos = %p\n", new_qos);
   6.565 +      memset(new_qos, 0, sizeof(_new_qos_data));
   6.566 +      new_qos->next_datapoint = 0;
   6.567 +      advance_next_datapoint(0);
   6.568 +      new_qos->structlen = i;
   6.569 +      new_qos->ncpu = ncpu;
   6.570 +      //      printf("structlen = 0x%x\n", i);
   6.571 +      cpu_qos_data[n] = new_qos;
   6.572 +    }
   6.573 +    free(dummy);
   6.574 +    new_qos = NULL;
   6.575 +}
   6.576 +
   6.577 +
   6.578 +#define xstr(x) str(x)
   6.579 +#define str(x) #x
   6.580 +
   6.581 +const struct argp_option cmd_opts[] =
   6.582 +{
   6.583 +    { .name = "log-thresh", .key='t', .arg="l",
   6.584 +        .doc =
   6.585 +            "Set number, l, of new records required to trigger a write to output "
   6.586 +            "(default " xstr(NEW_DATA_THRESH) ")." },
   6.587 +
   6.588 +    { .name = "poll-sleep", .key='s', .arg="p",
   6.589 +        .doc = 
   6.590 +            "Set sleep time, p, in milliseconds between polling the trace buffer "
   6.591 +            "for new data (default " xstr(POLL_SLEEP_MILLIS) ")." },
   6.592 +
   6.593 +    { .name = "ms_per_sample", .key='m', .arg="MS",
   6.594 +        .doc = 
   6.595 +            "Specify the number of milliseconds per sample "
   6.596 +            " (default " xstr(MS_PER_SAMPLE) ")." },
   6.597 +
   6.598 +    {0}
   6.599 +};
   6.600 +
   6.601 +const struct argp parser_def =
   6.602 +{
   6.603 +    .options = cmd_opts,
   6.604 +    .parser = cmd_parser,
   6.605 +    //    .args_doc = "[output file]",
   6.606 +    .doc =
   6.607 +        "Tool to capture and partially process Xen trace buffer data"
   6.608 +        "\v"
   6.609 +        "This tool is used to capture trace buffer data from Xen.  The data is "
   6.610 +        "saved in a shared memory structure to be further processed by xenmon."
   6.611 +};
   6.612 +
   6.613 +
   6.614 +const char *argp_program_version     = "xenbaked v1.3";
   6.615 +const char *argp_program_bug_address = "<rob.gardner@hp.com>";
   6.616 +
   6.617 +
   6.618 +int main(int argc, char **argv)
   6.619 +{
   6.620 +    int ret;
   6.621 +    struct sigaction act;
   6.622 +
   6.623 +    time(&start_time);
   6.624 +    opts.outfile = 0;
   6.625 +    opts.poll_sleep = millis_to_timespec(POLL_SLEEP_MILLIS);
   6.626 +    opts.new_data_thresh = NEW_DATA_THRESH;
   6.627 +    opts.ms_per_sample = MS_PER_SAMPLE;
   6.628 +    opts.cpu_freq = CPU_FREQ;
   6.629 +
   6.630 +    argp_parse(&parser_def, argc, argv, 0, 0, &opts);
   6.631 +    fprintf(stderr, "ms_per_sample = %ld\n", opts.ms_per_sample);
   6.632 +
   6.633 +
   6.634 +    /* ensure that if we get a signal, we'll do cleanup, then exit */
   6.635 +    act.sa_handler = close_handler;
   6.636 +    act.sa_flags = 0;
   6.637 +    sigemptyset(&act.sa_mask);
   6.638 +    sigaction(SIGHUP,  &act, NULL);
   6.639 +    sigaction(SIGTERM, &act, NULL);
   6.640 +    sigaction(SIGINT,  &act, NULL);
   6.641 +
   6.642 +    ret = monitor_tbufs();
   6.643 +
   6.644 +    dump_stats();
   6.645 +    msync(new_qos, sizeof(_new_qos_data), MS_SYNC);
   6.646 +
   6.647 +    return ret;
   6.648 +}
   6.649 +
   6.650 +int domain_runnable(int domid)
   6.651 +{
   6.652 +    return new_qos->domain_info[ID(domid)].runnable;
   6.653 +}
   6.654 +
   6.655 +
   6.656 +void update_blocked_time(int domid, uint64_t now)
   6.657 +{
   6.658 +    uint64_t t_blocked;
   6.659 +    int id = ID(domid);
   6.660 +
   6.661 +    if (new_qos->domain_info[id].blocked_start_time != 0) {
   6.662 +        if (now >= new_qos->domain_info[id].blocked_start_time)
   6.663 +            t_blocked = now - new_qos->domain_info[id].blocked_start_time;
   6.664 +        else
   6.665 +            t_blocked = now + (~0ULL - new_qos->domain_info[id].blocked_start_time);
   6.666 +        new_qos->qdata[new_qos->next_datapoint].ns_blocked[id] += t_blocked;
   6.667 +    }
   6.668 +
   6.669 +    if (domain_runnable(id))
   6.670 +        new_qos->domain_info[id].blocked_start_time = 0;
   6.671 +    else
   6.672 +        new_qos->domain_info[id].blocked_start_time = now;
   6.673 +}
   6.674 +
   6.675 +
   6.676 +// advance to next datapoint for all domains
   6.677 +void advance_next_datapoint(uint64_t now)
   6.678 +{
   6.679 +    int new, old, didx;
   6.680 +
   6.681 +    old = new_qos->next_datapoint;
   6.682 +    new = QOS_INCR(old);
   6.683 +    new_qos->next_datapoint = new;
   6.684 +    //	memset(&new_qos->qdata[new], 0, sizeof(uint64_t)*(2+5*NDOMAINS));
   6.685 +    for (didx = 0; didx < NDOMAINS; didx++) {
   6.686 +        new_qos->qdata[new].ns_gotten[didx] = 0;
   6.687 +        new_qos->qdata[new].ns_allocated[didx] = 0;
   6.688 +        new_qos->qdata[new].ns_waiting[didx] = 0;
   6.689 +        new_qos->qdata[new].ns_blocked[didx] = 0;
   6.690 +        new_qos->qdata[new].switchin_count[didx] = 0;
   6.691 +        new_qos->qdata[new].io_count[didx] = 0;
   6.692 +    }
   6.693 +    new_qos->qdata[new].ns_passed = 0;
   6.694 +    new_qos->qdata[new].lost_records = 0;
   6.695 +    new_qos->qdata[new].flip_free_periods = 0;
   6.696 +
   6.697 +    new_qos->qdata[new].timestamp = now;
   6.698 +}
   6.699 +
   6.700 +
   6.701 +
   6.702 +void qos_update_thread(int cpu, int domid, uint64_t now)
   6.703 +{
   6.704 +    int n, id;
   6.705 +    uint64_t last_update_time, start;
   6.706 +    int64_t time_since_update, run_time = 0;
   6.707 +
   6.708 +    id = ID(domid);
   6.709 +
   6.710 +    n = new_qos->next_datapoint;
   6.711 +    last_update_time = new_qos->domain_info[id].last_update_time;
   6.712 +
   6.713 +    time_since_update = now - last_update_time;
   6.714 +
   6.715 +    if (time_since_update < 0) {
   6.716 +      // what happened here? either a timestamp wraparound, or more likely,
   6.717 +      // a slight inconsistency among timestamps from various cpu's
   6.718 +      if (-time_since_update < billion) {
   6.719 +	// fairly small difference, let's just adjust 'now' to be a little
   6.720 +	// beyond last_update_time
   6.721 +	time_since_update = -time_since_update;
   6.722 +      }
   6.723 +      else if ( ((~0ULL - last_update_time) < billion) && (now < billion) ) {
   6.724 +	// difference is huge, must be a wraparound
   6.725 +	// last_update time should be "near" ~0ULL,
   6.726 +	// and now should be "near" 0
   6.727 +	time_since_update = now + (~0ULL - last_update_time);
   6.728 +	printf("time wraparound\n");
   6.729 +      }
   6.730 +      else {
   6.731 +	// none of the above, may be an out of order record
   6.732 +	// no good solution, just ignore and update again later
   6.733 +	return;
   6.734 +      }
   6.735 +    }
   6.736 +	
   6.737 +    new_qos->domain_info[id].last_update_time = now;
   6.738 +
   6.739 +    if (new_qos->domain_info[id].runnable_at_last_update && is_current(domid, cpu)) {
   6.740 +        start = new_qos->domain_info[id].start_time;
   6.741 +        if (start > now) {		// wrapped around
   6.742 +            run_time = now + (~0ULL - start);
   6.743 +	    printf("warning: start > now\n");
   6.744 +        }
   6.745 +        else
   6.746 +            run_time = now - start;
   6.747 +	//	if (run_time < 0)	// should not happen
   6.748 +	//	  printf("warning: run_time < 0; start = %lld now= %lld\n", start, now);
   6.749 +        new_qos->domain_info[id].ns_oncpu_since_boot += run_time;
   6.750 +        new_qos->domain_info[id].start_time = now;
   6.751 +        new_qos->domain_info[id].ns_since_boot += time_since_update;
   6.752 +#if 1
   6.753 +	new_qos->qdata[n].ns_gotten[id] += run_time;
   6.754 +	if (domid == 0 && cpu == 1)
   6.755 +	  printf("adding run time for dom0 on cpu1\r\n");
   6.756 +#endif
   6.757 +    }
   6.758 +
   6.759 +    new_qos->domain_info[id].runnable_at_last_update = domain_runnable(domid);
   6.760 +
   6.761 +    update_blocked_time(domid, now);
   6.762 +
   6.763 +    // how much time passed since this datapoint was updated?
   6.764 +    if (now >= new_qos->qdata[n].timestamp) {
   6.765 +        // all is right with the world, time is increasing
   6.766 +        new_qos->qdata[n].ns_passed += (now - new_qos->qdata[n].timestamp);
   6.767 +    }
   6.768 +    else {
   6.769 +        // time wrapped around
   6.770 +        //new_qos->qdata[n].ns_passed += (now + (~0LL - new_qos->qdata[n].timestamp));
   6.771 +        //    printf("why timewrap?\r\n");
   6.772 +    }
   6.773 +    new_qos->qdata[n].timestamp = now;
   6.774 +}
   6.775 +
   6.776 +
   6.777 +// called by dump routines to update all structures
   6.778 +void qos_update_all(uint64_t now, int cpu)
   6.779 +{
   6.780 +    int i;
   6.781 +
   6.782 +    for (i=0; i<NDOMAINS; i++)
   6.783 +        if (new_qos->domain_info[i].in_use)
   6.784 +            qos_update_thread(cpu, i, now);
   6.785 +}
   6.786 +
   6.787 +
   6.788 +void qos_update_thread_stats(int cpu, int domid, uint64_t now)
   6.789 +{
   6.790 +    if (new_qos->qdata[new_qos->next_datapoint].ns_passed > (million*opts.ms_per_sample)) {
   6.791 +        qos_update_all(now, cpu);
   6.792 +        advance_next_datapoint(now);
   6.793 +        return;
   6.794 +    }
   6.795 +    qos_update_thread(cpu, domid, now);
   6.796 +}
   6.797 +
   6.798 +
   6.799 +void qos_init_domain(int cpu, int domid, uint64_t now)
   6.800 +{
   6.801 +    int i, id;
   6.802 +
   6.803 +    id = ID(domid);
   6.804 +
   6.805 +    if (new_qos->domain_info[id].in_use)
   6.806 +        return;
   6.807 +
   6.808 +
   6.809 +    memset(&new_qos->domain_info[id], 0, sizeof(_domain_info));
   6.810 +    new_qos->domain_info[id].last_update_time = now;
   6.811 +    //  runnable_start_time[id] = 0;
   6.812 +    new_qos->domain_info[id].runnable_start_time = 0; // invalidate
   6.813 +    new_qos->domain_info[id].in_use = 1;
   6.814 +    new_qos->domain_info[id].blocked_start_time = 0;
   6.815 +    new_qos->domain_info[id].id = id;
   6.816 +    if (domid == IDLE_DOMAIN_ID)
   6.817 +        sprintf(new_qos->domain_info[id].name, "Idle Task%d", cpu);
   6.818 +    else
   6.819 +        sprintf(new_qos->domain_info[id].name, "Domain#%d", domid);
   6.820 +
   6.821 +    for (i=0; i<NSAMPLES; i++) {
   6.822 +        new_qos->qdata[i].ns_gotten[id] = 0;
   6.823 +        new_qos->qdata[i].ns_allocated[id] = 0;
   6.824 +        new_qos->qdata[i].ns_waiting[id] = 0;
   6.825 +        new_qos->qdata[i].ns_blocked[id] = 0;
   6.826 +        new_qos->qdata[i].switchin_count[id] = 0;
   6.827 +        new_qos->qdata[i].io_count[id] = 0;
   6.828 +    }
   6.829 +}
   6.830 +
   6.831 +
   6.832 +// called when a new thread gets the cpu
   6.833 +void qos_switch_in(int cpu, int domid, uint64_t now, unsigned long ns_alloc, unsigned long ns_waited)
   6.834 +{
   6.835 +    int id = ID(domid);
   6.836 +
   6.837 +    new_qos->domain_info[id].runnable = 1;
   6.838 +    update_blocked_time(domid, now);
   6.839 +    new_qos->domain_info[id].blocked_start_time = 0; // invalidate
   6.840 +    new_qos->domain_info[id].runnable_start_time = 0; // invalidate
   6.841 +    //runnable_start_time[id] = 0;
   6.842 +
   6.843 +    new_qos->domain_info[id].start_time = now;
   6.844 +    new_qos->qdata[new_qos->next_datapoint].switchin_count[id]++;
   6.845 +    new_qos->qdata[new_qos->next_datapoint].ns_allocated[id] += ns_alloc;
   6.846 +    new_qos->qdata[new_qos->next_datapoint].ns_waiting[id] += ns_waited;
   6.847 +    qos_update_thread_stats(cpu, domid, now);
   6.848 +    set_current(cpu, id);
   6.849 +
   6.850 +    // count up page flips for dom0 execution
   6.851 +    if (id == 0)
   6.852 +      dom0_flips = 0;
   6.853 +}
   6.854 +
   6.855 +// called when the current thread is taken off the cpu
   6.856 +void qos_switch_out(int cpu, int domid, uint64_t now, unsigned long gotten)
   6.857 +{
   6.858 +    int id = ID(domid);
   6.859 +    int n;
   6.860 +
   6.861 +    if (!is_current(id, cpu)) {
   6.862 +        //    printf("switching out domain %d but it is not current. gotten=%ld\r\n", id, gotten);
   6.863 +    }
   6.864 +
   6.865 +    if (gotten == 0) {
   6.866 +        printf("gotten==0 in qos_switchout(domid=%d)\n", domid);
   6.867 +    }
   6.868 +
   6.869 +    if (gotten < 100) {
   6.870 +        printf("gotten<100ns in qos_switchout(domid=%d)\n", domid);
   6.871 +    }
   6.872 +
   6.873 +
   6.874 +    n = new_qos->next_datapoint;
   6.875 +#if 0
   6.876 +    new_qos->qdata[n].ns_gotten[id] += gotten;
   6.877 +    if (gotten > new_qos->qdata[n].ns_passed)
   6.878 +      printf("inconsistency #257, diff = %lld\n",
   6.879 +	    gotten - new_qos->qdata[n].ns_passed );
   6.880 +#endif
   6.881 +    new_qos->domain_info[id].ns_oncpu_since_boot += gotten;
   6.882 +    new_qos->domain_info[id].runnable_start_time = now;
   6.883 +    //  runnable_start_time[id] = now;
   6.884 +    qos_update_thread_stats(cpu, id, now);
   6.885 +
   6.886 +    // process dom0 page flips
   6.887 +    if (id == 0)
   6.888 +      if (dom0_flips == 0)
   6.889 +	new_qos->qdata[n].flip_free_periods++;
   6.890 +}
   6.891 +
   6.892 +// called when domain is put to sleep, may also be called
   6.893 +// when thread is already asleep
   6.894 +void qos_state_sleeping(int cpu, int domid, uint64_t now) 
   6.895 +{
   6.896 +    int id = ID(domid);
   6.897 +
   6.898 +    if (!domain_runnable(id))	// double call?
   6.899 +        return;
   6.900 +
   6.901 +    new_qos->domain_info[id].runnable = 0;
   6.902 +    new_qos->domain_info[id].blocked_start_time = now;
   6.903 +    new_qos->domain_info[id].runnable_start_time = 0; // invalidate
   6.904 +    //  runnable_start_time[id] = 0; // invalidate
   6.905 +    qos_update_thread_stats(cpu, domid, now);
   6.906 +}
   6.907 +
   6.908 +
   6.909 +
   6.910 +void qos_kill_thread(int domid)
   6.911 +{
   6.912 +    new_qos->domain_info[ID(domid)].in_use = 0;
   6.913 +}
   6.914 +
   6.915 +
   6.916 +// called when thread becomes runnable, may also be called
   6.917 +// when thread is already runnable
   6.918 +void qos_state_runnable(int cpu, int domid, uint64_t now)
   6.919 +{
   6.920 +    int id = ID(domid);
   6.921 +
   6.922 +    if (domain_runnable(id))	// double call?
   6.923 +        return;
   6.924 +    new_qos->domain_info[id].runnable = 1;
   6.925 +    update_blocked_time(domid, now);
   6.926 +
   6.927 +    qos_update_thread_stats(cpu, domid, now);
   6.928 +
   6.929 +    new_qos->domain_info[id].blocked_start_time = 0; /* invalidate */
   6.930 +    new_qos->domain_info[id].runnable_start_time = now;
   6.931 +    //  runnable_start_time[id] = now;
   6.932 +}
   6.933 +
   6.934 +
   6.935 +void qos_count_packets(domid_t domid, uint64_t now)
   6.936 +{
   6.937 +  int i, id = ID(domid);
   6.938 +  _new_qos_data *cpu_data;
   6.939 +
   6.940 +  for (i=0; i<NCPU; i++) {
   6.941 +    cpu_data = cpu_qos_data[i];
   6.942 +    if (cpu_data->domain_info[id].in_use) {
   6.943 +      cpu_data->qdata[cpu_data->next_datapoint].io_count[id]++;
   6.944 +    }
   6.945 +  }
   6.946 +
   6.947 +  new_qos->qdata[new_qos->next_datapoint].io_count[0]++;
   6.948 +  dom0_flips++;
   6.949 +}
   6.950 +
   6.951 +
   6.952 +int domain_ok(int cpu, int domid, uint64_t now)
   6.953 +{
   6.954 +    if (domid == IDLE_DOMAIN_ID)
   6.955 +        domid = NDOMAINS-1;
   6.956 +    if (domid < 0 || domid >= NDOMAINS) {
   6.957 +        printf("bad domain id: %d\n", domid);
   6.958 +        return 0;
   6.959 +    }
   6.960 +    if (new_qos->domain_info[domid].in_use == 0)
   6.961 +        qos_init_domain(cpu, domid, now);
   6.962 +    return 1;
   6.963 +}
   6.964 +
   6.965 +
   6.966 +void process_record(int cpu, struct t_rec *r)
   6.967 +{
   6.968 +  uint64_t now;
   6.969 +
   6.970 +
   6.971 +  new_qos = cpu_qos_data[cpu];
   6.972 +
   6.973 +  rec_count++;
   6.974 +
   6.975 +  now = ((double)r->cycles) / (opts.cpu_freq / 1000.0);
   6.976 +
   6.977 +  log_event(r->event);
   6.978 +
   6.979 +  switch (r->event) {
   6.980 +
   6.981 +  case TRC_SCHED_SWITCH_INFPREV:
   6.982 +    // domain data[0] just switched out and received data[1] ns of cpu time
   6.983 +    if (domain_ok(cpu, r->data[0], now))
   6.984 +      qos_switch_out(cpu, r->data[0], now, r->data[1]);
   6.985 +    //    printf("ns_gotten %ld\n", r->data[1]);
   6.986 +    break;
   6.987 +    
   6.988 +  case TRC_SCHED_SWITCH_INFNEXT:
   6.989 +    // domain data[0] just switched in and
   6.990 +    // waited data[1] ns, and was allocated data[2] ns of cpu time
   6.991 +    if (domain_ok(cpu, r->data[0], now))
   6.992 +      qos_switch_in(cpu, r->data[0], now, r->data[2], r->data[1]);
   6.993 +    break;
   6.994 +    
   6.995 +  case TRC_SCHED_DOM_ADD:
   6.996 +    if (domain_ok(cpu, r->data[0], now))
   6.997 +      qos_init_domain(cpu, r->data[0],  now);
   6.998 +    break;
   6.999 +    
  6.1000 +  case TRC_SCHED_DOM_REM:
  6.1001 +    if (domain_ok(cpu, r->data[0], now))
  6.1002 +      qos_kill_thread(r->data[0]);
  6.1003 +    break;
  6.1004 +    
  6.1005 +  case TRC_SCHED_SLEEP:
  6.1006 +    if (domain_ok(cpu, r->data[0], now))
  6.1007 +      qos_state_sleeping(cpu, r->data[0], now);
  6.1008 +    break;
  6.1009 +    
  6.1010 +  case TRC_SCHED_WAKE:
  6.1011 +    if (domain_ok(cpu, r->data[0], now))
  6.1012 +      qos_state_runnable(cpu, r->data[0], now);
  6.1013 +    break;
  6.1014 +    
  6.1015 +  case TRC_SCHED_BLOCK:
  6.1016 +    if (domain_ok(cpu, r->data[0], now))
  6.1017 +      qos_state_sleeping(cpu, r->data[0], now);
  6.1018 +    break;
  6.1019 +    
  6.1020 +  case TRC_MEM_PAGE_GRANT_TRANSFER:
  6.1021 +    if (domain_ok(cpu, r->data[0], now))
  6.1022 +      qos_count_packets(r->data[0], now);
  6.1023 +    break;
  6.1024 +    
  6.1025 +  default:
  6.1026 +    break;
  6.1027 +  }
  6.1028 +  new_qos = NULL;
  6.1029 +}
  6.1030 +
  6.1031 +
  6.1032 +
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/tools/xenmon/xenbaked.h	Tue Nov 15 15:09:58 2005 +0100
     7.3 @@ -0,0 +1,101 @@
     7.4 +/******************************************************************************
     7.5 + * tools/xenbaked.h
     7.6 + *
     7.7 + * Header file for xenbaked
     7.8 + *
     7.9 + * Copyright (C) 2005 by Hewlett Packard, Palo Alto and Fort Collins
    7.10 + *
    7.11 + * Authors: Diwaker Gupta, diwaker.gupta@hp.com
    7.12 + *          Rob Gardner, rob.gardner@hp.com
    7.13 + *          Lucy Cherkasova, lucy.cherkasova.hp.com
    7.14 + * 
    7.15 + *  This program is free software; you can redistribute it and/or modify
    7.16 + *  it under the terms of the GNU General Public License as published by
    7.17 + *  the Free Software Foundation; under version 2 of the License.
    7.18 + *
    7.19 + *  This program is distributed in the hope that it will be useful,
    7.20 + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
    7.21 + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    7.22 + *  GNU General Public License for more details.
    7.23 + *
    7.24 + *  You should have received a copy of the GNU General Public License
    7.25 + *  along with this program; if not, write to the Free Software
    7.26 + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    7.27 + */
    7.28 +
    7.29 +#ifndef __QOS_H__
    7.30 +#define __QOS_H__
    7.31 +
    7.32 +///// qos stuff
    7.33 +#define million 1000000LL
    7.34 +#define billion 1000000000LL
    7.35 +
    7.36 +#define QOS_ADD(N,A) ((N+A)<(NSAMPLES-1) ? (N+A) : A)
    7.37 +#define QOS_INCR(N) ((N<(NSAMPLES-2)) ? (N+1) : 0)
    7.38 +#define QOS_DECR(N) ((N==0) ? (NSAMPLES-1) : (N-1))
    7.39 +
    7.40 +#define MAX_NAME_SIZE 32
    7.41 +#define IDLE_DOMAIN_ID 32767
    7.42 +
    7.43 +/* Number of domains we can keep track of in memory */
    7.44 +#define NDOMAINS 32
    7.45 +
    7.46 +/* Number of data points to keep */
    7.47 +#define NSAMPLES 100
    7.48 +
    7.49 +
    7.50 +// per domain stuff
    7.51 +typedef struct 
    7.52 +{
    7.53 +  uint64_t last_update_time;
    7.54 +  uint64_t start_time;		// when the thread started running
    7.55 +  uint64_t runnable_start_time;	// when the thread became runnable
    7.56 +  uint64_t blocked_start_time;	// when the thread became blocked
    7.57 +  uint64_t ns_since_boot;		// time gone by since boot
    7.58 +  uint64_t ns_oncpu_since_boot;	// total cpu time used by thread since boot
    7.59 +  //  uint64_t ns_runnable_since_boot;
    7.60 +  int runnable_at_last_update; // true if the thread was runnable last time we checked.
    7.61 +  int runnable;			// true if thread is runnable right now
    7.62 +  // tells us something about what happened during the 
    7.63 +  // sample period that we are analysing right now
    7.64 +  int in_use;			// 
    7.65 +  domid_t  id;
    7.66 +  char     name[MAX_NAME_SIZE];
    7.67 +} _domain_info;
    7.68 +
    7.69 +
    7.70 +
    7.71 +typedef struct 
    7.72 +{
    7.73 +  struct 
    7.74 +  {
    7.75 +// data point:
    7.76 +//   stuff that is recorded once for each measurement interval
    7.77 +    uint64_t ns_gotten[NDOMAINS];		// ns used in the last sample period
    7.78 +    uint64_t ns_allocated[NDOMAINS];		// ns allocated by scheduler
    7.79 +    uint64_t ns_waiting[NDOMAINS];		// ns spent waiting to execute, ie, time from
    7.80 +                                        // becoming runnable until actually running
    7.81 +    uint64_t ns_blocked[NDOMAINS];		// ns spent blocked
    7.82 +    uint64_t switchin_count[NDOMAINS]; // number of executions of the domain	
    7.83 +    uint64_t io_count[NDOMAINS];
    7.84 +    uint64_t ns_passed;              // ns gone by on the wall clock, ie, the sample period
    7.85 +    uint64_t timestamp;
    7.86 +    uint64_t lost_records;		// # of lost trace records this time period
    7.87 +    uint64_t flip_free_periods;	// # of executions of dom0 in which no page flips happened
    7.88 +  } qdata[NSAMPLES];
    7.89 +  
    7.90 +  _domain_info domain_info[NDOMAINS];
    7.91 +  
    7.92 +  // control information
    7.93 +  int next_datapoint;
    7.94 +  int ncpu;
    7.95 +  int structlen;
    7.96 +
    7.97 +  // parameters
    7.98 +  int measurement_frequency;	// for example
    7.99 +  
   7.100 +} _new_qos_data;
   7.101 +
   7.102 +
   7.103 +
   7.104 +#endif
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/tools/xenmon/xenmon.py	Tue Nov 15 15:09:58 2005 +0100
     8.3 @@ -0,0 +1,578 @@
     8.4 +#!/usr/bin/env python
     8.5 +
     8.6 +#####################################################################
     8.7 +# xenmon is a front-end for xenbaked.
     8.8 +# There is a curses interface for live monitoring. XenMon also allows
     8.9 +# logging to a file. For options, run python xenmon.py -h
    8.10 +#
    8.11 +# Copyright (C) 2005 by Hewlett Packard, Palo Alto and Fort Collins
    8.12 +# Authors: Lucy Cherkasova, lucy.cherkasova@hp.com
    8.13 +#          Rob Gardner, rob.gardner@hp.com
    8.14 +#          Diwaker Gupta, diwaker.gupta@hp.com
    8.15 +#####################################################################
    8.16 +#   This program is free software; you can redistribute it and/or modify
    8.17 +#   it under the terms of the GNU General Public License as published by
    8.18 +#   the Free Software Foundation; under version 2 of the License.
    8.19 +# 
    8.20 +#   This program is distributed in the hope that it will be useful,
    8.21 +#   but WITHOUT ANY WARRANTY; without even the implied warranty of
    8.22 +#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    8.23 +#   GNU General Public License for more details.
    8.24 +# 
    8.25 +#   You should have received a copy of the GNU General Public License
    8.26 +#   along with this program; if not, write to the Free Software
    8.27 +#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    8.28 +#####################################################################
    8.29 +
    8.30 +import mmap
    8.31 +import struct
    8.32 +import os
    8.33 +import time
    8.34 +import optparse as _o
    8.35 +import curses as _c
    8.36 +import math
    8.37 +import sys
    8.38 +
    8.39 +# constants
    8.40 +NSAMPLES = 100
    8.41 +NDOMAINS = 32
    8.42 +
    8.43 +# the struct strings for qos_info
    8.44 +ST_DOM_INFO = "6Q4i32s"
    8.45 +ST_QDATA = "%dQ" % (6*NDOMAINS + 4)
    8.46 +
    8.47 +# size of mmaped file
    8.48 +QOS_DATA_SIZE = struct.calcsize(ST_QDATA)*NSAMPLES + struct.calcsize(ST_DOM_INFO)*NDOMAINS + struct.calcsize("4i")
    8.49 +
    8.50 +# location of mmaped file, hard coded right now
    8.51 +SHM_FILE = "/tmp/xenq-shm"
    8.52 +
    8.53 +# format strings
    8.54 +TOTALS = 15*' ' + "%6.2f%%" + 35*' ' + "%6.2f%%"
    8.55 +
    8.56 +ALLOCATED = "Allocated"
    8.57 +GOTTEN = "Gotten"
    8.58 +BLOCKED = "Blocked"
    8.59 +WAITED = "Waited"
    8.60 +IOCOUNT = "I/O Count"
    8.61 +EXCOUNT = "Exec Count"
    8.62 +
    8.63 +# globals
    8.64 +# our curses screen
    8.65 +stdscr = None
    8.66 +
    8.67 +# parsed options
    8.68 +options, args = None, None
    8.69 +
    8.70 +# the optparse module is quite smart
    8.71 +# to see help, just run xenmon -h
    8.72 +def setup_cmdline_parser():
    8.73 +    parser = _o.OptionParser()
    8.74 +    parser.add_option("-l", "--live", dest="live", action="store_true",
    8.75 +                      default=True, help = "show the ncurses live monitoring frontend (default)")
    8.76 +    parser.add_option("-n", "--notlive", dest="live", action="store_false",
    8.77 +                      default="True", help = "write to file instead of live monitoring")
    8.78 +    parser.add_option("-p", "--prefix", dest="prefix",
    8.79 +                      default = "log", help="prefix to use for output files")
    8.80 +    parser.add_option("-t", "--time", dest="duration",
    8.81 +            action="store", type="int", default=10, 
    8.82 +            help="stop logging to file after this much time has elapsed (in seconds). set to 0 to keep logging indefinitely")
    8.83 +    parser.add_option("-i", "--interval", dest="interval",
    8.84 +            action="store", type="int", default=1000,
    8.85 +            help="interval for logging (in ms)")
    8.86 +    parser.add_option("--ms_per_sample", dest="mspersample",
    8.87 +            action="store", type="int", default=100,
    8.88 +            help = "determines how many ms worth of data goes in a sample")
    8.89 +    return parser
    8.90 +
    8.91 +# encapsulate information about a domain
    8.92 +class DomainInfo:
    8.93 +    def __init__(self):
    8.94 +        self.allocated_samples = []
    8.95 +        self.gotten_samples = []
    8.96 +        self.blocked_samples = []
    8.97 +        self.waited_samples = []
    8.98 +        self.execcount_samples = []
    8.99 +        self.iocount_samples = []
   8.100 +        self.ffp_samples = []
   8.101 +
   8.102 +    def gotten_stats(self, passed):
   8.103 +        total = float(sum(self.gotten_samples))
   8.104 +        per = 100*total/passed
   8.105 +        exs = sum(self.execcount_samples)
   8.106 +        if exs > 0:
   8.107 +            avg = total/exs
   8.108 +        else:
   8.109 +            avg = 0
   8.110 +        return [total/(float(passed)/10**9), per, avg]
   8.111 +
   8.112 +    def waited_stats(self, passed):
   8.113 +        total = float(sum(self.waited_samples))
   8.114 +        per = 100*total/passed
   8.115 +        exs = sum(self.execcount_samples)
   8.116 +        if exs > 0:
   8.117 +            avg = total/exs
   8.118 +        else:
   8.119 +            avg = 0
   8.120 +        return [total/(float(passed)/10**9), per, avg]
   8.121 +
   8.122 +    def blocked_stats(self, passed):
   8.123 +        total = float(sum(self.blocked_samples))
   8.124 +        per = 100*total/passed
   8.125 +        ios = sum(self.iocount_samples)
   8.126 +        if ios > 0:
   8.127 +            avg = total/float(ios)
   8.128 +        else:
   8.129 +            avg = 0
   8.130 +        return [total/(float(passed)/10**9), per, avg]
   8.131 +
   8.132 +    def allocated_stats(self, passed):
   8.133 +        total = sum(self.allocated_samples)
   8.134 +        exs = sum(self.execcount_samples)
   8.135 +        if exs > 0:
   8.136 +            return float(total)/exs
   8.137 +        else:
   8.138 +            return 0
   8.139 +
   8.140 +    def ec_stats(self, passed):
   8.141 +        total = float(sum(self.execcount_samples))/(float(passed)/10**9)
   8.142 +        return total
   8.143 +
   8.144 +    def io_stats(self, passed):
   8.145 +        total = float(sum(self.iocount_samples))
   8.146 +        exs = sum(self.execcount_samples)
   8.147 +        if exs > 0:
   8.148 +            avg = total/exs
   8.149 +        else:
   8.150 +            avg = 0
   8.151 +        return [total/(float(passed)/10**9), avg]
   8.152 +
   8.153 +    def stats(self, passed):
   8.154 +        return [self.gotten_stats(passed), self.allocated_stats(passed), self.blocked_stats(passed), 
   8.155 +                self.waited_stats(passed), self.ec_stats(passed), self.io_stats(passed)]
   8.156 +
   8.157 +# report values over desired interval
   8.158 +def summarize(startat, endat, duration, samples):
   8.159 +    dominfos = {}
   8.160 +    for i in range(0, NDOMAINS):
   8.161 +        dominfos[i] = DomainInfo()
   8.162 +        
   8.163 +    passed = 1              # to prevent zero division
   8.164 +    curid = startat
   8.165 +    numbuckets = 0
   8.166 +    lost_samples = []
   8.167 +    ffp_samples = []
   8.168 +    
   8.169 +    while passed < duration:
   8.170 +        for i in range(0, NDOMAINS):
   8.171 +            dominfos[i].gotten_samples.append(samples[curid][0*NDOMAINS + i])
   8.172 +            dominfos[i].allocated_samples.append(samples[curid][1*NDOMAINS + i])
   8.173 +            dominfos[i].waited_samples.append(samples[curid][2*NDOMAINS + i])
   8.174 +            dominfos[i].blocked_samples.append(samples[curid][3*NDOMAINS + i])
   8.175 +            dominfos[i].execcount_samples.append(samples[curid][4*NDOMAINS + i])
   8.176 +            dominfos[i].iocount_samples.append(samples[curid][5*NDOMAINS + i])
   8.177 +    
   8.178 +        passed += samples[curid][6*NDOMAINS]
   8.179 +        lost_samples.append(samples[curid][6*NDOMAINS + 2])
   8.180 +        ffp_samples.append(samples[curid][6*NDOMAINS + 3])
   8.181 +
   8.182 +        numbuckets += 1
   8.183 +
   8.184 +        if curid > 0:
   8.185 +            curid -= 1
   8.186 +        else:
   8.187 +            curid = NSAMPLES - 1
   8.188 +        if curid == endat:
   8.189 +            break
   8.190 +
   8.191 +    lostinfo = [min(lost_samples), sum(lost_samples), max(lost_samples)]
   8.192 +    ffpinfo = [min(ffp_samples), sum(ffp_samples), max(ffp_samples)]
   8.193 +    ldoms = map(lambda x: dominfos[x].stats(passed), range(0, NDOMAINS))
   8.194 +
   8.195 +    return [ldoms, lostinfo, ffpinfo]
   8.196 +
   8.197 +# scale microseconds to milliseconds or seconds as necessary
   8.198 +def time_scale(ns):
   8.199 +    if ns < 1000:
   8.200 +        return "%4.2f ns" % float(ns)
   8.201 +    elif ns < 1000*1000:
   8.202 +        return "%4.2f us" % (float(ns)/10**3)
   8.203 +    elif ns < 10**9:
   8.204 +	    return "%4.2f ms" % (float(ns)/10**6)
   8.205 +    else:
   8.206 +        return "%4.2f s" % (float(ns)/10**9)
   8.207 +
   8.208 +# paint message on curses screen, but detect screen size errors
   8.209 +def display(scr, row, col, str, attr=0):
   8.210 +    try:
   8.211 +        scr.addstr(row, col, str, attr)
   8.212 +    except:
   8.213 +        scr.erase()
   8.214 +        _c.nocbreak()
   8.215 +        scr.keypad(0)
   8.216 +        _c.echo()
   8.217 +        _c.endwin()
   8.218 +        print "Your terminal screen is not big enough; Please resize it."
   8.219 +        print "row=%d, col=%d, str='%s'" % (row, col, str)
   8.220 +        sys.exit(1)
   8.221 +
   8.222 +
   8.223 +# the live monitoring code
   8.224 +def show_livestats():
   8.225 +    cpu = 0          # cpu of interest to display data for
   8.226 +    ncpu = 1         # number of cpu's on this platform
   8.227 +    slen = 0         # size of shared data structure, incuding padding
   8.228 +    
   8.229 +    # mmap the (the first chunk of the) file
   8.230 +    shmf = open(SHM_FILE, "r+")
   8.231 +    shm = mmap.mmap(shmf.fileno(), QOS_DATA_SIZE)
   8.232 +
   8.233 +    samples = []
   8.234 +    doms = []
   8.235 +
   8.236 +    # initialize curses
   8.237 +    stdscr = _c.initscr()
   8.238 +    _c.noecho()
   8.239 +    _c.cbreak()
   8.240 +
   8.241 +    stdscr.keypad(1)
   8.242 +    stdscr.timeout(1000)
   8.243 +    [maxy, maxx] = stdscr.getmaxyx()
   8.244 +
   8.245 +    
   8.246 +
   8.247 +    # display in a loop
   8.248 +    while True:
   8.249 +
   8.250 +        for cpuidx in range(0, ncpu):
   8.251 +
   8.252 +            # calculate offset in mmap file to start from
   8.253 +            idx = cpuidx * slen
   8.254 +
   8.255 +
   8.256 +            samples = []
   8.257 +            doms = []
   8.258 +
   8.259 +            # read in data
   8.260 +            for i in range(0, NSAMPLES):
   8.261 +                len = struct.calcsize(ST_QDATA)
   8.262 +                sample = struct.unpack(ST_QDATA, shm[idx:idx+len])
   8.263 +                samples.append(sample)
   8.264 +                idx += len
   8.265 +
   8.266 +            for i in range(0, NDOMAINS):
   8.267 +                len = struct.calcsize(ST_DOM_INFO)
   8.268 +                dom = struct.unpack(ST_DOM_INFO, shm[idx:idx+len])
   8.269 +                doms.append(dom)
   8.270 +                idx += len
   8.271 +
   8.272 +            len = struct.calcsize("4i")
   8.273 +            oldncpu = ncpu
   8.274 +            (next, ncpu, slen, freq) = struct.unpack("4i", shm[idx:idx+len])
   8.275 +            idx += len
   8.276 +
   8.277 +            # xenbaked tells us how many cpu's it's got, so re-do
   8.278 +            # the mmap if necessary to get multiple cpu data
   8.279 +            if oldncpu != ncpu:
   8.280 +                shm = mmap.mmap(shmf.fileno(), ncpu*slen)
   8.281 +
   8.282 +            # if we've just calculated data for the cpu of interest, then
   8.283 +            # stop examining mmap data and start displaying stuff
   8.284 +            if cpuidx == cpu:
   8.285 +                break
   8.286 +
   8.287 +        # calculate starting and ending datapoints; never look at "next" since
   8.288 +        # it represents live data that may be in transition. 
   8.289 +        startat = next - 1
   8.290 +        if next + 10 < NSAMPLES:
   8.291 +            endat = next + 10
   8.292 +        else:
   8.293 +            endat = 10
   8.294 +
   8.295 +        # get summary over desired interval
   8.296 +        [h1, l1, f1] = summarize(startat, endat, 10**9, samples)
   8.297 +        [h2, l2, f2] = summarize(startat, endat, 10 * 10**9, samples)
   8.298 +
   8.299 +        # the actual display code
   8.300 +        row = 0
   8.301 +        display(stdscr, row, 1, "CPU = %d" % cpu, _c.A_STANDOUT)
   8.302 +
   8.303 +        display(stdscr, row, 10, "%sLast 10 seconds%sLast 1 second" % (6*' ', 30*' '), _c.A_BOLD)
   8.304 +        row +=1
   8.305 +        display(stdscr, row, 1, "%s" % ((maxx-2)*'='))
   8.306 +
   8.307 +        total_h1_cpu = 0
   8.308 +        total_h2_cpu = 0
   8.309 +
   8.310 +        for dom in range(0, NDOMAINS):
   8.311 +            if h1[dom][0][1] > 0 or dom == NDOMAINS - 1:
   8.312 +                # display gotten
   8.313 +                row += 1 
   8.314 +                col = 2
   8.315 +                display(stdscr, row, col, "%d" % dom)
   8.316 +                col += 4
   8.317 +                display(stdscr, row, col, "%s" % time_scale(h2[dom][0][0]))
   8.318 +                col += 12
   8.319 +                display(stdscr, row, col, "%3.2f%%" % h2[dom][0][1])
   8.320 +                col += 12
   8.321 +                display(stdscr, row, col, "%s/ex" % time_scale(h2[dom][0][2]))
   8.322 +                col += 18
   8.323 +                display(stdscr, row, col, "%s" % time_scale(h1[dom][0][0]))
   8.324 +                col += 12
   8.325 +                display(stdscr, row, col, "%3.2f%%" % h1[dom][0][1])
   8.326 +                col += 12
   8.327 +                display(stdscr, row, col, "%s/ex" % time_scale(h1[dom][0][2]))
   8.328 +                col += 18
   8.329 +                display(stdscr, row, col, "Gotten")
   8.330 +    
   8.331 +                # display allocated
   8.332 +                row += 1
   8.333 +                col = 2
   8.334 +                display(stdscr, row, col, "%d" % dom)
   8.335 +                col += 28
   8.336 +                display(stdscr, row, col, "%s/ex" % time_scale(h2[dom][1]))
   8.337 +                col += 42
   8.338 +                display(stdscr, row, col, "%s/ex" % time_scale(h1[dom][1]))
   8.339 +                col += 18
   8.340 +                display(stdscr, row, col, "Allocated")
   8.341 +
   8.342 +                # display blocked
   8.343 +                row += 1
   8.344 +                col = 2
   8.345 +                display(stdscr, row, col, "%d" % dom)
   8.346 +                col += 4
   8.347 +                display(stdscr, row, col, "%s" % time_scale(h2[dom][2][0]))
   8.348 +                col += 12
   8.349 +                display(stdscr, row, col, "%3.2f%%" % h2[dom][2][1])
   8.350 +                col += 12
   8.351 +                display(stdscr, row, col, "%s/io" % time_scale(h2[dom][2][2]))
   8.352 +                col += 18
   8.353 +                display(stdscr, row, col, "%s" % time_scale(h1[dom][2][0]))
   8.354 +                col += 12
   8.355 +                display(stdscr, row, col, "%3.2f%%" % h1[dom][2][1])
   8.356 +                col += 12
   8.357 +                display(stdscr, row, col, "%s/io" % time_scale(h1[dom][2][2]))
   8.358 +                col += 18
   8.359 +                display(stdscr, row, col, "Blocked")
   8.360 +
   8.361 +                # display waited
   8.362 +                row += 1
   8.363 +                col = 2
   8.364 +                display(stdscr, row, col, "%d" % dom)
   8.365 +                col += 4
   8.366 +                display(stdscr, row, col, "%s" % time_scale(h2[dom][3][0]))
   8.367 +                col += 12
   8.368 +                display(stdscr, row, col, "%3.2f%%" % h2[dom][3][1])
   8.369 +                col += 12
   8.370 +                display(stdscr, row, col, "%s/ex" % time_scale(h2[dom][3][2]))
   8.371 +                col += 18
   8.372 +                display(stdscr, row, col, "%s" % time_scale(h1[dom][3][0]))
   8.373 +                col += 12
   8.374 +                display(stdscr, row, col, "%3.2f%%" % h1[dom][3][1])
   8.375 +                col += 12
   8.376 +                display(stdscr, row, col, "%s/ex" % time_scale(h1[dom][3][2]))
   8.377 +                col += 18
   8.378 +                display(stdscr, row, col, "Waited")
   8.379 +
   8.380 +                # display ex count
   8.381 +                row += 1
   8.382 +                col = 2
   8.383 +                display(stdscr, row, col, "%d" % dom)
   8.384 +
   8.385 +                col += 28
   8.386 +                display(stdscr, row, col, "%d/s" % h2[dom][4])
   8.387 +                col += 42
   8.388 +                display(stdscr, row, col, "%d" % h1[dom][4])
   8.389 +                col += 18
   8.390 +                display(stdscr, row, col, "Execution count")
   8.391 +
   8.392 +                # display io count
   8.393 +                row += 1
   8.394 +                col = 2
   8.395 +                display(stdscr, row, col, "%d" % dom)
   8.396 +                col += 4
   8.397 +                display(stdscr, row, col, "%d/s" % h2[dom][5][0])
   8.398 +                col += 24
   8.399 +                display(stdscr, row, col, "%d/ex" % h2[dom][5][1])
   8.400 +                col += 18
   8.401 +                display(stdscr, row, col, "%d" % h1[dom][5][0])
   8.402 +                col += 24
   8.403 +                display(stdscr, row, col, "%3.2f/ex" % h1[dom][5][1])
   8.404 +                col += 18
   8.405 +                display(stdscr, row, col, "I/O Count")
   8.406 +
   8.407 +            #row += 1
   8.408 +            #stdscr.hline(row, 1, '-', maxx - 2)
   8.409 +            total_h1_cpu += h1[dom][0][1]
   8.410 +            total_h2_cpu += h2[dom][0][1]
   8.411 +
   8.412 +
   8.413 +        row += 1
   8.414 +        display(stdscr, row, 2, TOTALS % (total_h2_cpu, total_h1_cpu))
   8.415 +        row += 1
   8.416 +#        display(stdscr, row, 2, 
   8.417 +#                "\tFFP: %d (Min: %d, Max: %d)\t\t\tFFP: %d (Min: %d, Max %d)" % 
   8.418 +#                (math.ceil(f2[1]), f2[0], f2[2], math.ceil(f1[1]), f1[0], f1[2]), _c.A_BOLD)
   8.419 +
   8.420 +        if l1[1] > 1 :
   8.421 +            row += 1
   8.422 +            display(stdscr, row, 2, 
   8.423 +                    "\tRecords lost: %d (Min: %d, Max: %d)\t\t\tRecords lost: %d (Min: %d, Max %d)" % 
   8.424 +                    (math.ceil(l2[1]), l2[0], l2[2], math.ceil(l1[1]), l1[0], l1[2]), _c.A_BOLD)
   8.425 +
   8.426 +        # grab a char from tty input; exit if interrupt hit
   8.427 +        try:
   8.428 +            c = stdscr.getch()
   8.429 +        except:
   8.430 +            break
   8.431 +        
   8.432 +        # q = quit
   8.433 +        if c == ord('q'):
   8.434 +            break
   8.435 +    
   8.436 +        # c = cycle to a new cpu of interest
   8.437 +        if c == ord('c'):
   8.438 +            cpu = (cpu + 1) % ncpu
   8.439 +
   8.440 +        stdscr.erase()
   8.441 +
   8.442 +    _c.nocbreak()
   8.443 +    stdscr.keypad(0)
   8.444 +    _c.echo()
   8.445 +    _c.endwin()
   8.446 +    shm.close()
   8.447 +    shmf.close()
   8.448 +
   8.449 +
   8.450 +# simple functions to allow initialization of log files without actually
   8.451 +# physically creating files that are never used; only on the first real
   8.452 +# write does the file get created
   8.453 +class Delayed(file):
   8.454 +    def __init__(self, filename, mode):
   8.455 +	self.filename = filename
   8.456 +	self.saved_mode = mode
   8.457 +	self.delay_data = ""
   8.458 +	self.opened = 0
   8.459 +
   8.460 +    def delayed_write(self, str):
   8.461 +	self.delay_data = str
   8.462 +
   8.463 +    def write(self, str):
   8.464 +	if not self.opened:
   8.465 +	    self.file = open(self.filename, self.saved_mode)
   8.466 +	    self.opened = 1
   8.467 +            self.file.write(self.delay_data)
   8.468 +	self.file.write(str)
   8.469 +
   8.470 +    def flush(self):
   8.471 +        if  self.opened:
   8.472 +            self.file.flush()
   8.473 +
   8.474 +    def close(self):
   8.475 +        if  self.opened:
   8.476 +            self.file.close()
   8.477 +            
   8.478 +
   8.479 +def writelog():
   8.480 +    global options
   8.481 +
   8.482 +    ncpu = 1        # number of cpu's
   8.483 +    slen = 0        # size of shared structure inc. padding
   8.484 +
   8.485 +    shmf = open(SHM_FILE, "r+")
   8.486 +    shm = mmap.mmap(shmf.fileno(), QOS_DATA_SIZE)
   8.487 +
   8.488 +    interval = 0
   8.489 +    outfiles = {}
   8.490 +    for dom in range(0, NDOMAINS):
   8.491 +        outfiles[dom] = Delayed("%s-dom%d.log" % (options.prefix, dom), 'w')
   8.492 +        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")
   8.493 +
   8.494 +    while options.duration == 0 or interval < (options.duration * 1000):
   8.495 +        for cpuidx in range(0, ncpu):
   8.496 +            idx = cpuidx * slen      # offset needed in mmap file
   8.497 +
   8.498 +
   8.499 +            samples = []
   8.500 +            doms = []
   8.501 +
   8.502 +            for i in range(0, NSAMPLES):
   8.503 +                len = struct.calcsize(ST_QDATA)
   8.504 +                sample = struct.unpack(ST_QDATA, shm[idx:idx+len])
   8.505 +                samples.append(sample)
   8.506 +                idx += len
   8.507 +
   8.508 +            for i in range(0, NDOMAINS):
   8.509 +                len = struct.calcsize(ST_DOM_INFO)
   8.510 +                dom = struct.unpack(ST_DOM_INFO, shm[idx:idx+len])
   8.511 +                doms.append(dom)
   8.512 +                idx += len
   8.513 +
   8.514 +            len = struct.calcsize("4i")
   8.515 +            oldncpu = ncpu
   8.516 +            (next, ncpu, slen, freq) = struct.unpack("4i", shm[idx:idx+len])
   8.517 +            idx += len
   8.518 +
   8.519 +            if oldncpu != ncpu:
   8.520 +                shm = mmap.mmap(shmf.fileno(), ncpu*slen)
   8.521 +
   8.522 +            startat = next - 1
   8.523 +            if next + 10 < NSAMPLES:
   8.524 +                endat = next + 10
   8.525 +            else:
   8.526 +                endat = 10
   8.527 +
   8.528 +            [h1,l1, f1] = summarize(startat, endat, options.interval * 10**6, samples)
   8.529 +            for dom in range(0, NDOMAINS):
   8.530 +                if h1[dom][0][1] > 0 or dom == NDOMAINS - 1:
   8.531 +                    outfiles[dom].write("%.3f %d %d %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f\n" %
   8.532 +                                     (interval, cpuidx, dom,
   8.533 +                                     h1[dom][0][0], h1[dom][0][1], h1[dom][0][2],
   8.534 +                                     h1[dom][1],
   8.535 +                                     h1[dom][2][0], h1[dom][2][1], h1[dom][2][2],
   8.536 +                                     h1[dom][3][0], h1[dom][3][1], h1[dom][3][2],
   8.537 +                                     h1[dom][4], 
   8.538 +                                     h1[dom][5][0], h1[dom][5][1]))
   8.539 +                    outfiles[dom].flush()
   8.540 +
   8.541 +        interval += options.interval
   8.542 +        time.sleep(1)
   8.543 +
   8.544 +    for dom in range(0, NDOMAINS):
   8.545 +        outfiles[dom].close()
   8.546 +
   8.547 +# start xenbaked
   8.548 +def start_xenbaked():
   8.549 +    global options
   8.550 +    global args
   8.551 +    
   8.552 +    os.system("killall -9 xenbaked")
   8.553 +    # assumes that xenbaked is in your path
   8.554 +    os.system("xenbaked --ms_per_sample=%d &" %
   8.555 +              options.mspersample)
   8.556 +    time.sleep(1)
   8.557 +
   8.558 +# stop xenbaked
   8.559 +def stop_xenbaked():
   8.560 +    os.system("killall -s INT xenbaked")
   8.561 +
   8.562 +def main():
   8.563 +    global options
   8.564 +    global args
   8.565 +    global domains
   8.566 +
   8.567 +    parser = setup_cmdline_parser()
   8.568 +    (options, args) = parser.parse_args()
   8.569 +    
   8.570 +    start_xenbaked()
   8.571 +    if options.live:
   8.572 +        show_livestats()
   8.573 +    else:
   8.574 +        try:
   8.575 +            writelog()
   8.576 +        except:
   8.577 +            print 'Quitting.'
   8.578 +    stop_xenbaked()
   8.579 +
   8.580 +if __name__ == "__main__":
   8.581 +    main()
     9.1 --- a/tools/xentrace/setsize.c	Tue Nov 15 14:59:59 2005 +0100
     9.2 +++ b/tools/xentrace/setsize.c	Tue Nov 15 15:09:58 2005 +0100
     9.3 @@ -9,9 +9,9 @@ int main(int argc, char * argv[])
     9.4    int xc_handle = xc_interface_open();
     9.5    
     9.6    if (xc_tbuf_get_size(xc_handle, &size) != 0) {
     9.7 -    perror("Failure to get tbuf info from Xen. Guess size is 0.");
     9.8 -    printf("This may mean that tracing is not compiled into xen.\n");
     9.9 -    exit(1);
    9.10 +    perror("Failure to get tbuf info from Xen. Guess size is 0");
    9.11 +    printf("This may mean that tracing is not enabled in xen.\n");
    9.12 +    //    exit(1);
    9.13    }
    9.14    else
    9.15      printf("Current tbuf size: 0x%x\n", size);
    9.16 @@ -25,9 +25,10 @@ int main(int argc, char * argv[])
    9.17      perror("set_size Hypercall failure");
    9.18      exit(1);
    9.19    }
    9.20 +  printf("set_size succeeded.\n");
    9.21    
    9.22    if (xc_tbuf_get_size(xc_handle, &size) != 0)
    9.23 -    perror("Failure to get tbuf info from Xen. Guess size is 0.");
    9.24 +    perror("Failure to get tbuf info from Xen. Tracing must be enabled first");
    9.25    else
    9.26      printf("New tbuf size: 0x%x\n", size);
    9.27