跟着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.rhkb.cn/news/264793.html

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

相关文章

微信小程序的医院体检预约管理系统springboot+uniapp+python

本系统设计的目的是建立一个简化信息管理工作、便于操作的体检导引平台。共有以下四个模块&#xff1a; uni-app框架&#xff1a;使用Vue.js开发跨平台应用的前端框架&#xff0c;编写一套代码&#xff0c;可编译到Android、小程序等平台。 语言&#xff1a;pythonjavanode.js…

React Hooks概述及常用的React Hooks介绍

Hook可以让你在不编写class的情况下使用state以及其他React特性 useState ● useState就是一个Hook ● 通过在函数组件里调用它来给组件添加一些内部state,React会在重复渲染时保留这个state 纯函数组件没有状态&#xff0c;useState()用于设置和使用组件的状态属性。语法如下…

传统推荐算法库使用--mahout初体验

文章目录 前言环境准备调用混合总结 前言 郑重声明&#xff1a;本博文做法仅限毕设糊弄老师使用&#xff0c;不建议生产环境使用&#xff01;&#xff01;&#xff01; 老项目缝缝补补又是三年&#xff0c;本来是打算直接重写写个社区然后给毕设使用的。但是怎么说呢&#xff…

【ArcGIS】基于DEM/LUCC等数据统计得到各集水区流域特征

基于DEM/LUCC等数据统计得到各集水区流域特征 提取不同集水区各类土地利用类型比例步骤1&#xff1a;划分集水区为独立面单元步骤2&#xff1a;批量掩膜提取得到各集水区土地利用类型比例步骤3&#xff1a;导入各集水区LUCC数据并统计得到各类型占比 提取坡度特征流域面坡度河道…

现在学Oracle是49年入国军么?

今天周末&#xff0c;不聊技术&#xff0c;聊聊大家说的最多的一个话题 先说明一下&#xff0c;防止挨喷&#x1f606; 本人并不是职业dba&#xff0c;对数据库就是爱好&#xff0c;偶尔兼职&#xff0c;以下仅个人观点分析&#xff0c;如有不同观点请轻喷&#xff0c;哈哈&…

JSP实现数据传递与保存(一)

一、Web开发步骤 1.1两类模式 后端——————前端 先有前端&#xff0c;前端用的时候直接调用 后端已实现注册接口&#xff0c;接口名为doRegister.jsp 前端此时&#xff1a; 前端的form表单中的action提交地址就只能填doRegister.jsp&#xff0c;即&#xff1a; <f…

设计模式——抽象工厂模式

定义: 抽象工厂模式&#xff08;Abstract Factory Pattern&#xff09;提供一个创建一系列或相互依赖对象的接口&#xff0c;而无须指定它们具体的类。 概述:一个工厂可以提供创建多种相关产品的接口&#xff0c;而无需像工厂方法一样&#xff0c;为每一个产品都提供一个具体…

发现了一个老师都该知道的成绩发布神器!

老师们&#xff0c;你们是不是还在为每次考试后的成绩发布而烦恼&#xff1f;手动整理、逐个通知&#xff0c;简直让人头疼不已&#xff01; 想象一下&#xff0c;你只需将成绩整理成Excel表格&#xff0c;一键上传&#xff0c;立马就能生成一个专属的成绩查询小程序。是不是感…

Yolov8有效涨点:YOLOv8-AM,添加多种注意力模块提高检测精度,含代码,超详细

前言 2023 年&#xff0c;Ultralytics 推出了最新版本的 YOLO 模型。注意力机制是提高模型性能最热门的方法之一。 本次介绍的是YOLOv8-AM&#xff0c;它将注意力机制融入到原始的YOLOv8架构中。具体来说&#xff0c;我们分别采用四个注意力模块&#xff1a;卷积块注意力模块…

关于电脑功耗与电费消耗的问题,你了解多少?

一台电脑24小时运行需要多少电量&#xff1f; 大家好&#xff0c;我是一名拥有多年维修经验的上门维修师傅。 今天我就来回答大家关于电脑24小时运行需要多少电量的问题。 电脑功耗及用电量 首先我们来看看电脑的功耗情况。 普通台式电脑的功耗通常在300瓦左右&#xff0c;即…

