ia64/xen-unstable

changeset 7824:1831da8249ba

Merged.
author emellor@leeni.uk.xensource.com
date Tue Nov 15 15:44:37 2005 +0100 (2005-11-15)
parents 97d11e40d8ca e60d8a3ad96e
children 4bdcb7f8c3d7
files
line diff
     1.1 --- a/.hgignore	Tue Nov 15 15:36:42 2005 +0100
     1.2 +++ b/.hgignore	Tue Nov 15 15:44:37 2005 +0100
     1.3 @@ -148,6 +148,8 @@
     1.4  ^tools/vtpm_manager/manager/vtpm_managerd$
     1.5  ^tools/xcutils/xc_restore$
     1.6  ^tools/xcutils/xc_save$
     1.7 +^tools/xenmon/setmask$
     1.8 +^tools/xenmon/xenbaked$
     1.9  ^tools/xenstat/xentop/xentop$
    1.10  ^tools/xenstore/testsuite/tmp/.*$
    1.11  ^tools/xenstore/xen$
     2.1 --- a/tools/Makefile	Tue Nov 15 15:36:42 2005 +0100
     2.2 +++ b/tools/Makefile	Tue Nov 15 15:44:37 2005 +0100
     2.3 @@ -11,6 +11,7 @@ SUBDIRS += xcutils
     2.4  SUBDIRS += firmware
     2.5  SUBDIRS += security
     2.6  SUBDIRS += console
     2.7 +SUBDIRS += xenmon
     2.8  ifeq ($(VTPM_TOOLS),y)
     2.9  SUBDIRS += vtpm_manager
    2.10  SUBDIRS += vtpm
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/tools/xenmon/COPYING	Tue Nov 15 15:44:37 2005 +0100
     3.3 @@ -0,0 +1,340 @@
     3.4 +		    GNU GENERAL PUBLIC LICENSE
     3.5 +		       Version 2, June 1991
     3.6 +
     3.7 + Copyright (C) 1989, 1991 Free Software Foundation, Inc.
     3.8 +                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
     3.9 + Everyone is permitted to copy and distribute verbatim copies
    3.10 + of this license document, but changing it is not allowed.
    3.11 +
    3.12 +			    Preamble
    3.13 +
    3.14 +  The licenses for most software are designed to take away your
    3.15 +freedom to share and change it.  By contrast, the GNU General Public
    3.16 +License is intended to guarantee your freedom to share and change free
    3.17 +software--to make sure the software is free for all its users.  This
    3.18 +General Public License applies to most of the Free Software
    3.19 +Foundation's software and to any other program whose authors commit to
    3.20 +using it.  (Some other Free Software Foundation software is covered by
    3.21 +the GNU Library General Public License instead.)  You can apply it to
    3.22 +your programs, too.
    3.23 +
    3.24 +  When we speak of free software, we are referring to freedom, not
    3.25 +price.  Our General Public Licenses are designed to make sure that you
    3.26 +have the freedom to distribute copies of free software (and charge for
    3.27 +this service if you wish), that you receive source code or can get it
    3.28 +if you want it, that you can change the software or use pieces of it
    3.29 +in new free programs; and that you know you can do these things.
    3.30 +
    3.31 +  To protect your rights, we need to make restrictions that forbid
    3.32 +anyone to deny you these rights or to ask you to surrender the rights.
    3.33 +These restrictions translate to certain responsibilities for you if you
    3.34 +distribute copies of the software, or if you modify it.
    3.35 +
    3.36 +  For example, if you distribute copies of such a program, whether
    3.37 +gratis or for a fee, you must give the recipients all the rights that
    3.38 +you have.  You must make sure that they, too, receive or can get the
    3.39 +source code.  And you must show them these terms so they know their
    3.40 +rights.
    3.41 +
    3.42 +  We protect your rights with two steps: (1) copyright the software, and
    3.43 +(2) offer you this license which gives you legal permission to copy,
    3.44 +distribute and/or modify the software.
    3.45 +
    3.46 +  Also, for each author's protection and ours, we want to make certain
    3.47 +that everyone understands that there is no warranty for this free
    3.48 +software.  If the software is modified by someone else and passed on, we
    3.49 +want its recipients to know that what they have is not the original, so
    3.50 +that any problems introduced by others will not reflect on the original
    3.51 +authors' reputations.
    3.52 +
    3.53 +  Finally, any free program is threatened constantly by software
    3.54 +patents.  We wish to avoid the danger that redistributors of a free
    3.55 +program will individually obtain patent licenses, in effect making the
    3.56 +program proprietary.  To prevent this, we have made it clear that any
    3.57 +patent must be licensed for everyone's free use or not licensed at all.
    3.58 +
    3.59 +  The precise terms and conditions for copying, distribution and
    3.60 +modification follow.
    3.61 +
    3.62 +		    GNU GENERAL PUBLIC LICENSE
    3.63 +   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
    3.64 +
    3.65 +  0. This License applies to any program or other work which contains
    3.66 +a notice placed by the copyright holder saying it may be distributed
    3.67 +under the terms of this General Public License.  The "Program", below,
    3.68 +refers to any such program or work, and a "work based on the Program"
    3.69 +means either the Program or any derivative work under copyright law:
    3.70 +that is to say, a work containing the Program or a portion of it,
    3.71 +either verbatim or with modifications and/or translated into another
    3.72 +language.  (Hereinafter, translation is included without limitation in
    3.73 +the term "modification".)  Each licensee is addressed as "you".
    3.74 +
    3.75 +Activities other than copying, distribution and modification are not
    3.76 +covered by this License; they are outside its scope.  The act of
    3.77 +running the Program is not restricted, and the output from the Program
    3.78 +is covered only if its contents constitute a work based on the
    3.79 +Program (independent of having been made by running the Program).
    3.80 +Whether that is true depends on what the Program does.
    3.81 +
    3.82 +  1. You may copy and distribute verbatim copies of the Program's
    3.83 +source code as you receive it, in any medium, provided that you
    3.84 +conspicuously and appropriately publish on each copy an appropriate
    3.85 +copyright notice and disclaimer of warranty; keep intact all the
    3.86 +notices that refer to this License and to the absence of any warranty;
    3.87 +and give any other recipients of the Program a copy of this License
    3.88 +along with the Program.
    3.89 +
    3.90 +You may charge a fee for the physical act of transferring a copy, and
    3.91 +you may at your option offer warranty protection in exchange for a fee.
    3.92 +
    3.93 +  2. You may modify your copy or copies of the Program or any portion
    3.94 +of it, thus forming a work based on the Program, and copy and
    3.95 +distribute such modifications or work under the terms of Section 1
    3.96 +above, provided that you also meet all of these conditions:
    3.97 +
    3.98 +    a) You must cause the modified files to carry prominent notices
    3.99 +    stating that you changed the files and the date of any change.
   3.100 +
   3.101 +    b) You must cause any work that you distribute or publish, that in
   3.102 +    whole or in part contains or is derived from the Program or any
   3.103 +    part thereof, to be licensed as a whole at no charge to all third
   3.104 +    parties under the terms of this License.
   3.105 +
   3.106 +    c) If the modified program normally reads commands interactively
   3.107 +    when run, you must cause it, when started running for such
   3.108 +    interactive use in the most ordinary way, to print or display an
   3.109 +    announcement including an appropriate copyright notice and a
   3.110 +    notice that there is no warranty (or else, saying that you provide
   3.111 +    a warranty) and that users may redistribute the program under
   3.112 +    these conditions, and telling the user how to view a copy of this
   3.113 +    License.  (Exception: if the Program itself is interactive but
   3.114 +    does not normally print such an announcement, your work based on
   3.115 +    the Program is not required to print an announcement.)
   3.116 +
   3.117 +These requirements apply to the modified work as a whole.  If
   3.118 +identifiable sections of that work are not derived from the Program,
   3.119 +and can be reasonably considered independent and separate works in
   3.120 +themselves, then this License, and its terms, do not apply to those
   3.121 +sections when you distribute them as separate works.  But when you
   3.122 +distribute the same sections as part of a whole which is a work based
   3.123 +on the Program, the distribution of the whole must be on the terms of
   3.124 +this License, whose permissions for other licensees extend to the
   3.125 +entire whole, and thus to each and every part regardless of who wrote it.
   3.126 +
   3.127 +Thus, it is not the intent of this section to claim rights or contest
   3.128 +your rights to work written entirely by you; rather, the intent is to
   3.129 +exercise the right to control the distribution of derivative or
   3.130 +collective works based on the Program.
   3.131 +
   3.132 +In addition, mere aggregation of another work not based on the Program
   3.133 +with the Program (or with a work based on the Program) on a volume of
   3.134 +a storage or distribution medium does not bring the other work under
   3.135 +the scope of this License.
   3.136 +
   3.137 +  3. You may copy and distribute the Program (or a work based on it,
   3.138 +under Section 2) in object code or executable form under the terms of
   3.139 +Sections 1 and 2 above provided that you also do one of the following:
   3.140 +
   3.141 +    a) Accompany it with the complete corresponding machine-readable
   3.142 +    source code, which must be distributed under the terms of Sections
   3.143 +    1 and 2 above on a medium customarily used for software interchange; or,
   3.144 +
   3.145 +    b) Accompany it with a written offer, valid for at least three
   3.146 +    years, to give any third party, for a charge no more than your
   3.147 +    cost of physically performing source distribution, a complete
   3.148 +    machine-readable copy of the corresponding source code, to be
   3.149 +    distributed under the terms of Sections 1 and 2 above on a medium
   3.150 +    customarily used for software interchange; or,
   3.151 +
   3.152 +    c) Accompany it with the information you received as to the offer
   3.153 +    to distribute corresponding source code.  (This alternative is
   3.154 +    allowed only for noncommercial distribution and only if you
   3.155 +    received the program in object code or executable form with such
   3.156 +    an offer, in accord with Subsection b above.)
   3.157 +
   3.158 +The source code for a work means the preferred form of the work for
   3.159 +making modifications to it.  For an executable work, complete source
   3.160 +code means all the source code for all modules it contains, plus any
   3.161 +associated interface definition files, plus the scripts used to
   3.162 +control compilation and installation of the executable.  However, as a
   3.163 +special exception, the source code distributed need not include
   3.164 +anything that is normally distributed (in either source or binary
   3.165 +form) with the major components (compiler, kernel, and so on) of the
   3.166 +operating system on which the executable runs, unless that component
   3.167 +itself accompanies the executable.
   3.168 +
   3.169 +If distribution of executable or object code is made by offering
   3.170 +access to copy from a designated place, then offering equivalent
   3.171 +access to copy the source code from the same place counts as
   3.172 +distribution of the source code, even though third parties are not
   3.173 +compelled to copy the source along with the object code.
   3.174 +
   3.175 +  4. You may not copy, modify, sublicense, or distribute the Program
   3.176 +except as expressly provided under this License.  Any attempt
   3.177 +otherwise to copy, modify, sublicense or distribute the Program is
   3.178 +void, and will automatically terminate your rights under this License.
   3.179 +However, parties who have received copies, or rights, from you under
   3.180 +this License will not have their licenses terminated so long as such
   3.181 +parties remain in full compliance.
   3.182 +
   3.183 +  5. You are not required to accept this License, since you have not
   3.184 +signed it.  However, nothing else grants you permission to modify or
   3.185 +distribute the Program or its derivative works.  These actions are
   3.186 +prohibited by law if you do not accept this License.  Therefore, by
   3.187 +modifying or distributing the Program (or any work based on the
   3.188 +Program), you indicate your acceptance of this License to do so, and
   3.189 +all its terms and conditions for copying, distributing or modifying
   3.190 +the Program or works based on it.
   3.191 +
   3.192 +  6. Each time you redistribute the Program (or any work based on the
   3.193 +Program), the recipient automatically receives a license from the
   3.194 +original licensor to copy, distribute or modify the Program subject to
   3.195 +these terms and conditions.  You may not impose any further
   3.196 +restrictions on the recipients' exercise of the rights granted herein.
   3.197 +You are not responsible for enforcing compliance by third parties to
   3.198 +this License.
   3.199 +
   3.200 +  7. If, as a consequence of a court judgment or allegation of patent
   3.201 +infringement or for any other reason (not limited to patent issues),
   3.202 +conditions are imposed on you (whether by court order, agreement or
   3.203 +otherwise) that contradict the conditions of this License, they do not
   3.204 +excuse you from the conditions of this License.  If you cannot
   3.205 +distribute so as to satisfy simultaneously your obligations under this
   3.206 +License and any other pertinent obligations, then as a consequence you
   3.207 +may not distribute the Program at all.  For example, if a patent
   3.208 +license would not permit royalty-free redistribution of the Program by
   3.209 +all those who receive copies directly or indirectly through you, then
   3.210 +the only way you could satisfy both it and this License would be to
   3.211 +refrain entirely from distribution of the Program.
   3.212 +
   3.213 +If any portion of this section is held invalid or unenforceable under
   3.214 +any particular circumstance, the balance of the section is intended to
   3.215 +apply and the section as a whole is intended to apply in other
   3.216 +circumstances.
   3.217 +
   3.218 +It is not the purpose of this section to induce you to infringe any
   3.219 +patents or other property right claims or to contest validity of any
   3.220 +such claims; this section has the sole purpose of protecting the
   3.221 +integrity of the free software distribution system, which is
   3.222 +implemented by public license practices.  Many people have made
   3.223 +generous contributions to the wide range of software distributed
   3.224 +through that system in reliance on consistent application of that
   3.225 +system; it is up to the author/donor to decide if he or she is willing
   3.226 +to distribute software through any other system and a licensee cannot
   3.227 +impose that choice.
   3.228 +
   3.229 +This section is intended to make thoroughly clear what is believed to
   3.230 +be a consequence of the rest of this License.
   3.231 +
   3.232 +  8. If the distribution and/or use of the Program is restricted in
   3.233 +certain countries either by patents or by copyrighted interfaces, the
   3.234 +original copyright holder who places the Program under this License
   3.235 +may add an explicit geographical distribution limitation excluding
   3.236 +those countries, so that distribution is permitted only in or among
   3.237 +countries not thus excluded.  In such case, this License incorporates
   3.238 +the limitation as if written in the body of this License.
   3.239 +
   3.240 +  9. The Free Software Foundation may publish revised and/or new versions
   3.241 +of the General Public License from time to time.  Such new versions will
   3.242 +be similar in spirit to the present version, but may differ in detail to
   3.243 +address new problems or concerns.
   3.244 +
   3.245 +Each version is given a distinguishing version number.  If the Program
   3.246 +specifies a version number of this License which applies to it and "any
   3.247 +later version", you have the option of following the terms and conditions
   3.248 +either of that version or of any later version published by the Free
   3.249 +Software Foundation.  If the Program does not specify a version number of
   3.250 +this License, you may choose any version ever published by the Free Software
   3.251 +Foundation.
   3.252 +
   3.253 +  10. If you wish to incorporate parts of the Program into other free
   3.254 +programs whose distribution conditions are different, write to the author
   3.255 +to ask for permission.  For software which is copyrighted by the Free
   3.256 +Software Foundation, write to the Free Software Foundation; we sometimes
   3.257 +make exceptions for this.  Our decision will be guided by the two goals
   3.258 +of preserving the free status of all derivatives of our free software and
   3.259 +of promoting the sharing and reuse of software generally.
   3.260 +
   3.261 +			    NO WARRANTY
   3.262 +
   3.263 +  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
   3.264 +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
   3.265 +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
   3.266 +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
   3.267 +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
   3.268 +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
   3.269 +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
   3.270 +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
   3.271 +REPAIR OR CORRECTION.
   3.272 +
   3.273 +  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
   3.274 +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
   3.275 +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
   3.276 +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
   3.277 +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
   3.278 +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
   3.279 +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
   3.280 +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
   3.281 +POSSIBILITY OF SUCH DAMAGES.
   3.282 +
   3.283 +		     END OF TERMS AND CONDITIONS
   3.284 +
   3.285 +	    How to Apply These Terms to Your New Programs
   3.286 +
   3.287 +  If you develop a new program, and you want it to be of the greatest
   3.288 +possible use to the public, the best way to achieve this is to make it
   3.289 +free software which everyone can redistribute and change under these terms.
   3.290 +
   3.291 +  To do so, attach the following notices to the program.  It is safest
   3.292 +to attach them to the start of each source file to most effectively
   3.293 +convey the exclusion of warranty; and each file should have at least
   3.294 +the "copyright" line and a pointer to where the full notice is found.
   3.295 +
   3.296 +    <one line to give the program's name and a brief idea of what it does.>
   3.297 +    Copyright (C) <year>  <name of author>
   3.298 +
   3.299 +    This program is free software; you can redistribute it and/or modify
   3.300 +    it under the terms of the GNU General Public License as published by
   3.301 +    the Free Software Foundation; either version 2 of the License, or
   3.302 +    (at your option) any later version.
   3.303 +
   3.304 +    This program is distributed in the hope that it will be useful,
   3.305 +    but WITHOUT ANY WARRANTY; without even the implied warranty of
   3.306 +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   3.307 +    GNU General Public License for more details.
   3.308 +
   3.309 +    You should have received a copy of the GNU General Public License
   3.310 +    along with this program; if not, write to the Free Software
   3.311 +    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   3.312 +
   3.313 +
   3.314 +Also add information on how to contact you by electronic and paper mail.
   3.315 +
   3.316 +If the program is interactive, make it output a short notice like this
   3.317 +when it starts in an interactive mode:
   3.318 +
   3.319 +    Gnomovision version 69, Copyright (C) year name of author
   3.320 +    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
   3.321 +    This is free software, and you are welcome to redistribute it
   3.322 +    under certain conditions; type `show c' for details.
   3.323 +
   3.324 +The hypothetical commands `show w' and `show c' should show the appropriate
   3.325 +parts of the General Public License.  Of course, the commands you use may
   3.326 +be called something other than `show w' and `show c'; they could even be
   3.327 +mouse-clicks or menu items--whatever suits your program.
   3.328 +
   3.329 +You should also get your employer (if you work as a programmer) or your
   3.330 +school, if any, to sign a "copyright disclaimer" for the program, if
   3.331 +necessary.  Here is a sample; alter the names:
   3.332 +
   3.333 +  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
   3.334 +  `Gnomovision' (which makes passes at compilers) written by James Hacker.
   3.335 +
   3.336 +  <signature of Ty Coon>, 1 April 1989
   3.337 +  Ty Coon, President of Vice
   3.338 +
   3.339 +This General Public License does not permit incorporating your program into
   3.340 +proprietary programs.  If your program is a subroutine library, you may
   3.341 +consider it more useful to permit linking proprietary applications with the
   3.342 +library.  If this is what you want to do, use the GNU Library General
   3.343 +Public License instead of this License.
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/tools/xenmon/Makefile	Tue Nov 15 15:44:37 2005 +0100
     4.3 @@ -0,0 +1,51 @@
     4.4 +# Copyright (C) HP Labs, Palo Alto and Fort Collins, 2005
     4.5 +# Author: Diwaker Gupta <diwaker.gupta@hp.com>
     4.6 +#
     4.7 +# This program is free software; you can redistribute it and/or modify
     4.8 +# it under the terms of the GNU General Public License as published by
     4.9 +# the Free Software Foundation; under version 2 of the License.
    4.10 +#
    4.11 +# This program is distributed in the hope that it will be useful,
    4.12 +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    4.13 +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    4.14 +# GNU General Public License for more details.
    4.15 +
    4.16 +INSTALL         = install
    4.17 +INSTALL_PROG    = $(INSTALL) -m0755
    4.18 +INSTALL_DIR     = $(INSTALL) -d -m0755
    4.19 +INSTALL_DATA    = $(INSTALL) -m064
    4.20 +
    4.21 +prefix=/usr/local
    4.22 +mandir=$(prefix)/share/man
    4.23 +man1dir=$(mandir)/man1
    4.24 +sbindir=$(prefix)/sbin
    4.25 +
    4.26 +XEN_ROOT=../..
    4.27 +include $(XEN_ROOT)/tools/Rules.mk
    4.28 +
    4.29 +CFLAGS += -Wall -Werror -g
    4.30 +CFLAGS  += -I $(XEN_XC)
    4.31 +CFLAGS  += -I $(XEN_LIBXC)
    4.32 +LDFLAGS += -L $(XEN_LIBXC)
    4.33 +
    4.34 +BIN = setmask xenbaked
    4.35 +SCRIPTS = xenmon.py
    4.36 +
    4.37 +all: build
    4.38 +
    4.39 +build: $(BIN)
    4.40 +
    4.41 +install: xenbaked setmask
    4.42 +	[ -d $(DESTDIR)$(sbindir) ] || $(INSTALL_DIR) $(DESTDIR)$(sbindir)
    4.43 +	$(INSTALL_PROG) xenbaked $(DESTDIR)$(sbindir)/xenbaked
    4.44 +	$(INSTALL_PROG) setmask  $(DESTDIR)$(sbindir)/setmask
    4.45 +	$(INSTALL_PROG) xenmon.py  $(DESTDIR)$(sbindir)/xenmon.py
    4.46 +
    4.47 +clean:
    4.48 +	rm -f $(BIN)
    4.49 +
    4.50 +
    4.51 +%: %.c Makefile
    4.52 +	$(CC) $(CFLAGS) $(LDFLAGS) -lxenctrl -o $@ $<
    4.53 +
    4.54 +
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/tools/xenmon/README	Tue Nov 15 15:44:37 2005 +0100
     5.3 @@ -0,0 +1,104 @@
     5.4 +Xen Performance Monitor
     5.5 +-----------------------
     5.6 +
     5.7 +The xenmon tools make use of the existing xen tracing feature to provide fine
     5.8 +grained reporting of various domain related metrics. It should be stressed that
     5.9 +the xenmon.py script included here is just an example of the data that may be
    5.10 +displayed. The xenbake demon keeps a large amount of history in a shared memory
    5.11 +area that may be accessed by tools such as xenmon.
    5.12 +
    5.13 +For each domain, xenmon reports various metrics. One part of the display is a
    5.14 +group of metrics that have been accumulated over the last second, while another
    5.15 +part of the display shows data measured over 10 seconds. Other measurement
    5.16 +intervals are possible, but we have just chosen 1s and 10s as an example.
    5.17 +
    5.18 +
    5.19 +Execution Count
    5.20 +---------------
    5.21 + o The number of times that a domain was scheduled to run (ie, dispatched) over
    5.22 + the measurement interval
    5.23 +
    5.24 +
    5.25 +CPU usage
    5.26 +---------
    5.27 + o Total time used over the measurement interval
    5.28 + o Usage expressed as a percentage of the measurement interval
    5.29 + o Average cpu time used during each execution of the domain
    5.30 +
    5.31 +
    5.32 +Waiting time
    5.33 +------------
    5.34 +This is how much time the domain spent waiting to run, or put another way, the
    5.35 +amount of time the domain spent in the "runnable" state (or on the run queue)
    5.36 +but not actually running. Xenmon displays:
    5.37 +
    5.38 + o Total time waiting over the measurement interval
    5.39 + o Wait time expressed as a percentage of the measurement interval
    5.40 + o Average waiting time for each execution of the domain
    5.41 +
    5.42 +Blocked time
    5.43 +------------
    5.44 +This is how much time the domain spent blocked (or sleeping); Put another way,
    5.45 +the amount of time the domain spent not needing/wanting the cpu because it was
    5.46 +waiting for some event (ie, I/O). Xenmon reports:
    5.47 +
    5.48 + o Total time blocked over the measurement interval
    5.49 + o Blocked time expressed as a percentage of the measurement interval
    5.50 + o Blocked time per I/O (see I/O count below)
    5.51 +
    5.52 +Allocation time
    5.53 +---------------
    5.54 +This is how much cpu time was allocated to the domain by the scheduler; This is
    5.55 +distinct from cpu usage since the "time slice" given to a domain is frequently
    5.56 +cut short for one reason or another, ie, the domain requests I/O and blocks.
    5.57 +Xenmon reports:
    5.58 +
    5.59 + o Average allocation time per execution (ie, time slice)
    5.60 + o Min and Max allocation times
    5.61 +
    5.62 +I/O Count
    5.63 +---------
    5.64 +This is a rough measure of I/O requested by the domain. The number of page
    5.65 +exchanges (or page "flips") between the domain and dom0 are counted. The
    5.66 +number of pages exchanged may not accurately reflect the number of bytes
    5.67 +transferred to/from a domain due to partial pages being used by the network
    5.68 +protocols, etc. But it does give a good sense of the magnitude of I/O being
    5.69 +requested by a domain. Xenmon reports:
    5.70 +
    5.71 + o Total number of page exchanges during the measurement interval
    5.72 + o Average number of page exchanges per execution of the domain
    5.73 +
    5.74 +
    5.75 +Usage Notes and issues
    5.76 +----------------------
    5.77 + - Start xenmon by simply running xenmon.py; The xenbake demon is started and
    5.78 +   stopped automatically by xenmon.
    5.79 + - To see the various options for xenmon, run xenmon -h. Ditto for xenbaked.
    5.80 + - xenmon also has an option (-n) to output log data to a file instead of the
    5.81 +   curses interface.
    5.82 + - NDOMAINS is defined to be 32, but can be changed by recompiling xenbaked
    5.83 + - Xenmon.py appears to create 1-2% cpu overhead; Part of this is just the
    5.84 +   overhead of the python interpreter. Part of it may be the number of trace
    5.85 +   records being generated. The number of trace records generated can be
    5.86 +   limited by setting the trace mask (with a dom0 Op), which controls which
    5.87 +   events cause a trace record to be emitted.
    5.88 + - To exit xenmon, type 'q'
    5.89 + - To cycle the display to other physical cpu's, type 'c'
    5.90 +
    5.91 +Future Work
    5.92 +-----------
    5.93 +o RPC interface to allow external entities to programmatically access processed data
    5.94 +o I/O Count batching to reduce number of trace records generated
    5.95 +
    5.96 +Case Study
    5.97 +----------
    5.98 +We have written a case study which demonstrates some of the usefulness of
    5.99 +this tool and the metrics reported. It is available at:
   5.100 +http://www.hpl.hp.com/techreports/2005/HPL-2005-187.html
   5.101 +
   5.102 +Authors
   5.103 +-------
   5.104 +Diwaker Gupta   <diwaker.gupta@hp.com>
   5.105 +Rob Gardner     <rob.gardner@hp.com>
   5.106 +Lucy Cherkasova <lucy.cherkasova.hp.com>
   5.107 +
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/tools/xenmon/setmask.c	Tue Nov 15 15:44:37 2005 +0100
     6.3 @@ -0,0 +1,90 @@
     6.4 +/******************************************************************************
     6.5 + * tools/xenmon/setmask.c
     6.6 + * 
     6.7 + * Simple utility for getting/setting the event mask
     6.8 + *
     6.9 + * Copyright (C) 2005 by Hewlett-Packard, Palo Alto and Fort Collins
    6.10 + *
    6.11 + * Authors: Lucy Cherkasova, lucy.cherkasova.hp.com
    6.12 + *          Rob Gardner, rob.gardner@hp.com
    6.13 + *          Diwaker Gupta, diwaker.gupta@hp.com
    6.14 + * Date:   August, 2005
    6.15 + * 
    6.16 + *  This program is free software; you can redistribute it and/or modify
    6.17 + *  it under the terms of the GNU General Public License as published by
    6.18 + *  the Free Software Foundation; under version 2 of the License.
    6.19 + *
    6.20 + *  This program is distributed in the hope that it will be useful,
    6.21 + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
    6.22 + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    6.23 + *  GNU General Public License for more details.
    6.24 + *
    6.25 + *  You should have received a copy of the GNU General Public License
    6.26 + *  along with this program; if not, write to the Free Software
    6.27 + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    6.28 + */
    6.29 +
    6.30 +#include <stdlib.h>
    6.31 +#include <stdio.h>
    6.32 +#include <sys/types.h>
    6.33 +#include <fcntl.h>
    6.34 +#include <unistd.h>
    6.35 +#include <errno.h>
    6.36 +#include <getopt.h>
    6.37 +#include <xenctrl.h>
    6.38 +#include <xen/xen.h>
    6.39 +typedef struct { int counter; } atomic_t;
    6.40 +#include <xen/trace.h>
    6.41 +
    6.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)
    6.43 +
    6.44 +int main(int argc, char * argv[])
    6.45 +{
    6.46 +
    6.47 +    dom0_op_t op; 
    6.48 +    int ret;
    6.49 +
    6.50 +    int xc_handle = xc_interface_open();
    6.51 +    op.cmd = DOM0_TBUFCONTROL;
    6.52 +    op.interface_version = DOM0_INTERFACE_VERSION;
    6.53 +    op.u.tbufcontrol.op  = DOM0_TBUF_GET_INFO;
    6.54 +    ret = xc_dom0_op(xc_handle, &op);
    6.55 +    if ( ret != 0 )
    6.56 +    {
    6.57 +        perror("Failure to get event mask from Xen");
    6.58 +        exit(1);
    6.59 +    }
    6.60 +    else
    6.61 +    {
    6.62 +        printf("Current event mask: 0x%.8x\n", op.u.tbufcontrol.evt_mask);
    6.63 +    }
    6.64 +
    6.65 +    op.cmd = DOM0_TBUFCONTROL;
    6.66 +    op.interface_version = DOM0_INTERFACE_VERSION;
    6.67 +    op.u.tbufcontrol.op  = DOM0_TBUF_SET_EVT_MASK;
    6.68 +    op.u.tbufcontrol.evt_mask = XENMON;
    6.69 +
    6.70 +    ret = xc_dom0_op(xc_handle, &op);
    6.71 +    printf("Setting mask to 0x%.8x\n", op.u.tbufcontrol.evt_mask);
    6.72 +    if ( ret != 0 )
    6.73 +    {
    6.74 +        perror("Failure to get scheduler ID from Xen");
    6.75 +        exit(1);
    6.76 +    }
    6.77 +
    6.78 +    op.cmd = DOM0_TBUFCONTROL;
    6.79 +    op.interface_version = DOM0_INTERFACE_VERSION;
    6.80 +    op.u.tbufcontrol.op  = DOM0_TBUF_GET_INFO;
    6.81 +    ret = xc_dom0_op(xc_handle, &op);
    6.82 +    if ( ret != 0 )
    6.83 +    {
    6.84 +        perror("Failure to get event mask from Xen");
    6.85 +        exit(1);
    6.86 +    }
    6.87 +    else
    6.88 +    {
    6.89 +        printf("Current event mask: 0x%.8x\n", op.u.tbufcontrol.evt_mask);
    6.90 +    }
    6.91 +    xc_interface_close(xc_handle);
    6.92 +    return 0;
    6.93 +}
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/tools/xenmon/xenbaked.c	Tue Nov 15 15:44:37 2005 +0100
     7.3 @@ -0,0 +1,1029 @@
     7.4 +/******************************************************************************
     7.5 + * tools/xenbaked.c
     7.6 + *
     7.7 + * Tool for collecting raw trace buffer data from Xen and 
     7.8 + *  performing some accumulation operations and other processing
     7.9 + *  on it.
    7.10 + *
    7.11 + * Copyright (C) 2004 by Intel Research Cambridge
    7.12 + * Copyright (C) 2005 by Hewlett Packard, Palo Alto and Fort Collins
    7.13 + *
    7.14 + * Authors: Diwaker Gupta, diwaker.gupta@hp.com
    7.15 + *          Rob Gardner, rob.gardner@hp.com
    7.16 + *          Lucy Cherkasova, lucy.cherkasova.hp.com
    7.17 + * Much code based on xentrace, authored by Mark Williamson, mark.a.williamson@intel.com
    7.18 + * Date:   November, 2005
    7.19 + * 
    7.20 + *  This program is free software; you can redistribute it and/or modify
    7.21 + *  it under the terms of the GNU General Public License as published by
    7.22 + *  the Free Software Foundation; under version 2 of the License.
    7.23 + *
    7.24 + *  This program is distributed in the hope that it will be useful,
    7.25 + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
    7.26 + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    7.27 + *  GNU General Public License for more details.
    7.28 + *
    7.29 + *  You should have received a copy of the GNU General Public License
    7.30 + *  along with this program; if not, write to the Free Software
    7.31 + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    7.32 + */
    7.33 +
    7.34 +#include <time.h>
    7.35 +#include <stdlib.h>
    7.36 +#include <stdio.h>
    7.37 +#include <sys/mman.h>
    7.38 +#include <sys/stat.h>
    7.39 +#include <sys/types.h>
    7.40 +#include <fcntl.h>
    7.41 +#include <unistd.h>
    7.42 +#include <errno.h>
    7.43 +#include <argp.h>
    7.44 +#include <signal.h>
    7.45 +#include <xenctrl.h>
    7.46 +#include <xen/xen.h>
    7.47 +#include <string.h>
    7.48 +
    7.49 +#include "xc_private.h"
    7.50 +typedef struct { int counter; } atomic_t;
    7.51 +#define _atomic_read(v)		((v).counter)
    7.52 +
    7.53 +#include <xen/trace.h>
    7.54 +#include "xenbaked.h"
    7.55 +
    7.56 +extern FILE *stderr;
    7.57 +
    7.58 +/***** Compile time configuration of defaults ********************************/
    7.59 +
    7.60 +/* when we've got more records than this waiting, we log it to the output */
    7.61 +#define NEW_DATA_THRESH 1
    7.62 +
    7.63 +/* sleep for this long (milliseconds) between checking the trace buffers */
    7.64 +#define POLL_SLEEP_MILLIS 100
    7.65 +
    7.66 +/* Size of time period represented by each sample */
    7.67 +#define MS_PER_SAMPLE 100
    7.68 +
    7.69 +/* CPU Frequency */
    7.70 +#define MHZ
    7.71 +#define CPU_FREQ 2660 MHZ
    7.72 +
    7.73 +/***** The code **************************************************************/
    7.74 +
    7.75 +typedef struct settings_st {
    7.76 +    char *outfile;
    7.77 +    struct timespec poll_sleep;
    7.78 +    unsigned long new_data_thresh;
    7.79 +    unsigned long ms_per_sample;
    7.80 +    double cpu_freq;
    7.81 +} settings_t;
    7.82 +
    7.83 +settings_t opts;
    7.84 +
    7.85 +int interrupted = 0; /* gets set if we get a SIGHUP */
    7.86 +int rec_count = 0;
    7.87 +time_t start_time;
    7.88 +int dom0_flips = 0;
    7.89 +
    7.90 +_new_qos_data *new_qos;
    7.91 +_new_qos_data **cpu_qos_data;
    7.92 +
    7.93 +
    7.94 +#define ID(X) ((X>NDOMAINS-1)?(NDOMAINS-1):X)
    7.95 +
    7.96 +// array of currently running domains, indexed by cpu
    7.97 +int *running = NULL;
    7.98 +
    7.99 +// number of cpu's on this platform
   7.100 +int NCPU = 0;
   7.101 +
   7.102 +
   7.103 +void init_current(int ncpu)
   7.104 +{
   7.105 +  running = calloc(ncpu, sizeof(int));
   7.106 +  NCPU = ncpu;
   7.107 +  printf("Initialized with %d %s\n", ncpu, (ncpu == 1) ? "cpu" : "cpu's");
   7.108 +}
   7.109 +
   7.110 +int is_current(int domain, int cpu)
   7.111 +{
   7.112 +  //  int i;
   7.113 +  
   7.114 +  //  for (i=0; i<NCPU; i++)
   7.115 +    if (running[cpu] == domain)
   7.116 +      return 1;
   7.117 +  return 0;
   7.118 +}
   7.119 +
   7.120 +
   7.121 +// return the domain that's currently running on the given cpu
   7.122 +int current(int cpu)
   7.123 +{
   7.124 +  return running[cpu];
   7.125 +}
   7.126 +
   7.127 +void set_current(int cpu, int domain)
   7.128 +{
   7.129 +  running[cpu] = domain;
   7.130 +}
   7.131 +
   7.132 +
   7.133 +
   7.134 +void close_handler(int signal)
   7.135 +{
   7.136 +    interrupted = 1;
   7.137 +}
   7.138 +
   7.139 +#if 0
   7.140 +void dump_record(int cpu, struct t_rec *x)
   7.141 +{
   7.142 +    printf("record: cpu=%x, tsc=%lx, event=%x, d1=%lx\n", 
   7.143 +            cpu, x->cycles, x->event, x->data[0]);
   7.144 +}
   7.145 +#endif
   7.146 +
   7.147 +/**
   7.148 + * millis_to_timespec - convert a time in milliseconds to a struct timespec
   7.149 + * @millis:             time interval in milliseconds
   7.150 + */
   7.151 +struct timespec millis_to_timespec(unsigned long millis)
   7.152 +{
   7.153 +    struct timespec spec;
   7.154 +
   7.155 +    spec.tv_sec = millis / 1000;
   7.156 +    spec.tv_nsec = (millis % 1000) * 1000;
   7.157 +
   7.158 +    return spec;
   7.159 +}
   7.160 +
   7.161 +
   7.162 +typedef struct 
   7.163 +{
   7.164 +    int event_count;
   7.165 +    int event_id;
   7.166 +    char *text;
   7.167 +} stat_map_t;
   7.168 +
   7.169 +stat_map_t stat_map[] = {
   7.170 +    { 0,       0, 	    "Other" },
   7.171 +    { 0, TRC_SCHED_DOM_ADD, "Add Domain" },
   7.172 +    { 0, TRC_SCHED_DOM_REM, "Remove Domain" },
   7.173 +    { 0, TRC_SCHED_SLEEP, "Sleep" },
   7.174 +    { 0, TRC_SCHED_WAKE,  "Wake" },
   7.175 +    { 0, TRC_SCHED_BLOCK,  "Block" },
   7.176 +    { 0, TRC_SCHED_SWITCH,  "Switch" },
   7.177 +    { 0, TRC_SCHED_S_TIMER_FN, "Timer Func"},
   7.178 +    { 0, TRC_SCHED_SWITCH_INFPREV,  "Switch Prev" },
   7.179 +    { 0, TRC_SCHED_SWITCH_INFNEXT,  "Switch Next" },
   7.180 +    { 0, TRC_MEM_PAGE_GRANT_MAP,  "Page Map" },
   7.181 +    { 0, TRC_MEM_PAGE_GRANT_UNMAP,  "Page Unmap" },
   7.182 +    { 0, TRC_MEM_PAGE_GRANT_TRANSFER,  "Page Transfer" },
   7.183 +    { 0,      0, 		 0  }
   7.184 +};
   7.185 +
   7.186 +
   7.187 +void check_gotten_sum(void)
   7.188 +{
   7.189 +#if 0
   7.190 +    uint64_t sum, ns;
   7.191 +    extern uint64_t total_ns_gotten(uint64_t*);
   7.192 +    double percent;
   7.193 +    int i;
   7.194 +
   7.195 +    for (i=0; i<NCPU; i++) {
   7.196 +      new_qos = cpu_qos_data[i];
   7.197 +      ns = billion;
   7.198 +      sum = total_ns_gotten(&ns);
   7.199 +
   7.200 +      printf("[cpu%d] ns_gotten over all domains = %lldns, over %lldns\n",
   7.201 +	      i, sum, ns);
   7.202 +      percent = (double) sum;
   7.203 +      percent = (100.0*percent) / (double)ns;
   7.204 +      printf(" ==> ns_gotten = %7.3f%%\n", percent);
   7.205 +    }
   7.206 +#endif
   7.207 +}
   7.208 +
   7.209 +
   7.210 +
   7.211 +void dump_stats(void) 
   7.212 +{
   7.213 +    stat_map_t *smt = stat_map;
   7.214 +    time_t end_time, run_time;
   7.215 +
   7.216 +    time(&end_time);
   7.217 +
   7.218 +    run_time = end_time - start_time;
   7.219 +
   7.220 +    printf("Event counts:\n");
   7.221 +    while (smt->text != NULL) {
   7.222 +        printf("%08d\t%s\n", smt->event_count, smt->text);
   7.223 +        smt++;
   7.224 +    }
   7.225 +
   7.226 +    printf("processed %d total records in %d seconds (%ld per second)\n",
   7.227 +            rec_count, (int)run_time, rec_count/run_time);
   7.228 +
   7.229 +    check_gotten_sum();
   7.230 +}
   7.231 +
   7.232 +void log_event(int event_id) 
   7.233 +{
   7.234 +    stat_map_t *smt = stat_map;
   7.235 +
   7.236 +    //  printf("event_id = 0x%x\n", event_id);
   7.237 +
   7.238 +    while (smt->text != NULL) {
   7.239 +        if (smt->event_id == event_id) {
   7.240 +            smt->event_count++;
   7.241 +            return;
   7.242 +        }
   7.243 +        smt++;
   7.244 +    }
   7.245 +    if (smt->text == NULL)
   7.246 +        stat_map[0].event_count++;	// other
   7.247 +}
   7.248 +
   7.249 +
   7.250 +
   7.251 +/**
   7.252 + * get_tbufs - get pointer to and size of the trace buffers
   7.253 + * @mfn:  location to store mfn of the trace buffers to
   7.254 + * @size: location to store the size of a trace buffer to
   7.255 + *
   7.256 + * Gets the machine address of the trace pointer area and the size of the
   7.257 + * per CPU buffers.
   7.258 + */
   7.259 +void get_tbufs(unsigned long *mfn, unsigned long *size)
   7.260 +{
   7.261 +    int ret;
   7.262 +    dom0_op_t op;                        /* dom0 op we'll build             */
   7.263 +    int xc_handle = xc_interface_open(); /* for accessing control interface */
   7.264 +
   7.265 +    op.cmd = DOM0_TBUFCONTROL;
   7.266 +    op.interface_version = DOM0_INTERFACE_VERSION;
   7.267 +    op.u.tbufcontrol.op  = DOM0_TBUF_GET_INFO;
   7.268 +
   7.269 +    ret = do_dom0_op(xc_handle, &op);
   7.270 +
   7.271 +    xc_interface_close(xc_handle);
   7.272 +
   7.273 +    if ( ret != 0 )
   7.274 +    {
   7.275 +        PERROR("Failure to get trace buffer pointer from Xen");
   7.276 +        exit(EXIT_FAILURE);
   7.277 +    }
   7.278 +
   7.279 +    *mfn  = op.u.tbufcontrol.buffer_mfn;
   7.280 +    *size = op.u.tbufcontrol.size;
   7.281 +}
   7.282 +
   7.283 +/**
   7.284 + * map_tbufs - memory map Xen trace buffers into user space
   7.285 + * @tbufs_mfn: mfn of the trace buffers
   7.286 + * @num:       number of trace buffers to map
   7.287 + * @size:      size of each trace buffer
   7.288 + *
   7.289 + * Maps the Xen trace buffers them into process address space.
   7.290 + */
   7.291 +struct t_buf *map_tbufs(unsigned long tbufs_mfn, unsigned int num,
   7.292 +                        unsigned long size)
   7.293 +{
   7.294 +    int xc_handle;                  /* file descriptor for /proc/xen/privcmd */
   7.295 +    struct t_buf *tbufs_mapped;
   7.296 +
   7.297 +    xc_handle = xc_interface_open();
   7.298 +
   7.299 +    if ( xc_handle < 0 ) 
   7.300 +    {
   7.301 +        PERROR("Open /proc/xen/privcmd when mapping trace buffers\n");
   7.302 +        exit(EXIT_FAILURE);
   7.303 +    }
   7.304 +
   7.305 +    tbufs_mapped = xc_map_foreign_range(xc_handle, 0 /* Dom 0 ID */,
   7.306 +                                        size * num, PROT_READ | PROT_WRITE,
   7.307 +                                        tbufs_mfn);
   7.308 +
   7.309 +    xc_interface_close(xc_handle);
   7.310 +
   7.311 +    if ( tbufs_mapped == 0 ) 
   7.312 +    {
   7.313 +        PERROR("Failed to mmap trace buffers");
   7.314 +        exit(EXIT_FAILURE);
   7.315 +    }
   7.316 +
   7.317 +    return tbufs_mapped;
   7.318 +}
   7.319 +
   7.320 +/**
   7.321 + * init_bufs_ptrs - initialises an array of pointers to the trace buffers
   7.322 + * @bufs_mapped:    the userspace address where the trace buffers are mapped
   7.323 + * @num:            number of trace buffers
   7.324 + * @size:           trace buffer size
   7.325 + *
   7.326 + * Initialises an array of pointers to individual trace buffers within the
   7.327 + * mapped region containing all trace buffers.
   7.328 + */
   7.329 +struct t_buf **init_bufs_ptrs(void *bufs_mapped, unsigned int num,
   7.330 +        unsigned long size)
   7.331 +{
   7.332 +    int i;
   7.333 +    struct t_buf **user_ptrs;
   7.334 +
   7.335 +    user_ptrs = (struct t_buf **)calloc(num, sizeof(struct t_buf *));
   7.336 +    if ( user_ptrs == NULL )
   7.337 +    {
   7.338 +        PERROR( "Failed to allocate memory for buffer pointers\n");
   7.339 +        exit(EXIT_FAILURE);
   7.340 +    }
   7.341 +
   7.342 +    /* initialise pointers to the trace buffers - given the size of a trace
   7.343 +     * buffer and the value of bufs_maped, we can easily calculate these */
   7.344 +    for ( i = 0; i<num; i++ )
   7.345 +        user_ptrs[i] = (struct t_buf *)((unsigned long)bufs_mapped + size * i);
   7.346 +
   7.347 +    return user_ptrs;
   7.348 +}
   7.349 +
   7.350 +
   7.351 +/**
   7.352 + * init_rec_ptrs - initialises data area pointers to locations in user space
   7.353 + * @tbufs_mfn:     base mfn of the trace buffer area
   7.354 + * @tbufs_mapped:  user virtual address of base of trace buffer area
   7.355 + * @meta:          array of user-space pointers to struct t_buf's of metadata
   7.356 + * @num:           number of trace buffers
   7.357 + *
   7.358 + * Initialises data area pointers to the locations that data areas have been
   7.359 + * mapped in user space.  Note that the trace buffer metadata contains machine
   7.360 + * pointers - the array returned allows more convenient access to them.
   7.361 + */
   7.362 +struct t_rec **init_rec_ptrs(struct t_buf **meta, unsigned int num)
   7.363 +{
   7.364 +    int i;
   7.365 +    struct t_rec **data;
   7.366 +    
   7.367 +    data = calloc(num, sizeof(struct t_rec *));
   7.368 +    if ( data == NULL )
   7.369 +    {
   7.370 +        PERROR("Failed to allocate memory for data pointers\n");
   7.371 +        exit(EXIT_FAILURE);
   7.372 +    }
   7.373 +
   7.374 +    for ( i = 0; i < num; i++ )
   7.375 +        data[i] = (struct t_rec *)(meta[i] + 1);
   7.376 +
   7.377 +    return data;
   7.378 +}
   7.379 +
   7.380 +
   7.381 +
   7.382 +/**
   7.383 + * get_num_cpus - get the number of logical CPUs
   7.384 + */
   7.385 +unsigned int get_num_cpus()
   7.386 +{
   7.387 +    dom0_op_t op;
   7.388 +    int xc_handle = xc_interface_open();
   7.389 +    int ret;
   7.390 +
   7.391 +    op.cmd = DOM0_PHYSINFO;
   7.392 +    op.interface_version = DOM0_INTERFACE_VERSION;
   7.393 +
   7.394 +    ret = xc_dom0_op(xc_handle, &op);
   7.395 +
   7.396 +    if ( ret != 0 )
   7.397 +    {
   7.398 +        PERROR("Failure to get logical CPU count from Xen");
   7.399 +        exit(EXIT_FAILURE);
   7.400 +    }
   7.401 +
   7.402 +    xc_interface_close(xc_handle);
   7.403 +    opts.cpu_freq = (double)op.u.physinfo.cpu_khz/1000.0;
   7.404 +
   7.405 +    return (op.u.physinfo.threads_per_core *
   7.406 +            op.u.physinfo.cores_per_socket *
   7.407 +            op.u.physinfo.sockets_per_node *
   7.408 +            op.u.physinfo.nr_nodes);
   7.409 +}
   7.410 +
   7.411 +
   7.412 +/**
   7.413 + * monitor_tbufs - monitor the contents of tbufs
   7.414 + */
   7.415 +int monitor_tbufs()
   7.416 +{
   7.417 +    int i;
   7.418 +    extern void process_record(int, struct t_rec *);
   7.419 +    extern void alloc_qos_data(int ncpu);
   7.420 +
   7.421 +    void *tbufs_mapped;          /* pointer to where the tbufs are mapped    */
   7.422 +    struct t_buf **meta;         /* pointers to the trace buffer metadata    */
   7.423 +    struct t_rec **data;         /* pointers to the trace buffer data areas
   7.424 +                                  * where they are mapped into user space.   */
   7.425 +    unsigned long tbufs_mfn;     /* mfn of the tbufs                         */
   7.426 +    unsigned int  num;           /* number of trace buffers / logical CPUS   */
   7.427 +    unsigned long size;          /* size of a single trace buffer            */
   7.428 +
   7.429 +    int size_in_recs;
   7.430 +
   7.431 +    /* get number of logical CPUs (and therefore number of trace buffers) */
   7.432 +    num = get_num_cpus();
   7.433 +
   7.434 +    init_current(num);
   7.435 +    alloc_qos_data(num);
   7.436 +
   7.437 +    printf("CPU Frequency = %7.2f\n", opts.cpu_freq);
   7.438 +    
   7.439 +    /* setup access to trace buffers */
   7.440 +    get_tbufs(&tbufs_mfn, &size);
   7.441 +
   7.442 +    //    printf("from dom0op: %ld, t_buf: %d, t_rec: %d\n",
   7.443 +    //            size, sizeof(struct t_buf), sizeof(struct t_rec));
   7.444 +
   7.445 +    tbufs_mapped = map_tbufs(tbufs_mfn, num, size);
   7.446 +
   7.447 +    size_in_recs = (size - sizeof(struct t_buf)) / sizeof(struct t_rec);
   7.448 +    //    fprintf(stderr, "size_in_recs = %d\n", size_in_recs);
   7.449 +
   7.450 +    /* build arrays of convenience ptrs */
   7.451 +    meta  = init_bufs_ptrs (tbufs_mapped, num, size);
   7.452 +    data  = init_rec_ptrs(meta, num);
   7.453 +
   7.454 +    /* now, scan buffers for events */
   7.455 +    while ( !interrupted )
   7.456 +    {
   7.457 +        for ( i = 0; ( i < num ) && !interrupted; i++ )
   7.458 +            while ( meta[i]->cons != meta[i]->prod )
   7.459 +            {
   7.460 +                rmb(); /* read prod, then read item. */
   7.461 +                process_record(i, data[i] + meta[i]->cons % size_in_recs);
   7.462 +                mb(); /* read item, then update cons. */
   7.463 +                meta[i]->cons++;
   7.464 +            }
   7.465 +
   7.466 +        nanosleep(&opts.poll_sleep, NULL);
   7.467 +    }
   7.468 +
   7.469 +    /* cleanup */
   7.470 +    free(meta);
   7.471 +    free(data);
   7.472 +    /* don't need to munmap - cleanup is automatic */
   7.473 +
   7.474 +    return 0;
   7.475 +}
   7.476 +
   7.477 +
   7.478 +/******************************************************************************
   7.479 + * Various declarations / definitions GNU argp needs to do its work
   7.480 + *****************************************************************************/
   7.481 +
   7.482 +
   7.483 +/* command parser for GNU argp - see GNU docs for more info */
   7.484 +error_t cmd_parser(int key, char *arg, struct argp_state *state)
   7.485 +{
   7.486 +    settings_t *setup = (settings_t *)state->input;
   7.487 +
   7.488 +    switch ( key )
   7.489 +    {
   7.490 +        case 't': /* set new records threshold for logging */
   7.491 +            {
   7.492 +                char *inval;
   7.493 +                setup->new_data_thresh = strtol(arg, &inval, 0);
   7.494 +                if ( inval == arg )
   7.495 +                    argp_usage(state);
   7.496 +            }
   7.497 +            break;
   7.498 +
   7.499 +        case 's': /* set sleep time (given in milliseconds) */
   7.500 +            {
   7.501 +                char *inval;
   7.502 +                setup->poll_sleep = millis_to_timespec(strtol(arg, &inval, 0));
   7.503 +                if ( inval == arg )
   7.504 +                    argp_usage(state);
   7.505 +            }
   7.506 +            break;
   7.507 +
   7.508 +        case 'm': /* set ms_per_sample */
   7.509 +            {
   7.510 +                char *inval;
   7.511 +                setup->ms_per_sample = strtol(arg, &inval, 0);
   7.512 +                if ( inval == arg )
   7.513 +                    argp_usage(state);
   7.514 +            }
   7.515 +            break;
   7.516 +
   7.517 +        case ARGP_KEY_ARG:
   7.518 +            {
   7.519 +                if ( state->arg_num == 0 )
   7.520 +                    setup->outfile = arg;
   7.521 +                else
   7.522 +                    argp_usage(state);
   7.523 +            }
   7.524 +            break;
   7.525 +
   7.526 +        default:
   7.527 +            return ARGP_ERR_UNKNOWN;
   7.528 +    }
   7.529 +
   7.530 +    return 0;
   7.531 +}
   7.532 +
   7.533 +#define SHARED_MEM_FILE "/tmp/xenq-shm"
   7.534 +void alloc_qos_data(int ncpu)
   7.535 +{
   7.536 +    int i, n, pgsize, off=0;
   7.537 +    char *dummy;
   7.538 +    int qos_fd;
   7.539 +    void advance_next_datapoint(uint64_t);
   7.540 +
   7.541 +    cpu_qos_data = (_new_qos_data **) calloc(ncpu, sizeof(_new_qos_data *));
   7.542 +
   7.543 +
   7.544 +    qos_fd = open(SHARED_MEM_FILE, O_RDWR|O_CREAT|O_TRUNC, 0777);
   7.545 +    if (qos_fd < 0) {
   7.546 +        PERROR(SHARED_MEM_FILE);
   7.547 +        exit(2);
   7.548 +    }
   7.549 +    pgsize = getpagesize();
   7.550 +    dummy = malloc(pgsize);
   7.551 +
   7.552 +    for (n=0; n<ncpu; n++) {
   7.553 +
   7.554 +      for (i=0; i<sizeof(_new_qos_data); i=i+pgsize)
   7.555 +        write(qos_fd, dummy, pgsize);
   7.556 +
   7.557 +      new_qos = (_new_qos_data *) mmap(0, sizeof(_new_qos_data), PROT_READ|PROT_WRITE, 
   7.558 +				       MAP_SHARED, qos_fd, off);
   7.559 +      off += i;
   7.560 +      if (new_qos == NULL) {
   7.561 +        PERROR("mmap");
   7.562 +        exit(3);
   7.563 +      }
   7.564 +      //  printf("new_qos = %p\n", new_qos);
   7.565 +      memset(new_qos, 0, sizeof(_new_qos_data));
   7.566 +      new_qos->next_datapoint = 0;
   7.567 +      advance_next_datapoint(0);
   7.568 +      new_qos->structlen = i;
   7.569 +      new_qos->ncpu = ncpu;
   7.570 +      //      printf("structlen = 0x%x\n", i);
   7.571 +      cpu_qos_data[n] = new_qos;
   7.572 +    }
   7.573 +    free(dummy);
   7.574 +    new_qos = NULL;
   7.575 +}
   7.576 +
   7.577 +
   7.578 +#define xstr(x) str(x)
   7.579 +#define str(x) #x
   7.580 +
   7.581 +const struct argp_option cmd_opts[] =
   7.582 +{
   7.583 +    { .name = "log-thresh", .key='t', .arg="l",
   7.584 +        .doc =
   7.585 +            "Set number, l, of new records required to trigger a write to output "
   7.586 +            "(default " xstr(NEW_DATA_THRESH) ")." },
   7.587 +
   7.588 +    { .name = "poll-sleep", .key='s', .arg="p",
   7.589 +        .doc = 
   7.590 +            "Set sleep time, p, in milliseconds between polling the trace buffer "
   7.591 +            "for new data (default " xstr(POLL_SLEEP_MILLIS) ")." },
   7.592 +
   7.593 +    { .name = "ms_per_sample", .key='m', .arg="MS",
   7.594 +        .doc = 
   7.595 +            "Specify the number of milliseconds per sample "
   7.596 +            " (default " xstr(MS_PER_SAMPLE) ")." },
   7.597 +
   7.598 +    {0}
   7.599 +};
   7.600 +
   7.601 +const struct argp parser_def =
   7.602 +{
   7.603 +    .options = cmd_opts,
   7.604 +    .parser = cmd_parser,
   7.605 +    //    .args_doc = "[output file]",
   7.606 +    .doc =
   7.607 +        "Tool to capture and partially process Xen trace buffer data"
   7.608 +        "\v"
   7.609 +        "This tool is used to capture trace buffer data from Xen.  The data is "
   7.610 +        "saved in a shared memory structure to be further processed by xenmon."
   7.611 +};
   7.612 +
   7.613 +
   7.614 +const char *argp_program_version     = "xenbaked v1.3";
   7.615 +const char *argp_program_bug_address = "<rob.gardner@hp.com>";
   7.616 +
   7.617 +
   7.618 +int main(int argc, char **argv)
   7.619 +{
   7.620 +    int ret;
   7.621 +    struct sigaction act;
   7.622 +
   7.623 +    time(&start_time);
   7.624 +    opts.outfile = 0;
   7.625 +    opts.poll_sleep = millis_to_timespec(POLL_SLEEP_MILLIS);
   7.626 +    opts.new_data_thresh = NEW_DATA_THRESH;
   7.627 +    opts.ms_per_sample = MS_PER_SAMPLE;
   7.628 +    opts.cpu_freq = CPU_FREQ;
   7.629 +
   7.630 +    argp_parse(&parser_def, argc, argv, 0, 0, &opts);
   7.631 +    fprintf(stderr, "ms_per_sample = %ld\n", opts.ms_per_sample);
   7.632 +
   7.633 +
   7.634 +    /* ensure that if we get a signal, we'll do cleanup, then exit */
   7.635 +    act.sa_handler = close_handler;
   7.636 +    act.sa_flags = 0;
   7.637 +    sigemptyset(&act.sa_mask);
   7.638 +    sigaction(SIGHUP,  &act, NULL);
   7.639 +    sigaction(SIGTERM, &act, NULL);
   7.640 +    sigaction(SIGINT,  &act, NULL);
   7.641 +
   7.642 +    ret = monitor_tbufs();
   7.643 +
   7.644 +    dump_stats();
   7.645 +    msync(new_qos, sizeof(_new_qos_data), MS_SYNC);
   7.646 +
   7.647 +    return ret;
   7.648 +}
   7.649 +
   7.650 +int domain_runnable(int domid)
   7.651 +{
   7.652 +    return new_qos->domain_info[ID(domid)].runnable;
   7.653 +}
   7.654 +
   7.655 +
   7.656 +void update_blocked_time(int domid, uint64_t now)
   7.657 +{
   7.658 +    uint64_t t_blocked;
   7.659 +    int id = ID(domid);
   7.660 +
   7.661 +    if (new_qos->domain_info[id].blocked_start_time != 0) {
   7.662 +        if (now >= new_qos->domain_info[id].blocked_start_time)
   7.663 +            t_blocked = now - new_qos->domain_info[id].blocked_start_time;
   7.664 +        else
   7.665 +            t_blocked = now + (~0ULL - new_qos->domain_info[id].blocked_start_time);
   7.666 +        new_qos->qdata[new_qos->next_datapoint].ns_blocked[id] += t_blocked;
   7.667 +    }
   7.668 +
   7.669 +    if (domain_runnable(id))
   7.670 +        new_qos->domain_info[id].blocked_start_time = 0;
   7.671 +    else
   7.672 +        new_qos->domain_info[id].blocked_start_time = now;
   7.673 +}
   7.674 +
   7.675 +
   7.676 +// advance to next datapoint for all domains
   7.677 +void advance_next_datapoint(uint64_t now)
   7.678 +{
   7.679 +    int new, old, didx;
   7.680 +
   7.681 +    old = new_qos->next_datapoint;
   7.682 +    new = QOS_INCR(old);
   7.683 +    new_qos->next_datapoint = new;
   7.684 +    //	memset(&new_qos->qdata[new], 0, sizeof(uint64_t)*(2+5*NDOMAINS));
   7.685 +    for (didx = 0; didx < NDOMAINS; didx++) {
   7.686 +        new_qos->qdata[new].ns_gotten[didx] = 0;
   7.687 +        new_qos->qdata[new].ns_allocated[didx] = 0;
   7.688 +        new_qos->qdata[new].ns_waiting[didx] = 0;
   7.689 +        new_qos->qdata[new].ns_blocked[didx] = 0;
   7.690 +        new_qos->qdata[new].switchin_count[didx] = 0;
   7.691 +        new_qos->qdata[new].io_count[didx] = 0;
   7.692 +    }
   7.693 +    new_qos->qdata[new].ns_passed = 0;
   7.694 +    new_qos->qdata[new].lost_records = 0;
   7.695 +    new_qos->qdata[new].flip_free_periods = 0;
   7.696 +
   7.697 +    new_qos->qdata[new].timestamp = now;
   7.698 +}
   7.699 +
   7.700 +
   7.701 +
   7.702 +void qos_update_thread(int cpu, int domid, uint64_t now)
   7.703 +{
   7.704 +    int n, id;
   7.705 +    uint64_t last_update_time, start;
   7.706 +    int64_t time_since_update, run_time = 0;
   7.707 +
   7.708 +    id = ID(domid);
   7.709 +
   7.710 +    n = new_qos->next_datapoint;
   7.711 +    last_update_time = new_qos->domain_info[id].last_update_time;
   7.712 +
   7.713 +    time_since_update = now - last_update_time;
   7.714 +
   7.715 +    if (time_since_update < 0) {
   7.716 +      // what happened here? either a timestamp wraparound, or more likely,
   7.717 +      // a slight inconsistency among timestamps from various cpu's
   7.718 +      if (-time_since_update < billion) {
   7.719 +	// fairly small difference, let's just adjust 'now' to be a little
   7.720 +	// beyond last_update_time
   7.721 +	time_since_update = -time_since_update;
   7.722 +      }
   7.723 +      else if ( ((~0ULL - last_update_time) < billion) && (now < billion) ) {
   7.724 +	// difference is huge, must be a wraparound
   7.725 +	// last_update time should be "near" ~0ULL,
   7.726 +	// and now should be "near" 0
   7.727 +	time_since_update = now + (~0ULL - last_update_time);
   7.728 +	printf("time wraparound\n");
   7.729 +      }
   7.730 +      else {
   7.731 +	// none of the above, may be an out of order record
   7.732 +	// no good solution, just ignore and update again later
   7.733 +	return;
   7.734 +      }
   7.735 +    }
   7.736 +	
   7.737 +    new_qos->domain_info[id].last_update_time = now;
   7.738 +
   7.739 +    if (new_qos->domain_info[id].runnable_at_last_update && is_current(domid, cpu)) {
   7.740 +        start = new_qos->domain_info[id].start_time;
   7.741 +        if (start > now) {		// wrapped around
   7.742 +            run_time = now + (~0ULL - start);
   7.743 +	    printf("warning: start > now\n");
   7.744 +        }
   7.745 +        else
   7.746 +            run_time = now - start;
   7.747 +	//	if (run_time < 0)	// should not happen
   7.748 +	//	  printf("warning: run_time < 0; start = %lld now= %lld\n", start, now);
   7.749 +        new_qos->domain_info[id].ns_oncpu_since_boot += run_time;
   7.750 +        new_qos->domain_info[id].start_time = now;
   7.751 +        new_qos->domain_info[id].ns_since_boot += time_since_update;
   7.752 +#if 1
   7.753 +	new_qos->qdata[n].ns_gotten[id] += run_time;
   7.754 +	if (domid == 0 && cpu == 1)
   7.755 +	  printf("adding run time for dom0 on cpu1\r\n");
   7.756 +#endif
   7.757 +    }
   7.758 +
   7.759 +    new_qos->domain_info[id].runnable_at_last_update = domain_runnable(domid);
   7.760 +
   7.761 +    update_blocked_time(domid, now);
   7.762 +
   7.763 +    // how much time passed since this datapoint was updated?
   7.764 +    if (now >= new_qos->qdata[n].timestamp) {
   7.765 +        // all is right with the world, time is increasing
   7.766 +        new_qos->qdata[n].ns_passed += (now - new_qos->qdata[n].timestamp);
   7.767 +    }
   7.768 +    else {
   7.769 +        // time wrapped around
   7.770 +        //new_qos->qdata[n].ns_passed += (now + (~0LL - new_qos->qdata[n].timestamp));
   7.771 +        //    printf("why timewrap?\r\n");
   7.772 +    }
   7.773 +    new_qos->qdata[n].timestamp = now;
   7.774 +}
   7.775 +
   7.776 +
   7.777 +// called by dump routines to update all structures
   7.778 +void qos_update_all(uint64_t now, int cpu)
   7.779 +{
   7.780 +    int i;
   7.781 +
   7.782 +    for (i=0; i<NDOMAINS; i++)
   7.783 +        if (new_qos->domain_info[i].in_use)
   7.784 +            qos_update_thread(cpu, i, now);
   7.785 +}
   7.786 +
   7.787 +
   7.788 +void qos_update_thread_stats(int cpu, int domid, uint64_t now)
   7.789 +{
   7.790 +    if (new_qos->qdata[new_qos->next_datapoint].ns_passed > (million*opts.ms_per_sample)) {
   7.791 +        qos_update_all(now, cpu);
   7.792 +        advance_next_datapoint(now);
   7.793 +        return;
   7.794 +    }
   7.795 +    qos_update_thread(cpu, domid, now);
   7.796 +}
   7.797 +
   7.798 +
   7.799 +void qos_init_domain(int cpu, int domid, uint64_t now)
   7.800 +{
   7.801 +    int i, id;
   7.802 +
   7.803 +    id = ID(domid);
   7.804 +
   7.805 +    if (new_qos->domain_info[id].in_use)
   7.806 +        return;
   7.807 +
   7.808 +
   7.809 +    memset(&new_qos->domain_info[id], 0, sizeof(_domain_info));
   7.810 +    new_qos->domain_info[id].last_update_time = now;
   7.811 +    //  runnable_start_time[id] = 0;
   7.812 +    new_qos->domain_info[id].runnable_start_time = 0; // invalidate
   7.813 +    new_qos->domain_info[id].in_use = 1;
   7.814 +    new_qos->domain_info[id].blocked_start_time = 0;
   7.815 +    new_qos->domain_info[id].id = id;
   7.816 +    if (domid == IDLE_DOMAIN_ID)
   7.817 +        sprintf(new_qos->domain_info[id].name, "Idle Task%d", cpu);
   7.818 +    else
   7.819 +        sprintf(new_qos->domain_info[id].name, "Domain#%d", domid);
   7.820 +
   7.821 +    for (i=0; i<NSAMPLES; i++) {
   7.822 +        new_qos->qdata[i].ns_gotten[id] = 0;
   7.823 +        new_qos->qdata[i].ns_allocated[id] = 0;
   7.824 +        new_qos->qdata[i].ns_waiting[id] = 0;
   7.825 +        new_qos->qdata[i].ns_blocked[id] = 0;
   7.826 +        new_qos->qdata[i].switchin_count[id] = 0;
   7.827 +        new_qos->qdata[i].io_count[id] = 0;
   7.828 +    }
   7.829 +}
   7.830 +
   7.831 +
   7.832 +// called when a new thread gets the cpu
   7.833 +void qos_switch_in(int cpu, int domid, uint64_t now, unsigned long ns_alloc, unsigned long ns_waited)
   7.834 +{
   7.835 +    int id = ID(domid);
   7.836 +
   7.837 +    new_qos->domain_info[id].runnable = 1;
   7.838 +    update_blocked_time(domid, now);
   7.839 +    new_qos->domain_info[id].blocked_start_time = 0; // invalidate
   7.840 +    new_qos->domain_info[id].runnable_start_time = 0; // invalidate
   7.841 +    //runnable_start_time[id] = 0;
   7.842 +
   7.843 +    new_qos->domain_info[id].start_time = now;
   7.844 +    new_qos->qdata[new_qos->next_datapoint].switchin_count[id]++;
   7.845 +    new_qos->qdata[new_qos->next_datapoint].ns_allocated[id] += ns_alloc;
   7.846 +    new_qos->qdata[new_qos->next_datapoint].ns_waiting[id] += ns_waited;
   7.847 +    qos_update_thread_stats(cpu, domid, now);
   7.848 +    set_current(cpu, id);
   7.849 +
   7.850 +    // count up page flips for dom0 execution
   7.851 +    if (id == 0)
   7.852 +      dom0_flips = 0;
   7.853 +}
   7.854 +
   7.855 +// called when the current thread is taken off the cpu
   7.856 +void qos_switch_out(int cpu, int domid, uint64_t now, unsigned long gotten)
   7.857 +{
   7.858 +    int id = ID(domid);
   7.859 +    int n;
   7.860 +
   7.861 +    if (!is_current(id, cpu)) {
   7.862 +        //    printf("switching out domain %d but it is not current. gotten=%ld\r\n", id, gotten);
   7.863 +    }
   7.864 +
   7.865 +    if (gotten == 0) {
   7.866 +        printf("gotten==0 in qos_switchout(domid=%d)\n", domid);
   7.867 +    }
   7.868 +
   7.869 +    if (gotten < 100) {
   7.870 +        printf("gotten<100ns in qos_switchout(domid=%d)\n", domid);
   7.871 +    }
   7.872 +
   7.873 +
   7.874 +    n = new_qos->next_datapoint;
   7.875 +#if 0
   7.876 +    new_qos->qdata[n].ns_gotten[id] += gotten;
   7.877 +    if (gotten > new_qos->qdata[n].ns_passed)
   7.878 +      printf("inconsistency #257, diff = %lld\n",
   7.879 +	    gotten - new_qos->qdata[n].ns_passed );
   7.880 +#endif
   7.881 +    new_qos->domain_info[id].ns_oncpu_since_boot += gotten;
   7.882 +    new_qos->domain_info[id].runnable_start_time = now;
   7.883 +    //  runnable_start_time[id] = now;
   7.884 +    qos_update_thread_stats(cpu, id, now);
   7.885 +
   7.886 +    // process dom0 page flips
   7.887 +    if (id == 0)
   7.888 +      if (dom0_flips == 0)
   7.889 +	new_qos->qdata[n].flip_free_periods++;
   7.890 +}
   7.891 +
   7.892 +// called when domain is put to sleep, may also be called
   7.893 +// when thread is already asleep
   7.894 +void qos_state_sleeping(int cpu, int domid, uint64_t now) 
   7.895 +{
   7.896 +    int id = ID(domid);
   7.897 +
   7.898 +    if (!domain_runnable(id))	// double call?
   7.899 +        return;
   7.900 +
   7.901 +    new_qos->domain_info[id].runnable = 0;
   7.902 +    new_qos->domain_info[id].blocked_start_time = now;
   7.903 +    new_qos->domain_info[id].runnable_start_time = 0; // invalidate
   7.904 +    //  runnable_start_time[id] = 0; // invalidate
   7.905 +    qos_update_thread_stats(cpu, domid, now);
   7.906 +}
   7.907 +
   7.908 +
   7.909 +
   7.910 +void qos_kill_thread(int domid)
   7.911 +{
   7.912 +    new_qos->domain_info[ID(domid)].in_use = 0;
   7.913 +}
   7.914 +
   7.915 +
   7.916 +// called when thread becomes runnable, may also be called
   7.917 +// when thread is already runnable
   7.918 +void qos_state_runnable(int cpu, int domid, uint64_t now)
   7.919 +{
   7.920 +    int id = ID(domid);
   7.921 +
   7.922 +    if (domain_runnable(id))	// double call?
   7.923 +        return;
   7.924 +    new_qos->domain_info[id].runnable = 1;
   7.925 +    update_blocked_time(domid, now);
   7.926 +
   7.927 +    qos_update_thread_stats(cpu, domid, now);
   7.928 +
   7.929 +    new_qos->domain_info[id].blocked_start_time = 0; /* invalidate */
   7.930 +    new_qos->domain_info[id].runnable_start_time = now;
   7.931 +    //  runnable_start_time[id] = now;
   7.932 +}
   7.933 +
   7.934 +
   7.935 +void qos_count_packets(domid_t domid, uint64_t now)
   7.936 +{
   7.937 +  int i, id = ID(domid);
   7.938 +  _new_qos_data *cpu_data;
   7.939 +
   7.940 +  for (i=0; i<NCPU; i++) {
   7.941 +    cpu_data = cpu_qos_data[i];
   7.942 +    if (cpu_data->domain_info[id].in_use) {
   7.943 +      cpu_data->qdata[cpu_data->next_datapoint].io_count[id]++;
   7.944 +    }
   7.945 +  }
   7.946 +
   7.947 +  new_qos->qdata[new_qos->next_datapoint].io_count[0]++;
   7.948 +  dom0_flips++;
   7.949 +}
   7.950 +
   7.951 +
   7.952 +int domain_ok(int cpu, int domid, uint64_t now)
   7.953 +{
   7.954 +    if (domid == IDLE_DOMAIN_ID)
   7.955 +        domid = NDOMAINS-1;
   7.956 +    if (domid < 0 || domid >= NDOMAINS) {
   7.957 +        printf("bad domain id: %d\n", domid);
   7.958 +        return 0;
   7.959 +    }
   7.960 +    if (new_qos->domain_info[domid].in_use == 0)
   7.961 +        qos_init_domain(cpu, domid, now);
   7.962 +    return 1;
   7.963 +}
   7.964 +
   7.965 +
   7.966 +void process_record(int cpu, struct t_rec *r)
   7.967 +{
   7.968 +  uint64_t now;
   7.969 +
   7.970 +
   7.971 +  new_qos = cpu_qos_data[cpu];
   7.972 +
   7.973 +  rec_count++;
   7.974 +
   7.975 +  now = ((double)r->cycles) / (opts.cpu_freq / 1000.0);
   7.976 +
   7.977 +  log_event(r->event);
   7.978 +
   7.979 +  switch (r->event) {
   7.980 +
   7.981 +  case TRC_SCHED_SWITCH_INFPREV:
   7.982 +    // domain data[0] just switched out and received data[1] ns of cpu time
   7.983 +    if (domain_ok(cpu, r->data[0], now))
   7.984 +      qos_switch_out(cpu, r->data[0], now, r->data[1]);
   7.985 +    //    printf("ns_gotten %ld\n", r->data[1]);
   7.986 +    break;
   7.987 +    
   7.988 +  case TRC_SCHED_SWITCH_INFNEXT:
   7.989 +    // domain data[0] just switched in and
   7.990 +    // waited data[1] ns, and was allocated data[2] ns of cpu time
   7.991 +    if (domain_ok(cpu, r->data[0], now))
   7.992 +      qos_switch_in(cpu, r->data[0], now, r->data[2], r->data[1]);
   7.993 +    break;
   7.994 +    
   7.995 +  case TRC_SCHED_DOM_ADD:
   7.996 +    if (domain_ok(cpu, r->data[0], now))
   7.997 +      qos_init_domain(cpu, r->data[0],  now);
   7.998 +    break;
   7.999 +    
  7.1000 +  case TRC_SCHED_DOM_REM:
  7.1001 +    if (domain_ok(cpu, r->data[0], now))
  7.1002 +      qos_kill_thread(r->data[0]);
  7.1003 +    break;
  7.1004 +    
  7.1005 +  case TRC_SCHED_SLEEP:
  7.1006 +    if (domain_ok(cpu, r->data[0], now))
  7.1007 +      qos_state_sleeping(cpu, r->data[0], now);
  7.1008 +    break;
  7.1009 +    
  7.1010 +  case TRC_SCHED_WAKE:
  7.1011 +    if (domain_ok(cpu, r->data[0], now))
  7.1012 +      qos_state_runnable(cpu, r->data[0], now);
  7.1013 +    break;
  7.1014 +    
  7.1015 +  case TRC_SCHED_BLOCK:
  7.1016 +    if (domain_ok(cpu, r->data[0], now))
  7.1017 +      qos_state_sleeping(cpu, r->data[0], now);
  7.1018 +    break;
  7.1019 +    
  7.1020 +  case TRC_MEM_PAGE_GRANT_TRANSFER:
  7.1021 +    if (domain_ok(cpu, r->data[0], now))
  7.1022 +      qos_count_packets(r->data[0], now);
  7.1023 +    break;
  7.1024 +    
  7.1025 +  default:
  7.1026 +    break;
  7.1027 +  }
  7.1028 +  new_qos = NULL;
  7.1029 +}
  7.1030 +
  7.1031 +
  7.1032 +
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/tools/xenmon/xenbaked.h	Tue Nov 15 15:44:37 2005 +0100
     8.3 @@ -0,0 +1,101 @@
     8.4 +/******************************************************************************
     8.5 + * tools/xenbaked.h
     8.6 + *
     8.7 + * Header file for xenbaked
     8.8 + *
     8.9 + * Copyright (C) 2005 by Hewlett Packard, Palo Alto and Fort Collins
    8.10 + *
    8.11 + * Authors: Diwaker Gupta, diwaker.gupta@hp.com
    8.12 + *          Rob Gardner, rob.gardner@hp.com
    8.13 + *          Lucy Cherkasova, lucy.cherkasova.hp.com
    8.14 + * 
    8.15 + *  This program is free software; you can redistribute it and/or modify
    8.16 + *  it under the terms of the GNU General Public License as published by
    8.17 + *  the Free Software Foundation; under version 2 of the License.
    8.18 + *
    8.19 + *  This program is distributed in the hope that it will be useful,
    8.20 + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
    8.21 + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    8.22 + *  GNU General Public License for more details.
    8.23 + *
    8.24 + *  You should have received a copy of the GNU General Public License
    8.25 + *  along with this program; if not, write to the Free Software
    8.26 + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    8.27 + */
    8.28 +
    8.29 +#ifndef __QOS_H__
    8.30 +#define __QOS_H__
    8.31 +
    8.32 +///// qos stuff
    8.33 +#define million 1000000LL
    8.34 +#define billion 1000000000LL
    8.35 +
    8.36 +#define QOS_ADD(N,A) ((N+A)<(NSAMPLES-1) ? (N+A) : A)
    8.37 +#define QOS_INCR(N) ((N<(NSAMPLES-2)) ? (N+1) : 0)
    8.38 +#define QOS_DECR(N) ((N==0) ? (NSAMPLES-1) : (N-1))
    8.39 +
    8.40 +#define MAX_NAME_SIZE 32
    8.41 +#define IDLE_DOMAIN_ID 32767
    8.42 +
    8.43 +/* Number of domains we can keep track of in memory */
    8.44 +#define NDOMAINS 32
    8.45 +
    8.46 +/* Number of data points to keep */
    8.47 +#define NSAMPLES 100
    8.48 +
    8.49 +
    8.50 +// per domain stuff
    8.51 +typedef struct 
    8.52 +{
    8.53 +  uint64_t last_update_time;
    8.54 +  uint64_t start_time;		// when the thread started running
    8.55 +  uint64_t runnable_start_time;	// when the thread became runnable
    8.56 +  uint64_t blocked_start_time;	// when the thread became blocked
    8.57 +  uint64_t ns_since_boot;		// time gone by since boot
    8.58 +  uint64_t ns_oncpu_since_boot;	// total cpu time used by thread since boot
    8.59 +  //  uint64_t ns_runnable_since_boot;
    8.60 +  int runnable_at_last_update; // true if the thread was runnable last time we checked.
    8.61 +  int runnable;			// true if thread is runnable right now
    8.62 +  // tells us something about what happened during the 
    8.63 +  // sample period that we are analysing right now
    8.64 +  int in_use;			// 
    8.65 +  domid_t  id;
    8.66 +  char     name[MAX_NAME_SIZE];
    8.67 +} _domain_info;
    8.68 +
    8.69 +
    8.70 +
    8.71 +typedef struct 
    8.72 +{
    8.73 +  struct 
    8.74 +  {
    8.75 +// data point:
    8.76 +//   stuff that is recorded once for each measurement interval
    8.77 +    uint64_t ns_gotten[NDOMAINS];		// ns used in the last sample period
    8.78 +    uint64_t ns_allocated[NDOMAINS];		// ns allocated by scheduler
    8.79 +    uint64_t ns_waiting[NDOMAINS];		// ns spent waiting to execute, ie, time from
    8.80 +                                        // becoming runnable until actually running
    8.81 +    uint64_t ns_blocked[NDOMAINS];		// ns spent blocked
    8.82 +    uint64_t switchin_count[NDOMAINS]; // number of executions of the domain	
    8.83 +    uint64_t io_count[NDOMAINS];
    8.84 +    uint64_t ns_passed;              // ns gone by on the wall clock, ie, the sample period
    8.85 +    uint64_t timestamp;
    8.86 +    uint64_t lost_records;		// # of lost trace records this time period
    8.87 +    uint64_t flip_free_periods;	// # of executions of dom0 in which no page flips happened
    8.88 +  } qdata[NSAMPLES];
    8.89 +  
    8.90 +  _domain_info domain_info[NDOMAINS];
    8.91 +  
    8.92 +  // control information
    8.93 +  int next_datapoint;
    8.94 +  int ncpu;
    8.95 +  int structlen;
    8.96 +
    8.97 +  // parameters
    8.98 +  int measurement_frequency;	// for example
    8.99 +  
   8.100 +} _new_qos_data;
   8.101 +
   8.102 +
   8.103 +
   8.104 +#endif
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/tools/xenmon/xenmon.py	Tue Nov 15 15:44:37 2005 +0100
     9.3 @@ -0,0 +1,578 @@
     9.4 +#!/usr/bin/env python
     9.5 +
     9.6 +#####################################################################
     9.7 +# xenmon is a front-end for xenbaked.
     9.8 +# There is a curses interface for live monitoring. XenMon also allows
     9.9 +# logging to a file. For options, run python xenmon.py -h
    9.10 +#
    9.11 +# Copyright (C) 2005 by Hewlett Packard, Palo Alto and Fort Collins
    9.12 +# Authors: Lucy Cherkasova, lucy.cherkasova@hp.com
    9.13 +#          Rob Gardner, rob.gardner@hp.com
    9.14 +#          Diwaker Gupta, diwaker.gupta@hp.com
    9.15 +#####################################################################
    9.16 +#   This program is free software; you can redistribute it and/or modify
    9.17 +#   it under the terms of the GNU General Public License as published by
    9.18 +#   the Free Software Foundation; under version 2 of the License.
    9.19 +# 
    9.20 +#   This program is distributed in the hope that it will be useful,
    9.21 +#   but WITHOUT ANY WARRANTY; without even the implied warranty of
    9.22 +#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    9.23 +#   GNU General Public License for more details.
    9.24 +# 
    9.25 +#   You should have received a copy of the GNU General Public License
    9.26 +#   along with this program; if not, write to the Free Software
    9.27 +#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    9.28 +#####################################################################
    9.29 +
    9.30 +import mmap
    9.31 +import struct
    9.32 +import os
    9.33 +import time
    9.34 +import optparse as _o
    9.35 +import curses as _c
    9.36 +import math
    9.37 +import sys
    9.38 +
    9.39 +# constants
    9.40 +NSAMPLES = 100
    9.41 +NDOMAINS = 32
    9.42 +
    9.43 +# the struct strings for qos_info
    9.44 +ST_DOM_INFO = "6Q4i32s"
    9.45 +ST_QDATA = "%dQ" % (6*NDOMAINS + 4)
    9.46 +
    9.47 +# size of mmaped file
    9.48 +QOS_DATA_SIZE = struct.calcsize(ST_QDATA)*NSAMPLES + struct.calcsize(ST_DOM_INFO)*NDOMAINS + struct.calcsize("4i")
    9.49 +
    9.50 +# location of mmaped file, hard coded right now
    9.51 +SHM_FILE = "/tmp/xenq-shm"
    9.52 +
    9.53 +# format strings
    9.54 +TOTALS = 15*' ' + "%6.2f%%" + 35*' ' + "%6.2f%%"
    9.55 +
    9.56 +ALLOCATED = "Allocated"
    9.57 +GOTTEN = "Gotten"
    9.58 +BLOCKED = "Blocked"
    9.59 +WAITED = "Waited"
    9.60 +IOCOUNT = "I/O Count"
    9.61 +EXCOUNT = "Exec Count"
    9.62 +
    9.63 +# globals
    9.64 +# our curses screen
    9.65 +stdscr = None
    9.66 +
    9.67 +# parsed options
    9.68 +options, args = None, None
    9.69 +
    9.70 +# the optparse module is quite smart
    9.71 +# to see help, just run xenmon -h
    9.72 +def setup_cmdline_parser():
    9.73 +    parser = _o.OptionParser()
    9.74 +    parser.add_option("-l", "--live", dest="live", action="store_true",
    9.75 +                      default=True, help = "show the ncurses live monitoring frontend (default)")
    9.76 +    parser.add_option("-n", "--notlive", dest="live", action="store_false",
    9.77 +                      default="True", help = "write to file instead of live monitoring")
    9.78 +    parser.add_option("-p", "--prefix", dest="prefix",
    9.79 +                      default = "log", help="prefix to use for output files")
    9.80 +    parser.add_option("-t", "--time", dest="duration",
    9.81 +            action="store", type="int", default=10, 
    9.82 +            help="stop logging to file after this much time has elapsed (in seconds). set to 0 to keep logging indefinitely")
    9.83 +    parser.add_option("-i", "--interval", dest="interval",
    9.84 +            action="store", type="int", default=1000,
    9.85 +            help="interval for logging (in ms)")
    9.86 +    parser.add_option("--ms_per_sample", dest="mspersample",
    9.87 +            action="store", type="int", default=100,
    9.88 +            help = "determines how many ms worth of data goes in a sample")
    9.89 +    return parser
    9.90 +
    9.91 +# encapsulate information about a domain
    9.92 +class DomainInfo:
    9.93 +    def __init__(self):
    9.94 +        self.allocated_samples = []
    9.95 +        self.gotten_samples = []
    9.96 +        self.blocked_samples = []
    9.97 +        self.waited_samples = []
    9.98 +        self.execcount_samples = []
    9.99 +        self.iocount_samples = []
   9.100 +        self.ffp_samples = []
   9.101 +
   9.102 +    def gotten_stats(self, passed):
   9.103 +        total = float(sum(self.gotten_samples))
   9.104 +        per = 100*total/passed
   9.105 +        exs = sum(self.execcount_samples)
   9.106 +        if exs > 0:
   9.107 +            avg = total/exs
   9.108 +        else:
   9.109 +            avg = 0
   9.110 +        return [total/(float(passed)/10**9), per, avg]
   9.111 +
   9.112 +    def waited_stats(self, passed):
   9.113 +        total = float(sum(self.waited_samples))
   9.114 +        per = 100*total/passed
   9.115 +        exs = sum(self.execcount_samples)
   9.116 +        if exs > 0:
   9.117 +            avg = total/exs
   9.118 +        else:
   9.119 +            avg = 0
   9.120 +        return [total/(float(passed)/10**9), per, avg]
   9.121 +
   9.122 +    def blocked_stats(self, passed):
   9.123 +        total = float(sum(self.blocked_samples))
   9.124 +        per = 100*total/passed
   9.125 +        ios = sum(self.iocount_samples)
   9.126 +        if ios > 0:
   9.127 +            avg = total/float(ios)
   9.128 +        else:
   9.129 +            avg = 0
   9.130 +        return [total/(float(passed)/10**9), per, avg]
   9.131 +
   9.132 +    def allocated_stats(self, passed):
   9.133 +        total = sum(self.allocated_samples)
   9.134 +        exs = sum(self.execcount_samples)
   9.135 +        if exs > 0:
   9.136 +            return float(total)/exs
   9.137 +        else:
   9.138 +            return 0
   9.139 +
   9.140 +    def ec_stats(self, passed):
   9.141 +        total = float(sum(self.execcount_samples))/(float(passed)/10**9)
   9.142 +        return total
   9.143 +
   9.144 +    def io_stats(self, passed):
   9.145 +        total = float(sum(self.iocount_samples))
   9.146 +        exs = sum(self.execcount_samples)
   9.147 +        if exs > 0:
   9.148 +            avg = total/exs
   9.149 +        else:
   9.150 +            avg = 0
   9.151 +        return [total/(float(passed)/10**9), avg]
   9.152 +
   9.153 +    def stats(self, passed):
   9.154 +        return [self.gotten_stats(passed), self.allocated_stats(passed), self.blocked_stats(passed), 
   9.155 +                self.waited_stats(passed), self.ec_stats(passed), self.io_stats(passed)]
   9.156 +
   9.157 +# report values over desired interval
   9.158 +def summarize(startat, endat, duration, samples):
   9.159 +    dominfos = {}
   9.160 +    for i in range(0, NDOMAINS):
   9.161 +        dominfos[i] = DomainInfo()
   9.162 +        
   9.163 +    passed = 1              # to prevent zero division
   9.164 +    curid = startat
   9.165 +    numbuckets = 0
   9.166 +    lost_samples = []
   9.167 +    ffp_samples = []
   9.168 +    
   9.169 +    while passed < duration:
   9.170 +        for i in range(0, NDOMAINS):
   9.171 +            dominfos[i].gotten_samples.append(samples[curid][0*NDOMAINS + i])
   9.172 +            dominfos[i].allocated_samples.append(samples[curid][1*NDOMAINS + i])
   9.173 +            dominfos[i].waited_samples.append(samples[curid][2*NDOMAINS + i])
   9.174 +            dominfos[i].blocked_samples.append(samples[curid][3*NDOMAINS + i])
   9.175 +            dominfos[i].execcount_samples.append(samples[curid][4*NDOMAINS + i])
   9.176 +            dominfos[i].iocount_samples.append(samples[curid][5*NDOMAINS + i])
   9.177 +    
   9.178 +        passed += samples[curid][6*NDOMAINS]
   9.179 +        lost_samples.append(samples[curid][6*NDOMAINS + 2])
   9.180 +        ffp_samples.append(samples[curid][6*NDOMAINS + 3])
   9.181 +
   9.182 +        numbuckets += 1
   9.183 +
   9.184 +        if curid > 0:
   9.185 +            curid -= 1
   9.186 +        else:
   9.187 +            curid = NSAMPLES - 1
   9.188 +        if curid == endat:
   9.189 +            break
   9.190 +
   9.191 +    lostinfo = [min(lost_samples), sum(lost_samples), max(lost_samples)]
   9.192 +    ffpinfo = [min(ffp_samples), sum(ffp_samples), max(ffp_samples)]
   9.193 +    ldoms = map(lambda x: dominfos[x].stats(passed), range(0, NDOMAINS))
   9.194 +
   9.195 +    return [ldoms, lostinfo, ffpinfo]
   9.196 +
   9.197 +# scale microseconds to milliseconds or seconds as necessary
   9.198 +def time_scale(ns):
   9.199 +    if ns < 1000:
   9.200 +        return "%4.2f ns" % float(ns)
   9.201 +    elif ns < 1000*1000:
   9.202 +        return "%4.2f us" % (float(ns)/10**3)
   9.203 +    elif ns < 10**9:
   9.204 +	    return "%4.2f ms" % (float(ns)/10**6)
   9.205 +    else:
   9.206 +        return "%4.2f s" % (float(ns)/10**9)
   9.207 +
   9.208 +# paint message on curses screen, but detect screen size errors
   9.209 +def display(scr, row, col, str, attr=0):
   9.210 +    try:
   9.211 +        scr.addstr(row, col, str, attr)
   9.212 +    except:
   9.213 +        scr.erase()
   9.214 +        _c.nocbreak()
   9.215 +        scr.keypad(0)
   9.216 +        _c.echo()
   9.217 +        _c.endwin()
   9.218 +        print "Your terminal screen is not big enough; Please resize it."
   9.219 +        print "row=%d, col=%d, str='%s'" % (row, col, str)
   9.220 +        sys.exit(1)
   9.221 +
   9.222 +
   9.223 +# the live monitoring code
   9.224 +def show_livestats():
   9.225 +    cpu = 0          # cpu of interest to display data for
   9.226 +    ncpu = 1         # number of cpu's on this platform
   9.227 +    slen = 0         # size of shared data structure, incuding padding
   9.228 +    
   9.229 +    # mmap the (the first chunk of the) file
   9.230 +    shmf = open(SHM_FILE, "r+")
   9.231 +    shm = mmap.mmap(shmf.fileno(), QOS_DATA_SIZE)
   9.232 +
   9.233 +    samples = []
   9.234 +    doms = []
   9.235 +
   9.236 +    # initialize curses
   9.237 +    stdscr = _c.initscr()
   9.238 +    _c.noecho()
   9.239 +    _c.cbreak()
   9.240 +
   9.241 +    stdscr.keypad(1)
   9.242 +    stdscr.timeout(1000)
   9.243 +    [maxy, maxx] = stdscr.getmaxyx()
   9.244 +
   9.245 +    
   9.246 +
   9.247 +    # display in a loop
   9.248 +    while True:
   9.249 +
   9.250 +        for cpuidx in range(0, ncpu):
   9.251 +
   9.252 +            # calculate offset in mmap file to start from
   9.253 +            idx = cpuidx * slen
   9.254 +
   9.255 +
   9.256 +            samples = []
   9.257 +            doms = []
   9.258 +
   9.259 +            # read in data
   9.260 +            for i in range(0, NSAMPLES):
   9.261 +                len = struct.calcsize(ST_QDATA)
   9.262 +                sample = struct.unpack(ST_QDATA, shm[idx:idx+len])
   9.263 +                samples.append(sample)
   9.264 +                idx += len
   9.265 +
   9.266 +            for i in range(0, NDOMAINS):
   9.267 +                len = struct.calcsize(ST_DOM_INFO)
   9.268 +                dom = struct.unpack(ST_DOM_INFO, shm[idx:idx+len])
   9.269 +                doms.append(dom)
   9.270 +                idx += len
   9.271 +
   9.272 +            len = struct.calcsize("4i")
   9.273 +            oldncpu = ncpu
   9.274 +            (next, ncpu, slen, freq) = struct.unpack("4i", shm[idx:idx+len])
   9.275 +            idx += len
   9.276 +
   9.277 +            # xenbaked tells us how many cpu's it's got, so re-do
   9.278 +            # the mmap if necessary to get multiple cpu data
   9.279 +            if oldncpu != ncpu:
   9.280 +                shm = mmap.mmap(shmf.fileno(), ncpu*slen)
   9.281 +
   9.282 +            # if we've just calculated data for the cpu of interest, then
   9.283 +            # stop examining mmap data and start displaying stuff
   9.284 +            if cpuidx == cpu:
   9.285 +                break
   9.286 +
   9.287 +        # calculate starting and ending datapoints; never look at "next" since
   9.288 +        # it represents live data that may be in transition. 
   9.289 +        startat = next - 1
   9.290 +        if next + 10 < NSAMPLES:
   9.291 +            endat = next + 10
   9.292 +        else:
   9.293 +            endat = 10
   9.294 +
   9.295 +        # get summary over desired interval
   9.296 +        [h1, l1, f1] = summarize(startat, endat, 10**9, samples)
   9.297 +        [h2, l2, f2] = summarize(startat, endat, 10 * 10**9, samples)
   9.298 +
   9.299 +        # the actual display code
   9.300 +        row = 0
   9.301 +        display(stdscr, row, 1, "CPU = %d" % cpu, _c.A_STANDOUT)
   9.302 +
   9.303 +        display(stdscr, row, 10, "%sLast 10 seconds%sLast 1 second" % (6*' ', 30*' '), _c.A_BOLD)
   9.304 +        row +=1
   9.305 +        display(stdscr, row, 1, "%s" % ((maxx-2)*'='))
   9.306 +
   9.307 +        total_h1_cpu = 0
   9.308 +        total_h2_cpu = 0
   9.309 +
   9.310 +        for dom in range(0, NDOMAINS):
   9.311 +            if h1[dom][0][1] > 0 or dom == NDOMAINS - 1:
   9.312 +                # display gotten
   9.313 +                row += 1 
   9.314 +                col = 2
   9.315 +                display(stdscr, row, col, "%d" % dom)
   9.316 +                col += 4
   9.317 +                display(stdscr, row, col, "%s" % time_scale(h2[dom][0][0]))
   9.318 +                col += 12
   9.319 +                display(stdscr, row, col, "%3.2f%%" % h2[dom][0][1])
   9.320 +                col += 12
   9.321 +                display(stdscr, row, col, "%s/ex" % time_scale(h2[dom][0][2]))
   9.322 +                col += 18
   9.323 +                display(stdscr, row, col, "%s" % time_scale(h1[dom][0][0]))
   9.324 +                col += 12
   9.325 +                display(stdscr, row, col, "%3.2f%%" % h1[dom][0][1])
   9.326 +                col += 12
   9.327 +                display(stdscr, row, col, "%s/ex" % time_scale(h1[dom][0][2]))
   9.328 +                col += 18
   9.329 +                display(stdscr, row, col, "Gotten")
   9.330 +    
   9.331 +                # display allocated
   9.332 +                row += 1
   9.333 +                col = 2
   9.334 +                display(stdscr, row, col, "%d" % dom)
   9.335 +                col += 28
   9.336 +                display(stdscr, row, col, "%s/ex" % time_scale(h2[dom][1]))
   9.337 +                col += 42
   9.338 +                display(stdscr, row, col, "%s/ex" % time_scale(h1[dom][1]))
   9.339 +                col += 18
   9.340 +                display(stdscr, row, col, "Allocated")
   9.341 +
   9.342 +                # display blocked
   9.343 +                row += 1
   9.344 +                col = 2
   9.345 +                display(stdscr, row, col, "%d" % dom)
   9.346 +                col += 4
   9.347 +                display(stdscr, row, col, "%s" % time_scale(h2[dom][2][0]))
   9.348 +                col += 12
   9.349 +                display(stdscr, row, col, "%3.2f%%" % h2[dom][2][1])
   9.350 +                col += 12
   9.351 +                display(stdscr, row, col, "%s/io" % time_scale(h2[dom][2][2]))
   9.352 +                col += 18
   9.353 +                display(stdscr, row, col, "%s" % time_scale(h1[dom][2][0]))
   9.354 +                col += 12
   9.355 +                display(stdscr, row, col, "%3.2f%%" % h1[dom][2][1])
   9.356 +                col += 12
   9.357 +                display(stdscr, row, col, "%s/io" % time_scale(h1[dom][2][2]))
   9.358 +                col += 18
   9.359 +                display(stdscr, row, col, "Blocked")
   9.360 +
   9.361 +                # display waited
   9.362 +                row += 1
   9.363 +                col = 2
   9.364 +                display(stdscr, row, col, "%d" % dom)
   9.365 +                col += 4
   9.366 +                display(stdscr, row, col, "%s" % time_scale(h2[dom][3][0]))
   9.367 +                col += 12
   9.368 +                display(stdscr, row, col, "%3.2f%%" % h2[dom][3][1])
   9.369 +                col += 12
   9.370 +                display(stdscr, row, col, "%s/ex" % time_scale(h2[dom][3][2]))
   9.371 +                col += 18
   9.372 +                display(stdscr, row, col, "%s" % time_scale(h1[dom][3][0]))
   9.373 +                col += 12
   9.374 +                display(stdscr, row, col, "%3.2f%%" % h1[dom][3][1])
   9.375 +                col += 12
   9.376 +                display(stdscr, row, col, "%s/ex" % time_scale(h1[dom][3][2]))
   9.377 +                col += 18
   9.378 +                display(stdscr, row, col, "Waited")
   9.379 +
   9.380 +                # display ex count
   9.381 +                row += 1
   9.382 +                col = 2
   9.383 +                display(stdscr, row, col, "%d" % dom)
   9.384 +
   9.385 +                col += 28
   9.386 +                display(stdscr, row, col, "%d/s" % h2[dom][4])
   9.387 +                col += 42
   9.388 +                display(stdscr, row, col, "%d" % h1[dom][4])
   9.389 +                col += 18
   9.390 +                display(stdscr, row, col, "Execution count")
   9.391 +
   9.392 +                # display io count
   9.393 +                row += 1
   9.394 +                col = 2
   9.395 +                display(stdscr, row, col, "%d" % dom)
   9.396 +                col += 4
   9.397 +                display(stdscr, row, col, "%d/s" % h2[dom][5][0])
   9.398 +                col += 24
   9.399 +                display(stdscr, row, col, "%d/ex" % h2[dom][5][1])
   9.400 +                col += 18
   9.401 +                display(stdscr, row, col, "%d" % h1[dom][5][0])
   9.402 +                col += 24
   9.403 +                display(stdscr, row, col, "%3.2f/ex" % h1[dom][5][1])
   9.404 +                col += 18
   9.405 +                display(stdscr, row, col, "I/O Count")
   9.406 +
   9.407 +            #row += 1
   9.408 +            #stdscr.hline(row, 1, '-', maxx - 2)
   9.409 +            total_h1_cpu += h1[dom][0][1]
   9.410 +            total_h2_cpu += h2[dom][0][1]
   9.411 +
   9.412 +
   9.413 +        row += 1
   9.414 +        display(stdscr, row, 2, TOTALS % (total_h2_cpu, total_h1_cpu))
   9.415 +        row += 1
   9.416 +#        display(stdscr, row, 2, 
   9.417 +#                "\tFFP: %d (Min: %d, Max: %d)\t\t\tFFP: %d (Min: %d, Max %d)" % 
   9.418 +#                (math.ceil(f2[1]), f2[0], f2[2], math.ceil(f1[1]), f1[0], f1[2]), _c.A_BOLD)
   9.419 +
   9.420 +        if l1[1] > 1 :
   9.421 +            row += 1
   9.422 +            display(stdscr, row, 2, 
   9.423 +                    "\tRecords lost: %d (Min: %d, Max: %d)\t\t\tRecords lost: %d (Min: %d, Max %d)" % 
   9.424 +                    (math.ceil(l2[1]), l2[0], l2[2], math.ceil(l1[1]), l1[0], l1[2]), _c.A_BOLD)
   9.425 +
   9.426 +        # grab a char from tty input; exit if interrupt hit
   9.427 +        try:
   9.428 +            c = stdscr.getch()
   9.429 +        except:
   9.430 +            break
   9.431 +        
   9.432 +        # q = quit
   9.433 +        if c == ord('q'):
   9.434 +            break
   9.435 +    
   9.436 +        # c = cycle to a new cpu of interest
   9.437 +        if c == ord('c'):
   9.438 +            cpu = (cpu + 1) % ncpu
   9.439 +
   9.440 +        stdscr.erase()
   9.441 +
   9.442 +    _c.nocbreak()
   9.443 +    stdscr.keypad(0)
   9.444 +    _c.echo()
   9.445 +    _c.endwin()
   9.446 +    shm.close()
   9.447 +    shmf.close()
   9.448 +
   9.449 +
   9.450 +# simple functions to allow initialization of log files without actually
   9.451 +# physically creating files that are never used; only on the first real
   9.452 +# write does the file get created
   9.453 +class Delayed(file):
   9.454 +    def __init__(self, filename, mode):
   9.455 +	self.filename = filename
   9.456 +	self.saved_mode = mode
   9.457 +	self.delay_data = ""
   9.458 +	self.opened = 0
   9.459 +
   9.460 +    def delayed_write(self, str):
   9.461 +	self.delay_data = str
   9.462 +
   9.463 +    def write(self, str):
   9.464 +	if not self.opened:
   9.465 +	    self.file = open(self.filename, self.saved_mode)
   9.466 +	    self.opened = 1
   9.467 +            self.file.write(self.delay_data)
   9.468 +	self.file.write(str)
   9.469 +
   9.470 +    def flush(self):
   9.471 +        if  self.opened:
   9.472 +            self.file.flush()
   9.473 +
   9.474 +    def close(self):
   9.475 +        if  self.opened:
   9.476 +            self.file.close()
   9.477 +            
   9.478 +
   9.479 +def writelog():
   9.480 +    global options
   9.481 +
   9.482 +    ncpu = 1        # number of cpu's
   9.483 +    slen = 0        # size of shared structure inc. padding
   9.484 +
   9.485 +    shmf = open(SHM_FILE, "r+")
   9.486 +    shm = mmap.mmap(shmf.fileno(), QOS_DATA_SIZE)
   9.487 +
   9.488 +    interval = 0
   9.489 +    outfiles = {}
   9.490 +    for dom in range(0, NDOMAINS):
   9.491 +        outfiles[dom] = Delayed("%s-dom%d.log" % (options.prefix, dom), 'w')
   9.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")
   9.493 +
   9.494 +    while options.duration == 0 or interval < (options.duration * 1000):
   9.495 +        for cpuidx in range(0, ncpu):
   9.496 +            idx = cpuidx * slen      # offset needed in mmap file
   9.497 +
   9.498 +
   9.499 +            samples = []
   9.500 +            doms = []
   9.501 +
   9.502 +            for i in range(0, NSAMPLES):
   9.503 +                len = struct.calcsize(ST_QDATA)
   9.504 +                sample = struct.unpack(ST_QDATA, shm[idx:idx+len])
   9.505 +                samples.append(sample)
   9.506 +                idx += len
   9.507 +
   9.508 +            for i in range(0, NDOMAINS):
   9.509 +                len = struct.calcsize(ST_DOM_INFO)
   9.510 +                dom = struct.unpack(ST_DOM_INFO, shm[idx:idx+len])
   9.511 +                doms.append(dom)
   9.512 +                idx += len
   9.513 +
   9.514 +            len = struct.calcsize("4i")
   9.515 +            oldncpu = ncpu
   9.516 +            (next, ncpu, slen, freq) = struct.unpack("4i", shm[idx:idx+len])
   9.517 +            idx += len
   9.518 +
   9.519 +            if oldncpu != ncpu:
   9.520 +                shm = mmap.mmap(shmf.fileno(), ncpu*slen)
   9.521 +
   9.522 +            startat = next - 1
   9.523 +            if next + 10 < NSAMPLES:
   9.524 +                endat = next + 10
   9.525 +            else:
   9.526 +                endat = 10
   9.527 +
   9.528 +            [h1,l1, f1] = summarize(startat, endat, options.interval * 10**6, samples)
   9.529 +            for dom in range(0, NDOMAINS):
   9.530 +                if h1[dom][0][1] > 0 or dom == NDOMAINS - 1:
   9.531 +                    outfiles[dom].write("%.3f %d %d %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f\n" %
   9.532 +                                     (interval, cpuidx, dom,
   9.533 +                                     h1[dom][0][0], h1[dom][0][1], h1[dom][0][2],
   9.534 +                                     h1[dom][1],
   9.535 +                                     h1[dom][2][0], h1[dom][2][1], h1[dom][2][2],
   9.536 +                                     h1[dom][3][0], h1[dom][3][1], h1[dom][3][2],
   9.537 +                                     h1[dom][4], 
   9.538 +                                     h1[dom][5][0], h1[dom][5][1]))
   9.539 +                    outfiles[dom].flush()
   9.540 +
   9.541 +        interval += options.interval
   9.542 +        time.sleep(1)
   9.543 +
   9.544 +    for dom in range(0, NDOMAINS):
   9.545 +        outfiles[dom].close()
   9.546 +
   9.547 +# start xenbaked
   9.548 +def start_xenbaked():
   9.549 +    global options
   9.550 +    global args
   9.551 +    
   9.552 +    os.system("killall -9 xenbaked")
   9.553 +    # assumes that xenbaked is in your path
   9.554 +    os.system("xenbaked --ms_per_sample=%d &" %
   9.555 +              options.mspersample)
   9.556 +    time.sleep(1)
   9.557 +
   9.558 +# stop xenbaked
   9.559 +def stop_xenbaked():
   9.560 +    os.system("killall -s INT xenbaked")
   9.561 +
   9.562 +def main():
   9.563 +    global options
   9.564 +    global args
   9.565 +    global domains
   9.566 +
   9.567 +    parser = setup_cmdline_parser()
   9.568 +    (options, args) = parser.parse_args()
   9.569 +    
   9.570 +    start_xenbaked()
   9.571 +    if options.live:
   9.572 +        show_livestats()
   9.573 +    else:
   9.574 +        try:
   9.575 +            writelog()
   9.576 +        except:
   9.577 +            print 'Quitting.'
   9.578 +    stop_xenbaked()
   9.579 +
   9.580 +if __name__ == "__main__":
   9.581 +    main()
    10.1 --- a/tools/xentrace/setsize.c	Tue Nov 15 15:36:42 2005 +0100
    10.2 +++ b/tools/xentrace/setsize.c	Tue Nov 15 15:44:37 2005 +0100
    10.3 @@ -9,9 +9,9 @@ int main(int argc, char * argv[])
    10.4    int xc_handle = xc_interface_open();
    10.5    
    10.6    if (xc_tbuf_get_size(xc_handle, &size) != 0) {
    10.7 -    perror("Failure to get tbuf info from Xen. Guess size is 0.");
    10.8 -    printf("This may mean that tracing is not compiled into xen.\n");
    10.9 -    exit(1);
   10.10 +    perror("Failure to get tbuf info from Xen. Guess size is 0");
   10.11 +    printf("This may mean that tracing is not enabled in xen.\n");
   10.12 +    //    exit(1);
   10.13    }
   10.14    else
   10.15      printf("Current tbuf size: 0x%x\n", size);
   10.16 @@ -25,9 +25,10 @@ int main(int argc, char * argv[])
   10.17      perror("set_size Hypercall failure");
   10.18      exit(1);
   10.19    }
   10.20 +  printf("set_size succeeded.\n");
   10.21    
   10.22    if (xc_tbuf_get_size(xc_handle, &size) != 0)
   10.23 -    perror("Failure to get tbuf info from Xen. Guess size is 0.");
   10.24 +    perror("Failure to get tbuf info from Xen. Tracing must be enabled first");
   10.25    else
   10.26      printf("New tbuf size: 0x%x\n", size);
   10.27    
    11.1 --- a/xen/common/grant_table.c	Tue Nov 15 15:36:42 2005 +0100
    11.2 +++ b/xen/common/grant_table.c	Tue Nov 15 15:44:37 2005 +0100
    11.3 @@ -29,6 +29,7 @@
    11.4  #include <xen/shadow.h>
    11.5  #include <xen/mm.h>
    11.6  #include <acm/acm_hooks.h>
    11.7 +#include <xen/trace.h>
    11.8  
    11.9  #if defined(CONFIG_X86_64)
   11.10  #define GRANT_PTE_FLAGS (_PAGE_PRESENT|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER)
   11.11 @@ -379,6 +380,8 @@ static int
   11.12          }
   11.13      }
   11.14  
   11.15 +    TRACE_1D(TRC_MEM_PAGE_GRANT_MAP, dom);
   11.16 +
   11.17      ld->grant_table->maptrack[handle].domid         = dom;
   11.18      ld->grant_table->maptrack[handle].ref_and_flags =
   11.19          (ref << MAPTRACK_REF_SHIFT) |
   11.20 @@ -463,6 +466,8 @@ static int
   11.21          return GNTST_bad_domain;
   11.22      }
   11.23  
   11.24 +    TRACE_1D(TRC_MEM_PAGE_GRANT_UNMAP, dom);
   11.25 +
   11.26      act = &rd->grant_table->active[ref];
   11.27      sha = &rd->grant_table->shared[ref];
   11.28  
   11.29 @@ -802,6 +807,8 @@ gnttab_transfer(
   11.30          page_set_owner(page, e);
   11.31          
   11.32          spin_unlock(&e->page_alloc_lock);
   11.33 +
   11.34 +        TRACE_1D(TRC_MEM_PAGE_GRANT_TRANSFER, e->domain_id);
   11.35          
   11.36          /* Tell the guest about its new page frame. */
   11.37          sha = &e->grant_table->shared[gop->ref];
    12.1 --- a/xen/common/schedule.c	Tue Nov 15 15:36:42 2005 +0100
    12.2 +++ b/xen/common/schedule.c	Tue Nov 15 15:44:37 2005 +0100
    12.3 @@ -13,15 +13,6 @@
    12.4   *
    12.5   */
    12.6  
    12.7 -/*#define WAKE_HISTO*/
    12.8 -/*#define BLOCKTIME_HISTO*/
    12.9 -
   12.10 -#if defined(WAKE_HISTO)
   12.11 -#define BUCKETS 31
   12.12 -#elif defined(BLOCKTIME_HISTO)
   12.13 -#define BUCKETS 200
   12.14 -#endif
   12.15 -
   12.16  #include <xen/config.h>
   12.17  #include <xen/init.h>
   12.18  #include <xen/lib.h>
   12.19 @@ -45,6 +36,8 @@ extern void arch_getdomaininfo_ctxt(stru
   12.20  static char opt_sched[10] = "sedf";
   12.21  string_param("sched", opt_sched);
   12.22  
   12.23 +/*#define WAKE_HISTO*/
   12.24 +/*#define BLOCKTIME_HISTO*/
   12.25  #if defined(WAKE_HISTO)
   12.26  #define BUCKETS 31
   12.27  #elif defined(BLOCKTIME_HISTO)
   12.28 @@ -205,9 +198,7 @@ void vcpu_wake(struct vcpu *v)
   12.29      if ( likely(domain_runnable(v)) )
   12.30      {
   12.31          SCHED_OP(wake, v);
   12.32 -#ifdef WAKE_HISTO
   12.33          v->wokenup = NOW();
   12.34 -#endif
   12.35      }
   12.36      clear_bit(_VCPUF_cpu_migrated, &v->vcpu_flags);
   12.37      spin_unlock_irqrestore(&schedule_data[v->processor].schedule_lock, flags);
   12.38 @@ -416,11 +407,26 @@ static void __enter_scheduler(void)
   12.39          return continue_running(prev);
   12.40      }
   12.41  
   12.42 +    TRACE_2D(TRC_SCHED_SWITCH_INFPREV,
   12.43 +             prev->domain->domain_id, now - prev->lastschd);
   12.44 +    TRACE_3D(TRC_SCHED_SWITCH_INFNEXT,
   12.45 +             next->domain->domain_id, now - next->wokenup, r_time);
   12.46 +
   12.47      clear_bit(_VCPUF_running, &prev->vcpu_flags);
   12.48      set_bit(_VCPUF_running, &next->vcpu_flags);
   12.49  
   12.50      perfc_incrc(sched_ctx);
   12.51  
   12.52 +    /*
   12.53 +     * Logic of wokenup field in domain struct:
   12.54 +     * Used to calculate "waiting time", which is the time that a domain
   12.55 +     * spends being "runnable", but not actually running. wokenup is set
   12.56 +     * set whenever a domain wakes from sleeping. However, if wokenup is not
   12.57 +     * also set here then a preempted runnable domain will get a screwed up
   12.58 +     * "waiting time" value next time it is scheduled.
   12.59 +     */
   12.60 +    prev->wokenup = NOW();
   12.61 +
   12.62  #if defined(WAKE_HISTO)
   12.63      if ( !is_idle_task(next->domain) && next->wokenup )
   12.64      {
    13.1 --- a/xen/include/public/trace.h	Tue Nov 15 15:36:42 2005 +0100
    13.2 +++ b/xen/include/public/trace.h	Tue Nov 15 15:44:37 2005 +0100
    13.3 @@ -14,6 +14,7 @@
    13.4  #define TRC_SCHED   0x0002f000    /* Xen Scheduler trace      */
    13.5  #define TRC_DOM0OP  0x0004f000    /* Xen DOM0 operation trace */
    13.6  #define TRC_VMX     0x0008f000    /* Xen VMX trace            */
    13.7 +#define TRC_MEM     0x000af000    /* Xen memory trace         */
    13.8  #define TRC_ALL     0xfffff000
    13.9  
   13.10  /* Trace subclasses */
   13.11 @@ -40,6 +41,12 @@
   13.12  #define TRC_SCHED_S_TIMER_FN    (TRC_SCHED + 11)
   13.13  #define TRC_SCHED_T_TIMER_FN    (TRC_SCHED + 12)
   13.14  #define TRC_SCHED_DOM_TIMER_FN  (TRC_SCHED + 13)
   13.15 +#define TRC_SCHED_SWITCH_INFPREV (TRC_SCHED + 14)
   13.16 +#define TRC_SCHED_SWITCH_INFNEXT (TRC_SCHED + 15)
   13.17 +
   13.18 +#define TRC_MEM_PAGE_GRANT_MAP      (TRC_MEM + 1)
   13.19 +#define TRC_MEM_PAGE_GRANT_UNMAP    (TRC_MEM + 2)
   13.20 +#define TRC_MEM_PAGE_GRANT_TRANSFER (TRC_MEM + 3)
   13.21  
   13.22  /* trace events per subclass */
   13.23  #define TRC_VMX_VMEXIT          (TRC_VMXEXIT + 1)