• 跟着cherno手搓游戏引擎【26】Profile和Profile网页可视化


    封装Profile:

    Sandbox2D.h:ProfileResult结构体和ProfileResult容器,存储相应的信息

    1. #pragma once
    2. #include "YOTO.h"
    3. class Sandbox2D :public YOTO::Layer
    4. {public:
    5. Sandbox2D();
    6. virtual ~Sandbox2D() = default;
    7. virtual void OnAttach()override;
    8. virtual void OnDetach()override;
    9. void OnUpdate(YOTO::Timestep ts)override;
    10. virtual void OnImGuiRender() override;
    11. void OnEvent(YOTO::Event& e)override;
    12. private:
    13. YOTO::OrthographicCameraController m_CameraController;
    14. YOTO::Ref m_FlatColorShader;
    15. YOTO::Ref m_SquareVA;
    16. YOTO::Refm_CheckerboardTexture;
    17. struct ProfileResult {
    18. const char* Name;
    19. float Time;
    20. };
    21. std::vectorm_ProfileResults;
    22. glm::vec4 m_SquareColor = { 0.2f,0.3f,0.7f,1.0f };
    23. };

     Sandbox2D.cpp:实现timer并定义PROFILE_SCOPE使用(YT_PROFILE_SCOPE为网页可视化的内容,先放到这了)

    1. #include "Sandbox2D.h"
    2. #include
    3. #include
    4. //#include
    5. #include
    6. #include
    7. #include
    8. template<typename Fn>
    9. class Timer {
    10. public:
    11. Timer(const char* name, Fn&&func)
    12. :m_Name(name),m_Func(func),m_Stopped(false)
    13. {
    14. m_StartTimepoint = std::chrono::high_resolution_clock::now();
    15. }
    16. ~Timer() {
    17. if (!m_Stopped) {
    18. Stop();
    19. }
    20. }
    21. void Stop() {
    22. auto endTimepoint= std::chrono::high_resolution_clock::now();
    23. long long start = std::chrono::time_point_cast(m_StartTimepoint).time_since_epoch().count();
    24. long long end = std::chrono::time_point_cast(endTimepoint).time_since_epoch().count();
    25. m_Stopped = true;
    26. float duration = (end - start)*0.001f;
    27. m_Func({m_Name,duration});
    28. //std::cout << "Timer:"<< m_Name << "时差:" << duration << "ms" << std::endl;
    29. }
    30. private:
    31. const char* m_Name;
    32. std::chrono::time_pointm_StartTimepoint;
    33. bool m_Stopped;
    34. Fn m_Func;
    35. };
    36. //未找到匹配的重载:auto的问题,改回原来的类型就好了
    37. #define PROFILE_SCOPE(name) Timer timer##__LINE__(name,[&](ProfileResult profileResult) {m_ProfileResults.push_back(profileResult);})
    38. Sandbox2D::Sandbox2D()
    39. :Layer("Sandbox2D"), m_CameraController(1280.0f / 720.0f, true)
    40. {
    41. }
    42. void Sandbox2D::OnAttach()
    43. {
    44. m_CheckerboardTexture = YOTO::Texture2D::Create("assets/textures/Checkerboard.png");
    45. }
    46. void Sandbox2D::OnDetach()
    47. {
    48. }
    49. void Sandbox2D::OnUpdate(YOTO::Timestep ts)
    50. {
    51. YT_PROFILE_FUNCTION();
    52. PROFILE_SCOPE("Sandbox2D::OnUpdate");
    53. {
    54. YT_PROFILE_SCOPE("CameraController::OnUpdate");
    55. PROFILE_SCOPE("CameraController::OnUpdate");
    56. //update
    57. m_CameraController.OnUpdate(ts);
    58. }
    59. {
    60. YT_PROFILE_SCOPE("Renderer Prep");
    61. PROFILE_SCOPE("Renderer Prep");
    62. //Render
    63. YOTO::RenderCommand::SetClearColor({ 0.2f, 0.2f, 0.2f, 1.0f });
    64. YOTO::RenderCommand::Clear();
    65. }
    66. {
    67. YT_PROFILE_SCOPE("Renderer Draw");
    68. PROFILE_SCOPE("Renderer Draw");
    69. YOTO::Renderer2D::BeginScene(m_CameraController.GetCamera());
    70. {
    71. static glm::mat4 scale = glm::scale(glm::mat4(1.0f), glm::vec3(0.1f));
    72. glm::vec4 redColor(0.8f, 0.3f, 0.3f, 1.0f);
    73. glm::vec4 blueColor(0.2f, 0.3f, 0.8f, 1.0f);
    74. /*std::dynamic_pointer_cast(m_FlatColorShader)->Bind();
    75. std::dynamic_pointer_cast(m_FlatColorShader)->UploadUniformFloat4("u_Color", m_SquareColor);
    76. YOTO::Renderer::Submit(m_FlatColorShader, m_SquareVA, glm::scale(glm::mat4(1.0f), glm::vec3(1.5f)));*/
    77. YOTO::Renderer2D::DrawQuad({ -1.0f,0.0f }, { 0.8f,0.8f }, { 0.8f,0.2f,0.3f,1.0f });
    78. YOTO::Renderer2D::DrawQuad({ 0.5f,-0.5f }, { 0.5f,0.75f }, { 0.2f,0.3f,0.8f,1.0f });
    79. YOTO::Renderer2D::DrawQuad({ 0.0f,0.0f,-0.1f }, { 10.0f,10.0f }, m_CheckerboardTexture);
    80. YOTO::Renderer2D::EndScene();
    81. }
    82. }
    83. }
    84. void Sandbox2D::OnImGuiRender()
    85. {
    86. ImGui::Begin("Setting");
    87. ImGui::ColorEdit4("Color", glm::value_ptr(m_SquareColor));
    88. for (auto& res : m_ProfileResults) {
    89. char lable[50];
    90. strcpy(lable, "%.3fms ");
    91. strcat(lable, res.Name);
    92. ImGui::Text(lable, res.Time);
    93. }
    94. m_ProfileResults.clear();
    95. ImGui::End();
    96. }
    97. void Sandbox2D::OnEvent(YOTO::Event& e)
    98. {
    99. m_CameraController.OnEvent(e);
    100. }

    测试: 

    Profile网页可视化:

    创建.h文件:

     

    instrumentor.h:直接粘贴全部,实现跟封装的profile类似,但是多了生成json文件的代码

    1. #pragma once
    2. #include "YOTO/Core/Log.h"
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #include
    10. #include
    11. namespace YOTO {
    12. using FloatingPointMicroseconds = std::chrono::duration<double, std::micro>;
    13. struct ProfileResult
    14. {
    15. std::string Name;
    16. FloatingPointMicroseconds Start;
    17. std::chrono::microseconds ElapsedTime;
    18. std::thread::id ThreadID;
    19. };
    20. struct InstrumentationSession
    21. {
    22. std::string Name;
    23. };
    24. class Instrumentor
    25. {
    26. public:
    27. Instrumentor(const Instrumentor&) = delete;
    28. Instrumentor(Instrumentor&&) = delete;
    29. void BeginSession(const std::string& name, const std::string& filepath = "results.json")
    30. {
    31. std::lock_guard lock(m_Mutex);
    32. if (m_CurrentSession)
    33. {
    34. // If there is already a current session, then close it before beginning new one.
    35. // Subsequent profiling output meant for the original session will end up in the
    36. // newly opened session instead. That's better than having badly formatted
    37. // profiling output.
    38. if (YOTO::Log::GetCoreLogger()) // Edge case: BeginSession() might be before Log::Init()
    39. {
    40. YT_CORE_ERROR("Instrumentor::BeginSession('{0}') when session '{1}' already open.", name, m_CurrentSession->Name);
    41. }
    42. InternalEndSession();
    43. }
    44. m_OutputStream.open(filepath);
    45. if (m_OutputStream.is_open())
    46. {
    47. m_CurrentSession = new InstrumentationSession({ name });
    48. WriteHeader();
    49. }
    50. else
    51. {
    52. if (YOTO::Log::GetCoreLogger()) // Edge case: BeginSession() might be before Log::Init()
    53. {
    54. YT_CORE_ERROR("Instrumentor could not open results file '{0}'.", filepath);
    55. }
    56. }
    57. }
    58. void EndSession()
    59. {
    60. std::lock_guard lock(m_Mutex);
    61. InternalEndSession();
    62. }
    63. void WriteProfile(const ProfileResult& result)
    64. {
    65. std::stringstream json;
    66. json << std::setprecision(3) << std::fixed;
    67. json << ",{";
    68. json << "\"cat\":\"function\",";
    69. json << "\"dur\":" << (result.ElapsedTime.count()) << ',';
    70. json << "\"name\":\"" << result.Name << "\",";
    71. json << "\"ph\":\"X\",";
    72. json << "\"pid\":0,";
    73. json << "\"tid\":" << result.ThreadID << ",";
    74. json << "\"ts\":" << result.Start.count();
    75. json << "}";
    76. std::lock_guard lock(m_Mutex);
    77. if (m_CurrentSession)
    78. {
    79. m_OutputStream << json.str();
    80. m_OutputStream.flush();
    81. }
    82. }
    83. static Instrumentor& Get()
    84. {
    85. static Instrumentor instance;
    86. return instance;
    87. }
    88. private:
    89. Instrumentor()
    90. : m_CurrentSession(nullptr)
    91. {
    92. }
    93. ~Instrumentor()
    94. {
    95. EndSession();
    96. }
    97. void WriteHeader()
    98. {
    99. m_OutputStream << "{\"otherData\": {},\"traceEvents\":[{}";
    100. m_OutputStream.flush();
    101. }
    102. void WriteFooter()
    103. {
    104. m_OutputStream << "]}";
    105. m_OutputStream.flush();
    106. }
    107. // Note: you must already own lock on m_Mutex before
    108. // calling InternalEndSession()
    109. void InternalEndSession()
    110. {
    111. if (m_CurrentSession)
    112. {
    113. WriteFooter();
    114. m_OutputStream.close();
    115. delete m_CurrentSession;
    116. m_CurrentSession = nullptr;
    117. }
    118. }
    119. private:
    120. std::mutex m_Mutex;
    121. InstrumentationSession* m_CurrentSession;
    122. std::ofstream m_OutputStream;
    123. };
    124. class InstrumentationTimer
    125. {
    126. public:
    127. InstrumentationTimer(const char* name)
    128. : m_Name(name), m_Stopped(false)
    129. {
    130. m_StartTimepoint = std::chrono::steady_clock::now();
    131. }
    132. ~InstrumentationTimer()
    133. {
    134. if (!m_Stopped)
    135. Stop();
    136. }
    137. void Stop()
    138. {
    139. auto endTimepoint = std::chrono::steady_clock::now();
    140. auto highResStart = FloatingPointMicroseconds{ m_StartTimepoint.time_since_epoch() };
    141. auto elapsedTime = std::chrono::time_point_cast(endTimepoint).time_since_epoch() - std::chrono::time_point_cast(m_StartTimepoint).time_since_epoch();
    142. Instrumentor::Get().WriteProfile({ m_Name, highResStart, elapsedTime, std::this_thread::get_id() });
    143. m_Stopped = true;
    144. }
    145. private:
    146. const char* m_Name;
    147. std::chrono::time_point m_StartTimepoint;
    148. bool m_Stopped;
    149. };
    150. namespace InstrumentorUtils {
    151. template <size_t N>
    152. struct ChangeResult
    153. {
    154. char Data[N];
    155. };
    156. template <size_t N, size_t K>
    157. constexpr auto CleanupOutputString(const char(&expr)[N], const char(&remove)[K])
    158. {
    159. ChangeResult result = {};
    160. size_t srcIndex = 0;
    161. size_t dstIndex = 0;
    162. while (srcIndex < N)
    163. {
    164. size_t matchIndex = 0;
    165. while (matchIndex < K - 1 && srcIndex + matchIndex < N - 1 && expr[srcIndex + matchIndex] == remove[matchIndex])
    166. matchIndex++;
    167. if (matchIndex == K - 1)
    168. srcIndex += matchIndex;
    169. result.Data[dstIndex++] = expr[srcIndex] == '"' ? '\'' : expr[srcIndex];
    170. srcIndex++;
    171. }
    172. return result;
    173. }
    174. }
    175. }
    176. #define YT_PROFILE 0
    177. #if YT_PROFILE
    178. // Resolve which function signature macro will be used. Note that this only
    179. // is resolved when the (pre)compiler starts, so the syntax highlighting
    180. // could mark the wrong one in your editor!
    181. #if defined(__GNUC__) || (defined(__MWERKS__) && (__MWERKS__ >= 0x3000)) || (defined(__ICC) && (__ICC >= 600)) || defined(__ghs__)
    182. #define YT_FUNC_SIG __PRETTY_FUNCTION__
    183. #elif defined(__DMC__) && (__DMC__ >= 0x810)
    184. #define YT_FUNC_SIG __PRETTY_FUNCTION__
    185. #elif (defined(__FUNCSIG__) || (_MSC_VER))
    186. #define YT_FUNC_SIG __FUNCSIG__
    187. #elif (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 600)) || (defined(__IBMCPP__) && (__IBMCPP__ >= 500))
    188. #define YT_FUNC_SIG __FUNCTION__
    189. #elif defined(__BORLANDC__) && (__BORLANDC__ >= 0x550)
    190. #define YT_FUNC_SIG __FUNC__
    191. #elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901)
    192. #define YT_FUNC_SIG __func__
    193. #elif defined(__cplusplus) && (__cplusplus >= 201103)
    194. #define YT_FUNC_SIG __func__
    195. #else
    196. #define YT_FUNC_SIG "YT_FUNC_SIG unknown!"
    197. #endif
    198. #define YT_PROFILE_BEGIN_SESSION(name, filepath) ::YOTO::Instrumentor::Get().BeginSession(name, filepath)
    199. #define YT_PROFILE_END_SESSION() ::YOTO::Instrumentor::Get().EndSession()
    200. #define YT_PROFILE_SCOPE_LINE2(name, line) constexpr auto fixedName##line = ::YOTO::InstrumentorUtils::CleanupOutputString(name, "__cdecl ");\
    201. ::YOTO::InstrumentationTimer timer##line(fixedName##line.Data)
    202. #define YT_PROFILE_SCOPE_LINE(name, line) YT_PROFILE_SCOPE_LINE2(name, line)
    203. #define YT_PROFILE_SCOPE(name) YT_PROFILE_SCOPE_LINE(name, __LINE__)
    204. #define YT_PROFILE_FUNCTION() YT_PROFILE_SCOPE(YT_FUNC_SIG)
    205. #else
    206. #define YT_PROFILE_BEGIN_SESSION(name, filepath)
    207. #define YT_PROFILE_END_SESSION()
    208. #define YT_PROFILE_SCOPE(name)
    209. #define YT_PROFILE_FUNCTION()
    210. #endif

     EntryPoint.h:使用定义

    1. #pragma once
    2. #ifdef YT_PLATFORM_WINDOWS
    3. #include "YOTO.h"
    4. void main(int argc,char** argv) {
    5. //初始化日志
    6. YOTO::Log::Init();
    7. //YT_CORE_ERROR("EntryPoint测试警告信息");
    8. //int test = 1;
    9. //YT_CLIENT_INFO("EntryPoint测试info:test={0}",test);
    10. YT_PROFILE_BEGIN_SESSION("Start","YOTOProfile-Startup.json");
    11. auto app = YOTO::CreateApplication();
    12. YT_PROFILE_END_SESSION();
    13. YT_PROFILE_BEGIN_SESSION("Runtime", "YOTOProfile-Runtime.json");
    14. app->Run();
    15. YT_PROFILE_END_SESSION();
    16. YT_PROFILE_BEGIN_SESSION("Shutdown", "YOTOProfile-Shutdown.json");
    17. delete app;
    18. YT_PROFILE_END_SESSION();
    19. }
    20. #endif

    ytpch.h:

    1. #pragma once
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #include
    10. #include
    11. #include
    12. #include
    13. #include "YOTO/Core/Log.h"
    14. #include "YOTO/Debug/instrumentor.h"
    15. #ifdef YT_PLATFORM_WINDOWS
    16. #include
    17. #endif // YT_PLATFORM_WINDOWS

    测试: 

    在谷歌浏览器输入:chrome://tracing

    拖入json文件:

    cool,虽然看不太懂,但是文件有够大(运行了几秒就2000多k,平时使用还是用自己写的封装的叭) 

  • 相关阅读:
    Android Service异常销毁处理(START_NOT_STICKY、START_STICKY和START_REDELIVER_INTENT)
    国产步进电机驱动芯片TMI8420,可pin to pin​替代DRV8825
    华为OD机试真题-最大坐标值-2023年OD统一考试(C卷)--Python--开源
    购物车——js小项目实例
    HMS Core基于地理位置请求广告,流量变现快人一步
    WSL 配置 Linux
    try - catch 语句真的会影响性能吗?
    ros中对move_base的调用
    【游戏逆向】逆向基础之发包函数和线程发包
    [iOS]-网络请求总结
  • 原文地址:https://blog.csdn.net/weixin_61943345/article/details/136304312