vulnhub----hackme2-DHCP靶机

文章目录 一&#xff0c;信息收集1.网段探测2.端口扫描3.目录扫描 二&#xff0c;信息分析三&#xff0c;sql注入1.判断SQL注入2.查询显示位3.查询注入点4.查询库5.查询表6.查字段7. 查user表中的值8.登陆superadmin用户 四&#xff0c;漏洞利用文件上传命令执行蚁剑连接 五&am…

Ansible group模块 该模块主要用于添加或删除组。

目录 创建组验证删除组验证删除一个不存在的组 常用的选项如下&#xff1a; gid  #设置组的GID号 name  #指定组的名称 state  #指定组的状态&#xff0c;默认为创建&#xff0c;设置值为absent为删除 system  #设置值为yes&#xff0c;表示创建为系统组 创建组 ansib…

图扑数字孪生技术在航空航天方面的应用

"数字孪生"这一概念最早就是在航空航天领域使用&#xff0c;目的在于处理航天器的健康维护和保护问题。图扑软件依托自主研发的 HT for Web 产品&#xff0c;实现对民航机场、民航飞机、火箭发射、科技展馆的数字孪生展示。 图扑 HT 数字孪生技术助力航空航天数字孪…

nginx学习

nginx验证修改nginx.conf文件是否正确./sbin/nginx -t重启nginx./sbin/nginx -s reload一、nginx简介 1、什么是nginx&#xff0c;有什么特点&#xff1f; nginx: 是高性能的HTTP和反向代理web服务器 特点&#xff1a; 内存占有少&#xff0c;处理并发能力强。 2、正向代理…

【Go语言】Go语言中的数组

Go语言中的数组 1 数组的初始化和定义 在 Go 语言中&#xff0c;数组是固定长度的、同一类型的数据集合。数组中包含的每个数据项被称为数组元素&#xff0c;一个数组包含的元素个数被称为数组的长度。 在 Go 语言中&#xff0c;你可以通过 [] 来标识数组类型&#xff0c;但…

3D生成式AI模型与工具

当谈到技术炒作时&#xff0c;人工智能正在超越虚拟世界&#xff0c;吸引世界各地企业和消费者的注意力。 但人工智能可以进一步增强虚拟世界&#xff0c;至少在某种意义上&#xff1a;资产创造。 AI 有潜力扩大用于虚拟环境的 3D 资产的创建。 AI 3D生成使用人工智能生成3D模…

华为高级路由技术 2023-2024

2023-2024 一、2.26路由协议版本优先级和度量主和备路由最长匹配原则递归路由和默认路由 一、2.26 路由协议版本 &#xff08;1&#xff09;RIP&#xff1a; IPv4网&#xff1a;RIPv1&#xff0c;RIPv2&#xff08;v1和v2 不兼容&#xff09; IPv6网&#xff1a;RIPng(Next g…

备战蓝桥杯Day17 - 链表

链表 基本概念 链表是由一系列节点组成的元素集合。 每个节点包含两部分&#xff1a;数据域 item 、指向下一个节点的指针 next 通过节点之间的相互链接&#xff0c;形成一个链表 1. 链表的初始化 # 手动建立链表 # 链表的初始化 class Node(object):def __init__(self, …

WinForms中的Timer探究:Form Timer与Thread Timer的差异

WinForms中的Timer探究&#xff1a;Form Timer与Thread Timer的差异 在Windows Forms&#xff08;WinForms&#xff09;应用程序开发中&#xff0c;定时器&#xff08;Timer&#xff09;是一个常用的组件&#xff0c;它允许我们执行定时任务&#xff0c;如界面更新、周期性数据…

spring Boot快速入门

快速入门为主主要届介绍java web接口API的编写 java编辑器首选IntelliJ IDEA 官方链接&#xff1a;https://www.jetbrains.com/idea/ IEDA 前言 实例项目主要是web端API接口的使用&#xff0c;项目使用mysql数据库&#xff0c;把从数据库中的数据的查询出来后通过接口json数…