VirtualBox

source: vbox/trunk/src/VBox/Runtime/testcase/tstRTTraceLog.cpp@ 71983

Last change on this file since 71983 was 71492, checked in by vboxsync, 7 years ago

Runtime: Introduce RTTraceLog* API for creating and parsing binary trace log files. The format and API is designed with the

following goals in mind:

  1. Allow streaming the data via network or write it to a file.
  2. Embed the structure of the traced data into the log allowing arbitrary structured data to be embedded without requiring adaptions on the parsing side.
  3. Allow grouping of traced data belonging together to easily follow chains of events later on.
  4. Trace events can have a parent assigned to check where an event originally originated from.
  5. Low overhead on the creation side.

The current state implements the absolute basics on the creation and parsing side and is work in progress. This will
be used later on in the device emulation fuzzer to capture device and examine device states and changes.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.9 KB
Line 
1/* $Id: tstRTTraceLog.cpp 71492 2018-03-24 22:23:10Z vboxsync $ */
2/** @file
3 * IPRT Testcase - RTTraceLog.
4 */
5
6/*
7 * Copyright (C) 2018 Oracle Corporation
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 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include <iprt/tracelog.h>
32
33#include <iprt/err.h>
34#include <iprt/file.h>
35#include <iprt/mem.h>
36#include <iprt/string.h>
37#include <iprt/test.h>
38#include <iprt/time.h>
39
40
41/**
42 * Trace log buffer.
43 */
44typedef struct TSTRTTRACELOGBUF
45{
46 /** Size of the buffer. */
47 size_t cbBuf;
48 /** Current write offset. */
49 size_t offBuf;
50 /** Streamed data - variable in size. */
51 uint8_t abBuf[1];
52} TSTRTTRACELOGBUF;
53/** Pointer to a trace log buffer. */
54typedef TSTRTTRACELOGBUF *PTSTRTTRACELOGBUF;
55
56
57/**
58 * Structure matching the event descriptor.
59 */
60typedef struct RTTESTTRACELOGEVTDATA
61{
62 /** Test pointer. */
63 uintptr_t ptr;
64 /** Test size_t value. */
65 size_t sz;
66 /** Test 32bit value. */
67 uint32_t u32;
68 /** Test boolean. */
69 bool f;
70 /** Test raw data. */
71 uint8_t abRaw[42];
72} RTTESTTRACELOGEVTDATA;
73/** Pointer to event data. */
74typedef RTTESTTRACELOGEVTDATA *PRTTESTTRACELOGEVTDATA;
75
76
77/**
78 * Test event item descriptor.
79 */
80static RTTRACELOGEVTITEMDESC g_EvtItemDesc[] =
81{
82 {"TestPtr", NULL, RTTRACELOGTYPE_POINTER, 0},
83 {"TestSz", NULL, RTTRACELOGTYPE_SIZE, 0},
84 {"TestU32", NULL, RTTRACELOGTYPE_UINT32, 0},
85 {"TestBool", "This is a test description", RTTRACELOGTYPE_BOOL, 0},
86 {"TestRawStatic", NULL, RTTRACELOGTYPE_RAWDATA, 42}
87};
88
89
90/**
91 * Test event descriptor.
92 */
93static RTTRACELOGEVTDESC g_EvtDesc =
94{
95 "idTest",
96 "This is a test event",
97 RTTRACELOGEVTSEVERITY_INFO,
98 RT_ELEMENTS(g_EvtItemDesc),
99 g_EvtItemDesc
100};
101
102
103
104/**
105 * Allocates a new buffer for the raw trace log stream.
106 *
107 * @returns IPRT status code.
108 * @param cbBuf Size of the buffer in bytes.
109 * @param ppBuf Where to store the pointer to the buffer on success.
110 */
111static int tstRTTraceLogBufAlloc(size_t cbBuf, PTSTRTTRACELOGBUF *ppBuf)
112{
113 PTSTRTTRACELOGBUF pBuf = (PTSTRTTRACELOGBUF)RTMemAllocZ(RT_OFFSETOF(TSTRTTRACELOGBUF, abBuf[cbBuf]));
114 if (RT_LIKELY(pBuf))
115 {
116 pBuf->cbBuf = cbBuf;
117 pBuf->offBuf = 0;
118 *ppBuf = pBuf;
119 return VINF_SUCCESS;
120 }
121
122 return VERR_NO_MEMORY;
123}
124
125
126/**
127 * @copydoc{FNRTTRACELOGWRSTREAM}
128 */
129static DECLCALLBACK(int) tstRTTraceLogStreamOut(void *pvUser, const void *pvBuf, size_t cbBuf, size_t *pcbWritten)
130{
131 PTSTRTTRACELOGBUF pBuf = (PTSTRTTRACELOGBUF)pvUser;
132
133 if (pBuf)
134 {
135 size_t cbWrite = RT_MIN(cbBuf, pBuf->cbBuf - pBuf->offBuf);
136 if ( cbWrite != 0
137 && ( cbWrite >= cbBuf
138 || pcbWritten))
139 {
140 memcpy(&pBuf->abBuf[pBuf->offBuf], pvBuf, cbWrite);
141 pBuf->offBuf += cbWrite;
142 if (pcbWritten)
143 *pcbWritten = cbWrite;
144 return VINF_SUCCESS;
145 }
146
147 return VERR_DISK_FULL;
148 }
149
150 /* Benchmark mode, forget everything immediately. */
151 return VINF_SUCCESS;
152}
153
154
155/**
156 * @copydoc{FNRTTRACELOGRDRSTREAM}
157 */
158static DECLCALLBACK(int) tstRTTraceLogStreamIn(void *pvUser, void *pvBuf, size_t cbBuf, size_t *pcbRead,
159 RTMSINTERVAL cMsTimeout)
160{
161 RT_NOREF(cMsTimeout);
162 PTSTRTTRACELOGBUF pBuf = (PTSTRTTRACELOGBUF)pvUser;
163
164 size_t cbRead = RT_MIN(cbBuf, pBuf->cbBuf - pBuf->offBuf);
165 if ( cbRead != 0
166 && ( cbRead >= cbBuf
167 || pcbRead))
168 {
169 memcpy(pvBuf, &pBuf->abBuf[pBuf->offBuf], cbRead);
170 pBuf->offBuf += cbRead;
171 if (pcbRead)
172 *pcbRead = cbRead;
173 return VINF_SUCCESS;
174 }
175
176 return VERR_EOF;
177}
178
179
180/**
181 * @copydoc{FNRTTRACELOGSTREAMCLOSE}
182 */
183static DECLCALLBACK(int) tstRTTraceLogStreamClose(void *pvUser)
184{
185 RT_NOREF(pvUser);
186 return VINF_SUCCESS;
187}
188
189
190static PTSTRTTRACELOGBUF tstRTTraceLogWriter(void)
191{
192 RTTRACELOGWR hTraceLogWr = NIL_RTTRACELOGWR;
193 PTSTRTTRACELOGBUF pLogBuf = NULL;
194 RTTESTTRACELOGEVTDATA EvtData;
195
196 EvtData.ptr = (uintptr_t)&EvtData;
197 EvtData.sz = 0xdeadcafe;
198 EvtData.u32 = 0;
199 EvtData.f = true;
200 memset(&EvtData.abRaw[0], 0x42, sizeof(EvtData.abRaw));
201
202 /*
203 * Bad set pointer and handle values.
204 */
205 RTTestSub(NIL_RTTEST, "Writer");
206 RTTESTI_CHECK_RC(RTTraceLogWrCreate(NULL, NULL, NULL, NULL, NULL), VERR_INVALID_POINTER);
207 RTTESTI_CHECK_RC(RTTraceLogWrCreate(&hTraceLogWr, NULL, NULL, NULL, NULL), VERR_INVALID_POINTER);
208 RTTRACELOGWR hTraceLogWrInvl = (RTTRACELOGWR)(intptr_t)-3;
209 RTTESTI_CHECK_RC(RTTraceLogWrDestroy(hTraceLogWrInvl), VERR_INVALID_HANDLE);
210 RTTESTI_CHECK_RC(RTTraceLogWrAddEvtDesc(hTraceLogWr, NULL), VERR_INVALID_HANDLE);
211 RTTESTI_CHECK_RC(RTTraceLogWrEvtAdd(hTraceLogWr, NULL, 0, 0, 0, NULL, NULL), VERR_INVALID_HANDLE);
212
213 RTTESTI_CHECK_RC_RET(tstRTTraceLogBufAlloc(_4K, &pLogBuf), VINF_SUCCESS, NULL);
214 RTTESTI_CHECK_RC_RET(RTTraceLogWrCreate(&hTraceLogWr, NULL, tstRTTraceLogStreamOut,
215 tstRTTraceLogStreamClose, pLogBuf), VINF_SUCCESS, NULL);
216 RTTESTI_CHECK_RC_RET(RTTraceLogWrAddEvtDesc(hTraceLogWr, &g_EvtDesc), VINF_SUCCESS, NULL);
217 RTTESTI_CHECK_RC_RET(RTTraceLogWrAddEvtDesc(hTraceLogWr, &g_EvtDesc), VERR_ALREADY_EXISTS, NULL);
218 RTTESTI_CHECK_RC_RET(RTTraceLogWrEvtAdd(hTraceLogWr, &g_EvtDesc, 0, 0, 0, &EvtData, NULL), VINF_SUCCESS, NULL);
219 RTTESTI_CHECK_RC_RET(RTTraceLogWrDestroy(hTraceLogWr), VINF_SUCCESS, NULL);
220
221 return pLogBuf;
222}
223
224
225static void tstRTTraceLogWriterBenchmark(void)
226{
227 RTTRACELOGWR hTraceLogWr = NIL_RTTRACELOGWR;
228 RTTESTTRACELOGEVTDATA EvtData;
229
230 EvtData.ptr = (uintptr_t)&EvtData;
231 EvtData.sz = 0xdeadcafe;
232 EvtData.u32 = 0;
233 EvtData.f = true;
234 memset(&EvtData.abRaw[0], 0x42, sizeof(EvtData.abRaw));
235
236 RTTestSub(NIL_RTTEST, "Writer Benchmark");
237 RTTESTI_CHECK_RC_RETV(RTTraceLogWrCreate(&hTraceLogWr, NULL, tstRTTraceLogStreamOut,
238 tstRTTraceLogStreamClose, NULL), VINF_SUCCESS);
239 RTTESTI_CHECK_RC_RETV(RTTraceLogWrAddEvtDesc(hTraceLogWr, &g_EvtDesc), VINF_SUCCESS);
240
241 uint64_t tsStart = RTTimeNanoTS();
242 for (uint32_t i = 0; i < 1000000; i++)
243 {
244 RTTESTI_CHECK_RC_BREAK(RTTraceLogWrEvtAdd(hTraceLogWr, &g_EvtDesc, 0, 0, 0, &EvtData, NULL), VINF_SUCCESS);
245 }
246 uint64_t tsRuntime = RTTimeNanoTS() - tsStart;
247 RTTestValue(NIL_RTTEST, "RTTraceLogWrEvtAdd()", tsRuntime / 1000000, RTTESTUNIT_NS_PER_CALL);
248 RTTESTI_CHECK_RC(RTTraceLogWrDestroy(hTraceLogWr), VINF_SUCCESS);
249}
250
251static void tstRTTraceLogReader(PTSTRTTRACELOGBUF pLogBuf)
252{
253 RTTRACELOGRDRPOLLEVT enmEvt = RTTRACELOGRDRPOLLEVT_INVALID;
254 RTTRACELOGRDR hTraceLogRdr = NIL_RTTRACELOGRDR;
255
256 RTTestSub(NIL_RTTEST, "Reader");
257
258 /*
259 * Bad set pointer and handle values.
260 */
261 RTTESTI_CHECK_RC(RTTraceLogRdrCreate(NULL, NULL, NULL, NULL), VERR_INVALID_POINTER);
262 RTTESTI_CHECK_RC(RTTraceLogRdrCreate(&hTraceLogRdr, NULL, NULL, NULL), VERR_INVALID_POINTER);
263 RTTRACELOGRDR hTraceLogRdrInvl = (RTTRACELOGRDR)(intptr_t)-3;
264 RTTESTI_CHECK_RC(RTTraceLogRdrDestroy(hTraceLogRdrInvl), VERR_INVALID_HANDLE);
265 RTTESTI_CHECK_RC(RTTraceLogRdrEvtPoll(hTraceLogRdrInvl, NULL, RT_INDEFINITE_WAIT), VERR_INVALID_HANDLE);
266
267 /*
268 * Test with log buffer created previously.
269 */
270 RTTESTI_CHECK_RC_RETV(RTTraceLogRdrCreate(&hTraceLogRdr, tstRTTraceLogStreamIn, tstRTTraceLogStreamClose, pLogBuf),
271 VINF_SUCCESS);
272 RTTESTI_CHECK_RC_RETV(RTTraceLogRdrEvtPoll(hTraceLogRdr, &enmEvt, RT_INDEFINITE_WAIT), VINF_SUCCESS);
273 RTTESTI_CHECK_RETV(enmEvt == RTTRACELOGRDRPOLLEVT_HDR_RECVD);
274 RTTESTI_CHECK_RC_RETV(RTTraceLogRdrEvtPoll(hTraceLogRdr, &enmEvt, RT_INDEFINITE_WAIT), VINF_SUCCESS);
275 RTTESTI_CHECK_RETV(enmEvt == RTTRACELOGRDRPOLLEVT_TRACE_EVENT_RECVD);
276 RTTESTI_CHECK_RC_RETV(RTTraceLogRdrDestroy(hTraceLogRdr), VINF_SUCCESS);
277}
278
279
280int main()
281{
282 RTTEST hTest;
283 int rc = RTTestInitAndCreate("tstRTTraceLog", &hTest);
284 if (rc)
285 return rc;
286 RTTestBanner(hTest);
287
288 /*
289 * The tests.
290 */
291 bool fMayPanic = RTAssertMayPanic();
292 bool fQuiet = RTAssertAreQuiet();
293 RTAssertSetMayPanic(false);
294 RTAssertSetQuiet(true);
295 PTSTRTTRACELOGBUF pLogBuf = tstRTTraceLogWriter();
296 if (RTTestErrorCount(hTest) == 0)
297 {
298 pLogBuf->offBuf = 0;
299 tstRTTraceLogReader(pLogBuf);
300 }
301 RTMemFree(pLogBuf);
302 tstRTTraceLogWriterBenchmark();
303 RTAssertSetQuiet(fQuiet);
304 RTAssertSetMayPanic(fMayPanic);
305
306 /*
307 * Summary.
308 */
309 return RTTestSummaryAndDestroy(hTest);
310}
311
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