VirtualBox

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

Last change on this file since 11985 was 11311, checked in by vboxsync, 16 years ago

VMM: ELEMENTS -> RT_ELEMENTS.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 65.6 KB
Line 
1/* $Id: STAM.cpp 11311 2008-08-08 23:31:54Z vboxsync $ */
2/** @file
3 * STAM - The Statistics Manager.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
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 (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
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/uvm.h>
31#include <VBox/err.h>
32#include <VBox/dbg.h>
33#include <VBox/log.h>
34
35#include <iprt/assert.h>
36#include <iprt/asm.h>
37#include <iprt/alloc.h>
38#include <iprt/stream.h>
39#include <iprt/string.h>
40
41
42/*******************************************************************************
43* Structures and Typedefs *
44*******************************************************************************/
45/**
46 * Argument structure for stamR3PrintOne().
47 */
48typedef struct STAMR3PRINTONEARGS
49{
50 PVM pVM;
51 void *pvArg;
52 DECLCALLBACKMEMBER(void, pfnPrintf)(struct STAMR3PRINTONEARGS *pvArg, const char *pszFormat, ...);
53} STAMR3PRINTONEARGS, *PSTAMR3PRINTONEARGS;
54
55
56/**
57 * Argument structure to stamR3EnumOne().
58 */
59typedef struct STAMR3ENUMONEARGS
60{
61 PVM pVM;
62 PFNSTAMR3ENUM pfnEnum;
63 void *pvUser;
64} STAMR3ENUMONEARGS, *PSTAMR3ENUMONEARGS;
65
66
67/**
68 * The snapshot status structure.
69 * Argument package passed to stamR3SnapshotOne, stamR3SnapshotPrintf and stamR3SnapshotOutput.
70 */
71typedef struct STAMR3SNAPSHOTONE
72{
73 /** Pointer to the buffer start. */
74 char *pszStart;
75 /** Pointer to the buffer end. */
76 char *pszEnd;
77 /** Pointer to the current buffer position. */
78 char *psz;
79 /** The VM handle. */
80 PVM pVM;
81 /** The number of bytes allocated. */
82 size_t cbAllocated;
83 /** The status code. */
84 int rc;
85 /** Whether to include the description strings. */
86 bool fWithDesc;
87} STAMR3SNAPSHOTONE, *PSTAMR3SNAPSHOTONE;
88
89
90/**
91 * Init record for a ring-0 statistic sample.
92 */
93typedef struct STAMR0SAMPLE
94{
95 /** The GVMMSTATS structure offset of the variable. */
96 unsigned offVar;
97 /** The type. */
98 STAMTYPE enmType;
99 /** The unit. */
100 STAMUNIT enmUnit;
101 /** The name. */
102 const char *pszName;
103 /** The description. */
104 const char *pszDesc;
105} STAMR0SAMPLE;
106
107
108/*******************************************************************************
109* Internal Functions *
110*******************************************************************************/
111static int stamR3RegisterU(PUVM pUVM, void *pvSample, PFNSTAMR3CALLBACKRESET pfnReset, PFNSTAMR3CALLBACKPRINT pfnPrint,
112 STAMTYPE enmType, STAMVISIBILITY enmVisibility, const char *pszName, STAMUNIT enmUnit, const char *pszDesc);
113static int stamR3ResetOne(PSTAMDESC pDesc, void *pvArg);
114static DECLCALLBACK(void) stamR3EnumLogPrintf(PSTAMR3PRINTONEARGS pvArg, const char *pszFormat, ...);
115static DECLCALLBACK(void) stamR3EnumRelLogPrintf(PSTAMR3PRINTONEARGS pvArg, const char *pszFormat, ...);
116static DECLCALLBACK(void) stamR3EnumPrintf(PSTAMR3PRINTONEARGS pvArg, const char *pszFormat, ...);
117static int stamR3SnapshotOne(PSTAMDESC pDesc, void *pvArg);
118static int stamR3SnapshotPrintf(PSTAMR3SNAPSHOTONE pThis, const char *pszFormat, ...);
119static int stamR3PrintOne(PSTAMDESC pDesc, void *pvArg);
120static int stamR3EnumOne(PSTAMDESC pDesc, void *pvArg);
121static bool stamR3MultiMatch(const char * const *papszExpressions, unsigned cExpressions, unsigned *piExpression, const char *pszName);
122static char **stamR3SplitPattern(const char *pszPat, unsigned *pcExpressions, char **ppszCopy);
123static int stamR3EnumU(PUVM pUVM, const char *pszPat, bool fUpdateRing0, int (pfnCallback)(PSTAMDESC pDesc, void *pvArg), void *pvArg);
124static void stamR3Ring0StatsRegisterU(PUVM pUVM);
125static void stamR3Ring0StatsUpdateU(PUVM pUVM, const char *pszPat);
126static void stamR3Ring0StatsUpdateMultiU(PUVM pUVM, const char * const *papszExpressions, unsigned cExpressions);
127
128#ifdef VBOX_WITH_DEBUGGER
129static DECLCALLBACK(int) stamR3CmdStats(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
130static DECLCALLBACK(void) stamR3EnumDbgfPrintf(PSTAMR3PRINTONEARGS pArgs, const char *pszFormat, ...);
131static DECLCALLBACK(int) stamR3CmdStatsReset(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
132#endif
133
134
135/*******************************************************************************
136* Global Variables *
137*******************************************************************************/
138#ifdef VBOX_WITH_DEBUGGER
139/** Pattern argument. */
140static const DBGCVARDESC g_aArgPat[] =
141{
142 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
143 { 0, 1, DBGCVAR_CAT_STRING, 0, "pattern", "Which samples the command shall be applied to. Use '*' as wildcard. Use ';' to separate expression." }
144};
145
146/** Command descriptors. */
147static const DBGCCMD g_aCmds[] =
148{
149 /* pszCmd, cArgsMin, cArgsMax, paArgDesc, cArgDescs, pResultDesc, fFlags, pfnHandler pszSyntax, ....pszDescription */
150 { "stats", 0, 1, &g_aArgPat[0], RT_ELEMENTS(g_aArgPat), NULL, 0, stamR3CmdStats, "[pattern]", "Display statistics." },
151 { "statsreset", 0, 1, &g_aArgPat[0], RT_ELEMENTS(g_aArgPat), NULL, 0, stamR3CmdStatsReset,"[pattern]", "Resets statistics." }
152};
153#endif
154
155
156/**
157 * The GVMM mapping records.
158 */
159static const STAMR0SAMPLE g_aGVMMStats[] =
160{
161 { RT_UOFFSETOF(GVMMSTATS, SchedVM.cHaltCalls), STAMTYPE_U64_RESET, STAMUNIT_CALLS, "/GVMM/VM/HaltCalls", "The number of calls to GVMMR0SchedHalt." },
162 { RT_UOFFSETOF(GVMMSTATS, SchedVM.cHaltBlocking), STAMTYPE_U64_RESET, STAMUNIT_CALLS, "/GVMM/VM/HaltBlocking", "The number of times we did go to sleep in GVMMR0SchedHalt." },
163 { RT_UOFFSETOF(GVMMSTATS, SchedVM.cHaltTimeouts), STAMTYPE_U64_RESET, STAMUNIT_CALLS, "/GVMM/VM/HaltTimeouts", "The number of times we timed out in GVMMR0SchedHalt." },
164 { RT_UOFFSETOF(GVMMSTATS, SchedVM.cHaltNotBlocking), STAMTYPE_U64_RESET, STAMUNIT_CALLS, "/GVMM/VM/HaltNotBlocking", "The number of times we didn't go to sleep in GVMMR0SchedHalt." },
165 { RT_UOFFSETOF(GVMMSTATS, SchedVM.cHaltWakeUps), STAMTYPE_U64_RESET, STAMUNIT_CALLS, "/GVMM/VM/HaltWakeUps", "The number of wake ups done during GVMMR0SchedHalt." },
166 { RT_UOFFSETOF(GVMMSTATS, SchedVM.cWakeUpCalls), STAMTYPE_U64_RESET, STAMUNIT_CALLS, "/GVMM/VM/WakeUpCalls", "The number of calls to GVMMR0WakeUp." },
167 { RT_UOFFSETOF(GVMMSTATS, SchedVM.cWakeUpNotHalted), STAMTYPE_U64_RESET, STAMUNIT_CALLS, "/GVMM/VM/WakeUpNotHalted", "The number of times the EMT thread wasn't actually halted when GVMMR0WakeUp was called." },
168 { RT_UOFFSETOF(GVMMSTATS, SchedVM.cWakeUpWakeUps), STAMTYPE_U64_RESET, STAMUNIT_CALLS, "/GVMM/VM/WakeUpWakeUps", "The number of wake ups done during GVMMR0WakeUp (not counting the explicit one)." },
169 { RT_UOFFSETOF(GVMMSTATS, SchedVM.cPollCalls), STAMTYPE_U64_RESET, STAMUNIT_CALLS, "/GVMM/VM/PollCalls", "The number of calls to GVMMR0SchedPoll." },
170 { RT_UOFFSETOF(GVMMSTATS, SchedVM.cPollHalts), STAMTYPE_U64_RESET, STAMUNIT_CALLS, "/GVMM/VM/PollHalts", "The number of times the EMT has halted in a GVMMR0SchedPoll call." },
171 { RT_UOFFSETOF(GVMMSTATS, SchedVM.cPollWakeUps), STAMTYPE_U64_RESET, STAMUNIT_CALLS, "/GVMM/VM/PollWakeUps", "The number of wake ups done during GVMMR0SchedPoll." },
172
173 { RT_UOFFSETOF(GVMMSTATS, SchedSum.cHaltCalls), STAMTYPE_U64_RESET, STAMUNIT_CALLS, "/GVMM/Sum/HaltCalls", "The number of calls to GVMMR0SchedHalt." },
174 { RT_UOFFSETOF(GVMMSTATS, SchedSum.cHaltBlocking), STAMTYPE_U64_RESET, STAMUNIT_CALLS, "/GVMM/Sum/HaltBlocking", "The number of times we did go to sleep in GVMMR0SchedHalt." },
175 { RT_UOFFSETOF(GVMMSTATS, SchedSum.cHaltTimeouts), STAMTYPE_U64_RESET, STAMUNIT_CALLS, "/GVMM/Sum/HaltTimeouts", "The number of times we timed out in GVMMR0SchedHalt." },
176 { RT_UOFFSETOF(GVMMSTATS, SchedSum.cHaltNotBlocking), STAMTYPE_U64_RESET, STAMUNIT_CALLS, "/GVMM/Sum/HaltNotBlocking", "The number of times we didn't go to sleep in GVMMR0SchedHalt." },
177 { RT_UOFFSETOF(GVMMSTATS, SchedSum.cHaltWakeUps), STAMTYPE_U64_RESET, STAMUNIT_CALLS, "/GVMM/Sum/HaltWakeUps", "The number of wake ups done during GVMMR0SchedHalt." },
178 { RT_UOFFSETOF(GVMMSTATS, SchedSum.cWakeUpCalls), STAMTYPE_U64_RESET, STAMUNIT_CALLS, "/GVMM/Sum/WakeUpCalls", "The number of calls to GVMMR0WakeUp." },
179 { RT_UOFFSETOF(GVMMSTATS, SchedSum.cWakeUpNotHalted), STAMTYPE_U64_RESET, STAMUNIT_CALLS, "/GVMM/Sum/WakeUpNotHalted", "The number of times the EMT thread wasn't actually halted when GVMMR0WakeUp was called." },
180 { RT_UOFFSETOF(GVMMSTATS, SchedSum.cWakeUpWakeUps), STAMTYPE_U64_RESET, STAMUNIT_CALLS, "/GVMM/Sum/WakeUpWakeUps", "The number of wake ups done during GVMMR0WakeUp (not counting the explicit one)." },
181 { RT_UOFFSETOF(GVMMSTATS, SchedSum.cPollCalls), STAMTYPE_U64_RESET, STAMUNIT_CALLS, "/GVMM/Sum/PollCalls", "The number of calls to GVMMR0SchedPoll." },
182 { RT_UOFFSETOF(GVMMSTATS, SchedSum.cPollHalts), STAMTYPE_U64_RESET, STAMUNIT_CALLS, "/GVMM/Sum/PollHalts", "The number of times the EMT has halted in a GVMMR0SchedPoll call." },
183 { RT_UOFFSETOF(GVMMSTATS, SchedSum.cPollWakeUps), STAMTYPE_U64_RESET, STAMUNIT_CALLS, "/GVMM/Sum/PollWakeUps", "The number of wake ups done during GVMMR0SchedPoll." },
184
185 { RT_UOFFSETOF(GVMMSTATS, cVMs), STAMTYPE_U32, STAMUNIT_CALLS, "/GVMM/VMs", "The number of VMs accessible to the caller." },
186};
187
188
189/**
190 * Initializes the STAM.
191 *
192 * @returns VBox status code.
193 * @param pVM The VM to operate on.
194 */
195STAMR3DECL(int) STAMR3InitUVM(PUVM pUVM)
196{
197 LogFlow(("STAMR3Init\n"));
198
199 /*
200 * Assert alignment and sizes.
201 */
202 AssertCompile(sizeof(pUVM->stam.s) <= sizeof(pUVM->stam.padding));
203 AssertRelease(sizeof(pUVM->stam.s) <= sizeof(pUVM->stam.padding));
204
205 /*
206 * Setup any fixed pointers and offsets.
207 */
208 int rc = RTSemRWCreate(&pUVM->stam.s.RWSem);
209 AssertRCReturn(rc, rc);
210
211 /*
212 * Register the ring-0 statistics (GVMM/GMM).
213 */
214 stamR3Ring0StatsRegisterU(pUVM);
215
216#ifdef VBOX_WITH_DEBUGGER
217 /*
218 * Register debugger commands.
219 */
220 static bool fRegisteredCmds = false;
221 if (!fRegisteredCmds)
222 {
223 int rc = DBGCRegisterCommands(&g_aCmds[0], RT_ELEMENTS(g_aCmds));
224 if (VBOX_SUCCESS(rc))
225 fRegisteredCmds = true;
226 }
227#endif
228
229 return VINF_SUCCESS;
230}
231
232
233/**
234 * Terminates the STAM.
235 *
236 * @param pUVM Pointer to the user mode VM structure.
237 */
238STAMR3DECL(void) STAMR3TermUVM(PUVM pUVM)
239{
240 /*
241 * Free used memory and the RWLock.
242 */
243 PSTAMDESC pCur = pUVM->stam.s.pHead;
244 while (pCur)
245 {
246 void *pvFree = pCur;
247 pCur = pCur->pNext;
248 RTMemFree(pvFree);
249 }
250 pUVM->stam.s.pHead = NULL;
251
252 Assert(pUVM->stam.s.RWSem != NIL_RTSEMRW);
253 RTSemRWDestroy(pUVM->stam.s.RWSem);
254 pUVM->stam.s.RWSem = NIL_RTSEMRW;
255}
256
257
258/**
259 * Registers a sample with the statistics mamanger.
260 *
261 * Statistics are maintained on a per VM basis and is normally registered
262 * during the VM init stage, but there is nothing preventing you from
263 * register them at runtime.
264 *
265 * Use STAMR3Deregister() to deregister statistics at runtime, however do
266 * not bother calling at termination time.
267 *
268 * It is not possible to register the same sample twice.
269 *
270 * @returns VBox status.
271 * @param pUVM Pointer to the user mode VM structure.
272 * @param pvSample Pointer to the sample.
273 * @param enmType Sample type. This indicates what pvSample is pointing at.
274 * @param enmVisibility Visibility type specifying whether unused statistics should be visible or not.
275 * @param pszName Sample name. The name is on this form "/<component>/<sample>".
276 * Further nesting is possible.
277 * @param enmUnit Sample unit.
278 * @param pszDesc Sample description.
279 */
280STAMR3DECL(int) STAMR3RegisterU(PUVM pUVM, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility, const char *pszName, STAMUNIT enmUnit, const char *pszDesc)
281{
282 AssertReturn(enmType != STAMTYPE_CALLBACK, VERR_INVALID_PARAMETER);
283 return stamR3RegisterU(pUVM, pvSample, NULL, NULL, enmType, enmVisibility, pszName, enmUnit, pszDesc);
284}
285
286
287/**
288 * Registers a sample with the statistics mamanger.
289 *
290 * Statistics are maintained on a per VM basis and is normally registered
291 * during the VM init stage, but there is nothing preventing you from
292 * register them at runtime.
293 *
294 * Use STAMR3Deregister() to deregister statistics at runtime, however do
295 * not bother calling at termination time.
296 *
297 * It is not possible to register the same sample twice.
298 *
299 * @returns VBox status.
300 * @param pVM The VM handle.
301 * @param pvSample Pointer to the sample.
302 * @param enmType Sample type. This indicates what pvSample is pointing at.
303 * @param enmVisibility Visibility type specifying whether unused statistics should be visible or not.
304 * @param pszName Sample name. The name is on this form "/<component>/<sample>".
305 * Further nesting is possible.
306 * @param enmUnit Sample unit.
307 * @param pszDesc Sample description.
308 */
309STAMR3DECL(int) STAMR3Register(PVM pVM, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility, const char *pszName, STAMUNIT enmUnit, const char *pszDesc)
310{
311 AssertReturn(enmType != STAMTYPE_CALLBACK, VERR_INVALID_PARAMETER);
312 return stamR3RegisterU(pVM->pUVM, pvSample, NULL, NULL, enmType, enmVisibility, pszName, enmUnit, pszDesc);
313}
314
315
316/**
317 * Same as STAMR3RegisterU except that the name is specified in a
318 * RTStrPrintf like fashion.
319 *
320 * @returns VBox status.
321 * @param pUVM Pointer to the user mode VM structure.
322 * @param pvSample Pointer to the sample.
323 * @param enmType Sample type. This indicates what pvSample is pointing at.
324 * @param enmVisibility Visibility type specifying whether unused statistics should be visible or not.
325 * @param enmUnit Sample unit.
326 * @param pszDesc Sample description.
327 * @param pszName The sample name format string.
328 * @param ... Arguments to the format string.
329 */
330STAMR3DECL(int) STAMR3RegisterFU(PUVM pUVM, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility, STAMUNIT enmUnit,
331 const char *pszDesc, const char *pszName, ...)
332{
333 va_list args;
334 va_start(args, pszName);
335 int rc = STAMR3RegisterVU(pUVM, pvSample, enmType, enmVisibility, enmUnit, pszDesc, pszName, args);
336 va_end(args);
337 return rc;
338}
339
340
341/**
342 * Same as STAMR3Register except that the name is specified in a
343 * RTStrPrintf like fashion.
344 *
345 * @returns VBox status.
346 * @param pVM The VM handle.
347 * @param pvSample Pointer to the sample.
348 * @param enmType Sample type. This indicates what pvSample is pointing at.
349 * @param enmVisibility Visibility type specifying whether unused statistics should be visible or not.
350 * @param enmUnit Sample unit.
351 * @param pszDesc Sample description.
352 * @param pszName The sample name format string.
353 * @param ... Arguments to the format string.
354 */
355STAMR3DECL(int) STAMR3RegisterF(PVM pVM, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility, STAMUNIT enmUnit,
356 const char *pszDesc, const char *pszName, ...)
357{
358 va_list args;
359 va_start(args, pszName);
360 int rc = STAMR3RegisterVU(pVM->pUVM, pvSample, enmType, enmVisibility, enmUnit, pszDesc, pszName, args);
361 va_end(args);
362 return rc;
363}
364
365
366/**
367 * Same as STAMR3Register except that the name is specified in a
368 * RTStrPrintfV like fashion.
369 *
370 * @returns VBox status.
371 * @param pVM The VM handle.
372 * @param pvSample Pointer to the sample.
373 * @param enmType Sample type. This indicates what pvSample is pointing at.
374 * @param enmVisibility Visibility type specifying whether unused statistics should be visible or not.
375 * @param enmUnit Sample unit.
376 * @param pszDesc Sample description.
377 * @param pszName The sample name format string.
378 * @param args Arguments to the format string.
379 */
380STAMR3DECL(int) STAMR3RegisterVU(PUVM pUVM, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility, STAMUNIT enmUnit,
381 const char *pszDesc, const char *pszName, va_list args)
382{
383 AssertReturn(enmType != STAMTYPE_CALLBACK, VERR_INVALID_PARAMETER);
384
385 char *pszFormattedName;
386 RTStrAPrintfV(&pszFormattedName, pszName, args);
387 if (!pszFormattedName)
388 return VERR_NO_MEMORY;
389
390 int rc = STAMR3RegisterU(pUVM, pvSample, enmType, enmVisibility, pszFormattedName, enmUnit, pszDesc);
391 RTStrFree(pszFormattedName);
392 return rc;
393}
394
395
396/**
397 * Same as STAMR3Register except that the name is specified in a
398 * RTStrPrintfV like fashion.
399 *
400 * @returns VBox status.
401 * @param pVM The VM handle.
402 * @param pvSample Pointer to the sample.
403 * @param enmType Sample type. This indicates what pvSample is pointing at.
404 * @param enmVisibility Visibility type specifying whether unused statistics should be visible or not.
405 * @param enmUnit Sample unit.
406 * @param pszDesc Sample description.
407 * @param pszName The sample name format string.
408 * @param args Arguments to the format string.
409 */
410STAMR3DECL(int) STAMR3RegisterV(PVM pVM, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility, STAMUNIT enmUnit,
411 const char *pszDesc, const char *pszName, va_list args)
412{
413 return STAMR3RegisterVU(pVM->pUVM, pvSample, enmType, enmVisibility, enmUnit, pszDesc, pszName, args);
414}
415
416
417/**
418 * Similar to STAMR3Register except for the two callbacks, the implied type (STAMTYPE_CALLBACK),
419 * and name given in an RTStrPrintf like fashion.
420 *
421 * @returns VBox status.
422 * @param pVM The VM handle.
423 * @param pvSample Pointer to the sample.
424 * @param enmVisibility Visibility type specifying whether unused statistics should be visible or not.
425 * @param enmUnit Sample unit.
426 * @param pfnReset Callback for resetting the sample. NULL should be used if the sample can't be reset.
427 * @param pfnPrint Print the sample.
428 * @param pszDesc Sample description.
429 * @param pszName The sample name format string.
430 * @param ... Arguments to the format string.
431 * @remark There is currently no device or driver variant of this API. Add one if it should become necessary!
432 */
433STAMR3DECL(int) STAMR3RegisterCallback(PVM pVM, void *pvSample, STAMVISIBILITY enmVisibility, STAMUNIT enmUnit,
434 PFNSTAMR3CALLBACKRESET pfnReset, PFNSTAMR3CALLBACKPRINT pfnPrint,
435 const char *pszDesc, const char *pszName, ...)
436{
437 va_list args;
438 va_start(args, pszName);
439 int rc = STAMR3RegisterCallbackV(pVM, pvSample, enmVisibility, enmUnit, pfnReset, pfnPrint, pszDesc, pszName, args);
440 va_end(args);
441 return rc;
442}
443
444
445/**
446 * Same as STAMR3RegisterCallback() except for the ellipsis which is a va_list here.
447 *
448 * @returns VBox status.
449 * @param pVM The VM handle.
450 * @param pvSample Pointer to the sample.
451 * @param enmVisibility Visibility type specifying whether unused statistics should be visible or not.
452 * @param enmUnit Sample unit.
453 * @param pfnReset Callback for resetting the sample. NULL should be used if the sample can't be reset.
454 * @param pfnPrint Print the sample.
455 * @param pszDesc Sample description.
456 * @param pszName The sample name format string.
457 * @param args Arguments to the format string.
458 * @remark There is currently no device or driver variant of this API. Add one if it should become necessary!
459 */
460STAMR3DECL(int) STAMR3RegisterCallbackV(PVM pVM, void *pvSample, STAMVISIBILITY enmVisibility, STAMUNIT enmUnit,
461 PFNSTAMR3CALLBACKRESET pfnReset, PFNSTAMR3CALLBACKPRINT pfnPrint,
462 const char *pszDesc, const char *pszName, va_list args)
463{
464 char *pszFormattedName;
465 RTStrAPrintfV(&pszFormattedName, pszName, args);
466 if (!pszFormattedName)
467 return VERR_NO_MEMORY;
468
469 int rc = stamR3RegisterU(pVM->pUVM, pvSample, pfnReset, pfnPrint, STAMTYPE_CALLBACK, enmVisibility, pszFormattedName, enmUnit, pszDesc);
470 RTStrFree(pszFormattedName);
471 return rc;
472}
473
474
475/**
476 * Internal worker for the different register calls.
477 *
478 * @returns VBox status.
479 * @param pUVM Pointer to the user mode VM structure.
480 * @param pvSample Pointer to the sample.
481 * @param pfnReset Callback for resetting the sample. NULL should be used if the sample can't be reset.
482 * @param pfnPrint Print the sample.
483 * @param enmType Sample type. This indicates what pvSample is pointing at.
484 * @param enmVisibility Visibility type specifying whether unused statistics should be visible or not.
485 * @param enmUnit Sample unit.
486 * @param pszDesc Sample description.
487 * @param pszName The sample name format string.
488 * @param args Arguments to the format string.
489 * @remark There is currently no device or driver variant of this API. Add one if it should become necessary!
490 */
491static int stamR3RegisterU(PUVM pUVM, void *pvSample, PFNSTAMR3CALLBACKRESET pfnReset, PFNSTAMR3CALLBACKPRINT pfnPrint,
492 STAMTYPE enmType, STAMVISIBILITY enmVisibility, const char *pszName, STAMUNIT enmUnit, const char *pszDesc)
493{
494 STAM_LOCK_WR(pUVM);
495
496 /*
497 * Check if exists.
498 */
499 PSTAMDESC pPrev = NULL;
500 PSTAMDESC pCur = pUVM->stam.s.pHead;
501 while (pCur)
502 {
503 int iDiff = strcmp(pCur->pszName, pszName);
504 /* passed it */
505 if (iDiff > 0)
506 break;
507 /* found it. */
508 if (!iDiff)
509 {
510 STAM_UNLOCK_WR(pUVM);
511 AssertMsgFailed(("Duplicate sample name: %s\n", pszName));
512 return VERR_ALREADY_EXISTS;
513 }
514
515 /* next */
516 pPrev = pCur;
517 pCur = pCur->pNext;
518 }
519
520 /*
521 * Create a new node and insert it at the current location.
522 */
523 int rc;
524 size_t cchName = strlen(pszName) + 1;
525 size_t cchDesc = pszDesc ? strlen(pszDesc) + 1 : 0;
526 PSTAMDESC pNew = (PSTAMDESC)RTMemAlloc(sizeof(*pNew) + cchName + cchDesc);
527 if (pNew)
528 {
529 pNew->pszName = (char *)memcpy((char *)(pNew + 1), pszName, cchName);
530 pNew->enmType = enmType;
531 pNew->enmVisibility = enmVisibility;
532 if (enmType != STAMTYPE_CALLBACK)
533 pNew->u.pv = pvSample;
534 else
535 {
536 pNew->u.Callback.pvSample = pvSample;
537 pNew->u.Callback.pfnReset = pfnReset;
538 pNew->u.Callback.pfnPrint = pfnPrint;
539 }
540 pNew->enmUnit = enmUnit;
541 pNew->pszDesc = NULL;
542 if (pszDesc)
543 pNew->pszDesc = (char *)memcpy((char *)(pNew + 1) + cchName, pszDesc, cchDesc);
544
545 pNew->pNext = pCur;
546 if (pPrev)
547 pPrev->pNext = pNew;
548 else
549 pUVM->stam.s.pHead = pNew;
550
551 stamR3ResetOne(pNew, pUVM->pVM);
552 rc = VINF_SUCCESS;
553 }
554 else
555 rc = VERR_NO_MEMORY;
556
557 STAM_UNLOCK_WR(pUVM);
558 return rc;
559}
560
561
562/**
563 * Deregisters a sample previously registered by STAR3Register().
564 *
565 * This is intended used for devices which can be unplugged and for
566 * temporary samples.
567 *
568 * @returns VBox status.
569 * @param pUVM Pointer to the user mode VM structure.
570 * @param pvSample Pointer to the sample registered with STAMR3Register().
571 */
572STAMR3DECL(int) STAMR3DeregisterU(PUVM pUVM, void *pvSample)
573{
574 STAM_LOCK_WR(pUVM);
575
576 /*
577 * Search for it.
578 */
579 int rc = VERR_INVALID_HANDLE;
580 PSTAMDESC pPrev = NULL;
581 PSTAMDESC pCur = pUVM->stam.s.pHead;
582 while (pCur)
583 {
584 if (pCur->u.pv == pvSample)
585 {
586 void *pvFree = pCur;
587 pCur = pCur->pNext;
588 if (pPrev)
589 pPrev->pNext = pCur;
590 else
591 pUVM->stam.s.pHead = pCur;
592
593 RTMemFree(pvFree);
594 rc = VINF_SUCCESS;
595 continue;
596 }
597
598 /* next */
599 pPrev = pCur;
600 pCur = pCur->pNext;
601 }
602
603 STAM_UNLOCK_WR(pUVM);
604 return rc;
605}
606
607
608/**
609 * Deregisters a sample previously registered by STAR3Register().
610 *
611 * This is intended used for devices which can be unplugged and for
612 * temporary samples.
613 *
614 * @returns VBox status.
615 * @param pVM The VM handle.
616 * @param pvSample Pointer to the sample registered with STAMR3Register().
617 */
618STAMR3DECL(int) STAMR3Deregister(PVM pVM, void *pvSample)
619{
620 return STAMR3DeregisterU(pVM->pUVM, pvSample);
621}
622
623
624/**
625 * Resets statistics for the specified VM.
626 * It's possible to select a subset of the samples.
627 *
628 * @returns VBox status. (Basically, it cannot fail.)
629 * @param pVM The VM handle.
630 * @param pszPat The name matching pattern. See somewhere_where_this_is_described_in_detail.
631 * If NULL all samples are reset.
632 * @remarks Don't confuse this with the other 'XYZR3Reset' methods, it's not called at VM reset.
633 */
634STAMR3DECL(int) STAMR3ResetU(PUVM pUVM, const char *pszPat)
635{
636 int rc = VINF_SUCCESS;
637
638 /* ring-0 */
639 GVMMRESETSTATISTICSSREQ GVMMReq;
640 //GMMRESETSTATISTICSSREQ GMMReq;
641 bool fGVMMMatched = !pszPat || !*pszPat;
642 //bool fGMMMatched = fGVMMMatched;
643 if (fGVMMMatched)
644 memset(&GVMMReq.Stats, 0xff, sizeof(GVMMReq.Stats));
645 else
646 {
647 char *pszCopy;
648 unsigned cExpressions;
649 char **papszExpressions = stamR3SplitPattern(pszPat, &cExpressions, &pszCopy);
650 if (!papszExpressions)
651 return VERR_NO_MEMORY;
652
653 /* GVMM */
654 memset(&GVMMReq.Stats, 0, sizeof(GVMMReq.Stats));
655 for (unsigned i = 0; i < RT_ELEMENTS(g_aGVMMStats); i++)
656 if (stamR3MultiMatch(papszExpressions, cExpressions, NULL, g_aGVMMStats[i].pszName))
657 {
658 *((uint8_t *)&GVMMReq.Stats + g_aGVMMStats[i].offVar) = 0xff;
659 fGVMMMatched = true;
660 }
661
662 /* GMM */
663// memset(&GMMReq.Stats, 0, sizeof(GMMReq.Stats));
664// for (unsigned i = 0; i < RT_ELEMENTS(g_aGMMStats); i++)
665// if (stamR3MultiMatch(papszExpressions, cExpressions, NULL, g_aGMMStats[i].pszName))
666// {
667// *((uint8_t *)&GMMReq.Stats + g_aGMMStats[i].offVar) = 0xff;
668// fGMMMatched = true;
669// }
670
671 RTMemTmpFree(papszExpressions);
672 RTStrFree(pszCopy);
673 }
674
675 STAM_LOCK_WR(pUVM);
676 if (fGVMMMatched)
677 {
678 PVM pVM = pUVM->pVM;
679 GVMMReq.Hdr.cbReq = sizeof(GVMMReq);
680 GVMMReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
681 GVMMReq.pSession = pVM->pSession;
682 rc = SUPCallVMMR0Ex(pVM->pVMR0, VMMR0_DO_GVMM_RESET_STATISTICS, 0, &GVMMReq.Hdr);
683 }
684
685// if (fGMMMatched)
686// {
687// PVM pVM = pUVM->pVM;
688// GMMReq.Hdr.cbReq = sizeof(Req);
689// GMMReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
690// GMMReq.pSession = pVM->pSession;
691// rc = SUPCallVMMR0Ex(pVM->pVMR0, VMMR0_DO_GMM_RESET_STATISTICS, 0, &Req.Hdr);
692// }
693
694 /* and the reset */
695 stamR3EnumU(pUVM, pszPat, false /* fUpdateRing0 */, stamR3ResetOne, pUVM->pVM);
696
697 STAM_UNLOCK_WR(pUVM);
698 return rc;
699}
700
701/**
702 * Resets statistics for the specified VM.
703 * It's possible to select a subset of the samples.
704 *
705 * @returns VBox status. (Basically, it cannot fail.)
706 * @param pVM The VM handle.
707 * @param pszPat The name matching pattern. See somewhere_where_this_is_described_in_detail.
708 * If NULL all samples are reset.
709 * @remarks Don't confuse this with the other 'XYZR3Reset' methods, it's not called at VM reset.
710 */
711STAMR3DECL(int) STAMR3Reset(PVM pVM, const char *pszPat)
712{
713 return STAMR3ResetU(pVM->pUVM, pszPat);
714}
715
716
717
718/**
719 * Resets one statistics sample.
720 * Callback for stamR3EnumU().
721 *
722 * @returns VINF_SUCCESS
723 * @param pDesc Pointer to the current descriptor.
724 * @param pvArg User argument - The VM handle.
725 */
726static int stamR3ResetOne(PSTAMDESC pDesc, void *pvArg)
727{
728 switch (pDesc->enmType)
729 {
730 case STAMTYPE_COUNTER:
731 ASMAtomicXchgU64(&pDesc->u.pCounter->c, 0);
732 break;
733
734 case STAMTYPE_PROFILE:
735 case STAMTYPE_PROFILE_ADV:
736 ASMAtomicXchgU64(&pDesc->u.pProfile->cPeriods, 0);
737 ASMAtomicXchgU64(&pDesc->u.pProfile->cTicks, 0);
738 ASMAtomicXchgU64(&pDesc->u.pProfile->cTicksMax, 0);
739 ASMAtomicXchgU64(&pDesc->u.pProfile->cTicksMin, ~0);
740 break;
741
742 case STAMTYPE_RATIO_U32_RESET:
743 ASMAtomicXchgU32(&pDesc->u.pRatioU32->u32A, 0);
744 ASMAtomicXchgU32(&pDesc->u.pRatioU32->u32B, 0);
745 break;
746
747 case STAMTYPE_CALLBACK:
748 if (pDesc->u.Callback.pfnReset)
749 pDesc->u.Callback.pfnReset((PVM)pvArg, pDesc->u.Callback.pvSample);
750 break;
751
752 case STAMTYPE_U8_RESET:
753 case STAMTYPE_X8_RESET:
754 ASMAtomicXchgU8(pDesc->u.pu8, 0);
755 break;
756
757 case STAMTYPE_U16_RESET:
758 case STAMTYPE_X16_RESET:
759 ASMAtomicXchgU16(pDesc->u.pu16, 0);
760 break;
761
762 case STAMTYPE_U32_RESET:
763 case STAMTYPE_X32_RESET:
764 ASMAtomicXchgU32(pDesc->u.pu32, 0);
765 break;
766
767 case STAMTYPE_U64_RESET:
768 case STAMTYPE_X64_RESET:
769 ASMAtomicXchgU64(pDesc->u.pu64, 0);
770 break;
771
772 /* These are custom and will not be touched. */
773 case STAMTYPE_U8:
774 case STAMTYPE_X8:
775 case STAMTYPE_U16:
776 case STAMTYPE_X16:
777 case STAMTYPE_U32:
778 case STAMTYPE_X32:
779 case STAMTYPE_U64:
780 case STAMTYPE_X64:
781 case STAMTYPE_RATIO_U32:
782 break;
783
784 default:
785 AssertMsgFailed(("enmType=%d\n", pDesc->enmType));
786 break;
787 }
788 NOREF(pvArg);
789 return VINF_SUCCESS;
790}
791
792
793/**
794 * Get a snapshot of the statistics.
795 * It's possible to select a subset of the samples.
796 *
797 * @returns VBox status. (Basically, it cannot fail.)
798 * @param pUVM Pointer to the user mode VM structure.
799 * @param pszPat The name matching pattern. See somewhere_where_this_is_described_in_detail.
800 * If NULL all samples are reset.
801 * @param fWithDesc Whether to include the descriptions.
802 * @param ppszSnapshot Where to store the pointer to the snapshot data.
803 * The format of the snapshot should be XML, but that will have to be discussed
804 * when this function is implemented.
805 * The returned pointer must be freed by calling STAMR3SnapshotFree().
806 * @param pcchSnapshot Where to store the size of the snapshot data. (Excluding the trailing '\0')
807 */
808STAMR3DECL(int) STAMR3SnapshotU(PUVM pUVM, const char *pszPat, char **ppszSnapshot, size_t *pcchSnapshot, bool fWithDesc)
809{
810 STAMR3SNAPSHOTONE State = { NULL, NULL, NULL, pUVM->pVM, 0, VINF_SUCCESS, fWithDesc };
811
812 /*
813 * Write the XML header.
814 */
815 /** @todo Make this proper & valid XML. */
816 stamR3SnapshotPrintf(&State, "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n");
817
818 /*
819 * Write the content.
820 */
821 stamR3SnapshotPrintf(&State, "<Statistics>\n");
822 STAM_LOCK_RD(pUVM);
823 int rc = stamR3EnumU(pUVM, pszPat, true /* fUpdateRing0 */, stamR3SnapshotOne, &State);
824 STAM_UNLOCK_RD(pUVM);
825 stamR3SnapshotPrintf(&State, "</Statistics>\n");
826
827 if (VBOX_SUCCESS(rc))
828 rc = State.rc;
829 else
830 {
831 RTMemFree(State.pszStart);
832 State.pszStart = State.pszEnd = State.psz = NULL;
833 State.cbAllocated = 0;
834 }
835
836 /*
837 * Done.
838 */
839 *ppszSnapshot = State.pszStart;
840 if (pcchSnapshot)
841 *pcchSnapshot = State.psz - State.pszStart;
842 return rc;
843}
844
845
846/**
847 * Get a snapshot of the statistics.
848 * It's possible to select a subset of the samples.
849 *
850 * @returns VBox status. (Basically, it cannot fail.)
851 * @param pVM The VM handle.
852 * @param pszPat The name matching pattern. See somewhere_where_this_is_described_in_detail.
853 * If NULL all samples are reset.
854 * @param fWithDesc Whether to include the descriptions.
855 * @param ppszSnapshot Where to store the pointer to the snapshot data.
856 * The format of the snapshot should be XML, but that will have to be discussed
857 * when this function is implemented.
858 * The returned pointer must be freed by calling STAMR3SnapshotFree().
859 * @param pcchSnapshot Where to store the size of the snapshot data. (Excluding the trailing '\0')
860 */
861STAMR3DECL(int) STAMR3Snapshot(PVM pVM, const char *pszPat, char **ppszSnapshot, size_t *pcchSnapshot, bool fWithDesc)
862{
863 return STAMR3SnapshotU(pVM->pUVM, pszPat, ppszSnapshot, pcchSnapshot, fWithDesc);
864}
865
866
867/**
868 * stamR3EnumU callback employed by STAMR3Snapshot.
869 *
870 * @returns VBox status code, but it's interpreted as 0 == success / !0 == failure by enmR3Enum.
871 * @param pDesc The sample.
872 * @param pvArg The snapshot status structure.
873 */
874static int stamR3SnapshotOne(PSTAMDESC pDesc, void *pvArg)
875{
876 PSTAMR3SNAPSHOTONE pThis = (PSTAMR3SNAPSHOTONE)pvArg;
877
878 switch (pDesc->enmType)
879 {
880 case STAMTYPE_COUNTER:
881 if (pDesc->enmVisibility == STAMVISIBILITY_USED && pDesc->u.pCounter->c == 0)
882 return VINF_SUCCESS;
883 stamR3SnapshotPrintf(pThis, "<Counter c=\"%lld\"", pDesc->u.pCounter->c);
884 break;
885
886 case STAMTYPE_PROFILE:
887 case STAMTYPE_PROFILE_ADV:
888 if (pDesc->enmVisibility == STAMVISIBILITY_USED && pDesc->u.pProfile->cPeriods == 0)
889 return VINF_SUCCESS;
890 stamR3SnapshotPrintf(pThis, "<Profile cPeriods=\"%lld\" cTicks=\"%lld\" cTicksMin=\"%lld\" cTicksMax=\"%lld\"",
891 pDesc->u.pProfile->cPeriods, pDesc->u.pProfile->cTicks, pDesc->u.pProfile->cTicksMin,
892 pDesc->u.pProfile->cTicksMax);
893 break;
894
895 case STAMTYPE_RATIO_U32:
896 case STAMTYPE_RATIO_U32_RESET:
897 if (pDesc->enmVisibility == STAMVISIBILITY_USED && !pDesc->u.pRatioU32->u32A && !pDesc->u.pRatioU32->u32B)
898 return VINF_SUCCESS;
899 stamR3SnapshotPrintf(pThis, "<Ratio32 u32A=\"%lld\" u32B=\"%lld\"",
900 pDesc->u.pRatioU32->u32A, pDesc->u.pRatioU32->u32B);
901 break;
902
903 case STAMTYPE_CALLBACK:
904 {
905 char szBuf[512];
906 pDesc->u.Callback.pfnPrint(pThis->pVM, pDesc->u.Callback.pvSample, szBuf, sizeof(szBuf));
907 stamR3SnapshotPrintf(pThis, "<Callback val=\"%s\"", szBuf);
908 break;
909 }
910
911 case STAMTYPE_U8:
912 case STAMTYPE_U8_RESET:
913 if (pDesc->enmVisibility == STAMVISIBILITY_USED && *pDesc->u.pu8 == 0)
914 return VINF_SUCCESS;
915 stamR3SnapshotPrintf(pThis, "<U8 val=\"%u\"", *pDesc->u.pu8);
916 break;
917
918 case STAMTYPE_X8:
919 case STAMTYPE_X8_RESET:
920 if (pDesc->enmVisibility == STAMVISIBILITY_USED && *pDesc->u.pu8 == 0)
921 return VINF_SUCCESS;
922 stamR3SnapshotPrintf(pThis, "<X8 val=\"%#x\"", *pDesc->u.pu8);
923 break;
924
925 case STAMTYPE_U16:
926 case STAMTYPE_U16_RESET:
927 if (pDesc->enmVisibility == STAMVISIBILITY_USED && *pDesc->u.pu16 == 0)
928 return VINF_SUCCESS;
929 stamR3SnapshotPrintf(pThis, "<U16 val=\"%u\"", *pDesc->u.pu16);
930 break;
931
932 case STAMTYPE_X16:
933 case STAMTYPE_X16_RESET:
934 if (pDesc->enmVisibility == STAMVISIBILITY_USED && *pDesc->u.pu16 == 0)
935 return VINF_SUCCESS;
936 stamR3SnapshotPrintf(pThis, "<X16 val=\"%#x\"", *pDesc->u.pu16);
937 break;
938
939 case STAMTYPE_U32:
940 case STAMTYPE_U32_RESET:
941 if (pDesc->enmVisibility == STAMVISIBILITY_USED && *pDesc->u.pu32 == 0)
942 return VINF_SUCCESS;
943 stamR3SnapshotPrintf(pThis, "<U32 val=\"%u\"", *pDesc->u.pu32);
944 break;
945
946 case STAMTYPE_X32:
947 case STAMTYPE_X32_RESET:
948 if (pDesc->enmVisibility == STAMVISIBILITY_USED && *pDesc->u.pu32 == 0)
949 return VINF_SUCCESS;
950 stamR3SnapshotPrintf(pThis, "<X32 val=\"%#x\"", *pDesc->u.pu32);
951 break;
952
953 case STAMTYPE_U64:
954 case STAMTYPE_U64_RESET:
955 if (pDesc->enmVisibility == STAMVISIBILITY_USED && *pDesc->u.pu64 == 0)
956 return VINF_SUCCESS;
957 stamR3SnapshotPrintf(pThis, "<U64 val=\"%llu\"", *pDesc->u.pu64);
958 break;
959
960 case STAMTYPE_X64:
961 case STAMTYPE_X64_RESET:
962 if (pDesc->enmVisibility == STAMVISIBILITY_USED && *pDesc->u.pu64 == 0)
963 return VINF_SUCCESS;
964 stamR3SnapshotPrintf(pThis, "<X64 val=\"%#llx\"", *pDesc->u.pu64);
965 break;
966
967 default:
968 AssertMsgFailed(("%d\n", pDesc->enmType));
969 return 0;
970 }
971
972 stamR3SnapshotPrintf(pThis, " unit=\"%s\"", STAMR3GetUnit(pDesc->enmUnit));
973
974 switch (pDesc->enmVisibility)
975 {
976 default:
977 case STAMVISIBILITY_ALWAYS:
978 break;
979 case STAMVISIBILITY_USED:
980 stamR3SnapshotPrintf(pThis, " vis=\"used\"");
981 break;
982 case STAMVISIBILITY_NOT_GUI:
983 stamR3SnapshotPrintf(pThis, " vis=\"not-gui\"");
984 break;
985 }
986
987 stamR3SnapshotPrintf(pThis, " name=\"%s\"", pDesc->pszName);
988
989 if (pThis->fWithDesc && pDesc->pszDesc)
990 {
991 /*
992 * The description is a bit tricky as it may include chars that
993 * xml requires to be escaped.
994 */
995 const char *pszBadChar = strpbrk(pDesc->pszDesc, "&<>\"'");
996 if (!pszBadChar)
997 return stamR3SnapshotPrintf(pThis, " desc=\"%s\"/>\n", pDesc->pszDesc);
998
999 stamR3SnapshotPrintf(pThis, " desc=\"");
1000 const char *pszCur = pDesc->pszDesc;
1001 do
1002 {
1003 stamR3SnapshotPrintf(pThis, "%.*s", pszBadChar - pszCur, pszCur);
1004 switch (*pszBadChar)
1005 {
1006 case '&': stamR3SnapshotPrintf(pThis, "&amp;"); break;
1007 case '<': stamR3SnapshotPrintf(pThis, "&lt;"); break;
1008 case '>': stamR3SnapshotPrintf(pThis, "&gt;"); break;
1009 case '"': stamR3SnapshotPrintf(pThis, "&quot;"); break;
1010 case '\'': stamR3SnapshotPrintf(pThis, "&apos;"); break;
1011 default: AssertMsgFailed(("%c", *pszBadChar)); break;
1012 }
1013 pszCur = pszBadChar + 1;
1014 pszBadChar = strpbrk(pszCur, "&<>\"'");
1015 } while (pszBadChar);
1016 return stamR3SnapshotPrintf(pThis, "%s\"/>\n", pszCur);
1017 }
1018 return stamR3SnapshotPrintf(pThis, "/>\n");
1019}
1020
1021
1022/**
1023 * Output callback for stamR3SnapshotPrintf.
1024 *
1025 * @returns number of bytes written.
1026 * @param pvArg The snapshot status structure.
1027 * @param pach Pointer to an array of characters (bytes).
1028 * @param cch The number or chars (bytes) to write from the array.
1029 */
1030static DECLCALLBACK(size_t) stamR3SnapshotOutput(void *pvArg, const char *pach, size_t cch)
1031{
1032 PSTAMR3SNAPSHOTONE pThis = (PSTAMR3SNAPSHOTONE)pvArg;
1033
1034 /*
1035 * Make sure we've got space for it.
1036 */
1037 if (RT_UNLIKELY((uintptr_t)pThis->pszEnd - (uintptr_t)pThis->psz < cch + 1))
1038 {
1039 if (RT_FAILURE(pThis->rc))
1040 return 0;
1041
1042 size_t cbNewSize = pThis->cbAllocated;
1043 if (cbNewSize > cch)
1044 cbNewSize *= 2;
1045 else
1046 cbNewSize += RT_ALIGN(cch + 1, 0x1000);
1047 char *pszNew = (char *)RTMemRealloc(pThis->pszStart, cbNewSize);
1048 if (!pszNew)
1049 {
1050 /*
1051 * Free up immediately, out-of-memory is bad news and this
1052 * isn't an important allocations / API.
1053 */
1054 pThis->rc = VERR_NO_MEMORY;
1055 RTMemFree(pThis->pszStart);
1056 pThis->pszStart = pThis->pszEnd = pThis->psz = NULL;
1057 pThis->cbAllocated = 0;
1058 return 0;
1059 }
1060
1061 pThis->psz = pszNew + (pThis->psz - pThis->pszStart);
1062 pThis->pszStart = pszNew;
1063 pThis->pszEnd = pszNew + cbNewSize;
1064 pThis->cbAllocated = cbNewSize;
1065 }
1066
1067 /*
1068 * Copy the chars to the buffer and terminate it.
1069 */
1070 memcpy(pThis->psz, pach, cch);
1071 pThis->psz += cch;
1072 *pThis->psz = '\0';
1073 return cch;
1074}
1075
1076
1077/**
1078 * Wrapper around RTStrFormatV for use by the snapshot API.
1079 *
1080 * @returns VBox status code.
1081 * @param pThis The snapshot status structure.
1082 * @param pszFormat The format string.
1083 * @param ... Optional arguments.
1084 */
1085static int stamR3SnapshotPrintf(PSTAMR3SNAPSHOTONE pThis, const char *pszFormat, ...)
1086{
1087 va_list va;
1088 va_start(va, pszFormat);
1089 RTStrFormatV(stamR3SnapshotOutput, pThis, NULL, NULL, pszFormat, va);
1090 va_end(va);
1091 return pThis->rc;
1092}
1093
1094
1095/**
1096 * Releases a statistics snapshot returned by STAMR3Snapshot().
1097 *
1098 * @returns VBox status.
1099 * @param pUVM Pointer to the user mode VM structure.
1100 * @param pszSnapshot The snapshot data pointer returned by STAMR3Snapshot().
1101 * NULL is allowed.
1102 */
1103STAMR3DECL(int) STAMR3SnapshotFreeU(PUVM pUVM, char *pszSnapshot)
1104{
1105 if (!pszSnapshot)
1106 RTMemFree(pszSnapshot);
1107 return VINF_SUCCESS;
1108}
1109
1110
1111/**
1112 * Releases a statistics snapshot returned by STAMR3Snapshot().
1113 *
1114 * @returns VBox status.
1115 * @param pVM The VM handle.
1116 * @param pszSnapshot The snapshot data pointer returned by STAMR3Snapshot().
1117 * NULL is allowed.
1118 */
1119STAMR3DECL(int) STAMR3SnapshotFree(PVM pVM, char *pszSnapshot)
1120{
1121 return STAMR3SnapshotFreeU(pVM->pUVM, pszSnapshot);
1122}
1123
1124
1125/**
1126 * Dumps the selected statistics to the log.
1127 *
1128 * @returns VBox status.
1129 * @param pUVM Pointer to the user mode VM structure.
1130 * @param pszPat The name matching pattern. See somewhere_where_this_is_described_in_detail.
1131 * If NULL all samples are written to the log.
1132 */
1133STAMR3DECL(int) STAMR3DumpU(PUVM pUVM, const char *pszPat)
1134{
1135 STAMR3PRINTONEARGS Args;
1136 Args.pVM = pUVM->pVM;
1137 Args.pvArg = NULL;
1138 Args.pfnPrintf = stamR3EnumLogPrintf;
1139
1140 STAM_LOCK_RD(pUVM);
1141 stamR3EnumU(pUVM, pszPat, true /* fUpdateRing0 */, stamR3PrintOne, &Args);
1142 STAM_UNLOCK_RD(pUVM);
1143 return VINF_SUCCESS;
1144}
1145
1146
1147/**
1148 * Dumps the selected statistics to the log.
1149 *
1150 * @returns VBox status.
1151 * @param pVM The VM handle.
1152 * @param pszPat The name matching pattern. See somewhere_where_this_is_described_in_detail.
1153 * If NULL all samples are written to the log.
1154 */
1155STAMR3DECL(int) STAMR3Dump(PVM pVM, const char *pszPat)
1156{
1157 return STAMR3DumpU(pVM->pUVM, pszPat);
1158}
1159
1160
1161/**
1162 * Prints to the log.
1163 *
1164 * @param pArgs Pointer to the print one argument structure.
1165 * @param pszFormat Format string.
1166 * @param ... Format arguments.
1167 */
1168static DECLCALLBACK(void) stamR3EnumLogPrintf(PSTAMR3PRINTONEARGS pArgs, const char *pszFormat, ...)
1169{
1170 va_list va;
1171 va_start(va, pszFormat);
1172 RTLogPrintfV(pszFormat, va);
1173 va_end(va);
1174 NOREF(pArgs);
1175}
1176
1177
1178/**
1179 * Dumps the selected statistics to the release log.
1180 *
1181 * @returns VBox status.
1182 * @param pUVM Pointer to the user mode VM structure.
1183 * @param pszPat The name matching pattern. See somewhere_where_this_is_described_in_detail.
1184 * If NULL all samples are written to the log.
1185 */
1186STAMR3DECL(int) STAMR3DumpToReleaseLogU(PUVM pUVM, const char *pszPat)
1187{
1188 STAMR3PRINTONEARGS Args;
1189 Args.pVM = pUVM->pVM;
1190 Args.pvArg = NULL;
1191 Args.pfnPrintf = stamR3EnumRelLogPrintf;
1192
1193 STAM_LOCK_RD(pUVM);
1194 stamR3EnumU(pUVM, pszPat, true /* fUpdateRing0 */, stamR3PrintOne, &Args);
1195 STAM_UNLOCK_RD(pUVM);
1196 return VINF_SUCCESS;
1197}
1198
1199
1200/**
1201 * Dumps the selected statistics to the release log.
1202 *
1203 * @returns VBox status.
1204 * @param pVM The VM handle.
1205 * @param pszPat The name matching pattern. See somewhere_where_this_is_described_in_detail.
1206 * If NULL all samples are written to the log.
1207 */
1208STAMR3DECL(int) STAMR3DumpToReleaseLog(PVM pVM, const char *pszPat)
1209{
1210 return STAMR3DumpToReleaseLogU(pVM->pUVM, pszPat);
1211}
1212
1213
1214/**
1215 * Prints to the release log.
1216 *
1217 * @param pArgs Pointer to the print one argument structure.
1218 * @param pszFormat Format string.
1219 * @param ... Format arguments.
1220 */
1221static DECLCALLBACK(void) stamR3EnumRelLogPrintf(PSTAMR3PRINTONEARGS pArgs, const char *pszFormat, ...)
1222{
1223 va_list va;
1224 va_start(va, pszFormat);
1225 RTLogRelPrintfV(pszFormat, va);
1226 va_end(va);
1227 NOREF(pArgs);
1228}
1229
1230
1231/**
1232 * Prints the selected statistics to standard out.
1233 *
1234 * @returns VBox status.
1235 * @param pVM The VM handle.
1236 * @param pszPat The name matching pattern. See somewhere_where_this_is_described_in_detail.
1237 * If NULL all samples are reset.
1238 */
1239STAMR3DECL(int) STAMR3PrintU(PUVM pUVM, const char *pszPat)
1240{
1241 STAMR3PRINTONEARGS Args;
1242 Args.pVM = pUVM->pVM;
1243 Args.pvArg = NULL;
1244 Args.pfnPrintf = stamR3EnumPrintf;
1245
1246 STAM_LOCK_RD(pUVM);
1247 stamR3EnumU(pUVM, pszPat, true /* fUpdateRing0 */, stamR3PrintOne, &Args);
1248 STAM_UNLOCK_RD(pUVM);
1249 return VINF_SUCCESS;
1250}
1251
1252
1253/**
1254 * Prints the selected statistics to standard out.
1255 *
1256 * @returns VBox status.
1257 * @param pVM The VM handle.
1258 * @param pszPat The name matching pattern. See somewhere_where_this_is_described_in_detail.
1259 * If NULL all samples are reset.
1260 */
1261STAMR3DECL(int) STAMR3Print(PVM pVM, const char *pszPat)
1262{
1263 return STAMR3PrintU(pVM->pUVM, pszPat);
1264}
1265
1266
1267/**
1268 * Prints to stdout.
1269 *
1270 * @param pArgs Pointer to the print one argument structure.
1271 * @param pszFormat Format string.
1272 * @param ... Format arguments.
1273 */
1274static DECLCALLBACK(void) stamR3EnumPrintf(PSTAMR3PRINTONEARGS pArgs, const char *pszFormat, ...)
1275{
1276 va_list va;
1277 va_start(va, pszFormat);
1278 RTPrintfV(pszFormat, va);
1279 va_end(va);
1280 NOREF(pArgs);
1281}
1282
1283
1284/**
1285 * Prints one sample.
1286 * Callback for stamR3EnumU().
1287 *
1288 * @returns VINF_SUCCESS
1289 * @param pDesc Pointer to the current descriptor.
1290 * @param pvArg User argument - STAMR3PRINTONEARGS.
1291 */
1292static int stamR3PrintOne(PSTAMDESC pDesc, void *pvArg)
1293{
1294 PSTAMR3PRINTONEARGS pArgs = (PSTAMR3PRINTONEARGS)pvArg;
1295
1296 switch (pDesc->enmType)
1297 {
1298 case STAMTYPE_COUNTER:
1299 if (pDesc->enmVisibility == STAMVISIBILITY_USED && pDesc->u.pCounter->c == 0)
1300 return VINF_SUCCESS;
1301
1302 pArgs->pfnPrintf(pArgs, "%-32s %8llu %s\n", pDesc->pszName, pDesc->u.pCounter->c, STAMR3GetUnit(pDesc->enmUnit));
1303 break;
1304
1305 case STAMTYPE_PROFILE:
1306 case STAMTYPE_PROFILE_ADV:
1307 {
1308 if (pDesc->enmVisibility == STAMVISIBILITY_USED && pDesc->u.pProfile->cPeriods == 0)
1309 return VINF_SUCCESS;
1310
1311 uint64_t u64 = pDesc->u.pProfile->cPeriods ? pDesc->u.pProfile->cPeriods : 1;
1312 pArgs->pfnPrintf(pArgs, "%-32s %8llu %s (%12llu ticks, %7llu times, max %9llu, min %7lld)\n", pDesc->pszName,
1313 pDesc->u.pProfile->cTicks / u64, STAMR3GetUnit(pDesc->enmUnit),
1314 pDesc->u.pProfile->cTicks, pDesc->u.pProfile->cPeriods, pDesc->u.pProfile->cTicksMax, pDesc->u.pProfile->cTicksMin);
1315 break;
1316 }
1317
1318 case STAMTYPE_RATIO_U32:
1319 case STAMTYPE_RATIO_U32_RESET:
1320 if (pDesc->enmVisibility == STAMVISIBILITY_USED && !pDesc->u.pRatioU32->u32A && !pDesc->u.pRatioU32->u32B)
1321 return VINF_SUCCESS;
1322 pArgs->pfnPrintf(pArgs, "%-32s %8u:%-8u %s\n", pDesc->pszName,
1323 pDesc->u.pRatioU32->u32A, pDesc->u.pRatioU32->u32B, STAMR3GetUnit(pDesc->enmUnit));
1324 break;
1325
1326 case STAMTYPE_CALLBACK:
1327 {
1328 char szBuf[512];
1329 pDesc->u.Callback.pfnPrint(pArgs->pVM, pDesc->u.Callback.pvSample, szBuf, sizeof(szBuf));
1330 pArgs->pfnPrintf(pArgs, "%-32s %s %s\n", pDesc->pszName, szBuf, STAMR3GetUnit(pDesc->enmUnit));
1331 break;
1332 }
1333
1334 case STAMTYPE_U8:
1335 case STAMTYPE_U8_RESET:
1336 if (pDesc->enmVisibility == STAMVISIBILITY_USED && *pDesc->u.pu8 == 0)
1337 return VINF_SUCCESS;
1338 pArgs->pfnPrintf(pArgs, "%-32s %8u %s\n", pDesc->pszName, *pDesc->u.pu8, STAMR3GetUnit(pDesc->enmUnit));
1339 break;
1340
1341 case STAMTYPE_X8:
1342 case STAMTYPE_X8_RESET:
1343 if (pDesc->enmVisibility == STAMVISIBILITY_USED && *pDesc->u.pu8 == 0)
1344 return VINF_SUCCESS;
1345 pArgs->pfnPrintf(pArgs, "%-32s %8x %s\n", pDesc->pszName, *pDesc->u.pu8, STAMR3GetUnit(pDesc->enmUnit));
1346 break;
1347
1348 case STAMTYPE_U16:
1349 case STAMTYPE_U16_RESET:
1350 if (pDesc->enmVisibility == STAMVISIBILITY_USED && *pDesc->u.pu16 == 0)
1351 return VINF_SUCCESS;
1352 pArgs->pfnPrintf(pArgs, "%-32s %8u %s\n", pDesc->pszName, *pDesc->u.pu16, STAMR3GetUnit(pDesc->enmUnit));
1353 break;
1354
1355 case STAMTYPE_X16:
1356 case STAMTYPE_X16_RESET:
1357 if (pDesc->enmVisibility == STAMVISIBILITY_USED && *pDesc->u.pu16 == 0)
1358 return VINF_SUCCESS;
1359 pArgs->pfnPrintf(pArgs, "%-32s %8x %s\n", pDesc->pszName, *pDesc->u.pu16, STAMR3GetUnit(pDesc->enmUnit));
1360 break;
1361
1362 case STAMTYPE_U32:
1363 case STAMTYPE_U32_RESET:
1364 if (pDesc->enmVisibility == STAMVISIBILITY_USED && *pDesc->u.pu32 == 0)
1365 return VINF_SUCCESS;
1366 pArgs->pfnPrintf(pArgs, "%-32s %8u %s\n", pDesc->pszName, *pDesc->u.pu32, STAMR3GetUnit(pDesc->enmUnit));
1367 break;
1368
1369 case STAMTYPE_X32:
1370 case STAMTYPE_X32_RESET:
1371 if (pDesc->enmVisibility == STAMVISIBILITY_USED && *pDesc->u.pu32 == 0)
1372 return VINF_SUCCESS;
1373 pArgs->pfnPrintf(pArgs, "%-32s %8x %s\n", pDesc->pszName, *pDesc->u.pu32, STAMR3GetUnit(pDesc->enmUnit));
1374 break;
1375
1376 case STAMTYPE_U64:
1377 case STAMTYPE_U64_RESET:
1378 if (pDesc->enmVisibility == STAMVISIBILITY_USED && *pDesc->u.pu64 == 0)
1379 return VINF_SUCCESS;
1380 pArgs->pfnPrintf(pArgs, "%-32s %8llu %s\n", pDesc->pszName, *pDesc->u.pu64, STAMR3GetUnit(pDesc->enmUnit));
1381 break;
1382
1383 case STAMTYPE_X64:
1384 case STAMTYPE_X64_RESET:
1385 if (pDesc->enmVisibility == STAMVISIBILITY_USED && *pDesc->u.pu64 == 0)
1386 return VINF_SUCCESS;
1387 pArgs->pfnPrintf(pArgs, "%-32s %8llx %s\n", pDesc->pszName, *pDesc->u.pu64, STAMR3GetUnit(pDesc->enmUnit));
1388 break;
1389
1390 default:
1391 AssertMsgFailed(("enmType=%d\n", pDesc->enmType));
1392 break;
1393 }
1394 NOREF(pvArg);
1395 return VINF_SUCCESS;
1396}
1397
1398
1399/**
1400 * Enumerate the statistics by the means of a callback function.
1401 *
1402 * @returns Whatever the callback returns.
1403 *
1404 * @param pUVM Pointer to the user mode VM structure.
1405 * @param pszPat The pattern to match samples.
1406 * @param pfnEnum The callback function.
1407 * @param pvUser The pvUser argument of the callback function.
1408 */
1409STAMR3DECL(int) STAMR3EnumU(PUVM pUVM, const char *pszPat, PFNSTAMR3ENUM pfnEnum, void *pvUser)
1410{
1411 STAMR3ENUMONEARGS Args;
1412 Args.pVM = pUVM->pVM;
1413 Args.pfnEnum = pfnEnum;
1414 Args.pvUser = pvUser;
1415
1416 STAM_LOCK_RD(pUVM);
1417 int rc = stamR3EnumU(pUVM, pszPat, true /* fUpdateRing0 */, stamR3EnumOne, &Args);
1418 STAM_UNLOCK_RD(pUVM);
1419 return rc;
1420}
1421
1422
1423/**
1424 * Enumerate the statistics by the means of a callback function.
1425 *
1426 * @returns Whatever the callback returns.
1427 *
1428 * @param pVM The VM handle.
1429 * @param pszPat The pattern to match samples.
1430 * @param pfnEnum The callback function.
1431 * @param pvUser The pvUser argument of the callback function.
1432 */
1433STAMR3DECL(int) STAMR3Enum(PVM pVM, const char *pszPat, PFNSTAMR3ENUM pfnEnum, void *pvUser)
1434{
1435 return STAMR3EnumU(pVM->pUVM, pszPat, pfnEnum, pvUser);
1436}
1437
1438
1439/**
1440 * Callback function for STARTR3Enum().
1441 *
1442 * @returns whatever the callback returns.
1443 * @param pDesc Pointer to the current descriptor.
1444 * @param pvArg Points to a STAMR3ENUMONEARGS structure.
1445 */
1446static int stamR3EnumOne(PSTAMDESC pDesc, void *pvArg)
1447{
1448 PSTAMR3ENUMONEARGS pArgs = (PSTAMR3ENUMONEARGS)pvArg;
1449 int rc;
1450 if (pDesc->enmType == STAMTYPE_CALLBACK)
1451 {
1452 /* Give the enumerator something useful. */
1453 char szBuf[512];
1454 pDesc->u.Callback.pfnPrint(pArgs->pVM, pDesc->u.Callback.pvSample, szBuf, sizeof(szBuf));
1455 rc = pArgs->pfnEnum(pDesc->pszName, pDesc->enmType, szBuf, pDesc->enmUnit,
1456 pDesc->enmVisibility, pDesc->pszDesc, pArgs->pvUser);
1457 }
1458 else
1459 rc = pArgs->pfnEnum(pDesc->pszName, pDesc->enmType, pDesc->u.pv, pDesc->enmUnit,
1460 pDesc->enmVisibility, pDesc->pszDesc, pArgs->pvUser);
1461 return rc;
1462}
1463
1464
1465/**
1466 * Matches a sample name against a pattern.
1467 *
1468 * @returns True if matches, false if not.
1469 * @param pszPat Pattern.
1470 * @param pszName Name to match against the pattern.
1471 */
1472static bool stamR3Match(const char *pszPat, const char *pszName)
1473{
1474 /* ASSUMES ASCII */
1475 for (;;)
1476 {
1477 char chPat = *pszPat;
1478 switch (chPat)
1479 {
1480 default:
1481 if (*pszName != chPat)
1482 return false;
1483 break;
1484
1485 case '*':
1486 {
1487 while ((chPat = *++pszPat) == '*' || chPat == '?')
1488 /* nothing */;
1489
1490 for (;;)
1491 {
1492 char ch = *pszName++;
1493 if ( ch == chPat
1494 && ( !chPat
1495 || stamR3Match(pszPat + 1, pszName)))
1496 return true;
1497 if (!ch)
1498 return false;
1499 }
1500 /* won't ever get here */
1501 break;
1502 }
1503
1504 case '?':
1505 if (!*pszName)
1506 return false;
1507 break;
1508
1509 case '\0':
1510 return !*pszName;
1511 }
1512 pszName++;
1513 pszPat++;
1514 }
1515 return true;
1516}
1517
1518
1519/**
1520 * Match a name against an array of patterns.
1521 *
1522 * @returns true if it matches, false if it doesn't match.
1523 * @param papszExpressions The array of pattern expressions.
1524 * @param cExpressions The number of array entries.
1525 * @param piExpression Where to read/store the current skip index. Optional.
1526 * @param pszName The name to match.
1527 */
1528static bool stamR3MultiMatch(const char * const *papszExpressions, unsigned cExpressions,
1529 unsigned *piExpression, const char *pszName)
1530{
1531 for (unsigned i = piExpression ? *piExpression : 0; i < cExpressions; i++)
1532 {
1533 const char *pszPat = papszExpressions[i];
1534 if (stamR3Match(pszPat, pszName))
1535 {
1536 /* later:
1537 if (piExpression && i > *piExpression)
1538 {
1539 check if we can skip some expressions
1540 }*/
1541 return true;
1542 }
1543 }
1544 return false;
1545}
1546
1547
1548/**
1549 * Splits a multi pattern into single ones.
1550 *
1551 * @returns Pointer to an array of single patterns. Free it with RTMemTmpFree.
1552 * @param pszPat The pattern to split.
1553 * @param pcExpressions The number of array elements.
1554 * @param pszCopy The pattern copy to free using RTStrFree.
1555 */
1556static char **stamR3SplitPattern(const char *pszPat, unsigned *pcExpressions, char **ppszCopy)
1557{
1558 Assert(pszPat && *pszPat);
1559
1560 char *pszCopy = RTStrDup(pszPat);
1561 if (!pszCopy)
1562 return NULL;
1563
1564 /* count them & allocate array. */
1565 char *psz = pszCopy;
1566 unsigned cExpressions = 1;
1567 while ((psz = strchr(psz, '|')) != NULL)
1568 cExpressions++, psz++;
1569
1570 char **papszExpressions = (char **)RTMemTmpAllocZ((cExpressions + 1) * sizeof(char *));
1571 if (!papszExpressions)
1572 {
1573 RTStrFree(pszCopy);
1574 return NULL;
1575 }
1576
1577 /* split */
1578 psz = pszCopy;
1579 for (unsigned i = 0;;)
1580 {
1581 papszExpressions[i] = psz;
1582 if (++i >= cExpressions)
1583 break;
1584 psz = strchr(psz, '|');
1585 *psz++ = '\0';
1586 }
1587
1588 /* sort the array, putting '*' last. */
1589 /** @todo sort it... */
1590
1591 *pcExpressions = cExpressions;
1592 *ppszCopy = pszCopy;
1593 return papszExpressions;
1594}
1595
1596
1597/**
1598 * Enumerates the nodes selected by a pattern or all nodes if no pattern
1599 * is specified.
1600 *
1601 * The call must own at least a read lock to the STAM data.
1602 *
1603 * @returns The rc from the callback.
1604 * @param pUVM Pointer to the user mode VM structure.
1605 * @param pszPat Pattern.
1606 * @param fUpdateRing0 Update the ring-0 .
1607 * @param pfnCallback Callback function which shall be called for matching nodes.
1608 * If it returns anything but VINF_SUCCESS the enumeration is
1609 * terminated and the status code returned to the caller.
1610 * @param pvArg User parameter for the callback.
1611 */
1612static int stamR3EnumU(PUVM pUVM, const char *pszPat, bool fUpdateRing0, int (*pfnCallback)(PSTAMDESC pDesc, void *pvArg), void *pvArg)
1613{
1614 int rc = VINF_SUCCESS;
1615
1616 /*
1617 * All
1618 */
1619 if (!pszPat || !*pszPat || !strcmp(pszPat, "*"))
1620 {
1621 if (fUpdateRing0)
1622 stamR3Ring0StatsUpdateU(pUVM, "*");
1623
1624 PSTAMDESC pCur = pUVM->stam.s.pHead;
1625 while (pCur)
1626 {
1627 rc = pfnCallback(pCur, pvArg);
1628 if (rc)
1629 break;
1630
1631 /* next */
1632 pCur = pCur->pNext;
1633 }
1634 }
1635
1636 /*
1637 * Single expression pattern.
1638 */
1639 else if (!strchr(pszPat, '|'))
1640 {
1641 if (fUpdateRing0)
1642 stamR3Ring0StatsUpdateU(pUVM, pszPat);
1643
1644 /** @todo This needs to be optimized since the GUI is using this path for the VM info dialog.
1645 * Note that it's doing exact matching. Organizing the samples in a tree would speed up thing
1646 * no end (at least for debug and profile builds). */
1647 for (PSTAMDESC pCur = pUVM->stam.s.pHead; pCur; pCur = pCur->pNext)
1648 if (stamR3Match(pszPat, pCur->pszName))
1649 {
1650 rc = pfnCallback(pCur, pvArg);
1651 if (rc)
1652 break;
1653 }
1654 }
1655
1656 /*
1657 * Multi expression pattern.
1658 */
1659 else
1660 {
1661 /*
1662 * Split up the pattern first.
1663 */
1664 char *pszCopy;
1665 unsigned cExpressions;
1666 char **papszExpressions = stamR3SplitPattern(pszPat, &cExpressions, &pszCopy);
1667 if (!papszExpressions)
1668 return VERR_NO_MEMORY;
1669
1670 /*
1671 * Perform the enumeration.
1672 */
1673 if (fUpdateRing0)
1674 stamR3Ring0StatsUpdateMultiU(pUVM, papszExpressions, cExpressions);
1675
1676 unsigned iExpression = 0;
1677 for (PSTAMDESC pCur = pUVM->stam.s.pHead; pCur; pCur = pCur->pNext)
1678 if (stamR3MultiMatch(papszExpressions, cExpressions, &iExpression, pCur->pszName))
1679 {
1680 rc = pfnCallback(pCur, pvArg);
1681 if (rc)
1682 break;
1683 }
1684
1685 RTMemTmpFree(papszExpressions);
1686 RTStrFree(pszCopy);
1687 }
1688
1689 return rc;
1690}
1691
1692
1693/**
1694 * Registers the ring-0 statistics.
1695 *
1696 * @param pUVM Pointer to the user mode VM structure.
1697 */
1698static void stamR3Ring0StatsRegisterU(PUVM pUVM)
1699{
1700 /* GVMM */
1701 for (unsigned i = 0; i < RT_ELEMENTS(g_aGVMMStats); i++)
1702 stamR3RegisterU(pUVM, (uint8_t *)&pUVM->stam.s.GVMMStats + g_aGVMMStats[i].offVar, NULL, NULL,
1703 g_aGVMMStats[i].enmType, STAMVISIBILITY_ALWAYS, g_aGVMMStats[i].pszName,
1704 g_aGVMMStats[i].enmUnit, g_aGVMMStats[i].pszDesc);
1705}
1706
1707
1708/**
1709 * Updates the ring-0 statistics (the copy).
1710 *
1711 * @param pUVM Pointer to the user mode VM structure.
1712 * @param pszPat The pattern.
1713 */
1714static void stamR3Ring0StatsUpdateU(PUVM pUVM, const char *pszPat)
1715{
1716 stamR3Ring0StatsUpdateMultiU(pUVM, &pszPat, 1);
1717}
1718
1719
1720/**
1721 * Updates the ring-0 statistics.
1722 *
1723 * The ring-0 statistics aren't directly addressable from ring-3 and
1724 * must be copied when needed.
1725 *
1726 * @param pUVM Pointer to the user mode VM structure.
1727 * @param pszPat The pattern (for knowing when to skip).
1728 */
1729static void stamR3Ring0StatsUpdateMultiU(PUVM pUVM, const char * const *papszExpressions, unsigned cExpressions)
1730{
1731 PVM pVM = pUVM->pVM;
1732 if (!pVM || !pVM->pSession)
1733 return;
1734
1735 /* GVMM */
1736 bool fUpdate = false;
1737 for (unsigned i = 0; i < RT_ELEMENTS(g_aGVMMStats); i++)
1738 if (stamR3MultiMatch(papszExpressions, cExpressions, NULL, g_aGVMMStats[i].pszName))
1739 {
1740 fUpdate = true;
1741 break;
1742 }
1743 if (fUpdate)
1744 {
1745 GVMMQUERYSTATISTICSSREQ Req;
1746 Req.Hdr.cbReq = sizeof(Req);
1747 Req.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
1748 Req.pSession = pVM->pSession;
1749 int rc = SUPCallVMMR0Ex(pVM->pVMR0, VMMR0_DO_GVMM_QUERY_STATISTICS, 0, &Req.Hdr);
1750 if (RT_SUCCESS(rc))
1751 pUVM->stam.s.GVMMStats = Req.Stats;
1752 }
1753}
1754
1755
1756/**
1757 * Get the unit string.
1758 *
1759 * @returns Pointer to read only unit string.
1760 * @param enmUnit The unit.
1761 */
1762STAMR3DECL(const char *) STAMR3GetUnit(STAMUNIT enmUnit)
1763{
1764 switch (enmUnit)
1765 {
1766 case STAMUNIT_NONE: return "";
1767 case STAMUNIT_CALLS: return "calls";
1768 case STAMUNIT_COUNT: return "count";
1769 case STAMUNIT_BYTES: return "bytes";
1770 case STAMUNIT_PAGES: return "pages";
1771 case STAMUNIT_ERRORS: return "errors";
1772 case STAMUNIT_OCCURENCES: return "times";
1773 case STAMUNIT_TICKS_PER_CALL: return "ticks/call";
1774 case STAMUNIT_TICKS_PER_OCCURENCE: return "ticks/time";
1775 case STAMUNIT_GOOD_BAD: return "good:bad";
1776 case STAMUNIT_MEGABYTES: return "megabytes";
1777 case STAMUNIT_KILOBYTES: return "kilobytes";
1778 case STAMUNIT_NS: return "ns";
1779 case STAMUNIT_NS_PER_CALL: return "ns/call";
1780 case STAMUNIT_NS_PER_OCCURENCE: return "ns/time";
1781 case STAMUNIT_PCT: return "%";
1782
1783 default:
1784 AssertMsgFailed(("Unknown unit %d\n", enmUnit));
1785 return "(?unit?)";
1786 }
1787}
1788
1789
1790#ifdef VBOX_WITH_DEBUGGER
1791/**
1792 * The '.stats' command.
1793 *
1794 * @returns VBox status.
1795 * @param pCmd Pointer to the command descriptor (as registered).
1796 * @param pCmdHlp Pointer to command helper functions.
1797 * @param pVM Pointer to the current VM (if any).
1798 * @param paArgs Pointer to (readonly) array of arguments.
1799 * @param cArgs Number of arguments in the array.
1800 */
1801static DECLCALLBACK(int) stamR3CmdStats(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
1802{
1803 /*
1804 * Validate input.
1805 */
1806 if (!pVM)
1807 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: The command requires VM to be selected.\n");
1808 PUVM pUVM = pVM->pUVM;
1809 if (!pUVM->stam.s.pHead)
1810 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Sorry, no statistics present.\n");
1811
1812 /*
1813 * Do the printing.
1814 */
1815 STAMR3PRINTONEARGS Args;
1816 Args.pVM = pVM;
1817 Args.pvArg = pCmdHlp;
1818 Args.pfnPrintf = stamR3EnumDbgfPrintf;
1819
1820 STAM_LOCK_RD(pUVM);
1821 int rc = stamR3EnumU(pUVM, cArgs ? paArgs[0].u.pszString : NULL, true /* fUpdateRing0 */, stamR3PrintOne, &Args);
1822 STAM_UNLOCK_RD(pUVM);
1823
1824 return rc;
1825}
1826
1827
1828/**
1829 * Display one sample in the debugger.
1830 *
1831 * @param pArgs Pointer to the print one argument structure.
1832 * @param pszFormat Format string.
1833 * @param ... Format arguments.
1834 */
1835static DECLCALLBACK(void) stamR3EnumDbgfPrintf(PSTAMR3PRINTONEARGS pArgs, const char *pszFormat, ...)
1836{
1837 PDBGCCMDHLP pCmdHlp = (PDBGCCMDHLP)pArgs->pvArg;
1838
1839 va_list va;
1840 va_start(va, pszFormat);
1841 pCmdHlp->pfnPrintfV(pCmdHlp, NULL, pszFormat, va);
1842 va_end(va);
1843 NOREF(pArgs);
1844}
1845
1846
1847/**
1848 * The '.statsreset' command.
1849 *
1850 * @returns VBox status.
1851 * @param pCmd Pointer to the command descriptor (as registered).
1852 * @param pCmdHlp Pointer to command helper functions.
1853 * @param pVM Pointer to the current VM (if any).
1854 * @param paArgs Pointer to (readonly) array of arguments.
1855 * @param cArgs Number of arguments in the array.
1856 */
1857static DECLCALLBACK(int) stamR3CmdStatsReset(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
1858{
1859 /*
1860 * Validate input.
1861 */
1862 if (!pVM)
1863 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: The command requires VM to be selected.\n");
1864 PUVM pUVM = pVM->pUVM;
1865 if (!pUVM->stam.s.pHead)
1866 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Sorry, no statistics present.\n");
1867
1868 /*
1869 * Execute reset.
1870 */
1871 int rc = STAMR3ResetU(pUVM, cArgs ? paArgs[0].u.pszString : NULL);
1872 if (VBOX_SUCCESS(rc))
1873 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "info: Statistics reset.\n");
1874
1875 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Restting statistics.\n");
1876}
1877#endif
1878
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