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

封装Profile:

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<YOTO::Shader> m_FlatColorShader;YOTO::Ref<YOTO::VertexArray> m_SquareVA;YOTO::Ref<YOTO::Texture2D>m_CheckerboardTexture;struct ProfileResult {const char* Name;float Time;};std::vector<ProfileResult>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 <imgui/imgui.h>
#include <glm/gtc/matrix_transform.hpp>
//#include <Platform/OpenGL/OpenGLShader.h>
#include <glm/gtc/type_ptr.hpp>
#include<vector>
#include<chrono>
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<std::chrono::microseconds>(m_StartTimepoint).time_since_epoch().count();long long end = std::chrono::time_point_cast<std::chrono::microseconds>(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<std::chrono::steady_clock>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");//updatem_CameraController.OnUpdate(ts);}{YT_PROFILE_SCOPE("Renderer Prep");PROFILE_SCOPE("Renderer Prep");//RenderYOTO::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<YOTO::OpenGLShader>(m_FlatColorShader)->Bind();std::dynamic_pointer_cast<YOTO::OpenGLShader>(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);
}

测试: 

Profile网页可视化:

创建.h文件:

 

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

#pragma once#include "YOTO/Core/Log.h"#include <algorithm>
#include <chrono>
#include <fstream>
#include <iomanip>
#include <string>
#include <thread>
#include <mutex>
#include <sstream>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<std::chrono::microseconds>(endTimepoint).time_since_epoch() - std::chrono::time_point_cast<std::chrono::microseconds>(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<std::chrono::steady_clock> 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<N> 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<iostream>
#include<memory>
#include<utility>
#include<algorithm>
#include<functional>
#include<string>
#include<vector>
#include<unordered_map>
#include<unordered_set>
#include<sstream>
#include<array>
#include "YOTO/Core/Log.h"#include "YOTO/Debug/instrumentor.h"
#ifdef YT_PLATFORM_WINDOWS
#include<Windows.h>
#endif // YT_PLATFORM_WINDOWS

测试: 

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

拖入json文件:

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/704846.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Python 数据分析 实战案例】通过用户和订单的数据分析,制定营销策略

在互联网行业中&#xff0c;电子商务领域绝对是数据分析用途最多的地方&#xff0c;各大电商平台都依赖数据分析帮助其挖掘用户订单增长机会。比如某宝的随手买一件&#xff0c;核心思路也就是根据用户的日常浏览内容及停留时间&#xff0c;以及订单的关联度来进行推荐的。 本…

AI与大数据:智慧城市安全的护航者与变革引擎

一、引言 在数字化浪潮的席卷下&#xff0c;智慧城市正成为现代城市发展的新方向。作为城市的神经系统&#xff0c;AI与大数据的融合与应用为城市的安全与应急响应带来了革命性的变革。它们如同城市的“智慧之眼”和“聪明之脑”&#xff0c;不仅为城市管理者提供了强大的决策…

VScode连接远端服务器一直输入密码解决方法

文章目录 1 关闭远程连接2打开命令面板3 输入remote-ssh: kill vs code server on host… 1 关闭远程连接 2打开命令面板 3 输入remote-ssh: kill vs code server on host… remote-ssh: kill vs code server on host… 然后一路回车(选中出问题的主机)&#xff0c;输一遍密码…

tmux的使用方法

1. tmux的定义 我&#xff1a;什么是tmux&#xff1f; GPT&#xff1a;tmux&#xff08;terminal multiplexer&#xff09;是一个强大的终端复用器&#xff0c;它允许用户在一个终端窗口中创建、访问和控制多个会话。使用tmux&#xff0c;你可以在一个窗口中打开多个终端会话&…

SpringMVC(1)

目录 SpringMVC简介入门案例启动服务器初始化过程单次请求过程bean加载控制 PostMan请求与响应设置请求映射路径请求参数五种类型参数传递JSON数据日期类型参数传递响应 RestRest 简介RESTful快速开发 SpringMVC是隶属于Spring框架的一部分&#xff0c;主要是用来进行Web开发&a…

快速搭建宠物医院服务小程序的步骤,无需编程经验

如果你是一家宠物医院或者宠物服务机构&#xff0c;想要拥有一款方便用户预约、查询信息的小程序&#xff0c;那么乔拓云网提供的轻应用小程序是你的不二选择。下面将为你详细介绍如何轻松打造宠物医院服务小程序。 1. 进入乔拓云网后台&#xff0c;点击【轻应用小程序】中的【…

FDTD算法总结

计算电磁学(Computational Electromagnetics, CEM)是通过数值计算来研究电磁场的交叉学科。 数值求解电磁学问题的方法可以分成频域(Frequency Doamin, FD)、时域(Time Domain, TD)等两类。 频域法基于时谐微分&#xff0c;通过对多个采样值的傅里叶逆变换得到所需的脉冲响应…

代码随想录|学习工具分享

