├── .gitingnore ├── README.md ├── README_zh.md ├── example ├── Makefile ├── README.md ├── README_zh.md └── main.cpp └── tracer.h /.gitingnore: -------------------------------------------------------------------------------- 1 | *.o 2 | example/tracer_example 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Tracer - Lightweight Performance Tracing Library 2 | 3 | [![English](https://img.shields.io/badge/language-English-blue.svg)](README.md) 4 | [![中文](https://img.shields.io/badge/language-中文-red.svg)](README_zh.md) 5 | 6 | Tracer is a header-only lightweight performance tracing library for recording and analyzing C++ program execution. It helps developers identify performance bottlenecks, analyze function execution times, and outputs results in Chrome Tracing compatible format for easy visualization. 7 | 8 | ## Features 9 | 10 | - **Easy Integration**: Just include a single header file 11 | - **Low Overhead**: Designed to minimize impact on the analyzed program 12 | - **Visualization Friendly**: Generates Chrome Tracing compatible JSON output 13 | - **Thread-Safe**: Supports multi-threaded application analysis 14 | - **Automatic Management**: Uses RAII-style C++ objects for automatic scope tracing 15 | - **Optional Compilation**: Can be completely disabled at compile time via macro definition 16 | 17 | ## Quick Start 18 | 19 | 1. Copy the `tracer.h` file to your project 20 | 2. Include the header in source files you want to trace: 21 | ```cpp 22 | #include "tracer/tracer.h" 23 | ``` 24 | 3. Use the provided macros to trace code execution: 25 | 26 | ```cpp 27 | void some_function() { 28 | TRACE_SCOPE("some_function"); // Automatically traces function scope 29 | 30 | // Function code... 31 | 32 | TRACE_INSTANT("interesting_point"); // Records an instant event 33 | 34 | // More code... 35 | } 36 | ``` 37 | 38 | 4. Save trace results at the end of your program: 39 | ```cpp 40 | TRACE_SAVE("trace_result.json"); 41 | ``` 42 | 5. View results in Chrome browser: 43 | - Open Chrome 44 | - Visit `chrome://tracing` 45 | - Click "Load" button to load the generated JSON file 46 | 47 | ## API Documentation 48 | 49 | ### Macros 50 | 51 | - `TRACE_SCOPE(name)`: Creates a scope event that automatically records entry and exit times 52 | - `TRACE_INSTANT(name)`: Records an instant event 53 | - `TRACE_DATA(p_str)`: Gets collected trace data and saves to the specified string pointer 54 | - `TRACE_SAVE(filename)`: Saves trace data to a file 55 | 56 | ### Disabling Tracing 57 | 58 | Define the `TRACE_DISABLED` macro to disable all tracing code at compile time: 59 | 60 | ```cpp 61 | #define TRACE_DISABLED 62 | #include "tracer/tracer.h" 63 | ``` 64 | 65 | Or add to your compile command: 66 | 67 | ```bash 68 | g++ -DTRACE_DISABLED ... 69 | ``` 70 | 71 | ## Examples 72 | 73 | Check out the example program in the `example` directory to see how to use Tracer in a real project: 74 | 75 | ```bash 76 | cd example 77 | make 78 | ./tracer_example 79 | ``` 80 | 81 | The `trace_result.json` file generated by the example program can be directly opened in Chrome's tracing page. 82 | 83 | ## Performance Considerations 84 | 85 | - Tracer uses a ring buffer to store events, with a default capacity of 10,000 events 86 | - When capacity is reached, new events overwrite the oldest ones 87 | - Each event includes name, timestamp, duration, thread ID, process ID, and CPU usage information 88 | - Efficient multi-threading support is implemented via thread-local storage 89 | 90 | ## License 91 | 92 | This project is released under the MIT License. See the LICENSE file for details. 93 | 94 | ## Contributing 95 | 96 | Feedback and improvements are welcome via Issues and Pull Requests. 97 | -------------------------------------------------------------------------------- /README_zh.md: -------------------------------------------------------------------------------- 1 | # Tracer - 轻量级性能跟踪库 2 | 3 | [![English](https://img.shields.io/badge/language-English-blue.svg)](README.md) 4 | [![中文](https://img.shields.io/badge/language-中文-red.svg)](README_zh.md) 5 | 6 | Tracer 是一个头文件级的轻量级性能跟踪库,用于记录和分析 C++ 程序的执行性能。它可以帮助开发者识别性能瓶颈、分析函数执行时间,并以兼容 Chrome Tracing 格式输出结果,便于可视化分析。 7 | 8 | ## 特性 9 | 10 | - **易于集成**:仅需包含单个头文件 11 | - **低开销**:设计为最小化对被分析程序的影响 12 | - **可视化友好**:生成 Chrome Tracing 兼容的 JSON 格式输出 13 | - **线程安全**:支持多线程应用程序分析 14 | - **自动管理**:使用 RAII 风格的 C++ 对象自动管理作用域跟踪 15 | - **可选编译**:可通过宏定义在编译时完全禁用 16 | 17 | ## 快速开始 18 | 19 | 1. 将 `tracer.h` 文件复制到您的项目中 20 | 2. 在需要跟踪的源文件中包含头文件: 21 | ```cpp 22 | #include "tracer/tracer.h" 23 | ``` 24 | 3. 使用提供的宏跟踪代码执行: 25 | 26 | ```cpp 27 | void some_function() { 28 | TRACE_SCOPE("some_function"); // 自动跟踪函数作用域 29 | 30 | // 函数执行代码... 31 | 32 | TRACE_INSTANT("interesting_point"); // 记录即时事件 33 | 34 | // 更多代码... 35 | } 36 | ``` 37 | 38 | 4. 程序结束时保存跟踪结果: 39 | ```cpp 40 | TRACE_SAVE("trace_result.json"); 41 | ``` 42 | 5. 在 Chrome 浏览器中查看结果: 43 | - 打开 Chrome 44 | - 访问 `chrome://tracing` 45 | - 点击 "Load" 按钮加载生成的 JSON 文件 46 | 47 | ## API 文档 48 | 49 | ### 宏定义 50 | 51 | - `TRACE_SCOPE(name)`:创建一个作用域事件,自动记录进入和退出时间 52 | - `TRACE_INSTANT(name)`:记录一个即时事件 53 | - `TRACE_DATA(p_str)`:获取已收集的跟踪数据并保存到指定字符串指针 54 | - `TRACE_SAVE(filename)`:将跟踪数据保存到文件 55 | 56 | ### 禁用跟踪 57 | 58 | 定义 `TRACE_DISABLED` 宏可以在编译时禁用所有跟踪代码: 59 | 60 | ```cpp 61 | #define TRACE_DISABLED 62 | #include "tracer/tracer.h" 63 | ``` 64 | 65 | 或在编译命令中添加: 66 | 67 | ```bash 68 | g++ -DTRACE_DISABLED ... 69 | ``` 70 | 71 | ## 示例 72 | 73 | 查看 `example` 目录中的示例程序,了解如何在实际项目中使用 Tracer: 74 | 75 | ```bash 76 | cd example 77 | make 78 | ./tracer_example 79 | ``` 80 | 81 | 示例程序生成的 `trace_result.json` 文件可以直接在 Chrome 的 tracing 页面中打开查看。 82 | 83 | ## 性能考虑 84 | 85 | - Tracer 使用环形缓冲区存储事件,默认容量为 10,000 个事件 86 | - 达到容量上限后,新事件会覆盖最旧的事件 87 | - 每个事件包含名称、时间戳、持续时间、线程 ID、进程 ID 和 CPU 使用信息 88 | - 通过线程本地存储实现高效的多线程支持 89 | 90 | ## 许可 91 | 92 | 本项目采用 MIT 许可证发布,详情请查看 LICENSE 文件。 93 | 94 | ## 贡献 95 | 96 | 欢迎通过 Issue 和 Pull Request 提供反馈和改进。 97 | -------------------------------------------------------------------------------- /example/Makefile: -------------------------------------------------------------------------------- 1 | CC := g++ 2 | CFLAGS := -std=c++11 -Wall -Wextra -pthread 3 | 4 | # 目标可执行文件 5 | TARGET := tracer_example 6 | 7 | # 源文件 8 | SRCS := main.cpp 9 | 10 | # 头文件路径 11 | INCLUDES := -I.. 12 | 13 | # 目标文件 14 | OBJS := $(SRCS:.cpp=.o) 15 | 16 | # 默认目标 17 | all: $(TARGET) 18 | 19 | # 编译规则 20 | $(TARGET): $(OBJS) 21 | $(CC) $(CFLAGS) -o $@ $^ 22 | 23 | # 编译源文件 24 | %.o: %.cpp 25 | $(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@ 26 | 27 | # 禁用跟踪的编译选项 28 | disable_trace: CFLAGS += -DTRACE_DISABLED 29 | disable_trace: clean $(TARGET) 30 | 31 | # 清理生成的文件 32 | clean: 33 | rm -f $(OBJS) $(TARGET) trace_result.json 34 | 35 | # 运行示例 36 | run: $(TARGET) 37 | ./$(TARGET) 38 | 39 | # 查看跟踪结果 40 | view: run 41 | @echo "Trace file generated: trace_result.json" 42 | @echo "Please open chrome://tracing in your browser and load the file to view results" 43 | 44 | .PHONY: all clean run view disable_trace 45 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # Tracer Example 2 | 3 | [English](#english) | [中文](#chinese) 4 | 5 | 6 | 7 | ## English 8 | 9 | # Tracer Example 10 | 11 | [![English](https://img.shields.io/badge/language-English-blue.svg)](README.md) 12 | [![中文](https://img.shields.io/badge/language-中文-red.svg)](README_zh.md) 13 | 14 | This example demonstrates how to use the Tracer library to profile and analyze the performance of a multi-threaded application. 15 | 16 | ## Overview 17 | 18 | The example program creates multiple worker threads that perform a mix of compute-intensive and I/O-bound tasks. The Tracer library is used to record various events during execution, including: 19 | 20 | - Function entry/exit times 21 | - Instant events at specific points in the code 22 | - Thread names and IDs 23 | - CPU core usage 24 | 25 | ### Building the Example 26 | 27 | To build the example, use the provided Makefile: 28 | 29 | ```bash 30 | make 31 | ``` 32 | 33 | ### Running the Example 34 | 35 | After building, run the example: 36 | 37 | ```bash 38 | ./tracer_example 39 | ``` 40 | 41 | Alternatively, you can use the run target: 42 | 43 | ```bash 44 | make run 45 | ``` 46 | 47 | The program will generate a trace file named `trace_result.json` in the current directory. 48 | 49 | ### Viewing the Results 50 | 51 | To view the trace results: 52 | 53 | 1. Open Google Chrome 54 | 2. Navigate to `chrome://tracing/` 55 | 3. Click "Load" and select the `trace_result.json` file 56 | 57 | You can also use the view target, which builds, runs and reminds you how to view the results: 58 | 59 | ```bash 60 | make view 61 | ``` 62 | 63 | You'll see a timeline visualization of all the recorded events: 64 | 65 | - Each thread appears as a separate row 66 | - Function calls are shown as colored bars, with the width representing the duration 67 | - Instant events appear as vertical markers 68 | - Hover over events to see details like CPU core used and timing information 69 | 70 | ### Understanding the Output 71 | 72 | The visualization will help you identify: 73 | 74 | - Which functions take the most time 75 | - How work is distributed across threads 76 | - When CPU vs I/O bottlenecks occur 77 | - Thread synchronization issues 78 | - CPU core migration patterns 79 | 80 | ### Modifying the Example 81 | 82 | You can experiment with the example by: 83 | 84 | - Changing the number of worker threads 85 | - Adjusting the workload parameters 86 | - Adding more `TRACE_SCOPE` and `TRACE_INSTANT` markers 87 | - Enabling/disabling tracing with the `TRACE_DISABLED` macro (use `make disable_trace` to build with tracing disabled) 88 | 89 | ## Using Tracer in Your Own Projects 90 | 91 | To use Tracer in your own projects: 92 | 93 | 1. Copy the `tracer.h` file to your project 94 | 2. Include it in your source files: `#include "tracer.h"` 95 | 3. Add `TRACE_SCOPE()` calls around functions you want to profile 96 | 4. Use `TRACE_INSTANT()` for key events 97 | 5. Call `TRACE_SAVE()` to write results to a file 98 | 99 | --- 100 | 101 | 102 | 103 | ## 中文 104 | 105 | 本示例演示如何使用 Tracer 库来分析多线程应用程序的性能。 106 | 107 | ### 概述 108 | 109 | 示例程序创建多个工作线程,执行计算密集型和 I/O 密集型任务的组合。Tracer 库用于记录执行过程中的各种事件,包括: 110 | 111 | - 函数进入/退出时间 112 | - 代码中特定点的即时事件 113 | - 线程名称和 ID 114 | - CPU 核心使用情况 115 | 116 | ### 构建示例 117 | 118 | 使用提供的 Makefile 构建示例: 119 | 120 | ```bash 121 | make 122 | ``` 123 | 124 | ### 运行示例 125 | 126 | 构建完成后,运行示例: 127 | 128 | ```bash 129 | ./tracer_example 130 | ``` 131 | 132 | 或者,您可以使用 run 目标: 133 | 134 | ```bash 135 | make run 136 | ``` 137 | 138 | 程序将在当前目录中生成名为 `trace_result.json` 139 | -------------------------------------------------------------------------------- /example/README_zh.md: -------------------------------------------------------------------------------- 1 | # Tracer 示例程序 2 | 3 | [![English](https://img.shields.io/badge/language-English-blue.svg)](README.md) 4 | [![中文](https://img.shields.io/badge/language-中文-red.svg)](README_zh.md) 5 | 6 | 本示例展示了如何使用 Tracer 库来分析多线程应用程序的性能。 7 | 8 | ## 概述 9 | 10 | 示例程序创建多个工作线程,执行计算密集型和 I/O 密集型任务的组合。Tracer 库用于记录执行过程中的各种事件,包括: 11 | 12 | - 函数进入/退出时间 13 | - 代码中特定点的即时事件 14 | - 线程名称和 ID 15 | - CPU 核心使用情况 16 | 17 | ## 构建示例 18 | 19 | 使用提供的 Makefile 构建示例: 20 | 21 | ```bash 22 | make 23 | ``` 24 | 25 | ## 运行示例 26 | 27 | 构建后,运行示例程序: 28 | 29 | ```bash 30 | ./tracer_example 31 | ``` 32 | 33 | 或者,你可以使用 run 目标: 34 | 35 | ```bash 36 | make run 37 | ``` 38 | 39 | 程序将在当前目录中生成名为 `trace_result.json` 的跟踪文件。 40 | 41 | ## 查看结果 42 | 43 | 查看跟踪结果: 44 | 45 | 1. 打开 Google Chrome 浏览器 46 | 2. 访问 `chrome://tracing/` 47 | 3. 点击 "Load" 按钮并选择 `trace_result.json` 文件 48 | 49 | 你也可以使用 view 目标,它会构建、运行程序并提醒你如何查看结果: 50 | 51 | ```bash 52 | make view 53 | ``` 54 | 55 | 你将看到所有记录事件的时间线可视化: 56 | 57 | - 每个线程显示为单独的一行 58 | - 函数调用显示为彩色条形,宽度表示持续时间 59 | - 即时事件显示为垂直标记 60 | - 鼠标悬停在事件上可查看详细信息,如使用的 CPU 核心和时间信息 61 | 62 | ## 理解输出 63 | 64 | 可视化将帮助你识别: 65 | 66 | - 哪些函数占用最多时间 67 | - 工作如何在线程间分配 68 | - CPU 与 I/O 瓶颈发生的时间 69 | - 线程同步问题 70 | - CPU 核心迁移模式 71 | 72 | ## 修改示例 73 | 74 | 你可以通过以下方式实验修改示例: 75 | 76 | - 改变工作线程数量 77 | - 调整工作负载参数 78 | - 添加更多 `TRACE_SCOPE` 和 `TRACE_INSTANT` 标记 79 | - 使用 `TRACE_DISABLED` 宏启用/禁用跟踪(使用 `make disable_trace` 构建时禁用跟踪) 80 | 81 | ## 在自己的项目中使用 Tracer 82 | 83 | 要在自己的项目中使用 Tracer: 84 | 85 | 1. 将 `tracer.h` 文件复制到你的项目中 86 | 2. 在源文件中包含它:`#include "tracer.h"` 87 | 3. 在你想要分析的函数周围添加 `TRACE_SCOPE()` 调用 88 | 4. 对关键事件使用 `TRACE_INSTANT()` 89 | 5. 调用 `TRACE_SAVE()` 将结果写入文件 90 | -------------------------------------------------------------------------------- /example/main.cpp: -------------------------------------------------------------------------------- 1 | #include "../tracer.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | // 模拟一个计算密集型任务 10 | void compute_task(int iterations) { 11 | TRACE_SCOPE("compute_task"); 12 | 13 | volatile double result = 0.0; 14 | for (int i = 0; i < iterations; ++i) { 15 | TRACE_SCOPE("compute_iteration"); 16 | 17 | // 一些计算工作 18 | for (int j = 0; j < 1000000; ++j) { 19 | result += sin(j * 0.0001) * cos(j * 0.0001); 20 | } 21 | 22 | // 记录一个即时事件 23 | if (i % 5 == 0) { 24 | TRACE_INSTANT("iteration_milestone"); 25 | } 26 | 27 | // 短暂休眠模拟 I/O 等待 28 | if (i % 3 == 0) { 29 | std::this_thread::sleep_for(std::chrono::milliseconds(10)); 30 | } 31 | } 32 | } 33 | 34 | // 模拟一个 I/O 任务 35 | void io_task(int operations) { 36 | TRACE_SCOPE("io_task"); 37 | 38 | for (int i = 0; i < operations; ++i) { 39 | TRACE_SCOPE("io_operation"); 40 | 41 | // 模拟 I/O 操作的延迟 42 | std::this_thread::sleep_for(std::chrono::milliseconds(50)); 43 | 44 | // 模拟处理 I/O 结果的一些计算 45 | volatile double result = 0.0; 46 | for (int j = 0; j < 100000; ++j) { 47 | result += sin(j * 0.001); 48 | } 49 | } 50 | } 51 | 52 | // 多线程工作函数 53 | void worker_thread(int id, int compute_iterations, int io_operations) { 54 | TRACE_SCOPE("worker_thread"); 55 | 56 | // 设置线程名称 57 | char thread_name[32]; 58 | snprintf(thread_name, sizeof(thread_name), "Worker-%d", id); 59 | pthread_setname_np(pthread_self(), thread_name); 60 | 61 | // 执行一些计算任务 62 | compute_task(compute_iterations); 63 | 64 | // 执行一些 I/O 任务 65 | io_task(io_operations); 66 | } 67 | 68 | int main() { 69 | TRACE_SCOPE("main"); 70 | 71 | std::cout << "Tracer example program starting..." << std::endl; 72 | 73 | // 创建多个工作线程 74 | std::vector threads; 75 | const int num_threads = 4; 76 | 77 | for (int i = 0; i < num_threads; ++i) { 78 | // 每个线程执行不同工作量的任务 79 | int compute_iterations = 10 + i; 80 | int io_operations = 5 + (i % 3); 81 | 82 | threads.emplace_back(worker_thread, i, compute_iterations, io_operations); 83 | 84 | // 稍微错开线程启动时间 85 | std::this_thread::sleep_for(std::chrono::milliseconds(100)); 86 | } 87 | 88 | // 主线程也做一些工作 89 | { 90 | TRACE_SCOPE("main_processing"); 91 | 92 | // 主线程执行一些操作 93 | std::cout << "Main thread processing..." << std::endl; 94 | std::this_thread::sleep_for(std::chrono::milliseconds(500)); 95 | 96 | // 添加一些即时事件 97 | TRACE_INSTANT("main_work_checkpoint"); 98 | } 99 | 100 | // 等待所有线程完成 101 | for (auto &t : threads) { 102 | t.join(); 103 | } 104 | 105 | // 保存跟踪结果到文件 106 | std::cout 107 | << "\nAll threads completed.\nSaving trace to 'trace_result.json'..." 108 | << std::endl; 109 | TRACE_SAVE("trace_result.json"); 110 | 111 | std::cout << "Example completed. Open 'trace_result.json' in " 112 | "chrome://tracing to view results." 113 | << std::endl; 114 | return 0; 115 | } 116 | -------------------------------------------------------------------------------- /tracer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #ifdef TRACE_DISABLED 15 | #define TRACE_SCOPE(name) 16 | #define TRACE_INSTANT(name) 17 | #define TRACE_DATA(p_str) 18 | #define TRACE_SAVE(filename) 19 | #else 20 | #define TRACE_SCOPE(name) TraceScopeRAII __trace_scope_raii_##__LINE__(name) 21 | #define TRACE_INSTANT(name) Tracer::instance().recordInstant(name) 22 | #define TRACE_DATA(p_str) Tracer::instance().data(p_str) 23 | #define TRACE_SAVE(filename) Tracer::instance().save(filename) 24 | #endif 25 | 26 | class Tracer { 27 | public: 28 | struct KV { 29 | std::string name; 30 | std::string value; 31 | }; 32 | struct Event { 33 | const char *name; 34 | const char *phase; 35 | uint64_t ts_us; 36 | uint64_t dur_us; 37 | uint32_t pid; 38 | uint32_t tid; 39 | uint32_t cpu[2]; 40 | std::list args; 41 | 42 | std::string toJSON() const { 43 | std::string json; 44 | json.reserve(512); 45 | auto format_str = [](const char *fmt, ...) { 46 | char buffer[128] = {0}; 47 | va_list args; 48 | va_start(args, fmt); 49 | vsnprintf(buffer, sizeof(buffer), fmt, args); 50 | va_end(args); 51 | return std::string(buffer); 52 | }; 53 | 54 | json.append( 55 | format_str(R"({"name":"%s","cat":"function","ph":"%s","ts":%lu)", 56 | name, phase, ts_us)); 57 | if (phase[0] == 'X') { 58 | json.append(format_str(R"(,"dur":%lu)", dur_us)); 59 | } 60 | json.append(format_str(R"(,"pid":%u,"tid":%u)", pid, tid)); 61 | 62 | // args 63 | std::string args_str; 64 | auto append = [&](const std::string &str) { args_str.append(str); }; 65 | append("{"); 66 | for (const auto &kv : args) { 67 | append(format_str(R"("%s":"%s",)", kv.name.c_str(), kv.value.c_str())); 68 | } 69 | append(format_str(R"("cpu": %d,)", cpu[0])); 70 | append(format_str(R"("cpu2": %d})", cpu[1])); 71 | 72 | if (!args_str.empty()) { 73 | json.append(format_str(R"(,"args":%s})", args_str.c_str())); 74 | } else { 75 | json.append("}"); 76 | } 77 | return json; 78 | } 79 | }; 80 | 81 | static constexpr size_t MAX_EVENTS = 1e4; 82 | 83 | Tracer() : write_index_(0) { events_ = new Event[MAX_EVENTS]; } 84 | 85 | ~Tracer() { delete[] events_; } 86 | 87 | static Tracer &instance() { 88 | static Tracer inst; 89 | return inst; 90 | } 91 | 92 | void recordInstant(const char *name) { 93 | registerThreadName(); 94 | Event e{name, "i", now_us(), 0, pid(), tid(), {cpu(), 0}}; 95 | pushEvent(e); 96 | } 97 | 98 | void begin(const char *name) { 99 | registerThreadName(); 100 | uint64_t ts = now_us(); 101 | ThreadLocalData &data = tls(); 102 | data.stack.push_back({name, "X", ts, 0, pid(), tid(), {cpu(), 0}}); 103 | } 104 | 105 | void end() { 106 | uint64_t ts = now_us(); 107 | ThreadLocalData &data = tls(); 108 | if (data.stack.empty()) 109 | return; 110 | Event e = data.stack.back(); 111 | data.stack.pop_back(); 112 | e.dur_us = ts - e.ts_us; 113 | e.cpu[1] = cpu(); // end cpu 114 | pushEvent(e); 115 | } 116 | 117 | void data(std::string *out) { 118 | size_t snapshot = write_index_.load(std::memory_order_acquire); 119 | size_t count = full_ ? MAX_EVENTS : snapshot; 120 | size_t start = full_ ? snapshot % MAX_EVENTS : 0; 121 | 122 | out->clear(); 123 | out->reserve(count * 512); 124 | auto append = [&](const std::string &str) { out->append(str); }; 125 | append("{\"traceEvents\":[\n"); 126 | for (size_t i = 0; i < count; ++i) { 127 | size_t idx = (start + i) % MAX_EVENTS; 128 | append(events_[idx].toJSON()); 129 | if (i != count - 1) 130 | append(","); 131 | append("\n"); 132 | } 133 | append("]}\n"); 134 | } 135 | 136 | void save(const std::string &filename) { 137 | std::ofstream out(filename); 138 | std::string str; 139 | data(&str); 140 | out << str; 141 | out.close(); 142 | } 143 | void registerThreadName() { 144 | ThreadLocalData &data = tls(); 145 | if (data.thread_metadata_registered) 146 | return; 147 | 148 | data.thread_metadata_registered = true; 149 | 150 | uint32_t thread_id = tid(); 151 | char name[32]; 152 | pthread_getname_np(pthread_self(), name, sizeof(name)); 153 | std::string thread_name(name); 154 | Event meta; 155 | meta.name = "thread_name"; 156 | meta.phase = "M"; 157 | meta.ts_us = 0; 158 | meta.dur_us = 0; 159 | meta.pid = pid(); 160 | meta.tid = thread_id; 161 | meta.args.push_back({"name", thread_name}); 162 | 163 | pushEvent(meta); 164 | } 165 | 166 | private: 167 | struct ThreadLocalData { 168 | std::vector stack; 169 | bool thread_metadata_registered = false; 170 | }; 171 | 172 | static ThreadLocalData &tls() { 173 | thread_local ThreadLocalData data; 174 | return data; 175 | } 176 | 177 | uint64_t now_us() const { 178 | auto now = std::chrono::steady_clock::now(); 179 | return std::chrono::duration_cast( 180 | now.time_since_epoch()) 181 | .count(); 182 | } 183 | uint32_t cpu() const { return static_cast(sched_getcpu()); } 184 | uint32_t tid() const { return gettid(); } 185 | uint32_t pid() const { 186 | static uint32_t cached_pid = static_cast(getpid()); 187 | return cached_pid; 188 | } 189 | void pushEvent(const Event &e) { 190 | size_t idx = write_index_.fetch_add(1, std::memory_order_relaxed); 191 | if (idx >= MAX_EVENTS) { 192 | full_ = true; 193 | if (idx % MAX_EVENTS == 0) { 194 | tls().thread_metadata_registered = false; 195 | } 196 | } 197 | events_[idx % MAX_EVENTS] = e; 198 | } 199 | 200 | std::atomic write_index_; 201 | Event *events_; 202 | bool full_; 203 | }; 204 | 205 | // RAII 范围事件 206 | class TraceScopeRAII { 207 | public: 208 | TraceScopeRAII(const char *name) { Tracer::instance().begin(name); } 209 | ~TraceScopeRAII() { Tracer::instance().end(); } 210 | }; 211 | --------------------------------------------------------------------------------