adding profiler

This commit is contained in:
2024-01-10 18:32:40 +01:00
parent c3ffb80a10
commit fb6bda24a6
23 changed files with 1325 additions and 535 deletions

View File

@@ -6,7 +6,7 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/04 22:10:52 by maldavid #+# #+# */
/* Updated: 2023/12/27 21:30:10 by maldavid ### ########.fr */
/* Updated: 2024/01/10 16:44:14 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
@@ -48,6 +48,7 @@ namespace mlx::core
void* Application::newTexture(int w, int h)
{
MLX_PROFILE_FUNCTION();
#ifdef DEBUG
_textures.emplace_front().create(nullptr, w, h, VK_FORMAT_R8G8B8A8_UNORM, "__mlx_unamed_user_texture");
#else
@@ -58,12 +59,14 @@ namespace mlx::core
void* Application::newStbTexture(char* file, int* w, int* h)
{
MLX_PROFILE_FUNCTION();
_textures.emplace_front(stbTextureLoad(file, w, h));
return &_textures.front();
}
void Application::destroyTexture(void* ptr)
{
MLX_PROFILE_FUNCTION();
vkDeviceWaitIdle(Render_Core::get().getDevice().get()); // TODO : synchronize with another method than stopping all the GPU process
Texture* texture = static_cast<Texture*>(ptr);
texture->destroy();

View File

@@ -6,7 +6,7 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/04 21:49:46 by maldavid #+# #+# */
/* Updated: 2023/12/22 21:04:48 by kbz_8 ### ########.fr */
/* Updated: 2024/01/10 14:17:24 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
@@ -25,6 +25,7 @@
#include <core/graphics.h>
#include <platform/inputs.h>
#include <mlx_profile.h>
#include <core/profiler.h>
namespace mlx::core
{

View File

@@ -56,6 +56,7 @@ namespace mlx::core
void* Application::newGraphicsSuport(std::size_t w, std::size_t h, const char* title)
{
MLX_PROFILE_FUNCTION();
auto it = std::find_if(_textures.begin(), _textures.end(), [=](const Texture& texture)
{
return &texture == reinterpret_cast<Texture*>(const_cast<char*>(title));
@@ -77,24 +78,28 @@ namespace mlx::core
void Application::clearGraphicsSupport(void* win)
{
MLX_PROFILE_FUNCTION();
CHECK_WINDOW_PTR(win);
_graphics[*static_cast<int*>(win)]->clearRenderData();
}
void Application::destroyGraphicsSupport(void* win)
{
MLX_PROFILE_FUNCTION();
CHECK_WINDOW_PTR(win);
_graphics[*static_cast<int*>(win)].reset();
}
void Application::pixelPut(void* win, int x, int y, uint32_t color) const noexcept
{
MLX_PROFILE_FUNCTION();
CHECK_WINDOW_PTR(win);
_graphics[*static_cast<int*>(win)]->pixelPut(x, y, color);
}
void Application::stringPut(void* win, int x, int y, int color, char* str)
{
MLX_PROFILE_FUNCTION();
CHECK_WINDOW_PTR(win);
if(str == nullptr)
{
@@ -111,12 +116,14 @@ namespace mlx::core
void Application::loadFont(void* win, const std::filesystem::path& filepath, float scale)
{
MLX_PROFILE_FUNCTION();
CHECK_WINDOW_PTR(win);
_graphics[*static_cast<int*>(win)]->loadFont(filepath, scale);
}
void Application::texturePut(void* win, void* img, int x, int y)
{
MLX_PROFILE_FUNCTION();
CHECK_WINDOW_PTR(win);
if(img == nullptr)
{
@@ -132,6 +139,7 @@ namespace mlx::core
int Application::getTexturePixel(void* img, int x, int y)
{
MLX_PROFILE_FUNCTION();
if(img == nullptr)
{
core::error::report(e_kind::error, "wrong texture (NULL)");
@@ -148,6 +156,7 @@ namespace mlx::core
void Application::setTexturePixel(void* img, int x, int y, uint32_t color)
{
MLX_PROFILE_FUNCTION();
if(img == nullptr)
{
core::error::report(e_kind::error, "wrong texture (NULL)");

View File

@@ -6,7 +6,7 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/04/02 15:13:55 by maldavid #+# #+# */
/* Updated: 2023/12/27 21:27:48 by maldavid ### ########.fr */
/* Updated: 2024/01/10 18:23:26 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
@@ -22,6 +22,7 @@ namespace mlx
_height(h),
_id(id)
{
MLX_PROFILE_FUNCTION();
_renderer->setWindow(nullptr);
_renderer->init(render_target);
_pixel_put_pipeline.init(w, h, *_renderer);
@@ -36,6 +37,7 @@ namespace mlx
_height(h),
_id(id)
{
MLX_PROFILE_FUNCTION();
_renderer->setWindow(_window.get());
_renderer->init(nullptr);
_pixel_put_pipeline.init(w, h, *_renderer);
@@ -44,6 +46,7 @@ namespace mlx
void GraphicsSupport::render() noexcept
{
MLX_PROFILE_FUNCTION();
if(!_renderer->beginFrame())
return;
_proj = glm::ortho<float>(0, _width, 0, _height);
@@ -71,11 +74,12 @@ namespace mlx
}
_pixel_put_pipeline.present();
sets[1] = _pixel_put_pipeline.getDescriptorSet();
vkCmdBindDescriptorSets(cmd_buff, VK_PIPELINE_BIND_POINT_GRAPHICS, _renderer->getPipeline().getPipelineLayout(), 0, sets.size(), sets.data(), 0, nullptr);
_pixel_put_pipeline.render(*_renderer);
_text_put_pipeline->render(sets);
_renderer->endFrame();
for(auto& data : _textures_to_render)
@@ -94,6 +98,7 @@ namespace mlx
GraphicsSupport::~GraphicsSupport()
{
MLX_PROFILE_FUNCTION();
vkDeviceWaitIdle(Render_Core::get().getDevice().get());
_text_put_pipeline->destroy();
_pixel_put_pipeline.destroy();

View File

@@ -6,7 +6,7 @@
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/04/02 14:49:49 by maldavid #+# #+# */
/* Updated: 2024/01/07 01:27:09 by maldavid ### ########.fr */
/* Updated: 2024/01/10 14:18:48 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
@@ -27,6 +27,7 @@
#include <utils/non_copyable.h>
#include <renderer/images/texture.h>
#include <mlx_profile.h>
#include <core/profiler.h>
namespace mlx
{

View File

@@ -20,6 +20,7 @@ namespace mlx
void GraphicsSupport::clearRenderData() noexcept
{
MLX_PROFILE_FUNCTION();
_textures_to_render.clear();
_pixel_put_pipeline.clear();
_text_put_pipeline->clear();
@@ -27,16 +28,19 @@ namespace mlx
void GraphicsSupport::pixelPut(int x, int y, uint32_t color) noexcept
{
MLX_PROFILE_FUNCTION();
_pixel_put_pipeline.setPixel(x, y, color);
}
void GraphicsSupport::stringPut(int x, int y, int color, std::string str)
{
MLX_PROFILE_FUNCTION();
_text_put_pipeline->put(x, y, color, str);
}
void GraphicsSupport::texturePut(Texture* texture, int x, int y)
{
MLX_PROFILE_FUNCTION();
_textures_to_render.emplace_back(texture, x, y);
auto it = std::find(_textures_to_render.begin(), _textures_to_render.end() - 1, _textures_to_render.back());
if(it != _textures_to_render.end() - 1)
@@ -45,6 +49,7 @@ namespace mlx
void GraphicsSupport::loadFont(const std::filesystem::path& filepath, float scale)
{
MLX_PROFILE_FUNCTION();
_text_put_pipeline->loadFont(filepath, scale);
}
}

79
src/core/profiler.cpp git.filemode.normal_file
View File

@@ -0,0 +1,79 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* profiler.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/01/10 13:56:21 by maldavid #+# #+# */
/* Updated: 2024/01/10 18:17:35 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
#include <core/profiler.h>
#include <core/errors.h>
#include <iostream>
namespace mlx
{
void Profiler::beginRuntimeSession()
{
std::lock_guard lock(_mutex);
if(_runtime_session_began)
return;
_output_stream.open("./runtime_profile.mlx.json", std::ofstream::out | std::ofstream::trunc);
if(_output_stream.is_open())
writeHeader();
else
core::error::report(e_kind::error, "Profiler : cannot open runtime profile file");
_runtime_session_began = true;
}
void Profiler::appendProfileData(ProfileResult&& result)
{
std::lock_guard lock(_mutex);
auto it = _profile_data.find(result.name);
if(it != _profile_data.end())
{
result.elapsed_time = (result.elapsed_time + it->second.second.elapsed_time) / it->second.first;
_profile_data[result.name].first++;
_profile_data[result.name].second = result;
}
else
_profile_data[result.name] = std::make_pair(1, result);
}
void Profiler::writeProfile(const ProfileResult& result)
{
std::stringstream json;
json << std::setprecision(9) << std::fixed;
json << ",\n{\n";
json << "\t\"type\" : \"function\"," << '\n';
json << "\t\"name\" : \"" << result.name << "\"," << '\n';
json << "\t\"thread id\" : " << result.thread_id << "," << '\n';
json << "\t\"average duration\" : \"" << result.elapsed_time.count() << "ms\"\n";
json << "}";
_output_stream << json.str();
}
void Profiler::endRuntimeSession()
{
std::lock_guard lock(_mutex);
if(!_runtime_session_began)
return;
for(auto& [_, pair] : _profile_data)
writeProfile(pair.second);
writeFooter();
_output_stream.close();
_profile_data.clear();
_runtime_session_began = false;
}
Profiler::~Profiler()
{
if(!_runtime_session_began)
return;
endRuntimeSession();
}
}

146
src/core/profiler.h git.filemode.normal_file
View File

@@ -0,0 +1,146 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* profiler.h :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/01/10 13:35:45 by maldavid #+# #+# */
/* Updated: 2024/01/10 18:16:47 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
#ifndef __MLX_PROFILER__
#define __MLX_PROFILER__
#include <utils/singleton.h>
#include <mlx_profile.h>
#include <chrono>
#include <string>
#include <thread>
#include <mutex>
#include <sstream>
#include <fstream>
#include <iomanip>
#include <unordered_map>
namespace mlx
{
using FloatingPointMilliseconds = std::chrono::duration<double, std::milli>;
struct ProfileResult
{
std::string name;
FloatingPointMilliseconds elapsed_time;
std::thread::id thread_id;
};
class Profiler : public Singleton<Profiler>
{
friend class Singleton;
public:
Profiler(const Profiler&) = delete;
Profiler(Profiler&&) = delete;
void appendProfileData(ProfileResult&& result);
private:
Profiler() { beginRuntimeSession(); }
~Profiler();
void beginRuntimeSession();
void writeProfile(const ProfileResult& result);
void endRuntimeSession();
inline void writeHeader()
{
_output_stream << "{\"profileData\":[{}";
_output_stream.flush();
}
inline void writeFooter()
{
_output_stream << "]}";
_output_stream.flush();
}
private:
std::unordered_map<std::string, std::pair<std::size_t, ProfileResult>> _profile_data;
std::ofstream _output_stream;
std::mutex _mutex;
bool _runtime_session_began = false;
};
class ProfilerTimer
{
public:
ProfilerTimer(const char* name) : _name(name)
{
_start_timepoint = std::chrono::steady_clock::now();
}
inline void stop()
{
auto end_timepoint = std::chrono::steady_clock::now();
auto high_res_start = FloatingPointMilliseconds{ _start_timepoint.time_since_epoch() };
auto elapsed_time = std::chrono::time_point_cast<std::chrono::milliseconds>(end_timepoint).time_since_epoch() - std::chrono::time_point_cast<std::chrono::milliseconds>(_start_timepoint).time_since_epoch();
Profiler::get().appendProfileData({ _name, elapsed_time, std::this_thread::get_id() });
_stopped = true;
}
~ProfilerTimer()
{
if(!_stopped)
stop();
}
private:
std::chrono::time_point<std::chrono::steady_clock> _start_timepoint;
const char* _name;
bool _stopped = false;
};
namespace ProfilerUtils
{
template <std::size_t N>
struct ChangeResult
{
char data[N];
};
template <std::size_t N, std::size_t K>
constexpr auto cleanupOutputString(const char(&expr)[N], const char(&remove)[K])
{
ChangeResult<N> result = {};
std::size_t srcIndex = 0;
std::size_t dstIndex = 0;
while(srcIndex < N)
{
std::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;
}
}
}
#ifdef PROFILER
#define MLX_PROFILE_SCOPE_LINE2(name, line) constexpr auto fixedName##line = ::mlx::ProfilerUtils::cleanupOutputString(name, "__cdecl ");\
::mlx::ProfilerTimer timer##line(fixedName##line.data)
#define MLX_PROFILE_SCOPE_LINE(name, line) MLX_PROFILE_SCOPE_LINE2(name, line)
#define MLX_PROFILE_SCOPE(name) MLX_PROFILE_SCOPE_LINE(name, __LINE__)
#define MLX_PROFILE_FUNCTION() MLX_PROFILE_SCOPE(MLX_FUNC_SIG)
#else
#define MLX_PROFILE_SCOPE(name)
#define MLX_PROFILE_FUNCTION()
#endif
#endif