Sandbox2D.h:ProfileResult结构体和ProfileResult容器,存储相应的信息
- #pragma once
- #include "YOTO.h"
- class Sandbox2D :public YOTO::Layer
- {public:
- Sandbox2D();
- virtual ~Sandbox2D() = default;
- virtual void OnAttach()override;
- virtual void OnDetach()override;
-
- void OnUpdate(YOTO::Timestep ts)override;
- virtual void OnImGuiRender() override;
- void OnEvent(YOTO::Event& e)override;
- private:
- YOTO::OrthographicCameraController m_CameraController;
-
- YOTO::Ref
m_FlatColorShader; - YOTO::Ref
m_SquareVA; - YOTO::Ref
m_CheckerboardTexture; -
- struct ProfileResult {
-
- const char* Name;
- float Time;
- };
- std::vector
m_ProfileResults; - glm::vec4 m_SquareColor = { 0.2f,0.3f,0.7f,1.0f };
- };
-
Sandbox2D.cpp:实现timer并定义PROFILE_SCOPE使用(YT_PROFILE_SCOPE为网页可视化的内容,先放到这了)
- #include "Sandbox2D.h"
- #include
- #include
- //#include
- #include
- #include
- #include
- template<typename Fn>
- class Timer {
- public:
- Timer(const char* name, Fn&&func)
- :m_Name(name),m_Func(func),m_Stopped(false)
- {
- m_StartTimepoint = std::chrono::high_resolution_clock::now();
- }
- ~Timer() {
- if (!m_Stopped) {
- Stop();
- }
- }
- void Stop() {
- auto endTimepoint= std::chrono::high_resolution_clock::now();
- long long start = std::chrono::time_point_cast
(m_StartTimepoint).time_since_epoch().count(); - long long end = std::chrono::time_point_cast
(endTimepoint).time_since_epoch().count(); - m_Stopped = true;
- float duration = (end - start)*0.001f;
- m_Func({m_Name,duration});
- //std::cout << "Timer:"<< m_Name << "时差:" << duration << "ms" << std::endl;
- }
- private:
- const char* m_Name;
- std::chrono::time_point
m_StartTimepoint; - bool m_Stopped;
- Fn m_Func;
- };
- //未找到匹配的重载:auto的问题,改回原来的类型就好了
- #define PROFILE_SCOPE(name) Timer timer##__LINE__(name,[&](ProfileResult profileResult) {m_ProfileResults.push_back(profileResult);})
- Sandbox2D::Sandbox2D()
- :Layer("Sandbox2D"), m_CameraController(1280.0f / 720.0f, true)
- {
- }
- void Sandbox2D::OnAttach()
- {
- m_CheckerboardTexture = YOTO::Texture2D::Create("assets/textures/Checkerboard.png");
-
- }
- void Sandbox2D::OnDetach()
- {
- }
-
- void Sandbox2D::OnUpdate(YOTO::Timestep ts)
- {
- YT_PROFILE_FUNCTION();
- PROFILE_SCOPE("Sandbox2D::OnUpdate");
- {
- YT_PROFILE_SCOPE("CameraController::OnUpdate");
- PROFILE_SCOPE("CameraController::OnUpdate");
- //update
- m_CameraController.OnUpdate(ts);
- }
-
- {
- YT_PROFILE_SCOPE("Renderer Prep");
- PROFILE_SCOPE("Renderer Prep");
- //Render
- YOTO::RenderCommand::SetClearColor({ 0.2f, 0.2f, 0.2f, 1.0f });
- YOTO::RenderCommand::Clear();
- }
-
- {
- YT_PROFILE_SCOPE("Renderer Draw");
- PROFILE_SCOPE("Renderer Draw");
- YOTO::Renderer2D::BeginScene(m_CameraController.GetCamera());
- {
- static glm::mat4 scale = glm::scale(glm::mat4(1.0f), glm::vec3(0.1f));
- glm::vec4 redColor(0.8f, 0.3f, 0.3f, 1.0f);
- glm::vec4 blueColor(0.2f, 0.3f, 0.8f, 1.0f);
-
-
- /*std::dynamic_pointer_cast
(m_FlatColorShader)->Bind(); - std::dynamic_pointer_cast
(m_FlatColorShader)->UploadUniformFloat4("u_Color", m_SquareColor); - YOTO::Renderer::Submit(m_FlatColorShader, m_SquareVA, glm::scale(glm::mat4(1.0f), glm::vec3(1.5f)));*/
-
- YOTO::Renderer2D::DrawQuad({ -1.0f,0.0f }, { 0.8f,0.8f }, { 0.8f,0.2f,0.3f,1.0f });
- YOTO::Renderer2D::DrawQuad({ 0.5f,-0.5f }, { 0.5f,0.75f }, { 0.2f,0.3f,0.8f,1.0f });
- YOTO::Renderer2D::DrawQuad({ 0.0f,0.0f,-0.1f }, { 10.0f,10.0f }, m_CheckerboardTexture);
- YOTO::Renderer2D::EndScene();
- }
- }
-
- }
- void Sandbox2D::OnImGuiRender()
- {
- ImGui::Begin("Setting");
- ImGui::ColorEdit4("Color", glm::value_ptr(m_SquareColor));
- for (auto& res : m_ProfileResults) {
- char lable[50];
- strcpy(lable, "%.3fms ");
- strcat(lable, res.Name);
- ImGui::Text(lable, res.Time);
- }
- m_ProfileResults.clear();
- ImGui::End();
- }
-
- void Sandbox2D::OnEvent(YOTO::Event& e)
- {
- m_CameraController.OnEvent(e);
- }
创建.h文件:
instrumentor.h:直接粘贴全部,实现跟封装的profile类似,但是多了生成json文件的代码
- #pragma once
-
- #include "YOTO/Core/Log.h"
-
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
-
- namespace YOTO {
-
- using FloatingPointMicroseconds = std::chrono::duration<double, std::micro>;
-
- struct ProfileResult
- {
- std::string Name;
-
- FloatingPointMicroseconds Start;
- std::chrono::microseconds ElapsedTime;
- std::thread::id ThreadID;
- };
-
- struct InstrumentationSession
- {
- std::string Name;
- };
-
- class Instrumentor
- {
- public:
- Instrumentor(const Instrumentor&) = delete;
- Instrumentor(Instrumentor&&) = delete;
-
- void BeginSession(const std::string& name, const std::string& filepath = "results.json")
- {
- std::lock_guard lock(m_Mutex);
- if (m_CurrentSession)
- {
- // If there is already a current session, then close it before beginning new one.
- // Subsequent profiling output meant for the original session will end up in the
- // newly opened session instead. That's better than having badly formatted
- // profiling output.
- if (YOTO::Log::GetCoreLogger()) // Edge case: BeginSession() might be before Log::Init()
- {
- YT_CORE_ERROR("Instrumentor::BeginSession('{0}') when session '{1}' already open.", name, m_CurrentSession->Name);
- }
- InternalEndSession();
- }
- m_OutputStream.open(filepath);
-
- if (m_OutputStream.is_open())
- {
- m_CurrentSession = new InstrumentationSession({ name });
- WriteHeader();
- }
- else
- {
- if (YOTO::Log::GetCoreLogger()) // Edge case: BeginSession() might be before Log::Init()
- {
- YT_CORE_ERROR("Instrumentor could not open results file '{0}'.", filepath);
- }
- }
- }
-
- void EndSession()
- {
- std::lock_guard lock(m_Mutex);
- InternalEndSession();
- }
-
- void WriteProfile(const ProfileResult& result)
- {
- std::stringstream json;
-
- json << std::setprecision(3) << std::fixed;
- json << ",{";
- json << "\"cat\":\"function\",";
- json << "\"dur\":" << (result.ElapsedTime.count()) << ',';
- json << "\"name\":\"" << result.Name << "\",";
- json << "\"ph\":\"X\",";
- json << "\"pid\":0,";
- json << "\"tid\":" << result.ThreadID << ",";
- json << "\"ts\":" << result.Start.count();
- json << "}";
-
- std::lock_guard lock(m_Mutex);
- if (m_CurrentSession)
- {
- m_OutputStream << json.str();
- m_OutputStream.flush();
- }
- }
-
- static Instrumentor& Get()
- {
- static Instrumentor instance;
- return instance;
- }
- private:
- Instrumentor()
- : m_CurrentSession(nullptr)
- {
- }
-
- ~Instrumentor()
- {
- EndSession();
- }
-
- void WriteHeader()
- {
- m_OutputStream << "{\"otherData\": {},\"traceEvents\":[{}";
- m_OutputStream.flush();
- }
-
- void WriteFooter()
- {
- m_OutputStream << "]}";
- m_OutputStream.flush();
- }
-
- // Note: you must already own lock on m_Mutex before
- // calling InternalEndSession()
- void InternalEndSession()
- {
- if (m_CurrentSession)
- {
- WriteFooter();
- m_OutputStream.close();
- delete m_CurrentSession;
- m_CurrentSession = nullptr;
- }
- }
- private:
- std::mutex m_Mutex;
- InstrumentationSession* m_CurrentSession;
- std::ofstream m_OutputStream;
- };
-
- class InstrumentationTimer
- {
- public:
- InstrumentationTimer(const char* name)
- : m_Name(name), m_Stopped(false)
- {
- m_StartTimepoint = std::chrono::steady_clock::now();
- }
-
- ~InstrumentationTimer()
- {
- if (!m_Stopped)
- Stop();
- }
-
- void Stop()
- {
- auto endTimepoint = std::chrono::steady_clock::now();
- auto highResStart = FloatingPointMicroseconds{ m_StartTimepoint.time_since_epoch() };
- auto elapsedTime = std::chrono::time_point_cast
(endTimepoint).time_since_epoch() - std::chrono::time_point_cast(m_StartTimepoint).time_since_epoch(); -
- Instrumentor::Get().WriteProfile({ m_Name, highResStart, elapsedTime, std::this_thread::get_id() });
-
- m_Stopped = true;
- }
- private:
- const char* m_Name;
- std::chrono::time_point
m_StartTimepoint; - bool m_Stopped;
- };
-
- namespace InstrumentorUtils {
-
- template <size_t N>
- struct ChangeResult
- {
- char Data[N];
- };
-
- template <size_t N, size_t K>
- constexpr auto CleanupOutputString(const char(&expr)[N], const char(&remove)[K])
- {
- ChangeResult
result = {}; -
- size_t srcIndex = 0;
- size_t dstIndex = 0;
- while (srcIndex < N)
- {
- size_t matchIndex = 0;
- while (matchIndex < K - 1 && srcIndex + matchIndex < N - 1 && expr[srcIndex + matchIndex] == remove[matchIndex])
- matchIndex++;
- if (matchIndex == K - 1)
- srcIndex += matchIndex;
- result.Data[dstIndex++] = expr[srcIndex] == '"' ? '\'' : expr[srcIndex];
- srcIndex++;
- }
- return result;
- }
- }
- }
-
- #define YT_PROFILE 0
- #if YT_PROFILE
- // Resolve which function signature macro will be used. Note that this only
- // is resolved when the (pre)compiler starts, so the syntax highlighting
- // could mark the wrong one in your editor!
- #if defined(__GNUC__) || (defined(__MWERKS__) && (__MWERKS__ >= 0x3000)) || (defined(__ICC) && (__ICC >= 600)) || defined(__ghs__)
- #define YT_FUNC_SIG __PRETTY_FUNCTION__
- #elif defined(__DMC__) && (__DMC__ >= 0x810)
- #define YT_FUNC_SIG __PRETTY_FUNCTION__
- #elif (defined(__FUNCSIG__) || (_MSC_VER))
- #define YT_FUNC_SIG __FUNCSIG__
- #elif (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 600)) || (defined(__IBMCPP__) && (__IBMCPP__ >= 500))
- #define YT_FUNC_SIG __FUNCTION__
- #elif defined(__BORLANDC__) && (__BORLANDC__ >= 0x550)
- #define YT_FUNC_SIG __FUNC__
- #elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901)
- #define YT_FUNC_SIG __func__
- #elif defined(__cplusplus) && (__cplusplus >= 201103)
- #define YT_FUNC_SIG __func__
- #else
- #define YT_FUNC_SIG "YT_FUNC_SIG unknown!"
- #endif
-
- #define YT_PROFILE_BEGIN_SESSION(name, filepath) ::YOTO::Instrumentor::Get().BeginSession(name, filepath)
- #define YT_PROFILE_END_SESSION() ::YOTO::Instrumentor::Get().EndSession()
- #define YT_PROFILE_SCOPE_LINE2(name, line) constexpr auto fixedName##line = ::YOTO::InstrumentorUtils::CleanupOutputString(name, "__cdecl ");\
- ::YOTO::InstrumentationTimer timer##line(fixedName##line.Data)
- #define YT_PROFILE_SCOPE_LINE(name, line) YT_PROFILE_SCOPE_LINE2(name, line)
- #define YT_PROFILE_SCOPE(name) YT_PROFILE_SCOPE_LINE(name, __LINE__)
- #define YT_PROFILE_FUNCTION() YT_PROFILE_SCOPE(YT_FUNC_SIG)
- #else
- #define YT_PROFILE_BEGIN_SESSION(name, filepath)
- #define YT_PROFILE_END_SESSION()
- #define YT_PROFILE_SCOPE(name)
- #define YT_PROFILE_FUNCTION()
- #endif
EntryPoint.h:使用定义
- #pragma once
-
- #ifdef YT_PLATFORM_WINDOWS
-
- #include "YOTO.h"
- void main(int argc,char** argv) {
- //初始化日志
- YOTO::Log::Init();
- //YT_CORE_ERROR("EntryPoint测试警告信息");
- //int test = 1;
- //YT_CLIENT_INFO("EntryPoint测试info:test={0}",test);
- YT_PROFILE_BEGIN_SESSION("Start","YOTOProfile-Startup.json");
- auto app = YOTO::CreateApplication();
- YT_PROFILE_END_SESSION();
-
- YT_PROFILE_BEGIN_SESSION("Runtime", "YOTOProfile-Runtime.json");
- app->Run();
- YT_PROFILE_END_SESSION();
-
- YT_PROFILE_BEGIN_SESSION("Shutdown", "YOTOProfile-Shutdown.json");
- delete app;
- YT_PROFILE_END_SESSION();
- }
- #endif
ytpch.h:
- #pragma once
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include "YOTO/Core/Log.h"
-
- #include "YOTO/Debug/instrumentor.h"
- #ifdef YT_PLATFORM_WINDOWS
- #include
- #endif // YT_PLATFORM_WINDOWS
-
在谷歌浏览器输入:chrome://tracing
拖入json文件:
cool,虽然看不太懂,但是文件有够大(运行了几秒就2000多k,平时使用还是用自己写的封装的叭)