当前位置:   article > 正文

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

跟着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<YOTO::Shader> m_FlatColorShader;
  15. YOTO::Ref<YOTO::VertexArray> m_SquareVA;
  16. YOTO::Ref<YOTO::Texture2D>m_CheckerboardTexture;
  17. struct ProfileResult {
  18. const char* Name;
  19. float Time;
  20. };
  21. std::vector<ProfileResult>m_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 <imgui/imgui.h>
  3. #include <glm/gtc/matrix_transform.hpp>
  4. //#include <Platform/OpenGL/OpenGLShader.h>
  5. #include <glm/gtc/type_ptr.hpp>
  6. #include<vector>
  7. #include<chrono>
  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<std::chrono::microseconds>(m_StartTimepoint).time_since_epoch().count();
  24. long long end = std::chrono::time_point_cast<std::chrono::microseconds>(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_point<std::chrono::steady_clock>m_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<YOTO::OpenGLShader>(m_FlatColorShader)->Bind();
  75. std::dynamic_pointer_cast<YOTO::OpenGLShader>(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 <algorithm>
  4. #include <chrono>
  5. #include <fstream>
  6. #include <iomanip>
  7. #include <string>
  8. #include <thread>
  9. #include <mutex>
  10. #include <sstream>
  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<std::chrono::microseconds>(endTimepoint).time_since_epoch() - std::chrono::time_point_cast<std::chrono::microseconds>(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<std::chrono::steady_clock> 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<N> 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<iostream>
  3. #include<memory>
  4. #include<utility>
  5. #include<algorithm>
  6. #include<functional>
  7. #include<string>
  8. #include<vector>
  9. #include<unordered_map>
  10. #include<unordered_set>
  11. #include<sstream>
  12. #include<array>
  13. #include "YOTO/Core/Log.h"
  14. #include "YOTO/Debug/instrumentor.h"
  15. #ifdef YT_PLATFORM_WINDOWS
  16. #include<Windows.h>
  17. #endif // YT_PLATFORM_WINDOWS

测试: 

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

拖入json文件:

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/159694
推荐阅读
相关标签
  

闽ICP备14008679号