工具分享 画图 https://excalidraw.com/ 大家平时刷题可以用这个网站画草稿图帮助理解&#xff01;如果看题解很蒙或者思路不清晰的时候&#xff0c;跟着程序处理流程画一个图&#xff0c;90%的情况下都可以解决问题&#xff01; 数据结构可视化 https://www.cs.usfca.edu/…

Springboot应用执行器Actuator源码分析

文章目录 一、认识Actuator1、回顾Actuator2、Actuator重要端点 二、源码分析1、Endpoint自动装配&#xff08;1&#xff09;自动配置入口&#xff08;2&#xff09;普通Endpoint自动装配&#xff08;3&#xff09;配置Web - Endpoint&#xff08;4&#xff09;注册Endpoint为M…

vue_pdf,word,excel,pptx等文件预览

项目背景&#xff1a;vue3elementPlusvite 1.pdf 1.1 iframe预览 #toolbar0 拼接到src后&#xff0c;可隐藏iframe顶部的工具栏 <template><div class"viewPDF.vue"><uploadFile file"getFile" accept".pdf,.PDF" ></up…

redis八股

文章目录 数据类型字符串实现使用场景 List 列表实现使用场景 Hash 哈希实现使用场景 Set 集合实现使用场景 ZSet 有序集合实现使用场景 BitMap实现使用场景 Stream使用场景pubsub为什么不能作为消息队列 数据结构机制SDS 简单动态字符串压缩列表哈希表整数集合跳表quicklistli…

vue3+electron开发桌面应用,静态资源处理方式及路径问题总结

1、静态资源放到src/assets/目录下 静态资源,例如图片、静态的JSON文件、视频、CSS等等,放到src/assets目录下。 不然会很蛋疼,这个坑我踩过了。切记,切记!! 以下是CHATGPT-4 Turbo的回答: 在 Vue 应用程序中,src/assets 目录确实有特别的处理。当你使用 Vue CLI 创…

每日五道java面试题之spring篇(七)

目录&#xff1a; 第一题. 什么是Spring beans&#xff1f;第二题. 一个 Spring Bean 定义 包含什么&#xff1f;第三题. 如何给Spring 容器提供配置元数据&#xff1f;Spring有几种配置方式?第四题. Spring基于xml注入bean的几种方式?第五题&#xff1a;你怎样定义类的作用域…

【USENIX论文阅读】Day2

Birds of a Feather Flock Together: How Set Bias Helps to Deanonymize You via Revealed Intersection Sizes&#xff08;"物以类聚&#xff1a;集合偏差如何帮助去匿名化——通过揭示交集大小&#xff09; Xiaojie Guo, Ye Han, Zheli Liu, Ding Wang, Yan Jia, Jin L…

thinkphp6定时任务

这里主要是教没有用过定时任务没有头绪的朋友, 定时任务可以处理一些定时备份数据库等一系列操作, 具体根据自己的业务逻辑进行更改 直接上代码 首先, 是先在 tp 中的 command 方法中声明, 如果没有就自己新建一个, 代码如下 然后就是写你的业务逻辑 执行定时任务 方法写好了…

ConvNeXt V2:用MAE训练CNN

论文名称&#xff1a;ConvNeXt V2: Co-designing and Scaling ConvNets with Masked Autoencoders 发表时间&#xff1a;CVPR2023 code链接&#xff1a;代码 作者及组织: Sanghyun Woo&#xff0c;Shoubhik Debnath来自KAIST和Meta AI。 前言 ConvNextV2是借助MAE的思想来训练…

【PyTorch][chapter 18][李宏毅深度学习]【无监督学习][ VAE]

前言: VAE——Variational Auto-Encoder&#xff0c;变分自编码器&#xff0c;是由 Kingma 等人于 2014 年提出的基于变分贝叶斯&#xff08;Variational Bayes&#xff0c;VB&#xff09;推断的生成式网络结构。与传统的自编码器通过数值的方式描述潜在空间不同&#xff0c;它…

排序(9.17)

1.排序的概念及其运用 1.1排序的概念 排序 &#xff1a;所谓排序&#xff0c;就是使一串记录&#xff0c;按照其中的某个或某些关键字的大小&#xff0c;递增或递减的排列起来的操作。 稳定性 &#xff1a;假定在待排序的记录序列中&#xff0c;存在多个具有相同的关键字的记…

实战 vue3 使用百度编辑器ueditor

前言 在开发项目由于需求vue自带对编辑器不能满足使用&#xff0c;所以改为百度编辑器&#xff0c;但是在网上搜索发现都讲得非常乱&#xff0c;所以写一篇使用流程的文章 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、下载ueditor编辑器 一个“…

三数之和(哈希,双指针)

15. 三数之和 - 力扣&#xff08;LeetCode&#xff09; 方法1&#xff1a;哈希算法&#xff08;不推荐&#xff09; 缺点&#xff1a;时间复杂度O&#xff08;N^2&#xff09;&#xff0c;去重情况复杂 class Solution { public:vector<vector<int>> threeSum(ve…