use tracy profiler's features

This commit is contained in:
falsycat 2022-11-20 11:37:46 +09:00
parent d33330b6c3
commit 31924ce5b2
10 changed files with 199 additions and 59 deletions

View File

@ -10,6 +10,8 @@
#include <unordered_set>
#include <vector>
#include <tracy/Tracy.hpp>
#include "common/aggregate_promise.hh"
#include "common/factory.hh"
#include "common/future.hh"
@ -61,6 +63,7 @@ nf7::Future<std::shared_ptr<Obj<Obj_BufferMeta>>> Obj_BufferMeta::Create(
const std::shared_ptr<nf7::Context>& ctx) const noexcept {
nf7::Future<std::shared_ptr<Obj<Obj_BufferMeta>>>::Promise pro {ctx};
ctx->env().ExecGL(ctx, [=, *this]() mutable {
ZoneScopedN("create buffer");
GLuint id;
glGenBuffers(1, &id);
pro.Return(std::make_shared<Obj<Obj_BufferMeta>>(ctx, id, *this));
@ -73,6 +76,8 @@ nf7::Future<std::shared_ptr<Obj<Obj_TextureMeta>>> Obj_TextureMeta::Create(
const std::shared_ptr<nf7::Context>& ctx) const noexcept {
nf7::Future<std::shared_ptr<Obj<Obj_TextureMeta>>>::Promise pro {ctx};
ctx->env().ExecGL(ctx, [=, *this]() mutable {
ZoneScopedN("create texture");
GLuint id;
glGenTextures(1, &id);
@ -108,6 +113,8 @@ nf7::Future<std::shared_ptr<Obj<Obj_ShaderMeta>>> Obj_ShaderMeta::Create(
const std::string& src) const noexcept {
nf7::Future<std::shared_ptr<Obj<Obj_ShaderMeta>>>::Promise pro {ctx};
ctx->env().ExecGL(ctx, [=, *this]() mutable {
ZoneScopedN("create shader");
const auto t = gl::ToEnum(type);
const auto id = glCreateShader(t);
if (id == 0) {
@ -119,10 +126,13 @@ nf7::Future<std::shared_ptr<Obj<Obj_ShaderMeta>>> Obj_ShaderMeta::Create(
"#version 330\n"
"#extension GL_ARB_shading_language_include: require\n";
const GLchar* str[] = {kHeader, src.c_str()};
glShaderSource(id, 2, str, nullptr);
glCompileShader(id);
assert(0 == glGetError());
{
ZoneScopedN("compile");
const GLchar* str[] = {kHeader, src.c_str()};
glShaderSource(id, 2, str, nullptr);
glCompileShader(id);
assert(0 == glGetError());
}
GLint status;
glGetShaderiv(id, GL_COMPILE_STATUS, &status);
@ -155,6 +165,8 @@ nf7::Future<std::shared_ptr<Obj<Obj_ProgramMeta>>> Obj_ProgramMeta::Create(
nf7::Future<std::shared_ptr<Obj<Obj_ProgramMeta>>>::Promise pro {ctx};
apro.future().Chain(nf7::Env::kGL, ctx, pro, [*this, ctx, shs = std::move(shs)](auto&) {
ZoneScopedN("create program");
// check all shaders
for (auto& sh : shs) { sh.value(); }
@ -168,7 +180,11 @@ nf7::Future<std::shared_ptr<Obj<Obj_ProgramMeta>>> Obj_ProgramMeta::Create(
for (auto& sh : shs) {
glAttachShader(id, (*sh.value())->id());
}
glLinkProgram(id);
{
ZoneScopedN("link");
glLinkProgram(id);
}
// check status
GLint status;
@ -222,6 +238,8 @@ try {
LockAttachments(ctx).Chain(
nf7::Env::kGL, ctx, pro,
[*this, ctx, pro](auto& bufs) mutable {
ZoneScopedN("create va");
// check all buffers
if (index) {
assert(bufs.index);
@ -340,6 +358,8 @@ nf7::Future<std::shared_ptr<Obj<Obj_FramebufferMeta>>> Obj_FramebufferMeta::Crea
nf7::Future<std::shared_ptr<Obj<Obj_FramebufferMeta>>>::Promise pro {ctx};
LockAttachments(ctx).
Chain(nf7::Env::kGL, ctx, pro, [ctx, *this](auto& k) mutable {
ZoneScopedN("create fb");
GLuint id;
glGenFramebuffers(1, &id);

View File

@ -5,6 +5,8 @@
#include <tuple>
#include <unordered_set>
#include <tracy/Tracy.hpp>
#include "common/node.hh"
#include "common/node_root_lambda.hh"
@ -53,7 +55,11 @@ void Thread::Resume(lua_State* L, int narg) noexcept {
yield_ctx_.reset();
k.unlock();
const auto ret = lua_resume(L, narg);
int ret;
{
ZoneScopedN("lua_resume");
ret = lua_resume(L, narg);
}
k.lock();
active_ = false;

View File

@ -7,6 +7,8 @@
#include <mutex>
#include <utility>
#include <tracy/Tracy.hpp>
#include "nf7.hh"
#include "common/stopwatch.hh"
@ -68,6 +70,7 @@ class Thread final : public nf7::Context,
auto self = shared_from_this();
if (!entry) {
ZoneScopedN("thread task execution");
for (nf7::Stopwatch sw; sw.dur() < kTaskDur; ++tasks_done_) {
auto t = q_.Pop();
if (!t) break;

View File

@ -5,8 +5,11 @@
#include <typeinfo>
#include <imgui.h>
#include <miniaudio.h>
#include <tracy/Tracy.hpp>
#include "nf7.hh"
#include "common/audio_queue.hh"
@ -68,6 +71,7 @@ class AudioContext::Queue final : public nf7::audio::Queue,
}
void operator()(Task&& t) {
if (!data_->broken) {
ZoneScopedN("audio task");
t(&data_->ctx);
}
}

View File

@ -7,6 +7,8 @@
#include <imgui.h>
#include <tracy/Tracy.hpp>
#include "nf7.hh"
#include "common/dir_item.hh"
@ -65,6 +67,7 @@ class FontContext::Queue final : public nf7::font::Queue,
}
void operator()(Task&& t) noexcept {
if (!data_->broken) {
ZoneScopedN("font task");
t(data_->ft);
}
}

View File

@ -15,6 +15,8 @@
#include <magic_enum.hpp>
#include <tracy/Tracy.hpp>
#include <yaml-cpp/yaml.h>
#include <yas/serialize.hpp>
@ -351,6 +353,9 @@ struct Buffer {
const auto t = gl::ToEnum(buf.meta().target);
glBindBuffer(t, buf.id());
{
ZoneScopedN("upload buffer");
ZoneValue(vec->size());
auto& size = buf.param().size;
if (size != vec->size()) {
size = vec->size();
@ -508,14 +513,16 @@ struct Texture {
glBindTexture(t, tex.id());
switch (t) {
case GL_TEXTURE_2D:
case GL_TEXTURE_RECTANGLE:
case GL_TEXTURE_RECTANGLE: {
ZoneScopedN("glTexSubImage2D");
ZoneValue(buf->size());
glTexSubImage2D(t, 0,
static_cast<GLint>(offset[0]),
static_cast<GLint>(offset[1]),
static_cast<GLsizei>(size[0]),
static_cast<GLsizei>(size[1]),
fmt, type, buf->data());
break;
} break;
default:
assert(false);
break;
@ -554,25 +561,32 @@ struct Texture {
const auto size = tex.meta().size;
const auto texel = std::accumulate(size.begin(), size.end(), 1, std::multiplies<uint32_t> {});
const auto bsize = texel*gl::GetCompCount(comp)*gl::GetByteSize(numtype);
glBufferData(GL_PIXEL_PACK_BUFFER, static_cast<GLsizeiptr>(bsize), nullptr, GL_STREAM_READ);
const auto t = gl::ToEnum(tex.meta().target);
const auto t = gl::ToEnum(tex.meta().target);
glBindTexture(t, tex.id());
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glGetTexImage(t, 0, gl::ToEnum(comp), gl::ToEnum(numtype), nullptr);
glPixelStorei(GL_PACK_ALIGNMENT, 4);
glBindTexture(t, 0);
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
assert(0 == glGetError());
{
ZoneScopedN("request to download texture");
glBufferData(GL_PIXEL_PACK_BUFFER, static_cast<GLsizeiptr>(bsize), nullptr, GL_STREAM_READ);
glBindTexture(t, tex.id());
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glGetTexImage(t, 0, gl::ToEnum(comp), gl::ToEnum(numtype), nullptr);
glPixelStorei(GL_PACK_ALIGNMENT, 4);
glBindTexture(t, 0);
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
assert(0 == glGetError());
}
nf7::gl::ExecFenceSync(p.la).ThenIf([=, &tex](auto&) {
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo);
auto buf = std::make_shared<std::vector<uint8_t>>(bsize);
const auto ptr = glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY);
std::memcpy(buf->data(), ptr, static_cast<size_t>(bsize));
glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
{
ZoneScopedN("download texture");
const auto ptr = glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY);
std::memcpy(buf->data(), ptr, static_cast<size_t>(bsize));
glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
}
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
glDeleteBuffers(1, &pbo);
@ -916,6 +930,8 @@ struct Program {
// execute drawing after successful locking
apro.future().ThenIf(nf7::Env::kGL, p.la, [=, tex_fu = std::move(tex_fu)](auto&) {
ZoneScopedN("draw");
const auto& fbo = *fbo_fu.value().first;
const auto& vao = *vao_fu.value().first;
const auto& prog = *p.obj;
@ -956,8 +972,10 @@ struct Program {
config.ApplyState();
if (vao->meta().index) {
const auto numtype = gl::ToEnum(vao->meta().index->numtype);
ZoneScopedN("glDrawElementsInstanced");
glDrawElementsInstanced(mode, count, numtype, nullptr, inst);
} else {
ZoneScopedN("glDrawArraysInstanced");
glDrawArraysInstanced(mode, 0, count, inst);
}
config.RevertState();
@ -1357,7 +1375,10 @@ struct Framebuffer {
if (p.in.name == "clear") {
(**p.obj).meta().LockAttachments(p.la).ThenIf(nf7::Env::kGL, p.la, [=](auto&) {
glBindFramebuffer(GL_FRAMEBUFFER, (**p.obj).id());
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
{
ZoneScopedN("glClear");
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
});
return true;
@ -1386,9 +1407,12 @@ struct Framebuffer {
glBindFramebuffer(GL_READ_FRAMEBUFFER, src.id());
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dst.id());
glBlitFramebuffer(rect[0], rect[1], rect[2], rect[3],
rect[4], rect[5], rect[6], rect[7],
GL_COLOR_BUFFER_BIT, GL_LINEAR);
{
ZoneScopedN("glBlitFramebuffer");
glBlitFramebuffer(rect[0], rect[1], rect[2], rect[3],
rect[4], rect[5], rect[6], rect[7],
GL_COLOR_BUFFER_BIT, GL_LINEAR);
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);

View File

@ -3,6 +3,8 @@
#include <imgui.h>
#include <lua.hpp>
#include <tracy/Tracy.hpp>
#include "nf7.hh"
#include "common/dir_item.hh"
@ -67,8 +69,12 @@ class LuaContext::Queue final : public nf7::luajit::Queue,
Runner(const std::shared_ptr<SharedData>& data) noexcept : data_(data) {
}
void operator()(Task&& t) {
t(data_->L);
{
ZoneScopedN("LuaJIT task");
t(data_->L);
}
if (data_->L) {
ZoneScopedNC("GC", tracy::Color::Gray);
lua_gc(data_->L, LUA_GCCOLLECT, 0);
}
}

View File

@ -10,6 +10,8 @@
#include <ImNodes.h>
#include <tracy/Tracy.hpp>
#include <yaml-cpp/yaml.h>
#include <yas/serialize.hpp>
@ -218,6 +220,7 @@ try {
// start the thread
ljq->Push(ctx, [ctx, ljq, th, pro, script = mem_->script](auto L) mutable {
ZoneScopedN("build function for Node");
L = th->Init(L);
if (0 == luaL_loadstring(L, script.c_str())) {
th->Resume(L, 0);

View File

@ -11,6 +11,8 @@
#include <ImNodes.h>
#include <tracy/Tracy.hpp>
#include <yaml-cpp/yaml.h>
#include <yas/serialize.hpp>
@ -141,6 +143,7 @@ class Expr::Lambda final : public nf7::Node::Lambda,
void Handle(const nf7::Node::Lambda::Msg& in) noexcept override
try {
f_.EnforceAlive();
ZoneScopedN("ExprTk");
auto& obj = f_->obj_;
if (!obj) {

136
main.cc
View File

@ -17,6 +17,8 @@
#include <imgui_impl_opengl3.h>
#include <implot.h>
#include <tracy/Tracy.hpp>
#include "nf7.hh"
#include "common/queue.hh"
@ -63,18 +65,26 @@ nf7::Queue<std::exception_ptr> panicq_;
void WorkerThread() noexcept {
[[maybe_unused]] const char kThreadId[] = "SyncWorker";
tracy::SetThreadName("SyncWorker");
std::unique_lock<std::mutex> k {cycle_mtx_};
while (alive_) {
// wait for the end of GUI update
FrameMarkStart(kThreadId);
cycle_cv_.wait(k, []() { return cycle_ != kUpdate; });
k.unlock();
// exec main tasks
for (;;) {
std::shared_lock<std::shared_mutex> sk {task_mtx_};
auto task = mainq_.Pop();
if (!task) break;
try {
ZoneScopedNC("main task", tracy::Color::Orange);
if (task->first) {
const auto str = task->first->GetDescription();
ZoneText(str.data(), str.size());
}
task->second();
} catch (nf7::Exception&) {
sk.unlock();
@ -89,6 +99,11 @@ void WorkerThread() noexcept {
const auto task = subq_.Pop();
if (!task) break;
try {
ZoneScopedNC("sub task", tracy::Color::Green);
if (task->first) {
const auto str = task->first->GetDescription();
ZoneText(str.data(), str.size());
}
task->second();
} catch (nf7::Exception&) {
sk.unlock();
@ -107,12 +122,19 @@ void WorkerThread() noexcept {
k.lock();
cycle_ = kUpdate;
cycle_cv_.notify_all();
FrameMarkEnd(kThreadId);
}
}
void AsyncThread() noexcept {
[[maybe_unused]] const char kThreadId[] = "AsyncWorker";
tracy::SetThreadName("AsyncWorker");
std::unique_lock<std::mutex> k {cycle_mtx_};
while (alive_) {
FrameMarkStart(kThreadId);
const auto until = asyncq_.next().value_or(nf7::Env::Time::max());
cycle_cv_.wait_until(k, until, []() { return !alive_ || !asyncq_.idle(); });
k.unlock();
@ -122,6 +144,11 @@ void AsyncThread() noexcept {
auto task = asyncq_.Pop();
if (!task) break;
try {
ZoneScopedNC("async task", tracy::Color::Blue);
if (task->first) {
const auto str = task->first->GetDescription();
ZoneText(str.data(), str.size());
}
task->second();
} catch (nf7::Exception&) {
sk.unlock();
@ -129,10 +156,15 @@ void AsyncThread() noexcept {
}
}
k.lock();
FrameMarkEnd(kThreadId);
}
}
void GLThread(GLFWwindow* window) noexcept {
[[maybe_unused]] const char kThreadId[] = "AsyncWorker";
tracy::SetThreadName("GLWorker");
std::unique_lock<std::mutex> k {cycle_mtx_};
// does nothing when the first cycle because the main thread is using GL context
@ -141,6 +173,8 @@ void GLThread(GLFWwindow* window) noexcept {
cycle_cv_.notify_all();
while (alive_) {
FrameMarkStart(kThreadId);
// wait for the end of GUI drawing
cycle_cv_.wait(k, []() { return cycle_ != kDraw; });
k.unlock();
@ -151,6 +185,11 @@ void GLThread(GLFWwindow* window) noexcept {
auto task = glq_.Pop();
if (!task) break;
try {
ZoneScopedNC("GL task", tracy::Color::Aqua);
if (task->first) {
const auto str = task->first->GetDescription();
ZoneText(str.data(), str.size());
}
task->second();
} catch (nf7::Exception&) {
sk.unlock();
@ -167,6 +206,8 @@ void GLThread(GLFWwindow* window) noexcept {
cycle_ = kDraw;
cycle_cv_.notify_all();
}
FrameMarkEnd(kThreadId);
}
}
@ -176,6 +217,8 @@ class Env final : public nf7::Env {
static constexpr auto kFileName = "root.nf7";
Env() noexcept : nf7::Env(std::filesystem::current_path()) {
ZoneScopedN("nf7::Env constructor");
// deserialize
if (!std::filesystem::exists(kFileName)) {
root_ = CreateRoot(*this);
@ -196,6 +239,7 @@ class Env final : public nf7::Env {
}
void TearDownRoot() noexcept {
ZoneScoped;
if (root_) {
Save();
root_->Isolate();
@ -210,17 +254,21 @@ class Env final : public nf7::Env {
bool notify = false;
switch (type) {
case kMain:
TracyMessageL("queue main task");
mainq_.Push({ctx, std::move(task)});
break;
case kSub:
TracyMessageL("queue sub task");
subq_.Push(time, {ctx, std::move(task)});
notify = true;
break;
case kAsync:
TracyMessageL("queue async task");
asyncq_.Push(time, {ctx, std::move(task)});
notify = true;
break;
case kGL:
TracyMessageL("queue gl task");
glq_.Push(time, {ctx, std::move(task)});
notify = true;
break;
@ -254,10 +302,12 @@ class Env final : public nf7::Env {
}
void Exit() noexcept override {
TracyMessageL("exit requested");
exit_requested_ = true;
}
void Save() noexcept override
try {
ZoneScoped;
nf7::Serializer::Save(*this, kFileName, root_);
} catch (nf7::Exception&) {
panicq_.Push(std::current_exception());
@ -267,6 +317,7 @@ class Env final : public nf7::Env {
}
void Update() noexcept {
ZoneScoped;
ImGui::PushID(this);
{
if (root_) {
@ -333,6 +384,8 @@ class Env final : public nf7::Env {
void UpdatePanic() noexcept {
ZoneScoped;
static std::exception_ptr ptr_;
if (!ptr_) {
if (auto ptr = panicq_.Pop()) {
@ -438,18 +491,22 @@ int main(int, char**) {
}
// main loop
[[maybe_unused]] const char kThreadId[] = "GUI";
::Env env;
glfwShowWindow(window);
while (!glfwWindowShouldClose(window) && !env.exitRequested()) {
FrameMarkStart(kThreadId);
nf7::Stopwatch sw;
// handle events
glfwPollEvents();
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
{
ZoneScopedN("handle events");
glfwPollEvents();
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
}
// sync with worker thread
// wait for sync thrad
{
cycle_ = kSyncUpdate;
std::unique_lock<std::mutex> k {cycle_mtx_};
@ -457,13 +514,15 @@ int main(int, char**) {
cycle_cv_.wait(k, []() { return cycle_ == kUpdate; });
}
// GUI update (OpenGL call is forbidden)
assert(cycle_ == kUpdate);
env.Update();
UpdatePanic();
ImGui::Render();
{
ZoneScopedN("update GUI");
assert(cycle_ == kUpdate);
env.Update();
UpdatePanic();
ImGui::Render();
}
// sync with GL thread
// wait for GL thread
{
cycle_ = kSyncDraw;
std::unique_lock<std::mutex> k {cycle_mtx_};
@ -472,15 +531,18 @@ int main(int, char**) {
}
// GUI draw (OpenGL calls occur)
assert(cycle_ == kDraw);
glfwMakeContextCurrent(window);
int w, h;
glfwGetFramebufferSize(window, &w, &h);
glViewport(0, 0, w, h);
glClear(GL_COLOR_BUFFER_BIT);
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
glfwSwapBuffers(window);
glfwMakeContextCurrent(nullptr);
{
ZoneScopedN("update display");
assert(cycle_ == kDraw);
glfwMakeContextCurrent(window);
int w, h;
glfwGetFramebufferSize(window, &w, &h);
glViewport(0, 0, w, h);
glClear(GL_COLOR_BUFFER_BIT);
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
glfwSwapBuffers(window);
glfwMakeContextCurrent(nullptr);
}
// sleep
{
@ -489,6 +551,8 @@ int main(int, char**) {
cycle_cv_.notify_all();
}
std::this_thread::sleep_for(kFrameDur - sw.dur());
FrameMarkEnd(kThreadId);
}
// sync with worker thread and tear down filesystem
@ -508,7 +572,7 @@ int main(int, char**) {
cycle_cv_.notify_all();
}
// wait for all tasks
TracyMessageL("waiting for all tasks");
for (;;) {
std::unique_lock<std::shared_mutex> sk {task_mtx_};
if (!mainq_.size() && !subq_.size() && !asyncq_.size() && !glq_.size()) {
@ -517,7 +581,7 @@ int main(int, char**) {
std::this_thread::sleep_for(30ms);
}
// exit worker and async threads
TracyMessageL("exitting SyncWorker and AsyncWorker");
{
alive_ = false;
cycle_ = kSyncUpdate;
@ -527,7 +591,7 @@ int main(int, char**) {
for (auto& th : th_async) th.join();
th_worker.join();
// exit GL thread
TracyMessageL("exitting GLWorker");
{
cycle_ = kSyncDraw;
std::unique_lock<std::mutex> k {cycle_mtx_};
@ -535,14 +599,18 @@ int main(int, char**) {
}
th_gl.join();
// tear down ImGUI
ImGui_ImplOpenGL3_Shutdown();
ImGui_ImplGlfw_Shutdown();
ImPlot::DestroyContext();
ImGui::DestroyContext();
{
ZoneScopedN("tear down everything");
// tear down display
glfwDestroyWindow(window);
glfwTerminate();
// tear down ImGUI
ImGui_ImplOpenGL3_Shutdown();
ImGui_ImplGlfw_Shutdown();
ImPlot::DestroyContext();
ImGui::DestroyContext();
// tear down display
glfwDestroyWindow(window);
glfwTerminate();
}
return 0;
}