鱼C论坛

 找回密码
 立即注册
查看: 1281|回复: 4

为什么chrome://tracing的两个函数重叠在一起

[复制链接]
发表于 2024-7-24 14:58:52 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
为什么chrome://tracing的两个函数重叠在一起,有没有大佬帮我看看

代码如下:
  1. // #include "HeaderFolder\Timer.h"

  2. #include <iostream>        
  3. #include <string>
  4. #include <chrono>
  5. #include <algorithm>
  6. #include <fstream>

  7. #include <cmath>
  8. #include <thread>

  9. struct ProfileResult
  10. {
  11.         std::string Name;
  12.         long long Start, End;
  13.         uint32_t ThreadID;
  14. };

  15. struct InstrumentationSession
  16. {
  17.         std::string Name;
  18. };

  19. struct Instrumentor
  20. {
  21. private:
  22.         InstrumentationSession* m_CurrentSession;
  23.         std::ofstream m_OutpuyStream;
  24.         int m_ProfileCount;
  25. public:
  26.         Instrumentor()
  27.                 : m_CurrentSession(nullptr), m_ProfileCount(0)
  28.         {
  29.         }

  30.         void BeginSession(const std::string& name, const std::string& filepath = "results.json")
  31.         {
  32.                 m_OutpuyStream.open(filepath);
  33.                 WriteHeader();
  34.                 m_CurrentSession = new InstrumentationSession{ name };
  35.         }

  36.         void EndSession()
  37.         {
  38.                 WriteFooter();
  39.                 m_OutpuyStream.close();
  40.                 delete m_CurrentSession;
  41.                 m_CurrentSession = nullptr;
  42.                 m_ProfileCount = 0;
  43.         }

  44.         void WriteProfile(const ProfileResult& result)
  45.         {
  46.                 if (m_ProfileCount++ > 0)
  47.                         m_OutpuyStream << ",";

  48.                 std::string name = result.Name;
  49.                 std::replace(name.begin(), name.end(), '"', '\'');

  50.                 m_OutpuyStream << "{";
  51.                 m_OutpuyStream << ""cat":"function",";
  52.                 m_OutpuyStream << ""dur":" << (result.End - result.Start) << ",";
  53.                 m_OutpuyStream << ""name":"" << name << "",";
  54.                 m_OutpuyStream << ""ph":"X",";
  55.                 m_OutpuyStream << ""pid":0,";
  56.                 m_OutpuyStream << ""tid":" << result.ThreadID << ",";
  57.                 m_OutpuyStream << ""ts":" << result.Start;
  58.                 m_OutpuyStream << "}";

  59.                 m_OutpuyStream.flush();
  60.         }

  61.         void WriteHeader()
  62.         {
  63.                 m_OutpuyStream << "{"otherData": {},"traceEvents":[";
  64.                 m_OutpuyStream.flush();
  65.         }

  66.         void WriteFooter()
  67.         {
  68.                 m_OutpuyStream << "]}";
  69.                 m_OutpuyStream.flush();
  70.         }

  71.         static Instrumentor& Get()
  72.         {
  73.                 static Instrumentor* instance = new Instrumentor();
  74.                 return *instance;
  75.         }
  76. };

  77. class InstrumentationTimer
  78. {
  79. public:
  80.         InstrumentationTimer(const char* name)
  81.                 : m_Name(name), m_Stopped(false)
  82.         {
  83.                 m_StartTimepoint = std::chrono::high_resolution_clock::now();
  84.         }

  85.         ~InstrumentationTimer()
  86.         {
  87.                 if (!m_Stopped)
  88.                         Stop();
  89.         }

  90.         void Stop()
  91.         {
  92.                 auto endTimepoint = std::chrono::high_resolution_clock::now();

  93.                 long long start = std::chrono::time_point_cast<std::chrono::milliseconds>(m_StartTimepoint).time_since_epoch().count();
  94.                 long long end = std::chrono::time_point_cast<std::chrono::milliseconds>(endTimepoint).time_since_epoch().count();

  95.                 uint32_t threadID = std::hash<std::thread::id>{}(std::this_thread::get_id());
  96.                 Instrumentor::Get().WriteProfile({ m_Name, start, end, threadID });

  97.                 m_Stopped = true;
  98.         }

  99. private:
  100.         const char* m_Name;
  101.         std::chrono::high_resolution_clock::time_point m_StartTimepoint; // std::chrono::high_resolution_clock::time_point | std::chrono::time_point<std::chrono::steady_clock>
  102.         bool m_Stopped;
  103. };

  104. #define PROFING true

  105. #if PROFING
  106. #define PROFILE_SCOPE(name) InstrumentationTimer timer##__LINE__(name)
  107. #define        PROFILE_FUNCTION() PROFILE_SCOPE(__FUNCSIG__)
  108. #else
  109. #define PROFILE_SCOPE(name)
  110. #endif

  111. namespace Benchmark {
  112.         void PrintFunction(int value)
  113.         {
  114.                 PROFILE_FUNCTION();

  115.                 for (int i = 0; i < 1000; i++)
  116.                         std::cout << "Hello World! #" << (i + value) << std::endl;
  117.         }

  118.         void PrintFunction()
  119.         {
  120.                 PROFILE_FUNCTION();

  121.                 for (int i = 0; i < 1000; i++)
  122.                         std::cout << "Hello World! #" << sqrt(i) << std::endl;
  123.         }

  124.         void RunBenchmarks()
  125.         {
  126.                 PROFILE_FUNCTION();

  127.                 std::cout << "Running Banchmarks...\n";

  128.                 PrintFunction(2);
  129.                 PrintFunction();
  130.         }
  131. }

  132. int main()
  133. {
  134.         Instrumentor::Get().BeginSession("Profile");
  135.         Benchmark::RunBenchmarks();
  136.         Instrumentor::Get().EndSession();

  137.         std::cin.get();
  138. }        
复制代码
还有这个生成的json文件:
  1. {
  2.   "otherData": {},
  3.   "traceEvents": [
  4.     {
  5.       "cat": "function",
  6.       "dur": 86,
  7.       "name": "void __cdecl Benchmark::PrintFunction(int)",
  8.       "ph": "X",
  9.       "pid": 0,
  10.       "tid": 3404007327,
  11.       "ts": 14619163
  12.     },
  13.     {
  14.       "cat": "function",
  15.       "dur": 123,
  16.       "name": "void __cdecl Benchmark::PrintFunction(void)",
  17.       "ph": "X",
  18.       "pid": 0,
  19.       "tid": 3404007327,
  20.       "ts": 14619249
  21.     },
  22.     {
  23.       "cat": "function",
  24.       "dur": 209,
  25.       "name": "void __cdecl Benchmark::RunBenchmarks(void)",
  26.       "ph": "X",
  27.       "pid": 0,
  28.       "tid": 3404007327,
  29.       "ts": 14619163
  30.     }
  31.   ]
  32. }
复制代码

这个json文件中有两个的“ts”时一样的!!!
怎么解决这个问题?急!
file:///D:/lixxl/Pictures/Screenshots/Screenshot%202024-07-24%20145010.png

本帖被以下淘专辑推荐:

小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2024-7-24 14:59:45 | 显示全部楼层


小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2024-7-24 15:02:06 | 显示全部楼层
首先,欢迎来到鱼油的编程小课堂!我们今天要聊聊在 `chrome://tracing` 中看到的函数重叠现象。这就像糖果铺里你一不小心把两个糖捏在一起了,结果吃起来怪怪的。

根据你提供的代码,描述了一个简单的性能分析工具。对`ProfileResult`结构体来说,每次测量的开始和结束时间是关键。问题可能出现在以下几个方面:

1. **时间戳不准确**:如果计算开始 (`Start`) 和结束 (`End`) 时间的代码逻辑有问题,比如调用顺序错误或者没有正确记录时间,就会导致多个函数的时间戳重叠。

2. **没有足够的分隔**:如果在记录每个函数执行的过程时,没有为每个函数创建单独的 `ProfileResult` 实例,可能会将多个函数的执行结果写到同一个记录中,从而在最终输出时导致重叠。

3. **并发执行**:如果你的函数是多线程执行的,而你没有为每个线程的执行结果设置适当的锁或管理机制,这样多个线程的执行记录可能会交错在一起,表现为重叠。

4. **WriteProfile方法缺失**:你提供的代码片段在 `WriteProfile` 方法的实现上似乎没完整展示,确保这个方法能够正确地将每个函数的执行信息写入输出流中。如果这里没搞清楚,重叠问题就会出现。

修复这个问题的建议:
- 确保你在记录 `Start` 和 `End` 时使用的是准确的时间获取方法(比如用高精度计时器)。
- 确保每个测量都生成新的 `ProfileResult`,并且在写入时做好数据管理。
- 如果涉及多线程,看看是否需要加锁来防止数据竞争。

总之,要想在 `chrome://tracing` 中看到无重叠的函数表现,就像想要在糖果铺里找到完好无损的糖果,一定要注意细节哦!希望这些小建议能帮助到你,如果还有问题,随时问我!

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-7-24 16:15:12 | 显示全部楼层
FishC 发表于 2024-7-24 15:02
首先,欢迎来到鱼油的编程小课堂!我们今天要聊聊在 `chrome://tracing` 中看到的函数重叠现象。这就像糖果 ...

有代码吗
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-7-24 16:15:29 | 显示全部楼层


当然可以!下面是一个简化版的 `InstrumentationSession` 和 `Instrumentor` 的代码示例,加入了一些细节以帮助你避免函数重叠的问题。我们还补充了 `WriteProfile` 的完整实现和线程安全性考虑。

  1. #include <iostream>
  2. #include <fstream>
  3. #include <string>
  4. #include <chrono>
  5. #include <mutex>

  6. struct ProfileResult {
  7.     std::string Name;
  8.     long long Start, End;
  9.     uint32_t ThreadID;
  10. };

  11. struct InstrumentationSession {
  12.     std::string Name;
  13. };

  14. class Instrumentor {
  15. private:
  16.     InstrumentationSession* m_CurrentSession;
  17.     std::ofstream m_OutputStream;
  18.     int m_ProfileCount;
  19.     std::mutex m_Mutex; // 用于多线程保护

  20. public:
  21.     Instrumentor()
  22.         : m_CurrentSession(nullptr), m_ProfileCount(0) {}

  23.     void BeginSession(const std::string& name, const std::string& filepath = "results.json") {
  24.         std::lock_guard<std::mutex> lock(m_Mutex); // 保护代码块
  25.         m_OutputStream.open(filepath);
  26.         WriteHeader();
  27.         m_CurrentSession = new InstrumentationSession{ name };
  28.     }

  29.     void EndSession() {
  30.         std::lock_guard<std::mutex> lock(m_Mutex); // 保护代码块
  31.         WriteFooter();
  32.         m_OutputStream.close();
  33.         delete m_CurrentSession;
  34.         m_CurrentSession = nullptr;
  35.         m_ProfileCount = 0;
  36.     }

  37.     void WriteProfile(const ProfileResult& result) {
  38.         std::lock_guard<std::mutex> lock(m_Mutex); // 保护代码块
  39.         if (m_ProfileCount++ > 0) {
  40.             m_OutputStream << ",";
  41.         }
  42.         m_OutputStream << "{";
  43.         m_OutputStream << ""name":"" << result.Name << "",";
  44.         m_OutputStream << ""cat":"function",";
  45.         m_OutputStream << ""ph":"X",";
  46.         m_OutputStream << ""ts":" << result.Start << ",";
  47.         m_OutputStream << ""dur":" << (result.End - result.Start) << ",";
  48.         m_OutputStream << ""pid":0,";
  49.         m_OutputStream << ""tid":" << result.ThreadID;
  50.         m_OutputStream << "}";
  51.     }

  52. private:
  53.     void WriteHeader() {
  54.         m_OutputStream << "[";
  55.     }

  56.     void WriteFooter() {
  57.         m_OutputStream << "]";
  58.     }
  59. };

  60. // 使用示例
  61. void FunctionToProfile(Instrumentor& instrumentor) {
  62.     auto start = std::chrono::high_resolution_clock::now();
  63.    
  64.     // 假设这里是要测量的代码
  65.     std::this_thread::sleep_for(std::chrono::milliseconds(100));

  66.     auto end = std::chrono::high_resolution_clock::now();
  67.     long long startTime = std::chrono::duration_cast<std::chrono::microseconds>(start.time_since_epoch()).count();
  68.     long long endTime = std::chrono::duration_cast<std::chrono::microseconds>(end.time_since_epoch()).count();

  69.     instrumentor.WriteProfile({ "FunctionToProfile", startTime, endTime, std::this_thread::get_id() });
  70. }

  71. int main() {
  72.     Instrumentor instrumentor;
  73.     instrumentor.BeginSession("Profile Session");

  74.     // 这里可以启动多个线程来测试
  75.     FunctionToProfile(instrumentor);

  76.     instrumentor.EndSession();
  77.     return 0;
  78. }
复制代码


### 代码解释:
1. **多线程保护**:用 `std::mutex` 来确保在多线程环境下写入文件时不会发生数据竞争。
2. **时间戳的获取**:使用高分辨率时钟捕获开始和结束时间,并计算出持续时间,以防止函数重叠。
3. **`WriteProfile` 方法**:正确地格式化每个函数的执行结果并写入输出流,这将有助于降低输出重叠的风险。

在实际应用中,确保你调用 `BeginSession` 和 `EndSession` 的时候要匹配,并在它们之间的代码段使用 `WriteProfile` 来记录各个函数的执行情况。

希望这个代码示例能帮助你清晰地理解如何避免函数重叠问题!如果还有疑问,随时问我!

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-6-7 11:43

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表