1 /* Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 * Use of this source code is governed by a BSD-style license that can be
3 * found in the LICENSE file. */
6 /* XRay -- a simple profiler for Native Client */
17 #include "xray/xray_priv.h"
21 /* GTSC - Get Time Stamp Counter */
22 #if defined(__amd64__) && !defined(XRAY_NO_RDTSC)
23 XRAY_INLINE
uint64_t RDTSC64();
26 __asm__
__volatile__("rdtsc" : "=a" (a
), "=d" (d
));
27 return ((uint64_t)a
) | (((uint64_t)d
) << 32);
29 #define GTSC(_x) _x = RDTSC64()
30 #elif defined(__i386__) && !defined(XRAY_NO_RDTSC)
31 #define GTSC(_x) __asm__ __volatile__ ("rdtsc" : "=A" (_x));
33 XRAY_INLINE
uint64_t GTOD();
36 gettimeofday(&tv
, NULL
);
37 return (uint64_t)tv
.tv_sec
* 1000000 + (uint64_t)tv
.tv_usec
;
39 #define GTSC(_x) _x = GTOD();
42 /* Use a TLS variable for cheap thread uid. */
43 __thread
struct XRayTraceCapture
* g_xray_capture
= NULL
;
44 __thread
int g_xray_thread_id_placeholder
= 0;
47 struct XRayTraceStackEntry
{
51 uint32_t annotation_index
;
55 struct XRayTraceFrameEntry
{
56 /* Indices into global tracebuffer */
65 #ifndef XRAY_DISABLE_BROWSER_INTEGRATION
66 struct XRayTimestampPair start_time
;
67 struct XRayTimestampPair end_time
;
72 struct XRayTraceFrame
{
73 struct XRayTraceFrameEntry
* entry
;
80 struct XRayTraceCapture
{
81 /* Common variables share cache line */
84 uint32_t max_stack_depth
;
89 struct XRaySymbolTable
* symbols
;
91 uint32_t annotation_filter
;
93 struct XRayTraceStackEntry stack
[XRAY_TRACE_STACK_SIZE
] XRAY_ALIGN64
;
96 char annotation
[XRAY_ANNOTATION_STACK_SIZE
] XRAY_ALIGN64
;
98 struct XRayTraceBufferEntry
* buffer
;
99 struct XRayTraceFrame frame
;
101 #ifndef XRAY_DISABLE_BROWSER_INTEGRATION
111 #if defined(__pnacl__)
112 XRAY_NO_INSTRUMENT
void __pnacl_profile_func_enter(const char* fname
);
113 XRAY_NO_INSTRUMENT
void __pnacl_profile_func_exit(const char* fname
);
115 XRAY_NO_INSTRUMENT
void __cyg_profile_func_enter(void* this_fn
,
117 XRAY_NO_INSTRUMENT
void __cyg_profile_func_exit(void* this_fn
,
121 XRAY_INLINE
int XRayTraceDecrementIndexInline(
122 struct XRayTraceCapture
* capture
, int index
);
123 XRAY_INLINE
int XRayTraceIncrementIndexInline(
124 struct XRayTraceCapture
* capture
, int index
);
127 XRAY_NO_INSTRUMENT
void __xray_profile_append_annotation(
128 struct XRayTraceCapture
* capture
,
129 struct XRayTraceStackEntry
* se
,
130 struct XRayTraceBufferEntry
* be
);
136 /* Asserts that the guard values haven't changed. */
137 void XRayCheckGuards(struct XRayTraceCapture
* capture
) {
138 assert(capture
->guard0
== XRAY_GUARD_VALUE_0x12345678
);
139 assert(capture
->guard1
== XRAY_GUARD_VALUE_0x12345678
);
140 assert(capture
->guard2
== XRAY_GUARD_VALUE_0x87654321
);
141 assert(capture
->guard3
== XRAY_GUARD_VALUE_0x12345678
);
144 /* Decrements the trace index, wrapping around if needed. */
145 int XRayTraceDecrementIndexInline(
146 struct XRayTraceCapture
* capture
, int index
) {
149 index
= capture
->buffer_size
- 1;
153 /* Increments the trace index, wrapping around if needed. */
154 int XRayTraceIncrementIndexInline(
155 struct XRayTraceCapture
* capture
, int index
) {
157 if (index
>= capture
->buffer_size
)
162 /* Returns true if the trace entry is an annotation string. */
163 bool XRayTraceIsAnnotation(
164 struct XRayTraceCapture
* capture
, int index
) {
165 struct XRayTraceBufferEntry
* be
= &capture
->buffer
[index
];
166 char* dst
= (char*)be
;
170 int XRayTraceIncrementIndex(struct XRayTraceCapture
* capture
, int index
) {
171 return XRayTraceIncrementIndexInline(capture
, index
);
174 int XRayTraceDecrementIndex(struct XRayTraceCapture
* capture
, int index
) {
175 return XRayTraceDecrementIndexInline(capture
, index
);
178 /* The entry in the tracebuffer at index is an annotation string. */
179 /* Calculate the next index value representing the next trace entry. */
180 int XRayTraceSkipAnnotation(struct XRayTraceCapture
* capture
, int index
) {
181 /* Annotations are strings embedded in the trace buffer. */
182 /* An annotation string can span multiple trace entries. */
183 /* Skip over the string by looking for zero termination. */
185 assert(XRayTraceIsAnnotation(capture
, index
));
190 char* str
= (char*) &capture
->buffer
[index
];
191 const int num
= sizeof(capture
->buffer
[index
]);
192 for (i
= start_index
; i
< num
; ++i
) {
198 index
= XRayTraceIncrementIndexInline(capture
, index
);
205 struct XRayTraceBufferEntry
* XRayTraceGetEntry(
206 struct XRayTraceCapture
* capture
, int index
) {
207 return &capture
->buffer
[index
];
210 /* Starting at index, return the index into the trace buffer */
211 /* for the next trace entry. Index can wrap (ringbuffer) */
212 int XRayTraceNextEntry(struct XRayTraceCapture
* capture
, int index
) {
213 if (XRayTraceIsAnnotation(capture
, index
))
214 index
= XRayTraceSkipAnnotation(capture
, index
);
216 index
= XRayTraceIncrementIndexInline(capture
, index
);
220 int XRayFrameGetTraceStartIndex(struct XRayTraceCapture
* capture
, int frame
) {
222 assert(capture
->initialized
);
223 assert(!capture
->recording
);
224 return capture
->frame
.entry
[frame
].start
;
227 int XRayFrameGetTraceEndIndex(struct XRayTraceCapture
* capture
, int frame
) {
229 assert(capture
->initialized
);
230 assert(!capture
->recording
);
231 return capture
->frame
.entry
[frame
].end
;
234 /* Not very accurate, annotation strings will also be counted as "entries" */
235 int XRayFrameGetTraceCount(
236 struct XRayTraceCapture
* capture
, int frame
) {
237 assert(true == capture
->initialized
);
239 assert(frame
< capture
->frame
.count
);
240 assert(!capture
->recording
);
241 int start
= capture
->frame
.entry
[frame
].start
;
242 int end
= capture
->frame
.entry
[frame
].end
;
247 num
= capture
->buffer_size
- (start
- end
);
251 /* Append a string to trace buffer. */
252 void XRayTraceAppendString(struct XRayTraceCapture
* capture
, char* src
) {
253 int index
= capture
->buffer_index
;
258 char* dst
= (char*)&capture
->buffer
[index
];
259 const int num
= sizeof(capture
->buffer
[index
]);
262 for (i
= start_index
; i
< num
; ++i
) {
271 index
= XRayTraceIncrementIndexInline(capture
, index
);
272 dst
= (char*)&capture
->buffer
[index
];
275 capture
->buffer_index
= index
;
278 /* Copies annotation from trace buffer to output string. */
279 int XRayTraceCopyToString(
280 struct XRayTraceCapture
* capture
, int index
, char* dst
) {
281 assert(XRayTraceIsAnnotation(capture
, index
));
287 char* src
= (char*) &capture
->buffer
[index
];
288 const int num
= sizeof(capture
->buffer
[index
]);
289 for (i
= start_index
; i
< num
; ++i
) {
297 index
= XRayTraceIncrementIndexInline(capture
, index
);
304 /* Generic memory malloc for XRay */
305 /* validates pointer returned by malloc */
306 /* memsets memory block to zero */
307 void* XRayMalloc(size_t t
) {
311 printf("XRay: malloc(%d) failed, panic shutdown!\n", t
);
318 /* Generic memory free for XRay */
319 void XRayFree(void* data
) {
320 assert(NULL
!= data
);
325 /* Main profile capture function that is called at the start */
326 /* of every instrumented function. This function is implicitly */
327 /* called when code is compilied with the -finstrument-functions option */
328 #if defined(__pnacl__)
329 void __pnacl_profile_func_enter(const char* this_fn
) {
331 void __cyg_profile_func_enter(void* this_fn
, void* call_site
) {
333 struct XRayTraceCapture
* capture
= g_xray_capture
;
334 if (capture
&& capture
->recording
) {
335 uint32_t depth
= capture
->stack_depth
;
336 if (depth
< capture
->max_stack_depth
) {
337 struct XRayTraceStackEntry
* se
= &capture
->stack
[depth
];
338 uint32_t addr
= (uint32_t)(uintptr_t)this_fn
;
339 se
->depth_addr
= XRAY_PACK_DEPTH_ADDR(depth
, addr
);
340 se
->dest
= capture
->buffer_index
;
341 se
->annotation_index
= 0;
343 capture
->buffer_index
=
344 XRayTraceIncrementIndexInline(capture
, capture
->buffer_index
);
346 ++capture
->stack_depth
;
351 /* Main profile capture function that is called at the exit of */
352 /* every instrumented function. This function is implicity called */
353 /* when the code is compiled with the -finstrument-functions option */
354 #if defined(__pnacl__)
355 void __pnacl_profile_func_exit(const char* this_fn
) {
357 void __cyg_profile_func_exit(void* this_fn
, void* call_site
) {
359 struct XRayTraceCapture
* capture
= g_xray_capture
;
360 if (capture
&& capture
->recording
) {
361 --capture
->stack_depth
;
362 if (capture
->stack_depth
< capture
->max_stack_depth
) {
363 uint32_t depth
= capture
->stack_depth
;
364 struct XRayTraceStackEntry
* se
= &capture
->stack
[depth
];
365 uint32_t buffer_index
= se
->dest
;
367 struct XRayTraceBufferEntry
* be
= &capture
->buffer
[buffer_index
];
369 be
->depth_addr
= se
->depth_addr
;
370 be
->start_tick
= se
->tsc
;
372 be
->annotation_index
= 0;
373 if (0 != se
->annotation_index
)
374 __xray_profile_append_annotation(capture
, se
, be
);
379 #ifndef XRAY_DISABLE_BROWSER_INTEGRATION
380 void XRayGetTSC(uint64_t* tsc
) {
384 int32_t XRayGetSavedThreadID(struct XRayTraceCapture
* capture
) {
385 return capture
->thread_id
;
388 struct XRayTimestampPair
XRayFrameGetStartTimestampPair(
389 struct XRayTraceCapture
* capture
, int frame
) {
390 return capture
->frame
.entry
[frame
].start_time
;
393 struct XRayTimestampPair
XRayFrameGetEndTimestampPair(
394 struct XRayTraceCapture
* capture
, int frame
) {
395 return capture
->frame
.entry
[frame
].end_time
;
399 /* Special case appending annotation string to trace buffer */
400 /* this function should only ever be called from __cyg_profile_func_exit() */
401 void __xray_profile_append_annotation(struct XRayTraceCapture
* capture
,
402 struct XRayTraceStackEntry
* se
,
403 struct XRayTraceBufferEntry
* be
) {
404 struct XRayTraceStackEntry
* parent
= se
- 1;
405 int start
= parent
->annotation_index
;
406 be
->annotation_index
= capture
->buffer_index
;
407 char* str
= &capture
->annotation
[start
];
408 XRayTraceAppendString(capture
, str
);
410 ++capture
->annotation_count
;
415 /* Annotates the trace buffer. no filtering. */
416 void __XRayAnnotate(const char* fmt
, ...) {
418 struct XRayTraceCapture
* capture
= g_xray_capture
;
419 /* Only annotate functions recorded in the trace buffer. */
420 if (capture
&& capture
->initialized
) {
421 if (0 == capture
->disabled
) {
422 if (capture
->recording
) {
426 r
= vsnprintf(buffer
, sizeof(buffer
), fmt
, args
);
429 /* Get current string ptr */
430 int depth
= capture
->stack_depth
- 1;
431 struct XRayTraceStackEntry
* se
= &capture
->stack
[depth
];
432 if (0 == se
->annotation_index
) {
433 struct XRayTraceStackEntry
* parent
= se
- 1;
434 se
->annotation_index
= parent
->annotation_index
;
436 char* dst
= &capture
->annotation
[se
->annotation_index
];
438 int len
= strlen(dst
);
439 se
->annotation_index
+= len
;
447 /* Annotates the trace buffer with user strings. Can be filtered. */
448 void __XRayAnnotateFiltered(const uint32_t filter
, const char* fmt
, ...) {
450 struct XRayTraceCapture
* capture
= g_xray_capture
;
451 if (capture
&& capture
->initialized
) {
452 if (0 != (filter
& capture
->annotation_filter
)) {
453 if (0 == capture
->disabled
) {
454 if (capture
->recording
) {
455 char buffer
[XRAY_TRACE_ANNOTATION_LENGTH
];
458 r
= vsnprintf(buffer
, sizeof(buffer
), fmt
, args
);
461 /* get current string ptr */
462 int depth
= capture
->stack_depth
- 1;
463 struct XRayTraceStackEntry
* se
= &capture
->stack
[depth
];
464 if (0 == se
->annotation_index
) {
465 struct XRayTraceStackEntry
* parent
= se
- 1;
466 se
->annotation_index
= parent
->annotation_index
;
468 char* dst
= &capture
->annotation
[se
->annotation_index
];
470 int len
= strlen(dst
);
471 se
->annotation_index
+= len
;
480 /* Allows user to specify annotation filter value, a 32 bit mask. */
481 void XRaySetAnnotationFilter(struct XRayTraceCapture
* capture
,
483 capture
->annotation_filter
= filter
;
487 /* Reset xray profiler. */
488 void XRayReset(struct XRayTraceCapture
* capture
) {
490 assert(capture
->initialized
);
491 assert(!capture
->recording
);
492 capture
->buffer_index
= 0;
493 capture
->stack_depth
= 0;
494 capture
->disabled
= 0;
495 capture
->frame
.head
= 0;
496 capture
->frame
.tail
= 0;
497 memset(capture
->frame
.entry
, 0,
498 sizeof(capture
->frame
.entry
[0]) * capture
->frame
.count
);
499 memset(&capture
->stack
, 0,
500 sizeof(capture
->stack
[0]) * XRAY_TRACE_STACK_SIZE
);
501 XRayCheckGuards(capture
);
505 /* Change the maximum stack depth captures are made. */
506 void XRaySetMaxStackDepth(struct XRayTraceCapture
* capture
, int stack_depth
) {
508 assert(capture
->initialized
);
509 assert(!capture
->recording
);
512 if (stack_depth
>= XRAY_TRACE_STACK_SIZE
)
513 stack_depth
= (XRAY_TRACE_STACK_SIZE
- 1);
514 capture
->max_stack_depth
= stack_depth
;
518 int XRayFrameGetCount(struct XRayTraceCapture
* capture
) {
519 return capture
->frame
.count
;
522 int XRayFrameGetTail(struct XRayTraceCapture
* capture
) {
523 return capture
->frame
.tail
;
526 int XRayFrameGetHead(struct XRayTraceCapture
* capture
) {
527 return capture
->frame
.head
;
530 int XRayFrameGetPrev(struct XRayTraceCapture
* capture
, int i
) {
533 i
= capture
->frame
.count
- 1;
537 int XRayFrameGetNext(struct XRayTraceCapture
* capture
, int i
) {
539 if (i
>= capture
->frame
.count
)
544 bool XRayFrameIsValid(struct XRayTraceCapture
* capture
, int i
) {
545 return capture
->frame
.entry
[i
].valid
;
548 uint64_t XRayFrameGetTotalTicks(struct XRayTraceCapture
* capture
, int i
) {
549 return capture
->frame
.entry
[i
].total_ticks
;
552 int XRayFrameGetAnnotationCount(struct XRayTraceCapture
* capture
, int i
) {
553 return capture
->frame
.entry
[i
].annotation_count
;
556 void XRayFrameMakeLabel(struct XRayTraceCapture
* capture
,
559 snprintf(label
, XRAY_MAX_LABEL
, "@@@frame%d@@@", counter
);
563 /* Scans the ring buffer going backwards to find last valid complete frame. */
564 /* Will mark whether frames are valid or invalid during the traversal. */
565 int XRayFrameFindTail(struct XRayTraceCapture
* capture
) {
566 int head
= capture
->frame
.head
;
567 int index
= XRayFrameGetPrev(capture
, head
);
568 int total_capture
= 0;
569 int last_valid_frame
= index
;
570 /* Check for no captures */
571 if (capture
->frame
.head
== capture
->frame
.tail
)
572 return capture
->frame
.head
;
573 /* Go back and invalidate all captures that have been stomped. */
574 while (index
!= head
) {
575 bool valid
= capture
->frame
.entry
[index
].valid
;
577 total_capture
+= XRayFrameGetTraceCount(capture
, index
) + 1;
578 if (total_capture
< capture
->buffer_size
) {
579 last_valid_frame
= index
;
580 capture
->frame
.entry
[index
].valid
= true;
582 capture
->frame
.entry
[index
].valid
= false;
585 index
= XRayFrameGetPrev(capture
, index
);
587 return last_valid_frame
;
591 /* Starts a new frame and enables capturing, and must be paired with */
592 /* XRayEndFrame() Trace capturing only occurs on the thread which called */
593 /* XRayBeginFrame() and each instance of capture can only trace one thread */
595 void XRayStartFrame(struct XRayTraceCapture
* capture
) {
597 assert(NULL
== g_xray_capture
);
598 assert(capture
->initialized
);
599 assert(!capture
->recording
);
600 i
= capture
->frame
.head
;
601 XRayCheckGuards(capture
);
602 /* Add a trace entry marker so we can detect wrap around stomping */
603 struct XRayTraceBufferEntry
* be
= &capture
->buffer
[capture
->buffer_index
];
604 be
->depth_addr
= XRAY_FRAME_MARKER
;
605 capture
->buffer_index
=
606 XRayTraceIncrementIndex(capture
, capture
->buffer_index
);
607 /* Set start of the frame we're about to trace */
608 capture
->frame
.entry
[i
].start
= capture
->buffer_index
;
609 capture
->disabled
= 0;
610 capture
->stack_depth
= 1;
612 /* The trace stack[0] is reserved */
613 memset(&capture
->stack
[0], 0, sizeof(capture
->stack
[0]));
614 /* Annotation index 0 is reserved to indicate no annotation */
615 capture
->stack
[0].annotation_index
= 1;
616 capture
->annotation
[0] = 0;
617 capture
->annotation
[1] = 0;
618 capture
->annotation_count
= 0;
619 capture
->recording
= true;
620 GTSC(capture
->frame
.entry
[i
].start_tsc
);
621 g_xray_capture
= capture
;
623 #ifndef XRAY_DISABLE_BROWSER_INTEGRATION
624 capture
->frame
.entry
[i
].start_time
= XRayGenerateTimestampsNow();
629 /* Ends a frame and disables capturing. Advances to the next frame. */
630 /* Must be paired with XRayStartFrame(), and called from the same thread. */
631 void XRayEndFrame(struct XRayTraceCapture
* capture
) {
634 assert(capture
->initialized
);
635 assert(capture
->recording
);
636 assert(g_xray_capture
== capture
);
637 assert(0 == capture
->disabled
);
638 assert(1 == capture
->stack_depth
);
639 i
= capture
->frame
.head
;
640 GTSC(capture
->frame
.entry
[i
].end_tsc
);
641 capture
->frame
.entry
[i
].total_ticks
=
642 capture
->frame
.entry
[i
].end_tsc
- capture
->frame
.entry
[i
].start_tsc
;
643 capture
->recording
= NULL
;
644 capture
->frame
.entry
[i
].end
= capture
->buffer_index
;
645 capture
->frame
.entry
[i
].valid
= true;
646 capture
->frame
.entry
[i
].annotation_count
= capture
->annotation_count
;
647 capture
->frame
.head
= XRayFrameGetNext(capture
, capture
->frame
.head
);
648 /* If the table is filled, bump the tail. */
649 if (capture
->frame
.head
== capture
->frame
.tail
)
650 capture
->frame
.tail
= XRayFrameGetNext(capture
, capture
->frame
.tail
);
651 capture
->frame
.tail
= XRayFrameFindTail(capture
);
652 /* Check that we didn't stomp over trace entry marker. */
653 int marker
= XRayTraceDecrementIndex(capture
, capture
->frame
.entry
[i
].start
);
654 struct XRayTraceBufferEntry
* be
= &capture
->buffer
[marker
];
655 if (be
->depth_addr
!= XRAY_FRAME_MARKER
) {
657 "XRay: XRayStopFrame() detects insufficient trace buffer size!\n");
660 /* Replace marker with an empty annotation string. */
661 be
->depth_addr
= XRAY_NULL_ANNOTATION
;
662 XRayCheckGuards(capture
);
664 g_xray_capture
= NULL
;
666 #ifndef XRAY_DISABLE_BROWSER_INTEGRATION
667 capture
->frame
.entry
[i
].end_time
= XRayGenerateTimestampsNow();
672 /* Get the last frame captured. Do not call while capturing. */
673 /* (ie call outside of XRayStartFrame() / XRayStopFrame() pair) */
674 int XRayGetLastFrame(struct XRayTraceCapture
* capture
) {
676 assert(capture
->initialized
);
677 assert(!capture
->recording
);
678 assert(0 == capture
->disabled
);
679 assert(1 == capture
->stack_depth
);
680 int last_frame
= XRayFrameGetPrev(capture
, capture
->frame
.head
);
685 /* Disables capturing until a paired XRayEnableCapture() is called */
686 /* This call can be nested, but must be paired with an enable */
687 /* (If you need to just exclude a specific function and not its */
688 /* children, the XRAY_NO_INSTRUMENT modifier might be better) */
689 /* Must be called from same thread as XRayBeginFrame() / XRayEndFrame() */
690 void XRayDisableCapture(struct XRayTraceCapture
* capture
) {
692 assert(capture
== g_xray_capture
);
693 assert(capture
->initialized
);
695 capture
->recording
= false;
699 /* Re-enables capture. Must be paired with XRayDisableCapture() */
700 void XRayEnableCapture(struct XRayTraceCapture
* capture
) {
702 assert(capture
== g_xray_capture
);
703 assert(capture
->initialized
);
704 assert(0 < capture
->disabled
);
706 if (0 == capture
->disabled
) {
707 capture
->recording
= true;
713 struct XRaySymbolTable
* XRayGetSymbolTable(struct XRayTraceCapture
* capture
) {
714 return capture
->symbols
;
718 /* Initialize XRay */
719 struct XRayTraceCapture
* XRayInit(int stack_depth
,
722 const char* mapfilename
) {
723 struct XRayTraceCapture
* capture
;
724 capture
= (struct XRayTraceCapture
*)XRayMalloc(
725 sizeof(struct XRayTraceCapture
));
726 int adj_frame_count
= frame_count
+ 1;
727 size_t buffer_size_in_bytes
=
728 sizeof(capture
->buffer
[0]) * buffer_size
;
729 size_t frame_size_in_bytes
=
730 sizeof(capture
->frame
.entry
[0]) * adj_frame_count
;
732 (struct XRayTraceBufferEntry
*)XRayMalloc(buffer_size_in_bytes
);
733 capture
->frame
.entry
=
734 (struct XRayTraceFrameEntry
*)XRayMalloc(frame_size_in_bytes
);
735 capture
->buffer_size
= buffer_size
;
736 capture
->frame
.count
= adj_frame_count
;
737 capture
->frame
.head
= 0;
738 capture
->frame
.tail
= 0;
739 capture
->disabled
= 0;
740 capture
->annotation_filter
= 0xFFFFFFFF;
741 capture
->guard0
= XRAY_GUARD_VALUE_0x12345678
;
742 capture
->guard1
= XRAY_GUARD_VALUE_0x12345678
;
743 capture
->guard2
= XRAY_GUARD_VALUE_0x87654321
;
744 capture
->guard3
= XRAY_GUARD_VALUE_0x12345678
;
745 capture
->initialized
= true;
746 capture
->recording
= false;
747 XRaySetMaxStackDepth(capture
, stack_depth
);
750 /* Mapfile is optional; we don't need it for captures, only for reports. */
752 XRaySymbolTableCreate(XRAY_DEFAULT_SYMBOL_TABLE_SIZE
);
753 if (NULL
!= mapfilename
)
754 XRaySymbolTableParseMapfile(capture
->symbols
, mapfilename
);
756 #ifndef XRAY_DISABLE_BROWSER_INTEGRATION
757 /* Use the address of a thread local variable as a fake thread id. */
758 capture
->thread_id
= (int32_t)(&g_xray_thread_id_placeholder
);
765 /* Shut down and free memory used by XRay. */
766 void XRayShutdown(struct XRayTraceCapture
* capture
) {
768 assert(capture
->initialized
);
769 assert(!capture
->recording
);
770 XRayCheckGuards(capture
);
771 if (NULL
!= capture
->symbols
) {
772 XRaySymbolTableFree(capture
->symbols
);
774 XRayFree(capture
->frame
.entry
);
775 XRayFree(capture
->buffer
);
776 capture
->initialized
= false;