### Install BTrace with Homebrew and Poetry Source: https://github.com/bytedance/btrace/blob/master/btrace-iOS/BTraceTool/README.md Install necessary dependencies using Homebrew and then install BTrace using Poetry. ```bash # using homebrew brew install libusbmuxd brew install poetry # install btrace from the top-level 'BTraceTool' directory poetry install ``` -------------------------------- ### BTrace Core lifecycle methods Source: https://context7.com/bytedance/btrace/llms.txt Manages the entire tracing session using the BTrace singleton. Call `setupWithConfig:` once, then `start`/`stop` to bracket the region of interest. ```APIDOC ## iOS SDK ### `[BTrace shared]` / `-setupWithConfig:` / `-start` / `-stop` — Core lifecycle ### Description Manages the entire tracing session using the BTrace singleton. Call `setupWithConfig:` once, then `start`/`stop` to bracket the region of interest. ### Podfile ```ruby # Podfile pod 'BTrace', :subspecs => ['Core', 'Debug'], :path => 'path/to/btrace-iOS' pod 'fishhook', :git => 'https://github.com/facebook/fishhook.git', :branch => 'main' ``` ### AppDelegate.m ```objc // AppDelegate.m #import - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Optional: configure global settings via a dictionary. // Keys map to plugin names; values are plugin-specific config dicts. NSDictionary *config = @{}; [[BTrace shared] setupWithConfig:config]; // Begin recording [[BTrace shared] start]; return YES; } - (void)applicationDidEnterBackground:(UIApplication *)application { // Stop recording and receive raw data in the callback [[BTrace shared] stopWithCallback:^(NSData * _Nonnull data) { // persist or upload `data` (SQLite bytes) NSString *path = [NSTemporaryDirectory() stringByAppendingPathComponent:@"trace.sqlite"]; [data writeToFile:path atomically:YES]; NSLog(@"Trace saved to %@", path); }]; } ``` ``` -------------------------------- ### Initialize BTrace and start tracing in AppDelegate Source: https://context7.com/bytedance/btrace/llms.txt Initializes the BTrace singleton with optional configuration and begins recording trace data in the application's AppDelegate. ```objective-c // AppDelegate.m #import - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Optional: configure global settings via a dictionary. // Keys map to plugin names; values are plugin-specific config dicts. NSDictionary *config = @{}; [[BTrace shared] setupWithConfig:config]; // Begin recording [[BTrace shared] start]; return YES; } - (void)applicationDidEnterBackground:(UIApplication *)application { // Stop recording and receive raw data in the callback [[BTrace shared] stopWithCallback:^(NSData * _Nonnull data) { // persist or upload `data` (SQLite bytes) NSString *path = [NSTemporaryDirectory() stringByAppendingPathComponent:@ ``` -------------------------------- ### RheaTrace3.init(Context) Source: https://context7.com/bytedance/btrace/llms.txt Initializes the btrace Android tracing SDK. This is the only required setup call and should be placed in `Application.attachBaseContext()` to enable tracing from the earliest possible moment during app launch. ```APIDOC ## RheaTrace3.init(Context) — Initialize the Android tracing SDK ### Description The sole required setup call. Place it in `Application.attachBaseContext()` so that tracing can begin at the earliest possible moment (cold-launch capture). The method is a no-op in the noop build variant (`rhea-inhouse-noop`), enabling easy build-flag switching between tracing and production builds. ### Usage ```java // app/build.gradle dependencies { if (enable_btrace == 'true') { implementation 'com.bytedance.btrace:rhea-inhouse:3.0.0' } else { // Zero-overhead stub for production/release builds implementation 'com.bytedance.btrace:rhea-inhouse-noop:3.0.0' } } // gradle.properties enable_btrace=true // set false for production release ``` ```java // MyApplication.java import com.bytedance.rheatrace.RheaTrace3; public class MyApplication extends Application { @Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); // Starts cold-launch tracing if the system property // debug.rhea3.startWhenAppLaunch=1 is set, and launches // the internal HTTP server for ADB-driven start/stop commands. RheaTrace3.init(base); } } ``` ``` -------------------------------- ### Start interactive tracing Source: https://context7.com/bytedance/btrace/llms.txt Starts interactive tracing for a specified app package. Press Enter to stop recording. This command is macOS only. ```shell java -jar rhea-trace-shell-3.0.0.jar \ -a com.example.myapp \ -o output.pb ``` -------------------------------- ### Enable automatic cold-launch tracing Source: https://context7.com/bytedance/btrace/llms.txt Sets an Android system property to enable automatic cold-launch tracing when the app starts. This must be set before launching the app. ```shell adb shell setprop debug.rhea3.startWhenAppLaunch 1 ``` -------------------------------- ### Configure and Start CPU Profiler Source: https://context7.com/bytedance/btrace/llms.txt Initializes the BTrace CPU profiler with custom sampling periods and thread restrictions. Ensure to call `dump` to flush the buffer and `stop` when profiling is complete. ```objc #import #import // Start with defaults (period 10 ms, all threads, fast-unwind disabled) BTraceProfilerConfig *config = [BTraceProfilerConfig defaultConfig]; config.period = 10000; // foreground sampling period µs (10 ms) config.bg_period = 50000; // background period µs (50 ms) config.main_thread_only = false; // profile all threads config.active_thread_only = true; // skip idle/sleeping threads config.fast_unwind = false; // accurate but slower unwind config.merge_stack = true; // deduplicate identical consecutive stacks [[BTraceProfilerPlugin shared] updateConfig:config]; [[BTraceProfilerPlugin shared] start]; // ... trigger the workload to profile ... [[BTraceProfilerPlugin shared] dump]; // flush buffer [[BTraceProfilerPlugin shared] stop]; ``` -------------------------------- ### Configure and Start Memory Profiler Source: https://context7.com/bytedance/btrace/llms.txt Sets up the BTrace memory allocation profiler. Use `lite_mode = NO` for full call stacks at higher overhead, or `YES` for minimal impact. `interval` controls the sampling rate. ```objc #import #import BTraceMemProfilerConfig *memConfig = [BTraceMemProfilerConfig defaultConfig]; memConfig.lite_mode = NO; // full call-stack capture (higher overhead) memConfig.interval = 1; // capture every allocation (1 = no sub-sampling) memConfig.period = 10000; // foreground backtrace period µs memConfig.bg_period = 50000; // background backtrace period µs [[BTraceMemProfilerPlugin shared] updateConfig:memConfig]; [[BTraceMemProfilerPlugin shared] start]; // Trigger code under test [self doHeavyObjectCreation]; [[BTraceMemProfilerPlugin shared] dump]; [[BTraceMemProfilerPlugin shared] stop]; ``` -------------------------------- ### Install BTrace CLI Dependencies Source: https://context7.com/bytedance/btrace/llms.txt Install necessary dependencies for the BTrace iOS CLI tool on macOS using Homebrew and Poetry. Navigate to the tool's directory and run 'poetry install'. ```bash # Install dependencies (macOS) brew install libusbmuxd poetry cd btrace-iOS/BTraceTool poetry install ``` -------------------------------- ### Configure and Start GCD Dispatch Profiler Source: https://context7.com/bytedance/btrace/llms.txt Initializes the BTrace GCD dispatch profiler to track enqueue and execution stacks for dispatched blocks. Configure sampling `period` and `bg_period` as needed. ```objc #import #import BTraceDispatchProfilerConfig *dispConfig = [BTraceDispatchProfilerConfig defaultConfig]; dispConfig.period = 10000; // µs foreground dispConfig.bg_period = 50000; // µs background [[BTraceDispatchProfilerPlugin shared] updateConfig:dispConfig]; [[BTraceDispatchProfilerPlugin shared] start]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [self processLargeDataset]; }); [[BTraceDispatchProfilerPlugin shared] dump]; [[BTraceDispatchProfilerPlugin shared] stop]; ``` -------------------------------- ### Record Basic Android Trace with rhea-trace-shell Source: https://context7.com/bytedance/btrace/llms.txt Use the rhea-trace-shell.jar tool to record a trace for a specified duration. This command starts the trace, collects data, and outputs a Perfetto-compatible .pb file. ```shell # Basic 10-second trace of com.example.myapp, output to output.pb java -jar rhea-trace-shell-3.0.0.jar \ -a com.example.myapp \ -t 10 \ -o output.pb ``` -------------------------------- ### Configure and Start Lock Contention Profiler Source: https://context7.com/bytedance/btrace/llms.txt Enables the BTrace lock contention profiler by specifying which lock types to hook. Adjust `period` and `bg_period` for sampling frequency. ```objc #import #import BTraceLockProfilerConfig *lockConfig = [BTraceLockProfilerConfig defaultConfig]; lockConfig.period = 10000; // µs lockConfig.bg_period = 50000; // µs lockConfig.mtx = true; // pthread mutex lockConfig.rw = true; // read-write locks lockConfig.cond = true; // condition variables lockConfig.unfair = true; // os_unfair_lock [[BTraceLockProfilerPlugin shared] updateConfig:lockConfig]; [[BTraceLockProfilerPlugin shared] start]; // ... run multithreaded workload ... [[BTraceLockProfilerPlugin shared] dump]; [[BTraceLockProfilerPlugin shared] stop]; ``` -------------------------------- ### Execute btrace Tracing Command Source: https://github.com/bytedance/btrace/blob/master/README.MD Run the btrace tracing shell command from your computer's terminal. Ensure adb is set up, your device is connected, and the APK is installed. The output is saved to a .pb file for analysis. ```shell java -jar rhea-trace-shell.jar -a ${your_package_name} -t 10 -o output.pb -r sched ``` -------------------------------- ### Initialize btrace Android SDK Source: https://context7.com/bytedance/btrace/llms.txt Initialize the btrace tracing SDK by calling RheaTrace3.init(base) in your Application's attachBaseContext method. This ensures tracing starts as early as possible during cold launch and enables the HTTP server for ADB commands. ```java // MyApplication.java import com.bytedance.rheatrace.RheaTrace3; public class MyApplication extends Application { @Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); // Starts cold-launch tracing if the system property // debug.rhea3.startWhenAppLaunch=1 is set, and launches // the internal HTTP server for ADB-driven start/stop commands. RheaTrace3.init(base); } } ``` -------------------------------- ### Record trace in interactive mode Source: https://context7.com/bytedance/btrace/llms.txt Starts tracing an Android application and saves the output to a file. This mode is interactive on macOS, allowing you to press Enter to stop recording. ```APIDOC ## Record trace in interactive mode ### Description Starts tracing an Android application and saves the output to a file. This mode is interactive on macOS, allowing you to press Enter to stop recording. ### Command ```shell java -jar rhea-trace-shell-3.0.0.jar \ -a com.example.myapp \ -o output.pb ``` ### Output `press enter to stop tracing...` ``` -------------------------------- ### Get Thread CPU Time in Nanoseconds (C++) Source: https://github.com/bytedance/btrace/blob/master/INTRODUCTION.MD Obtain the current thread's CPU time in nanoseconds. This is useful for differentiating on-CPU execution from off-CPU blocking. ```C++ static uint64_t thread_cpu_time_nanos() { struct timespec t; clock_gettime(CLOCK_THREAD_CPUTIME_ID, &t); return t.tv_sec * 1000000000LL + t.tv_nsec; } ``` -------------------------------- ### Get Page Faults and Context Switches (C++) Source: https://github.com/bytedance/btrace/blob/master/INTRODUCTION.MD Retrieve the number of page faults and context switches at the thread level using getrusage. This helps in analyzing system-level performance. ```C++ struct rusage ru; if (getrusage(RUSAGE_THREAD, &ru) == 0) { r.mMajFlt = ru.ru_majflt; r.mNvCsw = ru.ru_nvcsw; r.mNivCsw = ru.ru_nivcsw; } ``` -------------------------------- ### Open and view trace file Source: https://context7.com/bytedance/btrace/llms.txt Opens the generated trace file in the Perfetto UI. Drag and drop the output.pb file into the UI. ```shell # Visit https://ui.perfetto.dev/ and drag-drop output.pb ``` -------------------------------- ### Record Cold App Launch Trace Source: https://context7.com/bytedance/btrace/llms.txt Record a trace that includes the application's cold launch. The -r flag automatically restarts the app before beginning the trace collection. ```shell # Trace cold app launch (restarts the app automatically) java -jar rhea-trace-shell-3.0.0.jar \ -a com.example.myapp \ -t 15 \ -o startup.pb \ -r # restart app before tracing ``` -------------------------------- ### Android system properties for runtime configuration Source: https://context7.com/bytedance/btrace/llms.txt Configure BTrace at startup using Android system properties for dynamic configuration without recompilation. ```APIDOC ## Android system properties — Runtime configuration ### Description Configure BTrace at startup using Android system properties for dynamic configuration without recompilation. ### Enable automatic cold-launch tracing ```shell # Enable automatic cold-launch tracing when the app starts # (set before launching the app) adb shell setprop debug.rhea3.startWhenAppLaunch 1 ``` ### Override ring buffer size ```shell # Override the ring buffer size at runtime (number of stack frames) adb shell setprop debug.rhea3.methodIdMaxSize 400000 ``` ### Override sampling interval ```shell # Override the sampling interval (nanoseconds) adb shell setprop debug.rhea3.sampleInterval 500000 ``` ### Override wait-for-trace-data timeout ```shell # Override the wait-for-trace-data timeout (seconds) adb shell setprop debug.rhea3.waitTraceTimeout 30 ``` ### Reset to defaults ```shell # Reset to defaults adb shell setprop debug.rhea3.startWhenAppLaunch 0 ``` ``` -------------------------------- ### Configure BTrace Monitor Plugin for Performance Thresholds Source: https://context7.com/bytedance/btrace/llms.txt Set up the BTraceMonitorConfig to trigger stack snapshots when CPU usage, memory spikes, hitches, hangs, or ANRs exceed defined thresholds. Ensure BTraceMonitorPlugin is imported. ```objc #import #import BTraceMonitorConfig *monConfig = [BTraceMonitorConfig defaultConfig]; // CPU usage spike: capture when any thread exceeds 80% CPU // over a 500 ms sliding window, sampled every 100 ms. CPUUsageConfig *cpuUsage = [[CPUUsageConfig alloc] initWithDictionary:nil]; cpuUsage.period = 100; // poll interval ms cpuUsage.window = 500; // sliding window ms cpuUsage.threshold = 0.8f; // 80% utilization trigger cpuUsage.single_thread = false; // consider aggregate CPU, not single thread monConfig.cpu_usage = cpuUsage; // Hang detection: hitch > 16 ms (1 dropped frame), hang > 500 ms, ANR > 5 s HangConfig *hang = [[HangConfig alloc] initWithDictionary:nil]; hang.hitch = 16; // ms — jank threshold hang.hang = 500; // ms — hang threshold hang.anr = 5; // s — ANR-class foreground hang.anr_bg = 30; // s — ANR-class background monConfig.hang = hang; // Memory spike: capture when resident memory grows > 20 MB // over 1 s window, sampled every 200 ms. MemorySpikeConfig *memSpike = [[MemorySpikeConfig alloc] initWithDictionary:nil]; memSpike.period = 200; // ms memSpike.window = 1000; // ms memSpike.threshold = 20.0f; // MB delta monConfig.mem_spike = memSpike; [[BTraceMonitorPlugin shared] updateConfig:monConfig]; [[BTraceMonitorPlugin shared] start]; ``` -------------------------------- ### Tune Trace Buffer Size and Sampling Interval Source: https://context7.com/bytedance/btrace/llms.txt Customize the trace recording by adjusting the maximum application trace buffer size with -maxAppTraceBufferSize and the sampling interval with -sampleInterval. A smaller interval captures more data but increases overhead. ```shell # Tune buffer size and sampling interval java -jar rhea-trace-shell-3.0.0.jar \ -a com.example.myapp \ -t 10 \ -o output.pb \ -maxAppTraceBufferSize 500000 \ -sampleInterval 500000 # 0.5 ms between samples (default 1 ms) ``` -------------------------------- ### Activate BTrace Virtual Environment Source: https://github.com/bytedance/btrace/blob/master/README.MD Activate the Poetry virtual environment before running BTrace commands. ```bash # activate from the BTraceTool directory poetry shell # or poetry env activate ``` -------------------------------- ### ART StackVisitor for Efficient Backtracing (C++) Source: https://github.com/bytedance/btrace/blob/master/INTRODUCTION.MD Implements a StackVisitor to efficiently capture method pointers during backtracing and store them for later symbolization. Preserves space for real StackVisitor fields using mSpaceHolder. ```C++ class StackVisitor { ... [[maybe_unused]] virtual bool VisitFrame(); // preserve for real StackVisitor's fields space [[maybe_unused]] char mSpaceHolder[2048]; ... }; bool StackVisitor::innerVisitOnce(JavaStack &stack, void *thread, uint64_t *outTime, uint64_t *outCpuTime) { StackVisitor visitor(stack); void *vptr = *reinterpret_cast(&visitor); // art::Context::Create() auto *context = sCreateContextCall(); // art::StackVisitor::StackVisitor(art::Thread*, art::Context*, art::StackVisitor::StackWalkKind, bool) sConstructCall(reinterpret_cast(&visitor), thread, context, StackWalkKind::kIncludeInlinedFrames, false); *reinterpret_cast(&visitor) = vptr; // void art::StackVisitor::WalkStack<(art::StackVisitor::CountTransitions)0>(bool) visitor.walk(); } [[maybe_unused]] bool StackVisitor::VisitFrame() { // art::StackVisitor::GetMethod() const auto *method = sGetMethodCall(reinterpret_cast(this)); mStack.mStackMethods[mCurIndex] = uint64_t(method); mCurIndex++; return true; } ``` -------------------------------- ### Reset tracing properties to defaults Source: https://context7.com/bytedance/btrace/llms.txt Resets the 'startWhenAppLaunch' tracing property to its default value (0). ```shell adb shell setprop debug.rhea3.startWhenAppLaunch 0 ``` -------------------------------- ### Record Trace Data with BTrace Source: https://github.com/bytedance/btrace/blob/master/btrace-iOS/BTraceTool/README.md Use the 'record' command to capture trace data from an iOS device. Specify device ID, bundle ID, and output path. If '-l' is not specified, the app must be running before recording. ```bash python3 -m btrace record [-h] [-i DEVICE_ID] [-b BUNDLE_ID] [-o OUTPUT] [-t TIME_LIMIT] [-d DSYM_PATH] [-m] [-l] [-s] ``` ```bash python3 -m btrace record -i xxx -b xxx -d /xxxDebug-iphoneos/xxx.app ``` ```bash python3 -m btrace record -i xxx -b xxx -d /xxxDebug-iphoneos/xxx.dSYM ``` -------------------------------- ### Initialize btrace in Application Class Source: https://github.com/bytedance/btrace/blob/master/README.MD Call RheaTrace3.init(base) within the attachBaseContext() method of your Application class to initialize btrace. This ensures initialization occurs early in the application lifecycle. ```java public class MyApp extends Application { @Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); // When rhea-inhouse-noop is used, RheaTrace3.init() has empty implementation. RheaTrace3.init(base); } } ``` -------------------------------- ### List available atrace categories Source: https://context7.com/bytedance/btrace/llms.txt Use this command to list available atrace categories for the connected device. ```shell java -jar rhea-trace-shell-3.0.0.jar --list ``` -------------------------------- ### rhea-trace-shell.jar CLI Source: https://context7.com/bytedance/btrace/llms.txt The command-line tool for recording traces on Android. It communicates with the in-app HTTP server over ADB to start/stop traces, collect data, merge it with system traces, and output a Perfetto-compatible `.pb` file. ```APIDOC ## rhea-trace-shell.jar CLI — Android trace recording tool ### Description The desktop-side Java tool that communicates with the in-app HTTP server over ADB to start/stop traces, collect the sampling data, merge it with system-level Perfetto traces, and write a `.pb` file ready for Perfetto UI. ### Usage Examples ```shell # Basic 10-second trace of com.example.myapp, output to output.pb java -jar rhea-trace-shell-3.0.0.jar \ -a com.example.myapp \ -t 10 \ -o output.pb # Trace cold app launch (restarts the app automatically) java -jar rhea-trace-shell-3.0.0.jar \ -a com.example.myapp \ -t 15 \ -o startup.pb \ -r # restart app before tracing # Obfuscated app: supply ProGuard mapping for symbol deobfuscation java -jar rhea-trace-shell-3.0.0.jar \ -a com.example.myapp \ -t 10 \ -o output.pb \ -m /path/to/mapping.txt # Tune buffer size and sampling interval java -jar rhea-trace-shell-3.0.0.jar \ -a com.example.myapp \ -t 10 \ -o output.pb \ -maxAppTraceBufferSize 500000 \ -sampleInterval 500000 # 0.5 ms between samples (default 1 ms) # Force simple (non-Perfetto) mode for Android < 8.1 devices java -jar rhea-trace-shell-3.0.0.jar \ -a com.example.myapp \ -t 10 \ -o output.pb \ -mode simple ``` ### Parameters - **-a [package_name]** - Required - The package name of the application to trace. - **-t [seconds]** - Required - The duration of the trace in seconds. - **-o [output_file]** - Required - The path to the output trace file (e.g., `output.pb`). - **-r** - Optional - Restart the application before starting the trace. - **-m [mapping_file]** - Optional - Path to the ProGuard mapping file for deobfuscating symbols in obfuscated apps. - **-maxAppTraceBufferSize [frames]** - Optional - Sets the maximum size of the application trace buffer in stack frames (default: 200000). - **-sampleInterval [nanoseconds]** - Optional - Sets the sampling interval in nanoseconds (default: 1000000, i.e., 1 ms). - **-mode [simple|perfetto]** - Optional - Specifies the trace mode. `simple` is for older Android versions (< 8.1), `perfetto` is the default for newer versions. ``` -------------------------------- ### CLI parameter reference Source: https://context7.com/bytedance/btrace/llms.txt Reference for the command-line parameters available for the rhea-trace-shell. ```APIDOC ## CLI parameter reference ### Description Reference for the command-line parameters available for the rhea-trace-shell. | Parameter | Default | Description | |---|---|---| | `-a $pkg` | required | App package name | | `-o $path` | auto-generated `pkg_versionName_timestamp.pb` | Output `.pb` path | | `-t $secs` | interactive (macOS) / required (Windows) | Trace duration in seconds | | `-m $path` | — | ProGuard mapping file path | | `-mode perfetto\|simple` | auto-detected from SDK version | Capture backend | | `-maxAppTraceBufferSize $n` | 200000 | Ring buffer capacity (stack frame count) | | `-sampleInterval $ns` | 1000000 | Minimum interval between stack captures (ns) | | `-waitTraceTimeout $secs` | 20 | Timeout waiting for trace data pull | | `-r` | false | Force-stop and restart app before tracing | | `-s $serial` | — | Target specific ADB device | ``` -------------------------------- ### Scoped manual snapshot Source: https://context7.com/bytedance/btrace/llms.txt Captures a snapshot of the in-memory trace buffer for a specific time window and tags it for later retrieval. Useful for capturing a precise time slice. ```APIDOC ### `-dumpWithTag:Info:BeginTime:EndTime:` — Scoped manual snapshot ### Description Captures a snapshot of the in-memory trace buffer for a specific time window and tags it for later retrieval. Useful for capturing a precise time slice (e.g., a slow network request) without stopping the whole session. ### Method Signature ```objc - (void)dumpWithTag:(const char *)tag Info:(const char *)info BeginTime:(int64_t)beginNs EndTime:(int64_t)endNs; ``` ### Example Usage ```objc #import // Measure a slow operation with nanosecond-precision timestamps int64_t beginNs = (int64_t)([[NSDate date] timeIntervalSince1970] * 1e9); // ... expensive work ... [NSThread sleepForTimeInterval:0.5]; int64_t endNs = (int64_t)([[NSDate date] timeIntervalSince1970] * 1e9); [[BTrace shared] dumpWithTag:"network_request" Info:"POST /api/upload" BeginTime:beginNs EndTime:endNs]; // The tagged slice is visible in the Perfetto flame chart with its label. ``` ``` -------------------------------- ### Parse Trace Data with BTrace Source: https://github.com/bytedance/btrace/blob/master/btrace-iOS/BTraceTool/README.md Use the 'parse' command to process recorded trace data, especially when the '-d' option was not used during recording or to re-parse data. Requires the path to the trace data file. ```bash python3 -m btrace parse [-h] [-d DSYM_PATH] [-f] [-s] file_path ``` ```bash btrace parse -d /xxx.dSYM xxx.sqlite ``` ```bash btrace parse -d /xxx.app xxx.sqlite ``` -------------------------------- ### Record BTrace Trace Over USB with CLI Source: https://context7.com/bytedance/btrace/llms.txt Use the 'btrace record' command to capture a trace from an iOS device. Options include specifying device UDID, bundle ID, trace duration, output path, app path for symbolization, and relaunching the app. ```bash # Activate environment poetry shell # Record a 60-second trace, auto-launch app, symbolize with dSYM python3 -m btrace record \ -i \ -b com.example.myapp \ -t 60 \ -o ~/Desktop/trace_output \ -d /path/to/MyApp.app \ -l # relaunch app before recording ``` ```bash # Record main thread only (lower overhead) python3 -m btrace record \ -b com.example.myapp \ -m \ -o ~/Desktop/trace_main ``` ```bash # Stop recording # Ctrl+C ``` -------------------------------- ### Configure btrace Build Switch in gradle.properties Source: https://github.com/bytedance/btrace/blob/master/README.MD Set the 'enable_btrace' flag in your gradle.properties file to control whether tracing is included in the build. Set to 'false' to disable tracing. ```properties # Turn on this switch when you want to build app that support tracing. enable_btrace=false ``` -------------------------------- ### BTraceMonitorPlugin Configuration Source: https://context7.com/bytedance/btrace/llms.txt Configure the BTraceMonitorPlugin to monitor CPU usage, memory spikes, hangs, and ANRs. Thresholds and sampling intervals can be customized for each sub-monitor. ```APIDOC ## BTraceMonitorPlugin / BTraceMonitorConfig — Threshold-based anomaly monitor plugin Monitors CPU usage spikes, memory spikes, hitches, hangs, and ANR-class stalls. When a threshold is crossed, btrace automatically captures a stack snapshot. All sub-monitors (`cpu_usage`, `cpu_level`, `mem_spike`, `hang`) are independently configurable. ### Configuration Example ```objc #import #import BTraceMonitorConfig *monConfig = [BTraceMonitorConfig defaultConfig]; // CPU usage spike: capture when any thread exceeds 80% CPU // over a 500 ms sliding window, sampled every 100 ms. CPUUsageConfig *cpuUsage = [[CPUUsageConfig alloc] initWithDictionary:nil]; cpuUsage.period = 100; // poll interval ms cpuUsage.window = 500; // sliding window ms cpuUsage.threshold = 0.8f; // 80% utilization trigger cpuUsage.single_thread = false; // consider aggregate CPU, not single thread monConfig.cpu_usage = cpuUsage; // Hang detection: hitch > 16 ms (1 dropped frame), hang > 500 ms, ANR > 5 s HangConfig *hang = [[HangConfig alloc] initWithDictionary:nil]; hang.hitch = 16; // ms — jank threshold hang.hang = 500; // ms — hang threshold hang.anr = 5; // s — ANR-class foreground hang.anr_bg = 30; // s — ANR-class background monConfig.hang = hang; // Memory spike: capture when resident memory grows > 20 MB // over 1 s window, sampled every 200 ms. MemorySpikeConfig *memSpike = [[MemorySpikeConfig alloc] initWithDictionary:nil]; memSpike.period = 200; // ms memSpike.window = 1000; // ms memSpike.threshold = 20.0f; // MB delta monConfig.mem_spike = memSpike; [[BTraceMonitorPlugin shared] updateConfig:monConfig]; [[BTraceMonitorPlugin shared] start]; ``` ``` -------------------------------- ### Deobfuscate Symbols with ProGuard Mapping Source: https://context7.com/bytedance/btrace/llms.txt When tracing an obfuscated app, provide the ProGuard mapping file using the -m flag to deobfuscate symbol names in the trace output. ```shell # Obfuscated app: supply ProGuard mapping for symbol deobfuscation java -jar rhea-trace-shell-3.0.0.jar \ -a com.example.myapp \ -t 10 \ -o output.pb \ -m /path/to/mapping.txt ``` -------------------------------- ### iOS btrace record CLI Source: https://context7.com/bytedance/btrace/llms.txt Use the `btrace record` command-line tool to capture traces from an iOS device over USB. This tool can automatically launch applications, symbolize data using dSYMs, and generate flamegraphs. ```APIDOC ## iOS `btrace record` CLI — Recording traces over USB The Python-based CLI tool that communicates with the device over `usbmuxd`, controls the in-app BTrace session, collects the raw SQLite database, and optionally symbolizes and opens a flamegraph automatically. ### Installation and Usage ```bash # Install dependencies (macOS) brew install libusbmuxd poetry cd btrace-iOS/BTraceTool poetry install # Activate environment poetry shell # Record a 60-second trace, auto-launch app, symbolize with dSYM python3 -m btrace record \ -i \ -b com.example.myapp \ -t 60 \ -o ~/Desktop/trace_output \ -d /path/to/MyApp.app \ # or .dSYM — triggers auto flamegraph display -l # relaunch app before recording # Record main thread only (lower overhead) python3 -m btrace record \ -b com.example.myapp \ -m \ -o ~/Desktop/trace_main # Stop recording # Ctrl+C ``` ``` -------------------------------- ### Add BTrace Core and Debug to Podfile Source: https://context7.com/bytedance/btrace/llms.txt Specifies the BTrace Core and Debug subspecs, along with the fishhook dependency, in the Podfile for iOS projects. ```ruby # Podfile pod 'BTrace', :subspecs => ['Core', 'Debug'], :path => 'path/to/btrace-iOS' pod 'fishhook', :git => 'https://github.com/facebook/fishhook.git', :branch => 'main' ``` -------------------------------- ### Parse BTrace Trace with CLI Source: https://context7.com/bytedance/btrace/llms.txt Use the 'btrace parse' command to process a recorded trace. Options include specifying the dSYM path for symbolication, forcing a re-parse, and including system library symbols. ```bash # Parse a previously recorded trace with a dSYM (deferred symbolication) python3 -m btrace parse \ -d /path/to/MyApp.dSYM \ ~/Desktop/trace_output/trace.sqlite ``` ```bash # Force re-parse an already-parsed trace python3 -m btrace parse \ -d /path/to/MyApp.app \ -f \ ~/Desktop/trace_output/trace.sqlite ``` ```bash # Include system library symbols python3 -m btrace parse \ -d /path/to/MyApp.dSYM \ -s \ ~/Desktop/trace_output/trace.sqlite ``` -------------------------------- ### List available atrace categories Source: https://context7.com/bytedance/btrace/llms.txt Lists all available atrace categories for the connected Android device. ```APIDOC ## List available atrace categories ### Description Lists all available atrace categories for the connected Android device. ### Command ```shell java -jar rhea-trace-shell-3.0.0.jar --list ``` ``` -------------------------------- ### Add BTrace to iOS Podfile Source: https://github.com/bytedance/btrace/blob/master/README.MD Include these lines in your Podfile to integrate BTrace Core and Debug functionalities, along with the fishhook dependency. ```ruby pod 'BTrace', :subspecs => ['Core', 'Debug'], :path => 'xxx/btrace-iOS' pod 'fishhook', :git => 'https://github.com/facebook/fishhook.git', :branch => 'main' ``` -------------------------------- ### iOS btrace parse CLI Source: https://context7.com/bytedance/btrace/llms.txt Use the `btrace parse` command-line tool to process previously recorded trace data. It supports parsing with dSYMs for symbolication, re-parsing, and including system library symbols. ```APIDOC ## iOS `btrace parse` CLI — Parsing and Symbolication ### Usage Examples ```bash # Parse a previously recorded trace with a dSYM (deferred symbolication) python3 -m btrace parse \ -d /path/to/MyApp.dSYM \ ~/Desktop/trace_output/trace.sqlite # Force re-parse an already-parsed trace python3 -m btrace parse \ -d /path/to/MyApp.app \ -f \ ~/Desktop/trace_output/trace.sqlite # Include system library symbols python3 -m btrace parse \ -d /path/to/MyApp.dSYM \ -s \ ~/Desktop/trace_output/trace.sqlite ``` ``` -------------------------------- ### Add btrace Dependencies to app/build.gradle Source: https://github.com/bytedance/btrace/blob/master/README.MD Include the btrace library in your Android project's build.gradle file. Use the 'rhea-inhouse-noop' implementation if tracing is disabled via the 'enable_btrace' flag. ```groovy dependencies { if (enable_btrace == 'true') { implementation 'com.bytedance.btrace:rhea-inhouse:3.0.0' } else { implementation 'com.bytedance.btrace:rhea-inhouse-noop:3.0.0' } } ``` -------------------------------- ### ShadowHook Instrumentation for Lock Acquisition (C++) Source: https://github.com/bytedance/btrace/blob/master/INTRODUCTION.MD Proxies the MonitorEnter function using ShadowHook to record stack traces and blocking durations for lock acquisition events. Utilizes ScopeSampling for timing. ```C++ void Monitor_Lock(void* monitor, void* threadSelf) { SHADOWHOOK_STACK_SCOPE(); rheatrace::ScopeSampling a(rheatrace::stack::SamplingType::kMonitor, threadSelf); SHADOWHOOK_CALL_PREV(Monitor_Lock, monitor, threadSelf); } class ScopeSampling { private: uint64_t beginNano_; uint64_t beginCpuNano_; public: ScopeSampling(SamplingType type, void *self = nullptr, bool force = false) : type_(type), self_(self), force_(force) { beginNano_ = rheatrace::current_time_nanos(); beginCpuNano_ = rheatrace::thread_cpu_time_nanos(); } ~ScopeSampling() { SamplingCollector::request(type_, self_, force_, true, beginNano_, beginCpuNano_); } }; ``` -------------------------------- ### Track Object Allocation Statistics (C++) Source: https://github.com/bytedance/btrace/blob/master/INTRODUCTION.MD Track allocation counts and sizes at the thread level. Use this to monitor memory allocation patterns. ```C++ thread_local rheatrace::JavaObjectStat::ObjectStat stats; void rheatrace::JavaObjectStat::onObjectAllocated(size_t b) { stats.objects++; stats.bytes += b; } ``` -------------------------------- ### Configure btrace Android SDK Dependency Source: https://context7.com/bytedance/btrace/llms.txt Add the btrace SDK dependency to your app's build.gradle file. Use a build flag to conditionally include the tracing library or a no-op stub for production builds. ```gradle // app/build.gradle dependencies { if (enable_btrace == 'true') { implementation 'com.bytedance.btrace:rhea-inhouse:3.0.0' } else { // Zero-overhead stub for production/release builds implementation 'com.bytedance.btrace:rhea-inhouse-noop:3.0.0' } } // gradle.properties enable_btrace=true // set false for production release ``` -------------------------------- ### Annotate BTrace Timeline with Custom Events Source: https://context7.com/bytedance/btrace/llms.txt Inject custom timestamped events like business metrics or user actions into the trace timeline using BTraceTimeSeriesPlugin. Ensure BTraceTimeSeriesPlugin and BTraceTimeSeriesData are imported. ```objc #import #import // Annotate a network request lifecycle BTraceTimeSeriesData *startEvent = [[BTraceTimeSeriesData alloc] initWithType:@"network" Dictionary:@{ @"url": @"https://api.example.com/data", @"method": @"POST", @"phase": @"start" }]; [[BTraceTimeSeriesPlugin shared] SaveTimeSeriesData:startEvent]; NSData *payload = [self buildRequestPayload]; NSURLSession *session = [NSURLSession sharedSession]; [[session dataTaskWithURL:[NSURL URLWithString:@"https://api.example.com/data"] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { mach_port_t tid = pthread_mach_thread_np(pthread_self()); int64_t now = (int64_t)([[NSDate date] timeIntervalSince1970] * 1e9); BTraceTimeSeriesData *endEvent = [[BTraceTimeSeriesData alloc] initWithTid:tid Timestamp:now Type:@"network" Dictionary:@{ @"url": @"https://api.example.com/data", @"status": @(((NSHTTPURLResponse *)response).statusCode), @"bytes": @(data.length), @"phase": @"end" }]; [[BTraceTimeSeriesPlugin shared] SaveTimeSeriesData:endEvent]; }] resume]; ``` -------------------------------- ### Force Simple Trace Mode for Older Android Versions Source: https://context7.com/bytedance/btrace/llms.txt For devices running Android versions older than 8.1, use the -mode simple flag to force a non-Perfetto trace mode. This ensures compatibility when Perfetto tracing is not supported. ```shell # Force simple (non-Perfetto) mode for Android < 8.1 devices java -jar rhea-trace-shell-3.0.0.jar \ -a com.example.myapp \ -t 10 \ -o output.pb \ -mode simple ``` -------------------------------- ### Monitor Thread Blocking and Lock Release (C++) Source: https://github.com/bytedance/btrace/blob/master/INTRODUCTION.MD Hook functions to record thread blocking durations and lock release events. This snippet specifically handles MonitorEnter and MonitorExit to track main thread blocking and wake-up events. ```C++ static void *currentMainMonitor = nullptr; static uint64_t currentMainNano = 0; void *Monitor_MonitorEnter(void *self, void *obj, bool trylock) { SHADOWHOOK_STACK_SCOPE(); if (rheatrace::isMainThread()) { rheatrace::ScopeSampling a(rheatrace::SamplingType::kMonitor, self); currentMainMonitor = obj; // 记录当前阻塞的锁 currentMainNano = a.beginNano_; void *result = SHADOWHOOK_CALL_PREV(Monitor_MonitorEnter, self, obj, trylock); currentMainMonitor = nullptr; // 锁已经拿到,这里重置 return result; } ... } bool Monitor_MonitorExit(void *self, void *obj) { SHADOWHOOK_STACK_SCOPE(); if (!rheatrace::isMainThread()) { if (currentMainMonitor == obj) { // 当前释放的锁正式主线程等待的锁 rheatrace::SamplingCollector::request(rheatrace::SamplingType::kUnlock, self, true, true, currentMainNano); // 强制抓栈,并通过 currentMainNano 和主线程建立联系 ALOGX("Monitor_MonitorExit wakeup main lock %ld", currentMainNano); } } return SHADOWHOOK_CALL_PREV(Monitor_MonitorExit, self, obj); } ``` -------------------------------- ### BTraceTimeSeriesPlugin - SaveTimeSeriesData Source: https://context7.com/bytedance/btrace/llms.txt Inject custom timestamped events into the trace timeline using BTraceTimeSeriesPlugin. These events can represent business metrics, counters, or user actions, appearing as annotations in Perfetto. ```APIDOC ## BTraceTimeSeriesPlugin / -SaveTimeSeriesData: — Custom event annotation Lets you inject arbitrary timestamped events (business metrics, custom counters, user actions) directly into the trace timeline. These appear as annotations alongside profiler data in Perfetto. ### Usage Example ```objc #import #import // Annotate a network request lifecycle BTraceTimeSeriesData *startEvent = [[BTraceTimeSeriesData alloc] initWithType:@"network" Dictionary:@{ @"url": @"https://api.example.com/data", @"method": @"POST", @"phase": @"start" }]; [[BTraceTimeSeriesPlugin shared] SaveTimeSeriesData:startEvent]; NSData *payload = [self buildRequestPayload]; NSURLSession *session = [NSURLSession sharedSession]; [[session dataTaskWithURL:[NSURL URLWithString:@"https://api.example.com/data"] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { mach_port_t tid = pthread_mach_thread_np(pthread_self()); int64_t now = (int64_t)([[NSDate date] timeIntervalSince1970] * 1e9); BTraceTimeSeriesData *endEvent = [[BTraceTimeSeriesData alloc] initWithTid:tid Timestamp:now Type:@"network" Dictionary:@{ @"url": @"https://api.example.com/data", @"status": @(((NSHTTPURLResponse *)response).statusCode), @"bytes": @(data.length), @"phase": @"end" }]; [[BTraceTimeSeriesPlugin shared] SaveTimeSeriesData:endEvent]; }] resume]; ``` ``` -------------------------------- ### Manually Capture Stack Trace in Kotlin Source: https://context7.com/bytedance/btrace/llms.txt Use RheaTrace3.captureStackTrace(force) to manually capture the current thread's call stack. Set force=false to respect the sample interval, or force=true to bypass it. This is useful for instrumenting fast or recursive methods. ```kotlin // Kotlin example: instrument a recursive fibonacci to guarantee // every call is captured even when execution is extremely fast. class App : Application() { override fun attachBaseContext(base: Context?) { super.attachBaseContext(base) RheaTrace3.init(base) } private fun fibonacci(n: Int): Int { // force=false respects the ns-level sample interval to avoid overhead RheaTrace3.captureStackTrace(false) if (n == 0) return 0 return if (n == 1) 1 else fibonacci(n - 1) + fibonacci(n - 2) } } ``` -------------------------------- ### RheaTrace3.captureStackTrace(boolean force) Source: https://context7.com/bytedance/btrace/llms.txt Manually captures the current thread's call stack and saves it into the sampling ring buffer. This is useful for instrumenting hot or recursive methods that might be missed by built-in hook points. The `force` parameter controls whether the sampling interval is respected. ```APIDOC ## RheaTrace3.captureStackTrace(boolean force) — Manual stack capture ### Description Manually captures the current thread's call stack and saves it into the sampling ring buffer. Use this inside hot or recursive methods that the built-in hook points may not cover. When `force=false` the capture respects the configured `sampleInterval`; when `force=true` the interval limit is bypassed. ### Parameters - **force** (boolean) - Required - If `true`, bypasses the configured `sampleInterval`. ### Usage Example ```kotlin // Kotlin example: instrument a recursive fibonacci to guarantee // every call is captured even when execution is extremely fast. class App : Application() { override fun attachBaseContext(base: Context?) { super.attachBaseContext(base) RheaTrace3.init(base) } private fun fibonacci(n: Int): Int { // force=false respects the ns-level sample interval to avoid overhead RheaTrace3.captureStackTrace(false) if (n == 0) return 0 return if (n == 1) 1 else fibonacci(n - 1) + fibonacci(n - 2) } } ``` ``` -------------------------------- ### Override sampling interval Source: https://context7.com/bytedance/btrace/llms.txt Overrides the sampling interval in nanoseconds by setting an Android system property. ```shell adb shell setprop debug.rhea3.sampleInterval 500000 ``` -------------------------------- ### Override wait-for-trace-data timeout Source: https://context7.com/bytedance/btrace/llms.txt Overrides the timeout for waiting for trace data in seconds by setting an Android system property. ```shell adb shell setprop debug.rhea3.waitTraceTimeout 30 ```