VirtualBox

source: vbox/trunk/src/VBox/VMM/STAM.cpp@ 1995

Last change on this file since 1995 was 552, checked in by vboxsync, 18 years ago

Added STAMUNIT_KILOBYTES

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 35.6 KB
Line 
1/* $Id: STAM.cpp 552 2007-02-02 14:06:32Z vboxsync $ */
2/** @file
3 * STAM - The Statistics Manager.
4 */
5
6/*
7 * Copyright (C) 2006 InnoTek Systemberatung GmbH
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License as published by the Free Software Foundation,
13 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
14 * distribution. VirtualBox OSE is distributed in the hope that it will
15 * be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * If you received this file as part of a commercial VirtualBox
18 * distribution, then only the terms of your commercial VirtualBox
19 * license agreement apply instead of the previous paragraph.
20 */
21
22
23/*******************************************************************************
24* Header Files *
25*******************************************************************************/
26#define LOG_GROUP LOG_GROUP_STAM
27#include <VBox/stam.h>
28#include "STAMInternal.h"
29#include <VBox/vm.h>
30#include <VBox/err.h>
31#include <VBox/dbg.h>
32#include <VBox/log.h>
33
34#include <iprt/assert.h>
35#include <iprt/asm.h>
36#include <iprt/alloc.h>
37#include <iprt/stream.h>
38#include <iprt/string.h>
39
40
41/*******************************************************************************
42* Structures and Typedefs *
43*******************************************************************************/
44/**
45 * Argument structure for stamR3PrintOne().
46 */
47typedef struct STAMR3PRINTONEARGS
48{
49 PVM pVM;
50 void *pvArg;
51 DECLCALLBACKMEMBER(void, pfnPrintf)(struct STAMR3PRINTONEARGS *pvArg, const char *pszFormat, ...);
52} STAMR3PRINTONEARGS, *PSTAMR3PRINTONEARGS;
53
54
55/**
56 * Argument structure to stamR3EnumOne().
57 */
58typedef struct STAMR3ENUMONEARGS
59{
60 PVM pVM;
61 PFNSTAMR3ENUM pfnEnum;
62 void *pvUser;
63} STAMR3ENUMONEARGS, *PSTAMR3ENUMONEARGS;
64
65
66/*******************************************************************************
67* Internal Functions *
68*******************************************************************************/
69static int stamR3Register(PVM pVM, void *pvSample, PFNSTAMR3CALLBACKRESET pfnReset, PFNSTAMR3CALLBACKPRINT pfnPrint,
70 STAMTYPE enmType, STAMVISIBILITY enmVisibility, const char *pszName, STAMUNIT enmUnit, const char *pszDesc);
71static int stamR3ResetOne(PSTAMDESC pDesc, void *pvArg);
72static DECLCALLBACK(void) stamR3EnumLogPrintf(PSTAMR3PRINTONEARGS pvArg, const char *pszFormat, ...);
73static DECLCALLBACK(void) stamR3EnumRelLogPrintf(PSTAMR3PRINTONEARGS pvArg, const char *pszFormat, ...);
74static DECLCALLBACK(void) stamR3EnumPrintf(PSTAMR3PRINTONEARGS pvArg, const char *pszFormat, ...);
75static int stamR3PrintOne(PSTAMDESC pDesc, void *pvArg);
76static int stamR3EnumOne(PSTAMDESC pDesc, void *pvArg);
77static int stamR3Enum(PVM pVM, const char *pszPat, int (pfnCallback)(PSTAMDESC pDesc, void *pvArg), void *pvArg);
78
79#ifdef VBOX_WITH_DEBUGGER
80static DECLCALLBACK(int) stamR3CmdStats(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
81static DECLCALLBACK(void) stamR3EnumDbgfPrintf(PSTAMR3PRINTONEARGS pArgs, const char *pszFormat, ...);
82static DECLCALLBACK(int) stamR3CmdStatsReset(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
83#endif
84
85
86/*******************************************************************************
87* Global Variables *
88*******************************************************************************/
89#ifdef VBOX_WITH_DEBUGGER
90/** Pattern argument. */
91static const DBGCVARDESC g_aArgPat[] =
92{
93 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
94 { 0, 1, DBGCVAR_CAT_STRING, 0, "pattern", "Which samples the command shall be applied to. Use '*' as wildcard. Use ';' to separate expression." }
95};
96
97/** Command descriptors. */
98static const DBGCCMD g_aCmds[] =
99{
100 /* pszCmd, cArgsMin, cArgsMax, paArgDesc, cArgDescs, pResultDesc, fFlags, pfnHandler pszSyntax, ....pszDescription */
101 { "stats", 0, 1, &g_aArgPat[0], ELEMENTS(g_aArgPat), NULL, 0, stamR3CmdStats, "[pattern]", "Display statistics." },
102 { "statsreset", 0, 1, &g_aArgPat[0], ELEMENTS(g_aArgPat), NULL, 0, stamR3CmdStatsReset,"[pattern]", "Resets statistics." }
103};
104#endif
105
106
107
108/**
109 * Initializes the STAM.
110 *
111 * @returns VBox status code.
112 * @param pVM The VM to operate on.
113 */
114STAMR3DECL(int) STAMR3Init(PVM pVM)
115{
116 LogFlow(("STAMR3Init\n"));
117
118 /*
119 * Assert alignment and sizes.
120 */
121 AssertRelease(!(RT_OFFSETOF(VM, stam.s) & 31));
122 AssertRelease(sizeof(pVM->stam.s) <= sizeof(pVM->stam.padding));
123
124 /*
125 * Setup any fixed pointers and offsets.
126 */
127 pVM->stam.s.offVM = RT_OFFSETOF(VM, stam);
128 int rc = RTSemRWCreate(&pVM->stam.s.RWSem);
129 AssertRC(rc);
130 if (VBOX_FAILURE(rc))
131 return rc;
132
133#ifdef VBOX_WITH_DEBUGGER
134 /*
135 * Register debugger commands.
136 */
137 static bool fRegisteredCmds = false;
138 if (!fRegisteredCmds)
139 {
140 int rc = DBGCRegisterCommands(&g_aCmds[0], ELEMENTS(g_aCmds));
141 if (VBOX_SUCCESS(rc))
142 fRegisteredCmds = true;
143 }
144#endif
145
146 return VINF_SUCCESS;
147}
148
149
150/**
151 * Applies relocations to data and code managed by this
152 * component. This function will be called at init and
153 * whenever the VMM need to relocate it self inside the GC.
154 *
155 * @param pVM The VM.
156 */
157STAMR3DECL(void) STAMR3Relocate(PVM pVM)
158{
159 LogFlow(("STAMR3Relocate\n"));
160 NOREF(pVM);
161}
162
163
164/**
165 * Terminates the STAM.
166 *
167 * Termination means cleaning up and freeing all resources,
168 * the VM it self is at this point powered off or suspended.
169 *
170 * @returns VBox status code.
171 * @param pVM The VM to operate on.
172 */
173STAMR3DECL(int) STAMR3Term(PVM pVM)
174{
175 /*
176 * Free used memory and RWLock.
177 */
178 PSTAMDESC pCur = pVM->stam.s.pHead;
179 while (pCur)
180 {
181 void *pvFree = pCur;
182 pCur = pCur->pNext;
183 RTMemFree(pvFree);
184 }
185
186 RTSemRWDestroy(pVM->stam.s.RWSem);
187 return VINF_SUCCESS;
188}
189
190
191
192
193/**
194 * Registers a sample with the statistics mamanger.
195 *
196 * Statistics are maintained on a per VM basis and should therefore
197 * be registered during the VM init stage. However, there is not problem
198 * registering temporary samples or samples for hotpluggable devices. Samples
199 * can be deregisterd using the STAMR3Deregister() function, but note that
200 * this is only necessary for temporary samples or hotpluggable devices.
201 *
202 * It is not possible to register the same sample twice.
203 *
204 * @returns VBox status.
205 * @param pVM The VM handle.
206 * @param pvSample Pointer to the sample.
207 * @param enmType Sample type. This indicates what pvSample is pointing at.
208 * @param enmVisibility Visibility type specifying whether unused statistics should be visible or not.
209 * @param pszName Sample name. The name is on this form "/<component>/<sample>".
210 * Further nesting is possible.
211 * @param enmUnit Sample unit.
212 * @param pszDesc Sample description.
213 */
214STAMR3DECL(int) STAMR3Register(PVM pVM, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility, const char *pszName, STAMUNIT enmUnit, const char *pszDesc)
215{
216 AssertReturn(enmType != STAMTYPE_CALLBACK, VERR_INVALID_PARAMETER);
217 return stamR3Register(pVM, pvSample, NULL, NULL, enmType, enmVisibility, pszName, enmUnit, pszDesc);
218}
219
220
221/**
222 * Same as STAMR3Register except that the name is specified in a
223 * RTStrPrintf like fashion.
224 *
225 * @returns VBox status.
226 * @param pVM The VM handle.
227 * @param pvSample Pointer to the sample.
228 * @param enmType Sample type. This indicates what pvSample is pointing at.
229 * @param enmVisibility Visibility type specifying whether unused statistics should be visible or not.
230 * @param enmUnit Sample unit.
231 * @param pszDesc Sample description.
232 * @param pszName The sample name format string.
233 * @param ... Arguments to the format string.
234 */
235STAMR3DECL(int) STAMR3RegisterF(PVM pVM, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility, STAMUNIT enmUnit,
236 const char *pszDesc, const char *pszName, ...)
237{
238 va_list args;
239 va_start(args, pszName);
240 int rc = STAMR3RegisterV(pVM, pvSample, enmType, enmVisibility, enmUnit, pszDesc, pszName, args);
241 va_end(args);
242 return rc;
243}
244
245
246/**
247 * Same as STAMR3Register except that the name is specified in a
248 * RTStrPrintfV like fashion.
249 *
250 * @returns VBox status.
251 * @param pVM The VM handle.
252 * @param pvSample Pointer to the sample.
253 * @param enmType Sample type. This indicates what pvSample is pointing at.
254 * @param enmVisibility Visibility type specifying whether unused statistics should be visible or not.
255 * @param enmUnit Sample unit.
256 * @param pszDesc Sample description.
257 * @param pszName The sample name format string.
258 * @param args Arguments to the format string.
259 */
260STAMR3DECL(int) STAMR3RegisterV(PVM pVM, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility, STAMUNIT enmUnit,
261 const char *pszDesc, const char *pszName, va_list args)
262{
263 AssertReturn(enmType != STAMTYPE_CALLBACK, VERR_INVALID_PARAMETER);
264
265 char *pszFormattedName;
266 RTStrAPrintfV(&pszFormattedName, pszName, args);
267 if (!pszFormattedName)
268 return VERR_NO_MEMORY;
269
270 int rc = STAMR3Register(pVM, pvSample, enmType, enmVisibility, pszFormattedName, enmUnit, pszDesc);
271 RTStrFree(pszFormattedName);
272 return rc;
273}
274
275
276/**
277 * Similar to STAMR3Register except for the two callbacks, the implied type (STAMTYPE_CALLBACK),
278 * and name given in an RTStrPrintf like fashion.
279 *
280 * @returns VBox status.
281 * @param pVM The VM handle.
282 * @param pvSample Pointer to the sample.
283 * @param enmVisibility Visibility type specifying whether unused statistics should be visible or not.
284 * @param enmUnit Sample unit.
285 * @param pfnReset Callback for resetting the sample. NULL should be used if the sample can't be reset.
286 * @param pfnPrint Print the sample.
287 * @param pszDesc Sample description.
288 * @param pszName The sample name format string.
289 * @param ... Arguments to the format string.
290 * @remark There is currently no device or driver variant of this API. Add one if it should become necessary!
291 */
292STAMR3DECL(int) STAMR3RegisterCallback(PVM pVM, void *pvSample, STAMVISIBILITY enmVisibility, STAMUNIT enmUnit,
293 PFNSTAMR3CALLBACKRESET pfnReset, PFNSTAMR3CALLBACKPRINT pfnPrint,
294 const char *pszDesc, const char *pszName, ...)
295{
296 va_list args;
297 va_start(args, pszName);
298 int rc = STAMR3RegisterCallbackV(pVM, pvSample, enmVisibility, enmUnit, pfnReset, pfnPrint, pszDesc, pszName, args);
299 va_end(args);
300 return rc;
301}
302
303
304/**
305 * Same as STAMR3RegisterCallback() except for the ellipsis which is a va_list here.
306 *
307 * @returns VBox status.
308 * @param pVM The VM handle.
309 * @param pvSample Pointer to the sample.
310 * @param enmVisibility Visibility type specifying whether unused statistics should be visible or not.
311 * @param enmUnit Sample unit.
312 * @param pfnReset Callback for resetting the sample. NULL should be used if the sample can't be reset.
313 * @param pfnPrint Print the sample.
314 * @param pszDesc Sample description.
315 * @param pszName The sample name format string.
316 * @param args Arguments to the format string.
317 * @remark There is currently no device or driver variant of this API. Add one if it should become necessary!
318 */
319STAMR3DECL(int) STAMR3RegisterCallbackV(PVM pVM, void *pvSample, STAMVISIBILITY enmVisibility, STAMUNIT enmUnit,
320 PFNSTAMR3CALLBACKRESET pfnReset, PFNSTAMR3CALLBACKPRINT pfnPrint,
321 const char *pszDesc, const char *pszName, va_list args)
322{
323 char *pszFormattedName;
324 RTStrAPrintfV(&pszFormattedName, pszName, args);
325 if (!pszFormattedName)
326 return VERR_NO_MEMORY;
327
328 int rc = stamR3Register(pVM, pvSample, pfnReset, pfnPrint, STAMTYPE_CALLBACK, enmVisibility, pszFormattedName, enmUnit, pszDesc);
329 RTStrFree(pszFormattedName);
330 return rc;
331}
332
333
334/**
335 * Internal worker for the different register calls.
336 *
337 * @returns VBox status.
338 * @param pVM The VM handle.
339 * @param pvSample Pointer to the sample.
340 * @param pfnReset Callback for resetting the sample. NULL should be used if the sample can't be reset.
341 * @param pfnPrint Print the sample.
342 * @param enmType Sample type. This indicates what pvSample is pointing at.
343 * @param enmVisibility Visibility type specifying whether unused statistics should be visible or not.
344 * @param enmUnit Sample unit.
345 * @param pszDesc Sample description.
346 * @param pszName The sample name format string.
347 * @param args Arguments to the format string.
348 * @remark There is currently no device or driver variant of this API. Add one if it should become necessary!
349 */
350static int stamR3Register(PVM pVM, void *pvSample, PFNSTAMR3CALLBACKRESET pfnReset, PFNSTAMR3CALLBACKPRINT pfnPrint,
351 STAMTYPE enmType, STAMVISIBILITY enmVisibility, const char *pszName, STAMUNIT enmUnit, const char *pszDesc)
352{
353 STAM_LOCK_WR(pVM);
354
355 /*
356 * Check if exists.
357 */
358 PSTAMDESC pPrev = NULL;
359 PSTAMDESC pCur = pVM->stam.s.pHead;
360 while (pCur)
361 {
362 int iDiff = strcmp(pCur->pszName, pszName);
363 /* passed it */
364 if (iDiff > 0)
365 break;
366 /* found it. */
367 if (!iDiff)
368 {
369 STAM_UNLOCK_WR(pVM);
370 AssertMsgFailed(("Duplicate sample name: %s\n", pszName));
371 return VERR_ALREADY_EXISTS;
372 }
373
374 /* next */
375 pPrev = pCur;
376 pCur = pCur->pNext;
377 }
378
379 /*
380 * Create a new node and insert it at the current location.
381 */
382 int rc;
383 int cchName = strlen(pszName) + 1;
384 int cchDesc = pszDesc ? strlen(pszDesc) + 1 : 0;
385 PSTAMDESC pNew = (PSTAMDESC)RTMemAlloc(sizeof(*pNew) + cchName + cchDesc);
386 if (pNew)
387 {
388 pNew->pszName = (char *)memcpy((char *)(pNew + 1), pszName, cchName);
389 pNew->enmType = enmType;
390 pNew->enmVisibility = enmVisibility;
391 if (enmType != STAMTYPE_CALLBACK)
392 pNew->u.pv = pvSample;
393 else
394 {
395 pNew->u.Callback.pvSample = pvSample;
396 pNew->u.Callback.pfnReset = pfnReset;
397 pNew->u.Callback.pfnPrint = pfnPrint;
398 }
399 pNew->enmUnit = enmUnit;
400 pNew->pszDesc = NULL;
401 if (pszDesc)
402 pNew->pszDesc = (char *)memcpy((char *)(pNew + 1) + cchName, pszDesc, cchDesc);
403
404 pNew->pNext = pCur;
405 if (pPrev)
406 pPrev->pNext = pNew;
407 else
408 pVM->stam.s.pHead = pNew;
409
410 stamR3ResetOne(pNew, pVM);
411 rc = VINF_SUCCESS;
412 }
413 else
414 rc = VERR_NO_MEMORY;
415
416 STAM_UNLOCK_WR(pVM);
417 return rc;
418}
419
420
421/**
422 * Deregisters a sample previously registered by STAR3Register().
423 *
424 * This is intended used for devices which can be unplugged and for
425 * temporary samples.
426 *
427 * @returns VBox status.
428 * @param pVM The VM handle.
429 * @param pvSample Pointer to the sample registered with STAMR3Register().
430 */
431STAMR3DECL(int) STAMR3Deregister(PVM pVM, void *pvSample)
432{
433 STAM_LOCK_WR(pVM);
434
435 /*
436 * Search for it.
437 */
438 int rc = VERR_INVALID_HANDLE;
439 PSTAMDESC pPrev = NULL;
440 PSTAMDESC pCur = pVM->stam.s.pHead;
441 while (pCur)
442 {
443 if (pCur->u.pv == pvSample)
444 {
445 void *pvFree = pCur;
446 pCur = pCur->pNext;
447 if (pPrev)
448 pPrev->pNext = pCur;
449 else
450 pVM->stam.s.pHead = pCur;
451
452 RTMemFree(pvFree);
453 rc = VINF_SUCCESS;
454 continue;
455 }
456
457 /* next */
458 pPrev = pCur;
459 pCur = pCur->pNext;
460 }
461
462 STAM_UNLOCK_WR(pVM);
463 return rc;
464}
465
466
467/**
468 * Resets statistics for the specified VM.
469 * It's possible to select a subset of the samples.
470 *
471 * @returns VBox status. (Basically, it cannot fail.)
472 * @param pVM The VM handle.
473 * @param pszPat The name matching pattern. See somewhere_where_this_is_described_in_detail.
474 * If NULL all samples are reset.
475 */
476STAMR3DECL(int) STAMR3Reset(PVM pVM, const char *pszPat)
477{
478 STAM_LOCK_WR(pVM);
479 stamR3Enum(pVM, pszPat, stamR3ResetOne, pVM);
480 STAM_UNLOCK_WR(pVM);
481 return VINF_SUCCESS;
482}
483
484
485/**
486 * Resets one statistics sample.
487 * Callback for stamR3Enum().
488 *
489 * @returns VINF_SUCCESS
490 * @param pDesc Pointer to the current descriptor.
491 * @param pvArg User argument - The VM handle.
492 */
493static int stamR3ResetOne(PSTAMDESC pDesc, void *pvArg)
494{
495 switch (pDesc->enmType)
496 {
497 case STAMTYPE_COUNTER:
498 ASMAtomicXchgU64(&pDesc->u.pCounter->c, 0);
499 break;
500
501 case STAMTYPE_PROFILE:
502 case STAMTYPE_PROFILE_ADV:
503 ASMAtomicXchgU64(&pDesc->u.pProfile->cPeriods, 0);
504 ASMAtomicXchgU64(&pDesc->u.pProfile->cTicks, 0);
505 ASMAtomicXchgU64(&pDesc->u.pProfile->cTicksMax, 0);
506 ASMAtomicXchgU64(&pDesc->u.pProfile->cTicksMin, ~0);
507 break;
508
509 case STAMTYPE_RATIO_U32_RESET:
510 ASMAtomicXchgU32(&pDesc->u.pRatioU32->u32A, 0);
511 ASMAtomicXchgU32(&pDesc->u.pRatioU32->u32B, 0);
512 break;
513
514 case STAMTYPE_CALLBACK:
515 if (pDesc->u.Callback.pfnReset)
516 pDesc->u.Callback.pfnReset((PVM)pvArg, pDesc->u.Callback.pvSample);
517 break;
518
519 case STAMTYPE_U8_RESET:
520 case STAMTYPE_X8_RESET:
521 ASMAtomicXchgU8(pDesc->u.pu8, 0);
522 break;
523
524 case STAMTYPE_U16_RESET:
525 case STAMTYPE_X16_RESET:
526 ASMAtomicXchgU16(pDesc->u.pu16, 0);
527 break;
528
529 case STAMTYPE_U32_RESET:
530 case STAMTYPE_X32_RESET:
531 ASMAtomicXchgU32(pDesc->u.pu32, 0);
532 break;
533
534 case STAMTYPE_U64_RESET:
535 case STAMTYPE_X64_RESET:
536 ASMAtomicXchgU64(pDesc->u.pu64, 0);
537 break;
538
539 /* These are custom and will not be touched. */
540 case STAMTYPE_U8:
541 case STAMTYPE_X8:
542 case STAMTYPE_U16:
543 case STAMTYPE_X16:
544 case STAMTYPE_U32:
545 case STAMTYPE_X32:
546 case STAMTYPE_U64:
547 case STAMTYPE_X64:
548 case STAMTYPE_RATIO_U32:
549 break;
550
551 default:
552 AssertMsgFailed(("enmType=%d\n", pDesc->enmType));
553 break;
554 }
555 NOREF(pvArg);
556 return VINF_SUCCESS;
557}
558
559
560/**
561 * Get a snapshot of the statistics.
562 * It's possible to select a subset of the samples.
563 *
564 * @returns VBox status. (Basically, it cannot fail.)
565 * @param pVM The VM handle.
566 * @param pszPat The name matching pattern. See somewhere_where_this_is_described_in_detail.
567 * If NULL all samples are reset.
568 * @param ppszSnapshot Where to store the pointer to the snapshot data.
569 * The format of the snapshot should be XML, but that will have to be discussed
570 * when this function is implemented.
571 * The returned pointer must be freed by calling STAMR3SnapshotFree().
572 * @param pcchSnapshot Where to store the size of the snapshot data. (Excluding the trailing '\0')
573 */
574STAMR3DECL(int) STAMR3Snapshot(PVM pVM, const char *pszPat, char **ppszSnapshot, size_t *pcchSnapshot)
575{
576 AssertMsgFailed(("not implemented yet\n"));
577 return VERR_NOT_IMPLEMENTED;
578}
579
580
581/**
582 * Releases a statistics snapshot returned by STAMR3Snapshot().
583 *
584 * @returns VBox status.
585 * @param pVM The VM handle.
586 * @param pszSnapshot The snapshot data pointer returned by STAMR3Snapshot().
587 * NULL is allowed.
588 */
589STAMR3DECL(int) STAMR3SnapshotFree(PVM pVM, char *pszSnapshot)
590{
591 if (!pszSnapshot)
592 RTMemFree(pszSnapshot);
593 return VINF_SUCCESS;
594}
595
596
597/**
598 * Dumps the selected statistics to the log.
599 *
600 * @returns VBox status.
601 * @param pVM The VM handle.
602 * @param pszPat The name matching pattern. See somewhere_where_this_is_described_in_detail.
603 * If NULL all samples are written to the log.
604 */
605STAMR3DECL(int) STAMR3Dump(PVM pVM, const char *pszPat)
606{
607 STAMR3PRINTONEARGS Args;
608 Args.pVM = pVM;
609 Args.pvArg = NULL;
610 Args.pfnPrintf = stamR3EnumLogPrintf;
611
612 STAM_LOCK_RD(pVM);
613 stamR3Enum(pVM, pszPat, stamR3PrintOne, &Args);
614 STAM_UNLOCK_RD(pVM);
615 return VINF_SUCCESS;
616}
617
618
619/**
620 * Prints to the log.
621 *
622 * @param pArgs Pointer to the print one argument structure.
623 * @param pszFormat Format string.
624 * @param ... Format arguments.
625 */
626static DECLCALLBACK(void) stamR3EnumLogPrintf(PSTAMR3PRINTONEARGS pArgs, const char *pszFormat, ...)
627{
628 va_list va;
629 va_start(va, pszFormat);
630 RTLogPrintfV(pszFormat, va);
631 va_end(va);
632 NOREF(pArgs);
633}
634
635
636/**
637 * Dumps the selected statistics to the release log.
638 *
639 * @returns VBox status.
640 * @param pVM The VM handle.
641 * @param pszPat The name matching pattern. See somewhere_where_this_is_described_in_detail.
642 * If NULL all samples are written to the log.
643 */
644STAMR3DECL(int) STAMR3DumpToReleaseLog(PVM pVM, const char *pszPat)
645{
646 STAMR3PRINTONEARGS Args;
647 Args.pVM = pVM;
648 Args.pvArg = NULL;
649 Args.pfnPrintf = stamR3EnumRelLogPrintf;
650
651 STAM_LOCK_RD(pVM);
652 stamR3Enum(pVM, pszPat, stamR3PrintOne, &Args);
653 STAM_UNLOCK_RD(pVM);
654
655 return VINF_SUCCESS;
656}
657
658
659/**
660 * Prints to the release log.
661 *
662 * @param pArgs Pointer to the print one argument structure.
663 * @param pszFormat Format string.
664 * @param ... Format arguments.
665 */
666static DECLCALLBACK(void) stamR3EnumRelLogPrintf(PSTAMR3PRINTONEARGS pArgs, const char *pszFormat, ...)
667{
668 va_list va;
669 va_start(va, pszFormat);
670 RTLogRelPrintfV(pszFormat, va);
671 va_end(va);
672 NOREF(pArgs);
673}
674
675
676/**
677 * Prints the selected statistics to standard out.
678 *
679 * @returns VBox status.
680 * @param pVM The VM handle.
681 * @param pszPat The name matching pattern. See somewhere_where_this_is_described_in_detail.
682 * If NULL all samples are reset.
683 */
684STAMR3DECL(int) STAMR3Print(PVM pVM, const char *pszPat)
685{
686 STAMR3PRINTONEARGS Args;
687 Args.pVM = pVM;
688 Args.pvArg = NULL;
689 Args.pfnPrintf = stamR3EnumPrintf;
690
691 STAM_LOCK_RD(pVM);
692 stamR3Enum(pVM, pszPat, stamR3PrintOne, &Args);
693 STAM_UNLOCK_RD(pVM);
694 return VINF_SUCCESS;
695}
696
697
698/**
699 * Prints to stdout.
700 *
701 * @param pArgs Pointer to the print one argument structure.
702 * @param pszFormat Format string.
703 * @param ... Format arguments.
704 */
705static DECLCALLBACK(void) stamR3EnumPrintf(PSTAMR3PRINTONEARGS pArgs, const char *pszFormat, ...)
706{
707 va_list va;
708 va_start(va, pszFormat);
709 RTPrintfV(pszFormat, va);
710 va_end(va);
711 NOREF(pArgs);
712}
713
714
715/**
716 * Prints one sample.
717 * Callback for stamR3Enum().
718 *
719 * @returns VINF_SUCCESS
720 * @param pDesc Pointer to the current descriptor.
721 * @param pvArg User argument - STAMR3PRINTONEARGS.
722 */
723static int stamR3PrintOne(PSTAMDESC pDesc, void *pvArg)
724{
725 PSTAMR3PRINTONEARGS pArgs = (PSTAMR3PRINTONEARGS)pvArg;
726
727 switch (pDesc->enmType)
728 {
729 case STAMTYPE_COUNTER:
730 if (pDesc->enmVisibility == STAMVISIBILITY_USED && pDesc->u.pCounter->c == 0)
731 return VINF_SUCCESS;
732
733 pArgs->pfnPrintf(pArgs, "%-32s %8llu %s\n", pDesc->pszName, pDesc->u.pCounter->c, STAMR3GetUnit(pDesc->enmUnit));
734 break;
735 case STAMTYPE_PROFILE:
736 case STAMTYPE_PROFILE_ADV:
737 {
738 if (pDesc->enmVisibility == STAMVISIBILITY_USED && pDesc->u.pProfile->cPeriods == 0)
739 return VINF_SUCCESS;
740
741 uint64_t u64 = pDesc->u.pProfile->cPeriods ? pDesc->u.pProfile->cPeriods : 1;
742 pArgs->pfnPrintf(pArgs, "%-32s %8llu %s (%12llu ticks, %7llu times, max %9llu, min %7lld)\n", pDesc->pszName,
743 pDesc->u.pProfile->cTicks / u64, STAMR3GetUnit(pDesc->enmUnit),
744 pDesc->u.pProfile->cTicks, pDesc->u.pProfile->cPeriods, pDesc->u.pProfile->cTicksMax, pDesc->u.pProfile->cTicksMin);
745 break;
746 }
747
748 case STAMTYPE_RATIO_U32:
749 case STAMTYPE_RATIO_U32_RESET:
750 if (pDesc->enmVisibility == STAMVISIBILITY_USED && !pDesc->u.pRatioU32->u32A && !pDesc->u.pRatioU32->u32B)
751 return VINF_SUCCESS;
752 pArgs->pfnPrintf(pArgs, "%-32s %8u:%-8u %s\n", pDesc->pszName,
753 pDesc->u.pRatioU32->u32A, pDesc->u.pRatioU32->u32B, STAMR3GetUnit(pDesc->enmUnit));
754 break;
755
756 case STAMTYPE_CALLBACK:
757 {
758 char szBuf[512];
759 pDesc->u.Callback.pfnPrint(pArgs->pVM, pDesc->u.Callback.pvSample, szBuf, sizeof(szBuf));
760 pArgs->pfnPrintf(pArgs, "%-32s %s %s\n", pDesc->pszName, szBuf, STAMR3GetUnit(pDesc->enmUnit));
761 break;
762 }
763
764 case STAMTYPE_U8:
765 case STAMTYPE_U8_RESET:
766 if (pDesc->enmVisibility == STAMVISIBILITY_USED && *pDesc->u.pu8 == 0)
767 return VINF_SUCCESS;
768 pArgs->pfnPrintf(pArgs, "%-32s %8u %s\n", pDesc->pszName, *pDesc->u.pu8, STAMR3GetUnit(pDesc->enmUnit));
769 break;
770
771 case STAMTYPE_X8:
772 case STAMTYPE_X8_RESET:
773 if (pDesc->enmVisibility == STAMVISIBILITY_USED && *pDesc->u.pu8 == 0)
774 return VINF_SUCCESS;
775 pArgs->pfnPrintf(pArgs, "%-32s %8x %s\n", pDesc->pszName, *pDesc->u.pu8, STAMR3GetUnit(pDesc->enmUnit));
776 break;
777
778 case STAMTYPE_U16:
779 case STAMTYPE_U16_RESET:
780 if (pDesc->enmVisibility == STAMVISIBILITY_USED && *pDesc->u.pu16 == 0)
781 return VINF_SUCCESS;
782 pArgs->pfnPrintf(pArgs, "%-32s %8u %s\n", pDesc->pszName, *pDesc->u.pu16, STAMR3GetUnit(pDesc->enmUnit));
783 break;
784
785 case STAMTYPE_X16:
786 case STAMTYPE_X16_RESET:
787 if (pDesc->enmVisibility == STAMVISIBILITY_USED && *pDesc->u.pu16 == 0)
788 return VINF_SUCCESS;
789 pArgs->pfnPrintf(pArgs, "%-32s %8x %s\n", pDesc->pszName, *pDesc->u.pu16, STAMR3GetUnit(pDesc->enmUnit));
790 break;
791
792 case STAMTYPE_U32:
793 case STAMTYPE_U32_RESET:
794 if (pDesc->enmVisibility == STAMVISIBILITY_USED && *pDesc->u.pu32 == 0)
795 return VINF_SUCCESS;
796 pArgs->pfnPrintf(pArgs, "%-32s %8u %s\n", pDesc->pszName, *pDesc->u.pu32, STAMR3GetUnit(pDesc->enmUnit));
797 break;
798
799 case STAMTYPE_X32:
800 case STAMTYPE_X32_RESET:
801 if (pDesc->enmVisibility == STAMVISIBILITY_USED && *pDesc->u.pu32 == 0)
802 return VINF_SUCCESS;
803 pArgs->pfnPrintf(pArgs, "%-32s %8x %s\n", pDesc->pszName, *pDesc->u.pu32, STAMR3GetUnit(pDesc->enmUnit));
804 break;
805
806 case STAMTYPE_U64:
807 case STAMTYPE_U64_RESET:
808 if (pDesc->enmVisibility == STAMVISIBILITY_USED && *pDesc->u.pu64 == 0)
809 return VINF_SUCCESS;
810 pArgs->pfnPrintf(pArgs, "%-32s %8llu %s\n", pDesc->pszName, *pDesc->u.pu64, STAMR3GetUnit(pDesc->enmUnit));
811 break;
812
813 case STAMTYPE_X64:
814 case STAMTYPE_X64_RESET:
815 if (pDesc->enmVisibility == STAMVISIBILITY_USED && *pDesc->u.pu64 == 0)
816 return VINF_SUCCESS;
817 pArgs->pfnPrintf(pArgs, "%-32s %8llx %s\n", pDesc->pszName, *pDesc->u.pu64, STAMR3GetUnit(pDesc->enmUnit));
818 break;
819
820 default:
821 AssertMsgFailed(("enmType=%d\n", pDesc->enmType));
822 break;
823 }
824 NOREF(pvArg);
825 return VINF_SUCCESS;
826}
827
828
829/**
830 * Enumerate the statistics by the means of a callback function.
831 *
832 * @returns Whatever the callback returns.
833 *
834 * @param pVM The VM handle.
835 * @param pszPat The pattern to match samples.
836 * @param pfnEnum The callback function.
837 * @param pvUser The pvUser argument of the callback function.
838 */
839STAMR3DECL(int) STAMR3Enum(PVM pVM, const char *pszPat, PFNSTAMR3ENUM pfnEnum, void *pvUser)
840{
841 STAMR3ENUMONEARGS Args;
842 Args.pVM = pVM;
843 Args.pfnEnum = pfnEnum;
844 Args.pvUser = pvUser;
845
846 STAM_LOCK_RD(pVM);
847 int rc = stamR3Enum(pVM, pszPat, stamR3EnumOne, &Args);
848 STAM_UNLOCK_RD(pVM);
849 return rc;
850}
851
852
853/**
854 * Callback function for STARTR3Enum().
855 *
856 * @returns whatever the callback returns.
857 * @param pDesc Pointer to the current descriptor.
858 * @param pvArg Points to a STAMR3ENUMONEARGS structure.
859 */
860static int stamR3EnumOne(PSTAMDESC pDesc, void *pvArg)
861{
862 PSTAMR3ENUMONEARGS pArgs = (PSTAMR3ENUMONEARGS)pvArg;
863 int rc;
864 if (pDesc->enmType == STAMTYPE_CALLBACK)
865 {
866 /* Give the enumerator something useful. */
867 char szBuf[512];
868 pDesc->u.Callback.pfnPrint(pArgs->pVM, pDesc->u.Callback.pvSample, szBuf, sizeof(szBuf));
869 rc = pArgs->pfnEnum(pDesc->pszName, pDesc->enmType, szBuf, pDesc->enmUnit,
870 pDesc->enmVisibility, pDesc->pszDesc, pArgs->pvUser);
871 }
872 else
873 rc = pArgs->pfnEnum(pDesc->pszName, pDesc->enmType, pDesc->u.pv, pDesc->enmUnit,
874 pDesc->enmVisibility, pDesc->pszDesc, pArgs->pvUser);
875 return rc;
876}
877
878
879/**
880 * Matches a sample name against a pattern.
881 *
882 * @returns True if matches, false if not.
883 * @param pszPat Pattern.
884 * @param pszName Name to match against the pattern.
885 */
886static bool stamr3Match(const char *pszPat, const char *pszName)
887{
888 if (!pszPat)
889 return true;
890
891 /* ASSUMES ASCII */
892 for (;;)
893 {
894 char chPat = *pszPat;
895 switch (chPat)
896 {
897 case '\0':
898 return !*pszName;
899
900 case '*':
901 {
902 while ((chPat = *++pszPat) == '*' || chPat == '?')
903 /* nothing */;
904
905 for (;;)
906 {
907 char ch = *pszName++;
908 if ( ch == chPat
909 && ( !chPat
910 || stamr3Match(pszPat + 1, pszName)))
911 return true;
912 if (!ch)
913 return false;
914 }
915 /* won't ever get here */
916 break;
917 }
918
919 case '?':
920 if (!*pszName)
921 return false;
922 break;
923
924 default:
925 if (*pszName != chPat)
926 return false;
927 break;
928 }
929 pszName++;
930 pszPat++;
931 }
932 return true;
933}
934
935
936/**
937 * Enumerates the nodes selected by a pattern or all nodes if no pattern
938 * is specified.
939 *
940 * The call must own at least a read lock to the STAM data.
941 *
942 * @returns The rc from the callback.
943 * @param pVM VM handle
944 * @param pszPat Pattern.
945 * @param pfnCallback Callback function which shall be called for matching nodes.
946 * If it returns anything but VINF_SUCCESS the enumeration is
947 * terminated and the status code returned to the caller.
948 * @param pvArg User parameter for the callback.
949 */
950static int stamR3Enum(PVM pVM, const char *pszPat, int (*pfnCallback)(PSTAMDESC pDesc, void *pvArg), void *pvArg)
951{
952 /*
953 * Search for it.
954 */
955 int rc = VINF_SUCCESS;
956 PSTAMDESC pCur = pVM->stam.s.pHead;
957 while (pCur)
958 {
959 if (stamr3Match(pszPat, pCur->pszName))
960 {
961 rc = pfnCallback(pCur, pvArg);
962 if (rc)
963 break;
964 }
965
966 /* next */
967 pCur = pCur->pNext;
968 }
969
970 return rc;
971}
972
973
974/**
975 * Get the unit string.
976 *
977 * @returns Pointer to read only unit string.
978 * @param enmUnit The unit.
979 */
980STAMR3DECL(const char *) STAMR3GetUnit(STAMUNIT enmUnit)
981{
982 switch (enmUnit)
983 {
984 case STAMUNIT_NONE: return "";
985 case STAMUNIT_CALLS: return "calls";
986 case STAMUNIT_COUNT: return "count";
987 case STAMUNIT_BYTES: return "bytes";
988 case STAMUNIT_PAGES: return "pages";
989 case STAMUNIT_ERRORS: return "errors";
990 case STAMUNIT_OCCURENCES: return "times";
991 case STAMUNIT_TICKS_PER_CALL: return "ticks/call";
992 case STAMUNIT_TICKS_PER_OCCURENCE: return "ticks/time";
993 case STAMUNIT_GOOD_BAD: return "good:bad";
994 case STAMUNIT_MEGABYTES: return "megabytes";
995 case STAMUNIT_KILOBYTES: return "kilobytes";
996
997 default:
998 AssertMsgFailed(("Unknown unit %d\n", enmUnit));
999 return "(?unit?)";
1000 }
1001}
1002
1003
1004#ifdef VBOX_WITH_DEBUGGER
1005/**
1006 * The '.stats' command.
1007 *
1008 * @returns VBox status.
1009 * @param pCmd Pointer to the command descriptor (as registered).
1010 * @param pCmdHlp Pointer to command helper functions.
1011 * @param pVM Pointer to the current VM (if any).
1012 * @param paArgs Pointer to (readonly) array of arguments.
1013 * @param cArgs Number of arguments in the array.
1014 */
1015static DECLCALLBACK(int) stamR3CmdStats(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
1016{
1017 /*
1018 * Validate input.
1019 */
1020 if (!pVM)
1021 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: The command requires VM to be selected.\n");
1022 if (!pVM->stam.s.pHead)
1023 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Sorry, no statistics present.\n");
1024
1025 /*
1026 * Do the printing.
1027 */
1028 STAMR3PRINTONEARGS Args;
1029 Args.pVM = pVM;
1030 Args.pvArg = pCmdHlp;
1031 Args.pfnPrintf = stamR3EnumDbgfPrintf;
1032
1033 STAM_LOCK_RD(pVM);
1034 int rc = stamR3Enum(pVM, cArgs ? paArgs[0].u.pszString : NULL, stamR3PrintOne, &Args);
1035 STAM_UNLOCK_RD(pVM);
1036
1037 return rc;
1038}
1039
1040
1041/**
1042 * Display one sample in the debugger.
1043 *
1044 * @param pArgs Pointer to the print one argument structure.
1045 * @param pszFormat Format string.
1046 * @param ... Format arguments.
1047 */
1048static DECLCALLBACK(void) stamR3EnumDbgfPrintf(PSTAMR3PRINTONEARGS pArgs, const char *pszFormat, ...)
1049{
1050 PDBGCCMDHLP pCmdHlp = (PDBGCCMDHLP)pArgs->pvArg;
1051
1052 va_list va;
1053 va_start(va, pszFormat);
1054 pCmdHlp->pfnPrintfV(pCmdHlp, NULL, pszFormat, va);
1055 va_end(va);
1056 NOREF(pArgs);
1057}
1058
1059
1060/**
1061 * The '.statsreset' command.
1062 *
1063 * @returns VBox status.
1064 * @param pCmd Pointer to the command descriptor (as registered).
1065 * @param pCmdHlp Pointer to command helper functions.
1066 * @param pVM Pointer to the current VM (if any).
1067 * @param paArgs Pointer to (readonly) array of arguments.
1068 * @param cArgs Number of arguments in the array.
1069 */
1070static DECLCALLBACK(int) stamR3CmdStatsReset(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
1071{
1072 /*
1073 * Validate input.
1074 */
1075 if (!pVM)
1076 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: The command requires VM to be selected.\n");
1077 if (!pVM->stam.s.pHead)
1078 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Sorry, no statistics present.\n");
1079
1080 /*
1081 * Execute reset.
1082 */
1083 int rc = STAMR3Reset(pVM, cArgs ? paArgs[0].u.pszString : NULL);
1084 if (VBOX_SUCCESS(rc))
1085 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "info: Statistics reset.\n");
1086
1087 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Restting statistics.\n");
1088}
1089#endif
1090
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette