Sky天曰 发表于 2024-7-24 14:58:52

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

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

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

#include <iostream>      
#include <string>
#include <chrono>
#include <algorithm>
#include <fstream>

#include <cmath>
#include <thread>

struct ProfileResult
{
      std::string Name;
      long long Start, End;
      uint32_t ThreadID;
};

struct InstrumentationSession
{
      std::string Name;
};

struct Instrumentor
{
private:
      InstrumentationSession* m_CurrentSession;
      std::ofstream m_OutpuyStream;
      int m_ProfileCount;
public:
      Instrumentor()
                : m_CurrentSession(nullptr), m_ProfileCount(0)
      {
      }

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

      void EndSession()
      {
                WriteFooter();
                m_OutpuyStream.close();
                delete m_CurrentSession;
                m_CurrentSession = nullptr;
                m_ProfileCount = 0;
      }

      void WriteProfile(const ProfileResult& result)
      {
                if (m_ProfileCount++ > 0)
                        m_OutpuyStream << ",";

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

                m_OutpuyStream << "{";
                m_OutpuyStream << "\"cat\":\"function\",";
                m_OutpuyStream << "\"dur\":" << (result.End - result.Start) << ",";
                m_OutpuyStream << "\"name\":\"" << name << "\",";
                m_OutpuyStream << "\"ph\":\"X\",";
                m_OutpuyStream << "\"pid\":0,";
                m_OutpuyStream << "\"tid\":" << result.ThreadID << ",";
                m_OutpuyStream << "\"ts\":" << result.Start;
                m_OutpuyStream << "}";

                m_OutpuyStream.flush();
      }

      void WriteHeader()
      {
                m_OutpuyStream << "{\"otherData\": {},\"traceEvents\":[";
                m_OutpuyStream.flush();
      }

      void WriteFooter()
      {
                m_OutpuyStream << "]}";
                m_OutpuyStream.flush();
      }

      static Instrumentor& Get()
      {
                static Instrumentor* instance = new Instrumentor();
                return *instance;
      }
};

class InstrumentationTimer
{
public:
      InstrumentationTimer(const char* name)
                : m_Name(name), m_Stopped(false)
      {
                m_StartTimepoint = std::chrono::high_resolution_clock::now();
      }

      ~InstrumentationTimer()
      {
                if (!m_Stopped)
                        Stop();
      }

      void Stop()
      {
                auto endTimepoint = std::chrono::high_resolution_clock::now();

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

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

                m_Stopped = true;
      }

private:
      const char* m_Name;
      std::chrono::high_resolution_clock::time_point m_StartTimepoint; // std::chrono::high_resolution_clock::time_point | std::chrono::time_point<std::chrono::steady_clock>
      bool m_Stopped;
};

#define PROFING true

#if PROFING
#define PROFILE_SCOPE(name) InstrumentationTimer timer##__LINE__(name)
#define      PROFILE_FUNCTION() PROFILE_SCOPE(__FUNCSIG__)
#else
#define PROFILE_SCOPE(name)
#endif

namespace Benchmark {
      void PrintFunction(int value)
      {
                PROFILE_FUNCTION();

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

      void PrintFunction()
      {
                PROFILE_FUNCTION();

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

      void RunBenchmarks()
      {
                PROFILE_FUNCTION();

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

                PrintFunction(2);
                PrintFunction();
      }
}

int main()
{
      Instrumentor::Get().BeginSession("Profile");
      Benchmark::RunBenchmarks();
      Instrumentor::Get().EndSession();

      std::cin.get();
}      
还有这个生成的json文件:
{
"otherData": {},
"traceEvents": [
    {
      "cat": "function",
      "dur": 86,
      "name": "void __cdecl Benchmark::PrintFunction(int)",
      "ph": "X",
      "pid": 0,
      "tid": 3404007327,
      "ts": 14619163
    },
    {
      "cat": "function",
      "dur": 123,
      "name": "void __cdecl Benchmark::PrintFunction(void)",
      "ph": "X",
      "pid": 0,
      "tid": 3404007327,
      "ts": 14619249
    },
    {
      "cat": "function",
      "dur": 209,
      "name": "void __cdecl Benchmark::RunBenchmarks(void)",
      "ph": "X",
      "pid": 0,
      "tid": 3404007327,
      "ts": 14619163
    }
]
}

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

Sky天曰 发表于 2024-7-24 14:59:45

{:10_266:}

FishC 发表于 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 小助理,如未能正确解答您的问题,请继续追问。

Sky天曰 发表于 2024-7-24 16:15:12

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

有代码吗

FishC 发表于 2024-7-24 16:15:29

Sky天曰 发表于 2024-07-24 16:15
有代码吗

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

#include <iostream>
#include <fstream>
#include <string>
#include <chrono>
#include <mutex>

struct ProfileResult {
    std::string Name;
    long long Start, End;
    uint32_t ThreadID;
};

struct InstrumentationSession {
    std::string Name;
};

class Instrumentor {
private:
    InstrumentationSession* m_CurrentSession;
    std::ofstream m_OutputStream;
    int m_ProfileCount;
    std::mutex m_Mutex; // 用于多线程保护

public:
    Instrumentor()
      : m_CurrentSession(nullptr), m_ProfileCount(0) {}

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

    void EndSession() {
      std::lock_guard<std::mutex> lock(m_Mutex); // 保护代码块
      WriteFooter();
      m_OutputStream.close();
      delete m_CurrentSession;
      m_CurrentSession = nullptr;
      m_ProfileCount = 0;
    }

    void WriteProfile(const ProfileResult& result) {
      std::lock_guard<std::mutex> lock(m_Mutex); // 保护代码块
      if (m_ProfileCount++ > 0) {
            m_OutputStream << ",";
      }
      m_OutputStream << "{";
      m_OutputStream << "\"name\":\"" << result.Name << "\",";
      m_OutputStream << "\"cat\":\"function\",";
      m_OutputStream << "\"ph\":\"X\",";
      m_OutputStream << "\"ts\":" << result.Start << ",";
      m_OutputStream << "\"dur\":" << (result.End - result.Start) << ",";
      m_OutputStream << "\"pid\":0,";
      m_OutputStream << "\"tid\":" << result.ThreadID;
      m_OutputStream << "}";
    }

private:
    void WriteHeader() {
      m_OutputStream << "[";
    }

    void WriteFooter() {
      m_OutputStream << "]";
    }
};

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

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

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

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

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

    instrumentor.EndSession();
    return 0;
}

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

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

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

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
页: [1]
查看完整版本: 为什么chrome://tracing的两个函数重叠在一起