鱼C论坛

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

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

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

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

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

x
为什么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

本帖被以下淘专辑推荐:

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

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


想知道小甲鱼最近在做啥?请访问 -> 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 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

有代码吗
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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


当然可以!下面是一个简化版的 `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 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-9-8 09:24

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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