Skip to content

Commit

Permalink
devtools: add resource frame time warnings
Browse files Browse the repository at this point in the history
  • Loading branch information
terbium committed Apr 29, 2018
1 parent ddab32b commit 1b0e0bf
Show file tree
Hide file tree
Showing 2 changed files with 140 additions and 1 deletion.
3 changes: 2 additions & 1 deletion code/components/devtools-five/component.json
Expand Up @@ -6,7 +6,8 @@
"vendor:imgui",
"conhost",
"gta:core",
"gta:streaming"
"gta:streaming",
"citizen:resources:core"
],
"provides": []
}
138 changes: 138 additions & 0 deletions code/components/devtools-five/src/ResourceTimeWarnings.cpp
@@ -0,0 +1,138 @@
#include "StdInc.h"

#include <Resource.h>
#include <ResourceManager.h>
#include <ConsoleHost.h>

#include <imgui.h>

#include <chrono>

using namespace std::chrono_literals;

inline std::chrono::milliseconds msec()
{
return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now().time_since_epoch());
}

struct ResourceMetrics
{
std::chrono::milliseconds tickStart;

int curTickTime = 0;
std::chrono::milliseconds tickTimes[16];
};

static InitFunction initFunction([]()
{
static bool resourceTimeWarningShown;
static std::chrono::milliseconds warningLastShown;
static std::string resourceTimeWarningText;
static std::mutex mutex;

static std::unordered_map<std::string, ResourceMetrics> metrics;

fx::Resource::OnInitializeInstance.Connect([](fx::Resource* resource)
{
resource->OnStart.Connect([resource]()
{
for (auto& tt : metrics[resource->GetName()].tickTimes)
{
tt = { 0 };
}
});

resource->OnTick.Connect([resource]()
{
metrics[resource->GetName()].tickStart = msec();
}, -99999999);

resource->OnTick.Connect([resource]()
{
auto& metric = metrics[resource->GetName()];
metric.tickTimes[metric.curTickTime++] = msec() - metric.tickStart;

if (metric.curTickTime >= _countof(metric.tickTimes))
{
metric.curTickTime = 0;
}
}, 99999999);

resource->OnStop.Connect([resource]()
{
metrics.erase(resource->GetName());
});
});

fx::ResourceManager::OnInitializeInstance.Connect([](fx::ResourceManager* manager)
{
manager->OnTick.Connect([]()
{
bool showWarning = false;
std::string warningText;

for (const auto& metricPair : metrics)
{
std::chrono::milliseconds avgTickTime(0);

for (auto tickTime : metricPair.second.tickTimes)
{
avgTickTime += tickTime;
}

avgTickTime /= _countof(metricPair.second.tickTimes);

if (avgTickTime > 3ms)
{
float fpsCount = (60 - (1000.f / (16.67f + avgTickTime.count())));

showWarning = true;
warningText += fmt::sprintf("%s is taking %d ms (or -%.1f FPS @ 60 Hz)\n", metricPair.first, avgTickTime.count(), fpsCount);
}
}

if (showWarning)
{
std::unique_lock<std::mutex> lock(mutex);

resourceTimeWarningShown = true;
warningLastShown = msec();
resourceTimeWarningText = warningText;
}
else
{
resourceTimeWarningShown = false;
}
});
});

ConHost::OnShouldDrawGui.Connect([](bool* should)
{
*should = *should || ((msec() - warningLastShown) < 1s);
});

ConHost::OnDrawGui.Connect([]()
{
if ((msec() - warningLastShown) >= 1s)
{
return;
}

const float DISTANCE = 10.0f;
ImVec2 window_pos = ImVec2(ImGui::GetIO().DisplaySize.x - DISTANCE, ImGui::GetIO().DisplaySize.y - DISTANCE);
ImVec2 window_pos_pivot = ImVec2(1.0f, 1.0f);
ImGui::SetNextWindowPos(window_pos, ImGuiCond_Always, window_pos_pivot);

ImGui::SetNextWindowBgAlpha(0.3f); // Transparent background
if (ImGui::Begin("Time Warning", NULL, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav))
{
ImGui::Text("/!\\ Resource time warning");
ImGui::Separator();
ImGui::Text(resourceTimeWarningText.c_str());
ImGui::Separator();
ImGui::Text("Please contact the server owner to resolve this issue.");
ImGui::End();
}

});
});

15 comments on commit 1b0e0bf

@manups4e
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there a way to disable the message via server? my script takes only 4ms to load and i don't think it's necessary that whoever is not a developer could see this message while playing

@vecchiotom
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is, so they can tell you that your script is broken!

@vecchiotom
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and 4ms will get you around an 11 fps drop

@JakeRyan1
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix the issue and they won't see it!

@manups4e
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there is no issue.. i mean.. what issue is that the script takes 1ms more than the others to load.. if it's working?

@vecchiotom
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it isnt about load times... it's about how much time your script blocks the client's game

@manups4e
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i didn't see the gain of 11fps disabling the script.. i still get 50 fps on the game..

@manups4e
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what i mean is not that is not useful.. is only that this should be an optional setting.. if i decide to use a script that takes 4ms to load it should be my choice..

@Blumlaut
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if i decide to use a script that takes 4ms to load it should be my choice

.. what? its not related to loading, and the "fps gain" is an estimate, not a guarantee.

@manups4e
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

then of course it's your decision.. i can still disable the script it's not a problem... it is just my point of view

@vecchiotom
Copy link
Contributor

@vecchiotom vecchiotom commented on 1b0e0bf Apr 29, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, but why flood this comments section with it? if you had done some research, you'd have seen it's been said it won't be changed...

@manups4e
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you like to be close minded it's ok... i was just trying to give you an advice as a developer that's all.. sorry

@vecchiotom
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hint: there are better channels than github

@manups4e
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry i didn't know where to write instead of here and since there is not a changelog on fivem forum

@vecchiotom
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.