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)