perf
This commit is contained in:
@@ -55,6 +55,12 @@ struct PerfStats
|
||||
struct FramePerfStats
|
||||
{
|
||||
uint64_t eventTicks = 0;
|
||||
uint64_t eventPumpTicks = 0;
|
||||
uint64_t eventPollTicks = 0;
|
||||
uint64_t eventProcessTicks = 0;
|
||||
uint64_t emptyPollTicks = 0;
|
||||
uint64_t maxEventPollTicks = 0;
|
||||
uint64_t maxEventProcessTicks = 0;
|
||||
uint64_t fenceWaitTicks = 0;
|
||||
uint64_t feedReadTicks = 0;
|
||||
uint64_t stageCopyTicks = 0;
|
||||
@@ -70,6 +76,18 @@ struct FramePerfStats
|
||||
uint64_t acquireTicks = 0;
|
||||
uint64_t submitPresentTicks = 0;
|
||||
uint64_t idleDelayTicks = 0;
|
||||
uint32_t events = 0;
|
||||
uint32_t windowEvents = 0;
|
||||
uint32_t resizeEvents = 0;
|
||||
uint32_t mouseMotionEvents = 0;
|
||||
uint32_t mouseButtonEvents = 0;
|
||||
uint32_t mouseWheelEvents = 0;
|
||||
uint32_t keyboardEvents = 0;
|
||||
uint32_t textEvents = 0;
|
||||
uint32_t quitEvents = 0;
|
||||
uint32_t otherEvents = 0;
|
||||
uint32_t maxPollEventType = 0;
|
||||
uint32_t maxProcessEventType = 0;
|
||||
};
|
||||
|
||||
struct FeedPerfStats
|
||||
@@ -88,6 +106,76 @@ struct FeedPerfStats
|
||||
bool hasLastGrain = false;
|
||||
};
|
||||
|
||||
static void recordEventStats(
|
||||
FramePerfStats& framePerf,
|
||||
const SDL_Event& event)
|
||||
{
|
||||
++framePerf.events;
|
||||
|
||||
if (event.type >= SDL_EVENT_WINDOW_FIRST &&
|
||||
event.type <= SDL_EVENT_WINDOW_LAST)
|
||||
{
|
||||
++framePerf.windowEvents;
|
||||
|
||||
if (event.type == SDL_EVENT_WINDOW_RESIZED ||
|
||||
event.type == SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED)
|
||||
{
|
||||
++framePerf.resizeEvents;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
switch (event.type)
|
||||
{
|
||||
case SDL_EVENT_MOUSE_MOTION:
|
||||
++framePerf.mouseMotionEvents;
|
||||
break;
|
||||
|
||||
case SDL_EVENT_MOUSE_BUTTON_DOWN:
|
||||
case SDL_EVENT_MOUSE_BUTTON_UP:
|
||||
++framePerf.mouseButtonEvents;
|
||||
break;
|
||||
|
||||
case SDL_EVENT_MOUSE_WHEEL:
|
||||
++framePerf.mouseWheelEvents;
|
||||
break;
|
||||
|
||||
case SDL_EVENT_KEY_DOWN:
|
||||
case SDL_EVENT_KEY_UP:
|
||||
++framePerf.keyboardEvents;
|
||||
break;
|
||||
|
||||
case SDL_EVENT_TEXT_EDITING:
|
||||
case SDL_EVENT_TEXT_INPUT:
|
||||
case SDL_EVENT_TEXT_EDITING_CANDIDATES:
|
||||
++framePerf.textEvents;
|
||||
break;
|
||||
|
||||
case SDL_EVENT_QUIT:
|
||||
++framePerf.quitEvents;
|
||||
break;
|
||||
|
||||
default:
|
||||
++framePerf.otherEvents;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void disableUnusedSdlEvents()
|
||||
{
|
||||
// Keep SDL's internal state updates, but avoid queuing noisy events
|
||||
// that the multiviewer does not consume. On Wayland these showed up
|
||||
// around SDL_PumpEvents() stalls during compositor/window activity.
|
||||
SDL_SetEventEnabled(SDL_EVENT_WINDOW_EXPOSED, false);
|
||||
SDL_SetEventEnabled(SDL_EVENT_WINDOW_FOCUS_GAINED, false);
|
||||
SDL_SetEventEnabled(SDL_EVENT_WINDOW_FOCUS_LOST, false);
|
||||
SDL_SetEventEnabled(SDL_EVENT_WINDOW_MOUSE_ENTER, false);
|
||||
SDL_SetEventEnabled(SDL_EVENT_WINDOW_MOUSE_LEAVE, false);
|
||||
SDL_SetEventEnabled(SDL_EVENT_MOUSE_MOTION, false);
|
||||
SDL_SetEventEnabled(SDL_EVENT_CLIPBOARD_UPDATE, false);
|
||||
}
|
||||
|
||||
struct ThreadCpuSample
|
||||
{
|
||||
uint64_t ticks = 0;
|
||||
@@ -459,6 +547,8 @@ int main(int argc, char* argv[])
|
||||
return 1;
|
||||
}
|
||||
|
||||
disableUnusedSdlEvents();
|
||||
|
||||
SDL_Window* window = SDL_CreateWindow(
|
||||
AppName,
|
||||
1280,
|
||||
@@ -1068,27 +1158,112 @@ int main(int argc, char* argv[])
|
||||
perfSectionStartTicks =
|
||||
SDL_GetPerformanceCounter();
|
||||
|
||||
while (SDL_PollEvent(&event))
|
||||
{
|
||||
ImGui_ImplSDL3_ProcessEvent(&event);
|
||||
const uint64_t pumpStartTicks =
|
||||
SDL_GetPerformanceCounter();
|
||||
|
||||
switch (event.type)
|
||||
SDL_PumpEvents();
|
||||
|
||||
if (config.logPerf)
|
||||
{
|
||||
case SDL_EVENT_QUIT:
|
||||
g_running = false;
|
||||
break;
|
||||
framePerf.eventPumpTicks +=
|
||||
SDL_GetPerformanceCounter() -
|
||||
pumpStartTicks;
|
||||
}
|
||||
}
|
||||
|
||||
case SDL_EVENT_WINDOW_RESIZED:
|
||||
case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED:
|
||||
framebufferResized = true;
|
||||
break;
|
||||
constexpr int EventBatchSize = 64;
|
||||
SDL_Event eventBatch[EventBatchSize];
|
||||
|
||||
case SDL_EVENT_KEY_DOWN:
|
||||
if (event.key.key == SDLK_ESCAPE)
|
||||
{
|
||||
g_running = false;
|
||||
while (true)
|
||||
{
|
||||
const uint64_t pollStartTicks =
|
||||
SDL_GetPerformanceCounter();
|
||||
|
||||
const int eventCount = SDL_PeepEvents(
|
||||
eventBatch,
|
||||
EventBatchSize,
|
||||
SDL_GETEVENT,
|
||||
SDL_EVENT_FIRST,
|
||||
SDL_EVENT_LAST
|
||||
);
|
||||
|
||||
if (eventCount <= 0)
|
||||
{
|
||||
if (config.logPerf)
|
||||
{
|
||||
framePerf.emptyPollTicks +=
|
||||
SDL_GetPerformanceCounter() -
|
||||
pollStartTicks;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (config.logPerf)
|
||||
{
|
||||
const uint64_t pollTicks =
|
||||
SDL_GetPerformanceCounter() -
|
||||
pollStartTicks;
|
||||
framePerf.eventPollTicks += pollTicks;
|
||||
if (pollTicks > framePerf.maxEventPollTicks)
|
||||
{
|
||||
framePerf.maxEventPollTicks = pollTicks;
|
||||
framePerf.maxPollEventType =
|
||||
static_cast<uint32_t>(
|
||||
eventBatch[0].type);
|
||||
}
|
||||
}
|
||||
|
||||
for (int eventIndex = 0;
|
||||
eventIndex < eventCount;
|
||||
++eventIndex)
|
||||
{
|
||||
event = eventBatch[eventIndex];
|
||||
|
||||
if (config.logPerf)
|
||||
{
|
||||
recordEventStats(framePerf, event);
|
||||
}
|
||||
|
||||
const uint64_t processStartTicks =
|
||||
SDL_GetPerformanceCounter();
|
||||
|
||||
ImGui_ImplSDL3_ProcessEvent(&event);
|
||||
|
||||
switch (event.type)
|
||||
{
|
||||
case SDL_EVENT_QUIT:
|
||||
g_running = false;
|
||||
break;
|
||||
|
||||
case SDL_EVENT_WINDOW_RESIZED:
|
||||
case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED:
|
||||
framebufferResized = true;
|
||||
break;
|
||||
|
||||
case SDL_EVENT_KEY_DOWN:
|
||||
if (event.key.key == SDLK_ESCAPE)
|
||||
{
|
||||
g_running = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (config.logPerf)
|
||||
{
|
||||
const uint64_t processTicks =
|
||||
SDL_GetPerformanceCounter() -
|
||||
processStartTicks;
|
||||
framePerf.eventProcessTicks += processTicks;
|
||||
if (processTicks >
|
||||
framePerf.maxEventProcessTicks)
|
||||
{
|
||||
framePerf.maxEventProcessTicks =
|
||||
processTicks;
|
||||
framePerf.maxProcessEventType =
|
||||
static_cast<uint32_t>(event.type);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1168,59 +1343,7 @@ int main(int argc, char* argv[])
|
||||
continue;
|
||||
}
|
||||
|
||||
// ---- frame timing ----
|
||||
|
||||
perfSectionStartTicks =
|
||||
SDL_GetPerformanceCounter();
|
||||
|
||||
vkWaitForFences(
|
||||
ctx.device(),
|
||||
1,
|
||||
&inFlightFence,
|
||||
VK_TRUE,
|
||||
UINT64_MAX
|
||||
);
|
||||
vkResetFences(
|
||||
ctx.device(),
|
||||
1,
|
||||
&inFlightFence
|
||||
);
|
||||
|
||||
if (config.logPerf)
|
||||
{
|
||||
const uint64_t elapsed =
|
||||
SDL_GetPerformanceCounter() -
|
||||
perfSectionStartTicks;
|
||||
perfStats.submitPresentTicks += elapsed;
|
||||
framePerf.fenceWaitTicks += elapsed;
|
||||
framePerf.submitPresentTicks += elapsed;
|
||||
}
|
||||
|
||||
++frameCounter;
|
||||
|
||||
if (config.logFps)
|
||||
{
|
||||
++framesSinceLastLog;
|
||||
Uint64 now = SDL_GetTicks();
|
||||
Uint64 elapsed = now - lastFpsLogTicks;
|
||||
|
||||
if (elapsed >= 1000)
|
||||
{
|
||||
double fps =
|
||||
static_cast<double>(
|
||||
framesSinceLastLog
|
||||
) * 1000.0 /
|
||||
static_cast<double>(elapsed);
|
||||
|
||||
std::cout << "FPS: " << fps
|
||||
<< std::endl;
|
||||
|
||||
framesSinceLastLog = 0;
|
||||
lastFpsLogTicks = now;
|
||||
}
|
||||
}
|
||||
|
||||
// ---- update feed pixels ----
|
||||
// ---- read feeds (overlap with GPU) ----
|
||||
|
||||
std::fill(
|
||||
feedUploadNeeded.begin(),
|
||||
@@ -1328,6 +1451,60 @@ int main(int argc, char* argv[])
|
||||
pendingUploadNeeded[i] = true;
|
||||
}
|
||||
|
||||
// ---- fence wait (now after CPU work) ----
|
||||
|
||||
perfSectionStartTicks =
|
||||
SDL_GetPerformanceCounter();
|
||||
|
||||
vkWaitForFences(
|
||||
ctx.device(),
|
||||
1,
|
||||
&inFlightFence,
|
||||
VK_TRUE,
|
||||
UINT64_MAX
|
||||
);
|
||||
vkResetFences(
|
||||
ctx.device(),
|
||||
1,
|
||||
&inFlightFence
|
||||
);
|
||||
|
||||
if (config.logPerf)
|
||||
{
|
||||
const uint64_t elapsed =
|
||||
SDL_GetPerformanceCounter() -
|
||||
perfSectionStartTicks;
|
||||
perfStats.submitPresentTicks += elapsed;
|
||||
framePerf.fenceWaitTicks += elapsed;
|
||||
framePerf.submitPresentTicks += elapsed;
|
||||
}
|
||||
|
||||
++frameCounter;
|
||||
|
||||
if (config.logFps)
|
||||
{
|
||||
++framesSinceLastLog;
|
||||
Uint64 now = SDL_GetTicks();
|
||||
Uint64 elapsed = now - lastFpsLogTicks;
|
||||
|
||||
if (elapsed >= 1000)
|
||||
{
|
||||
double fps =
|
||||
static_cast<double>(
|
||||
framesSinceLastLog
|
||||
) * 1000.0 /
|
||||
static_cast<double>(elapsed);
|
||||
|
||||
std::cout << "FPS: " << fps
|
||||
<< std::endl;
|
||||
|
||||
framesSinceLastLog = 0;
|
||||
lastFpsLogTicks = now;
|
||||
}
|
||||
}
|
||||
|
||||
// ---- stage uploads ----
|
||||
|
||||
const uint32_t maxV210Uploads =
|
||||
config.maxV210UploadsPerFrame == 0
|
||||
? feedCount
|
||||
@@ -1861,7 +2038,43 @@ int main(int argc, char* argv[])
|
||||
<< (currentFrameTicks * invMs)
|
||||
<< "ms event="
|
||||
<< (framePerf.eventTicks * invMs)
|
||||
<< "ms fence="
|
||||
<< "ms events="
|
||||
<< framePerf.events
|
||||
<< " pump="
|
||||
<< (framePerf.eventPumpTicks * invMs)
|
||||
<< "ms peep="
|
||||
<< (framePerf.eventPollTicks * invMs)
|
||||
<< "ms process="
|
||||
<< (framePerf.eventProcessTicks * invMs)
|
||||
<< "ms emptyPoll="
|
||||
<< (framePerf.emptyPollTicks * invMs)
|
||||
<< "ms maxPoll="
|
||||
<< (framePerf.maxEventPollTicks * invMs)
|
||||
<< "ms/type="
|
||||
<< framePerf.maxPollEventType
|
||||
<< " maxProcess="
|
||||
<< (framePerf.maxEventProcessTicks * invMs)
|
||||
<< "ms/type="
|
||||
<< framePerf.maxProcessEventType
|
||||
<< " win="
|
||||
<< framePerf.windowEvents
|
||||
<< " resize="
|
||||
<< framePerf.resizeEvents
|
||||
<< " motion="
|
||||
<< framePerf.mouseMotionEvents
|
||||
<< " button="
|
||||
<< framePerf.mouseButtonEvents
|
||||
<< " wheel="
|
||||
<< framePerf.mouseWheelEvents
|
||||
<< " key="
|
||||
<< framePerf.keyboardEvents
|
||||
<< " text="
|
||||
<< framePerf.textEvents
|
||||
<< " quit="
|
||||
<< framePerf.quitEvents
|
||||
<< " otherEvents="
|
||||
<< framePerf.otherEvents
|
||||
<< " fence="
|
||||
<< (framePerf.fenceWaitTicks * invMs)
|
||||
<< "ms feedRead="
|
||||
<< (framePerf.feedReadTicks * invMs)
|
||||
|
||||
Reference in New Issue
Block a user