VirtualBox

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

Last change on this file since 7554 was 6796, checked in by vboxsync, 17 years ago

Fixed init problems wrt. VM ownership by implementing the UVM structure (U = user mode) and moving problematic ring-3 stuff over there (emt+reqs, r3heap, stam, loader[VMMR0.r0]). Big change, but it works fine here... :-)

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