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. */ 4 5 6 /* XRay -- a simple profiler for Native Client */ 7 8 #include <assert.h> 9 #include <errno.h> 10 #include <stdarg.h> 11 #include <stdint.h> 12 #include <stdio.h> 13 #include <stdlib.h> 14 #include <string.h> 15 #include <sys/time.h> 16 #include <unistd.h> 17 #include "xray/xray_priv.h" 18 19 #if defined(XRAY) 20 21 #define FORCE_INLINE __attribute__((always_inline)) 22 23 /* GTSC - Get Time Stamp Counter */ 24 #if defined(__amd64__) && !defined(XRAY_NO_RDTSC) 25 FORCE_INLINE uint64_t RDTSC64() { 26 uint64_t a, d; 27 __asm__ __volatile__("rdtsc" : "=a" (a), "=d" (d)); 28 return ((uint64_t)a) | (((uint64_t)d) << 32); 29 } 30 #define GTSC(_x) _x = RDTSC64() 31 #elif defined(__i386__) && !defined(XRAY_NO_RDTSC) 32 #define GTSC(_x) __asm__ __volatile__ ("rdtsc" : "=A" (_x)); 33 #else 34 FORCE_INLINE uint64_t GTOD() { 35 struct timeval tv; 36 gettimeofday(&tv, NULL); 37 return (uint64_t)tv.tv_sec * 1000000 + (uint64_t)tv.tv_usec; 38 } 39 #define GTSC(_x) _x = GTOD(); 40 #endif 41 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; 45 46 47 struct XRayTraceStackEntry { 48 uint32_t depth_addr; 49 uint64_t tsc; 50 uint32_t dest; 51 uint32_t annotation_index; 52 }; 53 54 55 struct XRayTraceFrameEntry { 56 /* Indices into global tracebuffer */ 57 int start; 58 int end; 59 uint64_t start_tsc; 60 uint64_t end_tsc; 61 uint64_t total_ticks; 62 int annotation_count; 63 bool valid; 64 65 #ifndef XRAY_DISABLE_BROWSER_INTEGRATION 66 struct XRayTimestampPair start_time; 67 struct XRayTimestampPair end_time; 68 #endif 69 }; 70 71 72 struct XRayTraceFrame { 73 struct XRayTraceFrameEntry* entry; 74 int head; 75 int tail; 76 int count; 77 }; 78 79 80 struct XRayTraceCapture { 81 /* Common variables share cache line */ 82 bool recording; 83 uint32_t stack_depth; 84 uint32_t max_stack_depth; 85 int buffer_index; 86 int buffer_size; 87 int disabled; 88 int annotation_count; 89 struct XRaySymbolTable* symbols; 90 bool initialized; 91 uint32_t annotation_filter; 92 uint32_t guard0; 93 struct XRayTraceStackEntry stack[XRAY_TRACE_STACK_SIZE] XRAY_ALIGN64; 94 uint32_t guard1; 95 uint32_t guard2; 96 char annotation[XRAY_ANNOTATION_STACK_SIZE] XRAY_ALIGN64; 97 uint32_t guard3; 98 struct XRayTraceBufferEntry* buffer; 99 struct XRayTraceFrame frame; 100 101 #ifndef XRAY_DISABLE_BROWSER_INTEGRATION 102 int32_t thread_id; 103 #endif 104 } XRAY_ALIGN64; 105 106 107 #ifdef __cplusplus 108 extern "C" { 109 #endif 110 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); 114 #else 115 XRAY_NO_INSTRUMENT void __cyg_profile_func_enter(void* this_fn, 116 void* call_site); 117 XRAY_NO_INSTRUMENT void __cyg_profile_func_exit(void* this_fn, 118 void* call_site); 119 #endif 120 121 XRAY_NO_INSTRUMENT void __xray_profile_append_annotation( 122 struct XRayTraceCapture* capture, 123 struct XRayTraceStackEntry* se, 124 struct XRayTraceBufferEntry* be); 125 126 #ifdef __cplusplus 127 } 128 #endif 129 130 /* Asserts that the guard values haven't changed. */ 131 void XRayCheckGuards(struct XRayTraceCapture* capture) { 132 assert(capture->guard0 == XRAY_GUARD_VALUE_0x12345678); 133 assert(capture->guard1 == XRAY_GUARD_VALUE_0x12345678); 134 assert(capture->guard2 == XRAY_GUARD_VALUE_0x87654321); 135 assert(capture->guard3 == XRAY_GUARD_VALUE_0x12345678); 136 } 137 138 /* Decrements the trace index, wrapping around if needed. */ 139 XRAY_FORCE_INLINE int XRayTraceDecrementIndexInline( 140 struct XRayTraceCapture* capture, int index) { 141 --index; 142 if (index < 0) 143 index = capture->buffer_size - 1; 144 return index; 145 } 146 147 /* Increments the trace index, wrapping around if needed. */ 148 XRAY_FORCE_INLINE int XRayTraceIncrementIndexInline( 149 struct XRayTraceCapture* capture, int index) { 150 ++index; 151 if (index >= capture->buffer_size) 152 index = 0; 153 return index; 154 } 155 156 /* Returns true if the trace entry is an annotation string. */ 157 bool XRayTraceIsAnnotation( 158 struct XRayTraceCapture* capture, int index) { 159 struct XRayTraceBufferEntry* be = &capture->buffer[index]; 160 char* dst = (char*)be; 161 return 0 == *dst; 162 } 163 164 int XRayTraceIncrementIndex(struct XRayTraceCapture* capture, int index) { 165 return XRayTraceIncrementIndexInline(capture, index); 166 } 167 168 int XRayTraceDecrementIndex(struct XRayTraceCapture* capture, int index) { 169 return XRayTraceDecrementIndexInline(capture, index); 170 } 171 172 /* The entry in the tracebuffer at index is an annotation string. */ 173 /* Calculate the next index value representing the next trace entry. */ 174 int XRayTraceSkipAnnotation(struct XRayTraceCapture* capture, int index) { 175 /* Annotations are strings embedded in the trace buffer. */ 176 /* An annotation string can span multiple trace entries. */ 177 /* Skip over the string by looking for zero termination. */ 178 assert(capture); 179 assert(XRayTraceIsAnnotation(capture, index)); 180 bool done = false; 181 int start_index = 1; 182 int i; 183 while (!done) { 184 char* str = (char*) &capture->buffer[index]; 185 const int num = sizeof(capture->buffer[index]); 186 for (i = start_index; i < num; ++i) { 187 if (0 == str[i]) { 188 done = true; 189 break; 190 } 191 } 192 index = XRayTraceIncrementIndexInline(capture, index); 193 start_index = 0; 194 } 195 return index; 196 } 197 198 199 struct XRayTraceBufferEntry* XRayTraceGetEntry( 200 struct XRayTraceCapture* capture, int index) { 201 return &capture->buffer[index]; 202 } 203 204 /* Starting at index, return the index into the trace buffer */ 205 /* for the next trace entry. Index can wrap (ringbuffer) */ 206 int XRayTraceNextEntry(struct XRayTraceCapture* capture, int index) { 207 if (XRayTraceIsAnnotation(capture, index)) 208 index = XRayTraceSkipAnnotation(capture, index); 209 else 210 index = XRayTraceIncrementIndexInline(capture, index); 211 return index; 212 } 213 214 int XRayFrameGetTraceStartIndex(struct XRayTraceCapture* capture, int frame) { 215 assert(capture); 216 assert(capture->initialized); 217 assert(!capture->recording); 218 return capture->frame.entry[frame].start; 219 } 220 221 int XRayFrameGetTraceEndIndex(struct XRayTraceCapture* capture, int frame) { 222 assert(capture); 223 assert(capture->initialized); 224 assert(!capture->recording); 225 return capture->frame.entry[frame].end; 226 } 227 228 /* Not very accurate, annotation strings will also be counted as "entries" */ 229 int XRayFrameGetTraceCount( 230 struct XRayTraceCapture* capture, int frame) { 231 assert(true == capture->initialized); 232 assert(frame >= 0); 233 assert(frame < capture->frame.count); 234 assert(!capture->recording); 235 int start = capture->frame.entry[frame].start; 236 int end = capture->frame.entry[frame].end; 237 int num; 238 if (start < end) 239 num = end - start; 240 else 241 num = capture->buffer_size - (start - end); 242 return num; 243 } 244 245 /* Append a string to trace buffer. */ 246 void XRayTraceAppendString(struct XRayTraceCapture* capture, char* src) { 247 int index = capture->buffer_index; 248 bool done = false; 249 int start_index = 1; 250 int s = 0; 251 int i; 252 char* dst = (char*)&capture->buffer[index]; 253 const int num = sizeof(capture->buffer[index]); 254 dst[0] = 0; 255 while (!done) { 256 for (i = start_index; i < num; ++i) { 257 dst[i] = src[s]; 258 if (0 == src[s]) { 259 dst[i] = 0; 260 done = true; 261 break; 262 } 263 ++s; 264 } 265 index = XRayTraceIncrementIndexInline(capture, index); 266 dst = (char*)&capture->buffer[index]; 267 start_index = 0; 268 } 269 capture->buffer_index = index; 270 } 271 272 /* Copies annotation from trace buffer to output string. */ 273 int XRayTraceCopyToString( 274 struct XRayTraceCapture* capture, int index, char* dst) { 275 assert(XRayTraceIsAnnotation(capture, index)); 276 bool done = false; 277 int i; 278 int d = 0; 279 int start_index = 1; 280 while (!done) { 281 char* src = (char*) &capture->buffer[index]; 282 const int num = sizeof(capture->buffer[index]); 283 for (i = start_index; i < num; ++i) { 284 dst[d] = src[i]; 285 if (0 == src[i]) { 286 done = true; 287 break; 288 } 289 ++d; 290 } 291 index = XRayTraceIncrementIndexInline(capture, index); 292 start_index = 0; 293 } 294 return index; 295 } 296 297 298 /* Generic memory malloc for XRay */ 299 /* validates pointer returned by malloc */ 300 /* memsets memory block to zero */ 301 void* XRayMalloc(size_t t) { 302 void* data; 303 data = calloc(1, t); 304 if (NULL == data) { 305 printf("XRay: malloc(%d) failed, panic shutdown!\n", t); 306 exit(-1); 307 } 308 return data; 309 } 310 311 312 /* Generic memory free for XRay */ 313 void XRayFree(void* data) { 314 assert(NULL != data); 315 free(data); 316 } 317 318 319 /* Main profile capture function that is called at the start */ 320 /* of every instrumented function. This function is implicitly */ 321 /* called when code is compilied with the -finstrument-functions option */ 322 #if defined(__pnacl__) 323 void __pnacl_profile_func_enter(const char* this_fn) { 324 #else 325 void __cyg_profile_func_enter(void* this_fn, void* call_site) { 326 #endif 327 struct XRayTraceCapture* capture = g_xray_capture; 328 if (capture && capture->recording) { 329 uint32_t depth = capture->stack_depth; 330 if (depth < capture->max_stack_depth) { 331 struct XRayTraceStackEntry* se = &capture->stack[depth]; 332 uint32_t addr = (uint32_t)this_fn; 333 se->depth_addr = XRAY_PACK_DEPTH_ADDR(depth, addr); 334 se->dest = capture->buffer_index; 335 se->annotation_index = 0; 336 GTSC(se->tsc); 337 capture->buffer_index = 338 XRayTraceIncrementIndexInline(capture, capture->buffer_index); 339 } 340 ++capture->stack_depth; 341 } 342 } 343 344 345 /* Main profile capture function that is called at the exit of */ 346 /* every instrumented function. This function is implicity called */ 347 /* when the code is compiled with the -finstrument-functions option */ 348 #if defined(__pnacl__) 349 void __pnacl_profile_func_exit(const char* this_fn) { 350 #else 351 void __cyg_profile_func_exit(void* this_fn, void* call_site) { 352 #endif 353 struct XRayTraceCapture* capture = g_xray_capture; 354 if (capture && capture->recording) { 355 --capture->stack_depth; 356 if (capture->stack_depth < capture->max_stack_depth) { 357 uint32_t depth = capture->stack_depth; 358 struct XRayTraceStackEntry* se = &capture->stack[depth]; 359 uint32_t buffer_index = se->dest; 360 uint64_t tsc; 361 struct XRayTraceBufferEntry* be = &capture->buffer[buffer_index]; 362 GTSC(tsc); 363 be->depth_addr = se->depth_addr; 364 be->start_tick = se->tsc; 365 be->end_tick = tsc; 366 be->annotation_index = 0; 367 if (0 != se->annotation_index) 368 __xray_profile_append_annotation(capture, se, be); 369 } 370 } 371 } 372 373 #ifndef XRAY_DISABLE_BROWSER_INTEGRATION 374 void XRayGetTSC(uint64_t* tsc) { 375 GTSC(*tsc); 376 } 377 378 int32_t XRayGetSavedThreadID(struct XRayTraceCapture* capture) { 379 return capture->thread_id; 380 } 381 382 struct XRayTimestampPair XRayFrameGetStartTimestampPair( 383 struct XRayTraceCapture* capture, int frame) { 384 return capture->frame.entry[frame].start_time; 385 } 386 387 struct XRayTimestampPair XRayFrameGetEndTimestampPair( 388 struct XRayTraceCapture* capture, int frame) { 389 return capture->frame.entry[frame].end_time; 390 } 391 #endif 392 393 /* Special case appending annotation string to trace buffer */ 394 /* this function should only ever be called from __cyg_profile_func_exit() */ 395 void __xray_profile_append_annotation(struct XRayTraceCapture* capture, 396 struct XRayTraceStackEntry* se, 397 struct XRayTraceBufferEntry* be) { 398 struct XRayTraceStackEntry* parent = se - 1; 399 int start = parent->annotation_index; 400 be->annotation_index = capture->buffer_index; 401 char* str = &capture->annotation[start]; 402 XRayTraceAppendString(capture, str); 403 *str = 0; 404 ++capture->annotation_count; 405 } 406 407 408 409 /* Annotates the trace buffer. no filtering. */ 410 void __XRayAnnotate(const char* fmt, ...) { 411 va_list args; 412 struct XRayTraceCapture* capture = g_xray_capture; 413 /* Only annotate functions recorded in the trace buffer. */ 414 if (capture && capture->initialized) { 415 if (0 == capture->disabled) { 416 if (capture->recording) { 417 char buffer[1024]; 418 int r; 419 va_start(args, fmt); 420 r = vsnprintf(buffer, sizeof(buffer), fmt, args); 421 va_end(args); 422 { 423 /* Get current string ptr */ 424 int depth = capture->stack_depth - 1; 425 struct XRayTraceStackEntry* se = &capture->stack[depth]; 426 if (0 == se->annotation_index) { 427 struct XRayTraceStackEntry* parent = se - 1; 428 se->annotation_index = parent->annotation_index; 429 } 430 char* dst = &capture->annotation[se->annotation_index]; 431 strcpy(dst, buffer); 432 int len = strlen(dst); 433 se->annotation_index += len; 434 } 435 } 436 } 437 } 438 } 439 440 441 /* Annotates the trace buffer with user strings. Can be filtered. */ 442 void __XRayAnnotateFiltered(const uint32_t filter, const char* fmt, ...) { 443 va_list args; 444 struct XRayTraceCapture* capture = g_xray_capture; 445 if (capture && capture->initialized) { 446 if (0 != (filter & capture->annotation_filter)) { 447 if (0 == capture->disabled) { 448 if (capture->recording) { 449 char buffer[XRAY_TRACE_ANNOTATION_LENGTH]; 450 int r; 451 va_start(args, fmt); 452 r = vsnprintf(buffer, sizeof(buffer), fmt, args); 453 va_end(args); 454 { 455 /* get current string ptr */ 456 int depth = capture->stack_depth - 1; 457 struct XRayTraceStackEntry* se = &capture->stack[depth]; 458 if (0 == se->annotation_index) { 459 struct XRayTraceStackEntry* parent = se - 1; 460 se->annotation_index = parent->annotation_index; 461 } 462 char* dst = &capture->annotation[se->annotation_index]; 463 strcpy(dst, buffer); 464 int len = strlen(dst); 465 se->annotation_index += len; 466 } 467 } 468 } 469 } 470 } 471 } 472 473 474 /* Allows user to specify annotation filter value, a 32 bit mask. */ 475 void XRaySetAnnotationFilter(struct XRayTraceCapture* capture, 476 uint32_t filter) { 477 capture->annotation_filter = filter; 478 } 479 480 481 /* Reset xray profiler. */ 482 void XRayReset(struct XRayTraceCapture* capture) { 483 assert(capture); 484 assert(capture->initialized); 485 assert(!capture->recording); 486 capture->buffer_index = 0; 487 capture->stack_depth = 0; 488 capture->disabled = 0; 489 capture->frame.head = 0; 490 capture->frame.tail = 0; 491 memset(capture->frame.entry, 0, 492 sizeof(capture->frame.entry[0]) * capture->frame.count); 493 memset(&capture->stack, 0, 494 sizeof(capture->stack[0]) * XRAY_TRACE_STACK_SIZE); 495 XRayCheckGuards(capture); 496 } 497 498 499 /* Change the maximum stack depth captures are made. */ 500 void XRaySetMaxStackDepth(struct XRayTraceCapture* capture, int stack_depth) { 501 assert(capture); 502 assert(capture->initialized); 503 assert(!capture->recording); 504 if (stack_depth < 1) 505 stack_depth = 1; 506 if (stack_depth >= XRAY_TRACE_STACK_SIZE) 507 stack_depth = (XRAY_TRACE_STACK_SIZE - 1); 508 capture->max_stack_depth = stack_depth; 509 } 510 511 512 int XRayFrameGetCount(struct XRayTraceCapture* capture) { 513 return capture->frame.count; 514 } 515 516 int XRayFrameGetTail(struct XRayTraceCapture* capture) { 517 return capture->frame.tail; 518 } 519 520 int XRayFrameGetHead(struct XRayTraceCapture* capture) { 521 return capture->frame.head; 522 } 523 524 int XRayFrameGetPrev(struct XRayTraceCapture* capture, int i) { 525 i = i - 1; 526 if (i < 0) 527 i = capture->frame.count - 1; 528 return i; 529 } 530 531 int XRayFrameGetNext(struct XRayTraceCapture* capture, int i) { 532 i = i + 1; 533 if (i >= capture->frame.count) 534 i = 0; 535 return i; 536 } 537 538 bool XRayFrameIsValid(struct XRayTraceCapture* capture, int i) { 539 return capture->frame.entry[i].valid; 540 } 541 542 int XRayFrameGetTotalTicks(struct XRayTraceCapture* capture, int i) { 543 return capture->frame.entry[i].total_ticks; 544 } 545 546 int XRayFrameGetAnnotationCount(struct XRayTraceCapture* capture, int i) { 547 return capture->frame.entry[i].annotation_count; 548 } 549 550 void XRayFrameMakeLabel(struct XRayTraceCapture* capture, 551 int counter, 552 char* label) { 553 snprintf(label, XRAY_MAX_LABEL, "@@@frame%d@@@", counter); 554 } 555 556 557 /* Scans the ring buffer going backwards to find last valid complete frame. */ 558 /* Will mark whether frames are valid or invalid during the traversal. */ 559 int XRayFrameFindTail(struct XRayTraceCapture* capture) { 560 int head = capture->frame.head; 561 int index = XRayFrameGetPrev(capture, head); 562 int total_capture = 0; 563 int last_valid_frame = index; 564 /* Check for no captures */ 565 if (capture->frame.head == capture->frame.tail) 566 return capture->frame.head; 567 /* Go back and invalidate all captures that have been stomped. */ 568 while (index != head) { 569 bool valid = capture->frame.entry[index].valid; 570 if (valid) { 571 total_capture += XRayFrameGetTraceCount(capture, index) + 1; 572 if (total_capture < capture->buffer_size) { 573 last_valid_frame = index; 574 capture->frame.entry[index].valid = true; 575 } else { 576 capture->frame.entry[index].valid = false; 577 } 578 } 579 index = XRayFrameGetPrev(capture, index); 580 } 581 return last_valid_frame; 582 } 583 584 585 /* Starts a new frame and enables capturing, and must be paired with */ 586 /* XRayEndFrame() Trace capturing only occurs on the thread which called */ 587 /* XRayBeginFrame() and each instance of capture can only trace one thread */ 588 /* at a time. */ 589 void XRayStartFrame(struct XRayTraceCapture* capture) { 590 int i; 591 assert(NULL == g_xray_capture); 592 assert(capture->initialized); 593 assert(!capture->recording); 594 i = capture->frame.head; 595 XRayCheckGuards(capture); 596 /* Add a trace entry marker so we can detect wrap around stomping */ 597 struct XRayTraceBufferEntry* be = &capture->buffer[capture->buffer_index]; 598 be->depth_addr = XRAY_FRAME_MARKER; 599 capture->buffer_index = 600 XRayTraceIncrementIndex(capture, capture->buffer_index); 601 /* Set start of the frame we're about to trace */ 602 capture->frame.entry[i].start = capture->buffer_index; 603 capture->disabled = 0; 604 capture->stack_depth = 1; 605 /* The trace stack[0] is reserved */ 606 memset(&capture->stack[0], 0, sizeof(capture->stack[0])); 607 /* Annotation index 0 is reserved to indicate no annotation */ 608 capture->stack[0].annotation_index = 1; 609 capture->annotation[0] = 0; 610 capture->annotation[1] = 0; 611 capture->annotation_count = 0; 612 capture->recording = true; 613 GTSC(capture->frame.entry[i].start_tsc); 614 g_xray_capture = capture; 615 616 #ifndef XRAY_DISABLE_BROWSER_INTEGRATION 617 capture->frame.entry[i].start_time = XRayGenerateTimestampsNow(); 618 #endif 619 620 } 621 622 623 /* Ends a frame and disables capturing. Advances to the next frame. */ 624 /* Must be paired with XRayStartFrame(), and called from the same thread. */ 625 void XRayEndFrame(struct XRayTraceCapture* capture) { 626 int i; 627 assert(capture); 628 assert(capture->initialized); 629 assert(capture->recording); 630 assert(g_xray_capture == capture); 631 assert(0 == capture->disabled); 632 assert(1 == capture->stack_depth); 633 i = capture->frame.head; 634 GTSC(capture->frame.entry[i].end_tsc); 635 capture->frame.entry[i].total_ticks = 636 capture->frame.entry[i].end_tsc - capture->frame.entry[i].start_tsc; 637 capture->recording = NULL; 638 capture->frame.entry[i].end = capture->buffer_index; 639 capture->frame.entry[i].valid = true; 640 capture->frame.entry[i].annotation_count = capture->annotation_count; 641 capture->frame.head = XRayFrameGetNext(capture, capture->frame.head); 642 /* If the table is filled, bump the tail. */ 643 if (capture->frame.head == capture->frame.tail) 644 capture->frame.tail = XRayFrameGetNext(capture, capture->frame.tail); 645 capture->frame.tail = XRayFrameFindTail(capture); 646 /* Check that we didn't stomp over trace entry marker. */ 647 int marker = XRayTraceDecrementIndex(capture, capture->frame.entry[i].start); 648 struct XRayTraceBufferEntry* be = &capture->buffer[marker]; 649 if (be->depth_addr != XRAY_FRAME_MARKER) { 650 fprintf(stderr, 651 "XRay: XRayStopFrame() detects insufficient trace buffer size!\n"); 652 XRayReset(capture); 653 } else { 654 /* Replace marker with an empty annotation string. */ 655 be->depth_addr = XRAY_NULL_ANNOTATION; 656 XRayCheckGuards(capture); 657 } 658 g_xray_capture = NULL; 659 660 #ifndef XRAY_DISABLE_BROWSER_INTEGRATION 661 capture->frame.entry[i].end_time = XRayGenerateTimestampsNow(); 662 #endif 663 } 664 665 666 /* Get the last frame captured. Do not call while capturing. */ 667 /* (ie call outside of XRayStartFrame() / XRayStopFrame() pair) */ 668 int XRayGetLastFrame(struct XRayTraceCapture* capture) { 669 assert(capture); 670 assert(capture->initialized); 671 assert(!capture->recording); 672 assert(0 == capture->disabled); 673 assert(1 == capture->stack_depth); 674 int last_frame = XRayFrameGetPrev(capture, capture->frame.head); 675 return last_frame; 676 } 677 678 679 /* Disables capturing until a paired XRayEnableCapture() is called */ 680 /* This call can be nested, but must be paired with an enable */ 681 /* (If you need to just exclude a specific function and not its */ 682 /* children, the XRAY_NO_INSTRUMENT modifier might be better) */ 683 /* Must be called from same thread as XRayBeginFrame() / XRayEndFrame() */ 684 void XRayDisableCapture(struct XRayTraceCapture* capture) { 685 assert(capture); 686 assert(capture == g_xray_capture); 687 assert(capture->initialized); 688 ++capture->disabled; 689 capture->recording = false; 690 } 691 692 693 /* Re-enables capture. Must be paired with XRayDisableCapture() */ 694 void XRayEnableCapture(struct XRayTraceCapture* capture) { 695 assert(capture); 696 assert(capture == g_xray_capture); 697 assert(capture->initialized); 698 assert(0 < capture->disabled); 699 --capture->disabled; 700 if (0 == capture->disabled) { 701 capture->recording = true; 702 } 703 } 704 705 706 707 struct XRaySymbolTable* XRayGetSymbolTable(struct XRayTraceCapture* capture) { 708 return capture->symbols; 709 } 710 711 712 /* Initialize XRay */ 713 struct XRayTraceCapture* XRayInit(int stack_depth, 714 int buffer_size, 715 int frame_count, 716 const char* mapfilename) { 717 struct XRayTraceCapture* capture; 718 capture = (struct XRayTraceCapture*)XRayMalloc( 719 sizeof(struct XRayTraceCapture)); 720 int adj_frame_count = frame_count + 1; 721 size_t buffer_size_in_bytes = 722 sizeof(capture->buffer[0]) * buffer_size; 723 size_t frame_size_in_bytes = 724 sizeof(capture->frame.entry[0]) * adj_frame_count; 725 capture->buffer = 726 (struct XRayTraceBufferEntry *)XRayMalloc(buffer_size_in_bytes); 727 capture->frame.entry = 728 (struct XRayTraceFrameEntry *)XRayMalloc(frame_size_in_bytes); 729 capture->buffer_size = buffer_size; 730 capture->frame.count = adj_frame_count; 731 capture->frame.head = 0; 732 capture->frame.tail = 0; 733 capture->disabled = 0; 734 capture->annotation_filter = 0xFFFFFFFF; 735 capture->guard0 = XRAY_GUARD_VALUE_0x12345678; 736 capture->guard1 = XRAY_GUARD_VALUE_0x12345678; 737 capture->guard2 = XRAY_GUARD_VALUE_0x87654321; 738 capture->guard3 = XRAY_GUARD_VALUE_0x12345678; 739 capture->initialized = true; 740 capture->recording = false; 741 XRaySetMaxStackDepth(capture, stack_depth); 742 XRayReset(capture); 743 744 /* Mapfile is optional; we don't need it for captures, only for reports. */ 745 capture->symbols = 746 XRaySymbolTableCreate(XRAY_DEFAULT_SYMBOL_TABLE_SIZE); 747 if (NULL != mapfilename) 748 XRaySymbolTableParseMapfile(capture->symbols, mapfilename); 749 750 #ifndef XRAY_DISABLE_BROWSER_INTEGRATION 751 /* Use the address of a thread local variable as a fake thread id. */ 752 capture->thread_id = (int32_t)(&g_xray_thread_id_placeholder); 753 #endif 754 755 return capture; 756 } 757 758 759 /* Shut down and free memory used by XRay. */ 760 void XRayShutdown(struct XRayTraceCapture* capture) { 761 assert(capture); 762 assert(capture->initialized); 763 assert(!capture->recording); 764 XRayCheckGuards(capture); 765 if (NULL != capture->symbols) { 766 XRaySymbolTableFree(capture->symbols); 767 } 768 XRayFree(capture->frame.entry); 769 XRayFree(capture->buffer); 770 capture->initialized = false; 771 XRayFree(capture); 772 } 773 774 #endif /* XRAY */ 775