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 /* GTSC - Get Time Stamp Counter */ 22 #if defined(__amd64__) && !defined(XRAY_NO_RDTSC) 23 XRAY_INLINE uint64_t RDTSC64(); 24 uint64_t RDTSC64() { 25 uint64_t a, d; 26 __asm__ __volatile__("rdtsc" : "=a" (a), "=d" (d)); 27 return ((uint64_t)a) | (((uint64_t)d) << 32); 28 } 29 #define GTSC(_x) _x = RDTSC64() 30 #elif defined(__i386__) && !defined(XRAY_NO_RDTSC) 31 #define GTSC(_x) __asm__ __volatile__ ("rdtsc" : "=A" (_x)); 32 #else 33 XRAY_INLINE uint64_t GTOD(); 34 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_INLINE int XRayTraceDecrementIndexInline( 122 struct XRayTraceCapture* capture, int index); 123 XRAY_INLINE int XRayTraceIncrementIndexInline( 124 struct XRayTraceCapture* capture, int index); 125 126 127 XRAY_NO_INSTRUMENT void __xray_profile_append_annotation( 128 struct XRayTraceCapture* capture, 129 struct XRayTraceStackEntry* se, 130 struct XRayTraceBufferEntry* be); 131 132 #ifdef __cplusplus 133 } 134 #endif 135 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); 142 } 143 144 /* Decrements the trace index, wrapping around if needed. */ 145 int XRayTraceDecrementIndexInline( 146 struct XRayTraceCapture* capture, int index) { 147 --index; 148 if (index < 0) 149 index = capture->buffer_size - 1; 150 return index; 151 } 152 153 /* Increments the trace index, wrapping around if needed. */ 154 int XRayTraceIncrementIndexInline( 155 struct XRayTraceCapture* capture, int index) { 156 ++index; 157 if (index >= capture->buffer_size) 158 index = 0; 159 return index; 160 } 161 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; 167 return 0 == *dst; 168 } 169 170 int XRayTraceIncrementIndex(struct XRayTraceCapture* capture, int index) { 171 return XRayTraceIncrementIndexInline(capture, index); 172 } 173 174 int XRayTraceDecrementIndex(struct XRayTraceCapture* capture, int index) { 175 return XRayTraceDecrementIndexInline(capture, index); 176 } 177 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. */ 184 assert(capture); 185 assert(XRayTraceIsAnnotation(capture, index)); 186 bool done = false; 187 int start_index = 1; 188 int i; 189 while (!done) { 190 char* str = (char*) &capture->buffer[index]; 191 const int num = sizeof(capture->buffer[index]); 192 for (i = start_index; i < num; ++i) { 193 if (0 == str[i]) { 194 done = true; 195 break; 196 } 197 } 198 index = XRayTraceIncrementIndexInline(capture, index); 199 start_index = 0; 200 } 201 return index; 202 } 203 204 205 struct XRayTraceBufferEntry* XRayTraceGetEntry( 206 struct XRayTraceCapture* capture, int index) { 207 return &capture->buffer[index]; 208 } 209 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); 215 else 216 index = XRayTraceIncrementIndexInline(capture, index); 217 return index; 218 } 219 220 int XRayFrameGetTraceStartIndex(struct XRayTraceCapture* capture, int frame) { 221 assert(capture); 222 assert(capture->initialized); 223 assert(!capture->recording); 224 return capture->frame.entry[frame].start; 225 } 226 227 int XRayFrameGetTraceEndIndex(struct XRayTraceCapture* capture, int frame) { 228 assert(capture); 229 assert(capture->initialized); 230 assert(!capture->recording); 231 return capture->frame.entry[frame].end; 232 } 233 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); 238 assert(frame >= 0); 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; 243 int num; 244 if (start < end) 245 num = end - start; 246 else 247 num = capture->buffer_size - (start - end); 248 return num; 249 } 250 251 /* Append a string to trace buffer. */ 252 void XRayTraceAppendString(struct XRayTraceCapture* capture, char* src) { 253 int index = capture->buffer_index; 254 bool done = false; 255 int start_index = 1; 256 int s = 0; 257 int i; 258 char* dst = (char*)&capture->buffer[index]; 259 const int num = sizeof(capture->buffer[index]); 260 dst[0] = 0; 261 while (!done) { 262 for (i = start_index; i < num; ++i) { 263 dst[i] = src[s]; 264 if (0 == src[s]) { 265 dst[i] = 0; 266 done = true; 267 break; 268 } 269 ++s; 270 } 271 index = XRayTraceIncrementIndexInline(capture, index); 272 dst = (char*)&capture->buffer[index]; 273 start_index = 0; 274 } 275 capture->buffer_index = index; 276 } 277 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)); 282 bool done = false; 283 int i; 284 int d = 0; 285 int start_index = 1; 286 while (!done) { 287 char* src = (char*) &capture->buffer[index]; 288 const int num = sizeof(capture->buffer[index]); 289 for (i = start_index; i < num; ++i) { 290 dst[d] = src[i]; 291 if (0 == src[i]) { 292 done = true; 293 break; 294 } 295 ++d; 296 } 297 index = XRayTraceIncrementIndexInline(capture, index); 298 start_index = 0; 299 } 300 return index; 301 } 302 303 304 /* Generic memory malloc for XRay */ 305 /* validates pointer returned by malloc */ 306 /* memsets memory block to zero */ 307 void* XRayMalloc(size_t t) { 308 void* data; 309 data = calloc(1, t); 310 if (NULL == data) { 311 printf("XRay: malloc(%d) failed, panic shutdown!\n", t); 312 exit(-1); 313 } 314 return data; 315 } 316 317 318 /* Generic memory free for XRay */ 319 void XRayFree(void* data) { 320 assert(NULL != data); 321 free(data); 322 } 323 324 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) { 330 #else 331 void __cyg_profile_func_enter(void* this_fn, void* call_site) { 332 #endif 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; 342 GTSC(se->tsc); 343 capture->buffer_index = 344 XRayTraceIncrementIndexInline(capture, capture->buffer_index); 345 } 346 ++capture->stack_depth; 347 } 348 } 349 350 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) { 356 #else 357 void __cyg_profile_func_exit(void* this_fn, void* call_site) { 358 #endif 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; 366 uint64_t tsc; 367 struct XRayTraceBufferEntry* be = &capture->buffer[buffer_index]; 368 GTSC(tsc); 369 be->depth_addr = se->depth_addr; 370 be->start_tick = se->tsc; 371 be->end_tick = tsc; 372 be->annotation_index = 0; 373 if (0 != se->annotation_index) 374 __xray_profile_append_annotation(capture, se, be); 375 } 376 } 377 } 378 379 #ifndef XRAY_DISABLE_BROWSER_INTEGRATION 380 void XRayGetTSC(uint64_t* tsc) { 381 GTSC(*tsc); 382 } 383 384 int32_t XRayGetSavedThreadID(struct XRayTraceCapture* capture) { 385 return capture->thread_id; 386 } 387 388 struct XRayTimestampPair XRayFrameGetStartTimestampPair( 389 struct XRayTraceCapture* capture, int frame) { 390 return capture->frame.entry[frame].start_time; 391 } 392 393 struct XRayTimestampPair XRayFrameGetEndTimestampPair( 394 struct XRayTraceCapture* capture, int frame) { 395 return capture->frame.entry[frame].end_time; 396 } 397 #endif 398 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); 409 *str = 0; 410 ++capture->annotation_count; 411 } 412 413 414 415 /* Annotates the trace buffer. no filtering. */ 416 void __XRayAnnotate(const char* fmt, ...) { 417 va_list args; 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) { 423 char buffer[1024]; 424 int r; 425 va_start(args, fmt); 426 r = vsnprintf(buffer, sizeof(buffer), fmt, args); 427 va_end(args); 428 { 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; 435 } 436 char* dst = &capture->annotation[se->annotation_index]; 437 strcpy(dst, buffer); 438 int len = strlen(dst); 439 se->annotation_index += len; 440 } 441 } 442 } 443 } 444 } 445 446 447 /* Annotates the trace buffer with user strings. Can be filtered. */ 448 void __XRayAnnotateFiltered(const uint32_t filter, const char* fmt, ...) { 449 va_list args; 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]; 456 int r; 457 va_start(args, fmt); 458 r = vsnprintf(buffer, sizeof(buffer), fmt, args); 459 va_end(args); 460 { 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; 467 } 468 char* dst = &capture->annotation[se->annotation_index]; 469 strcpy(dst, buffer); 470 int len = strlen(dst); 471 se->annotation_index += len; 472 } 473 } 474 } 475 } 476 } 477 } 478 479 480 /* Allows user to specify annotation filter value, a 32 bit mask. */ 481 void XRaySetAnnotationFilter(struct XRayTraceCapture* capture, 482 uint32_t filter) { 483 capture->annotation_filter = filter; 484 } 485 486 487 /* Reset xray profiler. */ 488 void XRayReset(struct XRayTraceCapture* capture) { 489 assert(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); 502 } 503 504 505 /* Change the maximum stack depth captures are made. */ 506 void XRaySetMaxStackDepth(struct XRayTraceCapture* capture, int stack_depth) { 507 assert(capture); 508 assert(capture->initialized); 509 assert(!capture->recording); 510 if (stack_depth < 1) 511 stack_depth = 1; 512 if (stack_depth >= XRAY_TRACE_STACK_SIZE) 513 stack_depth = (XRAY_TRACE_STACK_SIZE - 1); 514 capture->max_stack_depth = stack_depth; 515 } 516 517 518 int XRayFrameGetCount(struct XRayTraceCapture* capture) { 519 return capture->frame.count; 520 } 521 522 int XRayFrameGetTail(struct XRayTraceCapture* capture) { 523 return capture->frame.tail; 524 } 525 526 int XRayFrameGetHead(struct XRayTraceCapture* capture) { 527 return capture->frame.head; 528 } 529 530 int XRayFrameGetPrev(struct XRayTraceCapture* capture, int i) { 531 i = i - 1; 532 if (i < 0) 533 i = capture->frame.count - 1; 534 return i; 535 } 536 537 int XRayFrameGetNext(struct XRayTraceCapture* capture, int i) { 538 i = i + 1; 539 if (i >= capture->frame.count) 540 i = 0; 541 return i; 542 } 543 544 bool XRayFrameIsValid(struct XRayTraceCapture* capture, int i) { 545 return capture->frame.entry[i].valid; 546 } 547 548 uint64_t XRayFrameGetTotalTicks(struct XRayTraceCapture* capture, int i) { 549 return capture->frame.entry[i].total_ticks; 550 } 551 552 int XRayFrameGetAnnotationCount(struct XRayTraceCapture* capture, int i) { 553 return capture->frame.entry[i].annotation_count; 554 } 555 556 void XRayFrameMakeLabel(struct XRayTraceCapture* capture, 557 int counter, 558 char* label) { 559 snprintf(label, XRAY_MAX_LABEL, "@@@frame%d@@@", counter); 560 } 561 562 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; 576 if (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; 581 } else { 582 capture->frame.entry[index].valid = false; 583 } 584 } 585 index = XRayFrameGetPrev(capture, index); 586 } 587 return last_valid_frame; 588 } 589 590 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 */ 594 /* at a time. */ 595 void XRayStartFrame(struct XRayTraceCapture* capture) { 596 int i; 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; 611 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; 622 623 #ifndef XRAY_DISABLE_BROWSER_INTEGRATION 624 capture->frame.entry[i].start_time = XRayGenerateTimestampsNow(); 625 #endif 626 } 627 628 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) { 632 int i; 633 assert(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) { 656 fprintf(stderr, 657 "XRay: XRayStopFrame() detects insufficient trace buffer size!\n"); 658 XRayReset(capture); 659 } else { 660 /* Replace marker with an empty annotation string. */ 661 be->depth_addr = XRAY_NULL_ANNOTATION; 662 XRayCheckGuards(capture); 663 } 664 g_xray_capture = NULL; 665 666 #ifndef XRAY_DISABLE_BROWSER_INTEGRATION 667 capture->frame.entry[i].end_time = XRayGenerateTimestampsNow(); 668 #endif 669 } 670 671 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) { 675 assert(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); 681 return last_frame; 682 } 683 684 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) { 691 assert(capture); 692 assert(capture == g_xray_capture); 693 assert(capture->initialized); 694 ++capture->disabled; 695 capture->recording = false; 696 } 697 698 699 /* Re-enables capture. Must be paired with XRayDisableCapture() */ 700 void XRayEnableCapture(struct XRayTraceCapture* capture) { 701 assert(capture); 702 assert(capture == g_xray_capture); 703 assert(capture->initialized); 704 assert(0 < capture->disabled); 705 --capture->disabled; 706 if (0 == capture->disabled) { 707 capture->recording = true; 708 } 709 } 710 711 712 713 struct XRaySymbolTable* XRayGetSymbolTable(struct XRayTraceCapture* capture) { 714 return capture->symbols; 715 } 716 717 718 /* Initialize XRay */ 719 struct XRayTraceCapture* XRayInit(int stack_depth, 720 int buffer_size, 721 int frame_count, 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; 731 capture->buffer = 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); 748 XRayReset(capture); 749 750 /* Mapfile is optional; we don't need it for captures, only for reports. */ 751 capture->symbols = 752 XRaySymbolTableCreate(XRAY_DEFAULT_SYMBOL_TABLE_SIZE); 753 if (NULL != mapfilename) 754 XRaySymbolTableParseMapfile(capture->symbols, mapfilename); 755 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); 759 #endif 760 761 return capture; 762 } 763 764 765 /* Shut down and free memory used by XRay. */ 766 void XRayShutdown(struct XRayTraceCapture* capture) { 767 assert(capture); 768 assert(capture->initialized); 769 assert(!capture->recording); 770 XRayCheckGuards(capture); 771 if (NULL != capture->symbols) { 772 XRaySymbolTableFree(capture->symbols); 773 } 774 XRayFree(capture->frame.entry); 775 XRayFree(capture->buffer); 776 capture->initialized = false; 777 XRayFree(capture); 778 } 779 780 #endif /* XRAY */ 781