Benchmark mode with csv output

refs #269
This commit is contained in:
saschawillems 2017-07-29 19:31:00 +02:00
parent 8d158bbff5
commit b2136e639f
2 changed files with 126 additions and 101 deletions

View file

@ -39,9 +39,9 @@ VkResult VulkanExampleBase::createInstance(bool enableValidation)
#elif defined(__linux__) #elif defined(__linux__)
instanceExtensions.push_back(VK_KHR_XCB_SURFACE_EXTENSION_NAME); instanceExtensions.push_back(VK_KHR_XCB_SURFACE_EXTENSION_NAME);
#elif defined(VK_USE_PLATFORM_IOS_MVK) #elif defined(VK_USE_PLATFORM_IOS_MVK)
instanceExtensions.push_back(VK_MVK_IOS_SURFACE_EXTENSION_NAME); instanceExtensions.push_back(VK_MVK_IOS_SURFACE_EXTENSION_NAME);
#elif defined(VK_USE_PLATFORM_MACOS_MVK) #elif defined(VK_USE_PLATFORM_MACOS_MVK)
instanceExtensions.push_back(VK_MVK_MACOS_SURFACE_EXTENSION_NAME); instanceExtensions.push_back(VK_MVK_MACOS_SURFACE_EXTENSION_NAME);
#endif #endif
VkInstanceCreateInfo instanceCreateInfo = {}; VkInstanceCreateInfo instanceCreateInfo = {};
@ -185,7 +185,7 @@ void VulkanExampleBase::prepare()
setupRenderPass(); setupRenderPass();
createPipelineCache(); createPipelineCache();
setupFrameBuffer(); setupFrameBuffer();
enableTextOverlay = enableTextOverlay && (!benchmark.active);
if (enableTextOverlay) if (enableTextOverlay)
{ {
// Load the text rendering shaders // Load the text rendering shaders
@ -224,103 +224,106 @@ VkPipelineShaderStageCreateInfo VulkanExampleBase::loadShader(std::string fileNa
void VulkanExampleBase::renderFrame() void VulkanExampleBase::renderFrame()
{ {
#if (defined(VK_USE_PLATFORM_IOS_MVK) || defined(VK_USE_PLATFORM_MACOS_MVK)) auto tStart = std::chrono::high_resolution_clock::now();
auto tStart = std::chrono::high_resolution_clock::now(); if (viewUpdated)
if (viewUpdated) {
{ viewUpdated = false;
viewUpdated = false; viewChanged();
viewChanged(); }
}
render(); render();
frameCounter++; frameCounter++;
auto tEnd = std::chrono::high_resolution_clock::now(); auto tEnd = std::chrono::high_resolution_clock::now();
auto tDiff = std::chrono::duration<double, std::milli>(tEnd - tStart).count(); auto tDiff = std::chrono::duration<double, std::milli>(tEnd - tStart).count();
frameTimer = tDiff / 1000.0f; frameTimer = (float)tDiff / 1000.0f;
camera.update(frameTimer); camera.update(frameTimer);
if (camera.moving()) if (camera.moving())
{ {
viewUpdated = true; viewUpdated = true;
} }
// Convert to clamped timer value // Convert to clamped timer value
if (!paused) if (!paused)
{ {
timer += timerSpeed * frameTimer; timer += timerSpeed * frameTimer;
if (timer > 1.0) if (timer > 1.0)
{ {
timer -= 1.0f; timer -= 1.0f;
} }
} }
fpsTimer += (float)tDiff; fpsTimer += (float)tDiff;
if (fpsTimer > 1000.0f) if (fpsTimer > 1000.0f)
{ {
lastFPS = frameCounter; #if defined(_WIN32)
updateTextOverlay(); if (!enableTextOverlay) {
fpsTimer = 0.0f; std::string windowTitle = getWindowTitle();
frameCounter = 0; SetWindowText(window, windowTitle.c_str());
} }
#endif #endif
lastFPS = static_cast<uint32_t>(1.0f / frameTimer);
updateTextOverlay();
fpsTimer = 0.0f;
frameCounter = 0;
}
}
void VulkanExampleBase::benchmarkLoop()
{
for (uint32_t i = 0; i < benchmark.iterations; i++) {
for (uint32_t f = 0; f < 1000; f++) {
auto tStart = std::chrono::high_resolution_clock::now();
render();
auto tEnd = std::chrono::high_resolution_clock::now();
auto tDiff = std::chrono::duration<double, std::milli>(tEnd - tStart).count();
double frameTime = (double)tDiff / 1000;
benchmark.iterationTime[benchmark.currIteration] += frameTime;
}
benchmark.currIteration++;
}
vkDeviceWaitIdle(device);
// Save results as comma separated file
std::ofstream result("benchresults.csv", std::ios::out);
if (result.is_open()) {
double tMin = *std::min_element(benchmark.iterationTime.begin(), benchmark.iterationTime.end());
double tMax = *std::max_element(benchmark.iterationTime.begin(), benchmark.iterationTime.end());
double tAvg = std::accumulate(benchmark.iterationTime.begin(), benchmark.iterationTime.end(), 0.0) / benchmark.iterations;
result << std::fixed << std::setprecision(3);
result << title << std::endl;
result << ",iterations,time(ms),fps" << std::endl;;
for (size_t i = 0; i < benchmark.iterationTime.size(); i++) {
result << "," << i << "," << benchmark.iterationTime[i] << "," << (1000.0 / benchmark.iterationTime[i]) << std::endl;
}
result << ",summary" << std::endl;
result << ",,time(ms),fps" << std::endl;
result << ",min," << tMin << "," << (1000.0 / tMin) << std::endl;
result << ",max," << tMax << "," << (1000.0 / tMax) << std::endl;
result << ",avg," << tAvg << "," << (1000.0 / tAvg) << std::endl;
}
} }
void VulkanExampleBase::renderLoop() void VulkanExampleBase::renderLoop()
{ {
if (benchmark.active) {
benchmarkLoop();
return;
}
destWidth = width; destWidth = width;
destHeight = height; destHeight = height;
#if defined(_WIN32) #if defined(_WIN32)
MSG msg; MSG msg;
bool quitMessageReceived = false; bool quitMessageReceived = false;
while (!quitMessageReceived) while (!quitMessageReceived) {
{ while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
auto tStart = std::chrono::high_resolution_clock::now();
if (viewUpdated)
{
viewUpdated = false;
viewChanged();
}
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg); TranslateMessage(&msg);
DispatchMessage(&msg); DispatchMessage(&msg);
if (msg.message == WM_QUIT) {
if (msg.message == WM_QUIT)
{
quitMessageReceived = true; quitMessageReceived = true;
break; break;
} }
} }
renderFrame();
render();
frameCounter++;
auto tEnd = std::chrono::high_resolution_clock::now();
auto tDiff = std::chrono::duration<double, std::milli>(tEnd - tStart).count();
frameTimer = (float)tDiff / 1000.0f;
camera.update(frameTimer);
if (camera.moving())
{
viewUpdated = true;
}
// Convert to clamped timer value
if (!paused)
{
timer += timerSpeed * frameTimer;
if (timer > 1.0)
{
timer -= 1.0f;
}
}
fpsTimer += (float)tDiff;
if (fpsTimer > 1000.0f)
{
if (!enableTextOverlay)
{
std::string windowTitle = getWindowTitle();
SetWindowText(window, windowTitle.c_str());
}
lastFPS = static_cast<uint32_t>(1.0f / frameTimer);
updateTextOverlay();
fpsTimer = 0.0f;
frameCounter = 0;
}
} }
#elif defined(__ANDROID__) #elif defined(__ANDROID__)
while (1) while (1)
@ -674,30 +677,38 @@ VulkanExampleBase::VulkanExampleBase(bool enableValidation)
// Parse command line arguments // Parse command line arguments
for (size_t i = 0; i < args.size(); i++) for (size_t i = 0; i < args.size(); i++)
{ {
if (args[i] == std::string("-validation")) if (args[i] == std::string("-validation")) {
{
settings.validation = true; settings.validation = true;
} }
if (args[i] == std::string("-vsync")) if (args[i] == std::string("-vsync")) {
{
settings.vsync = true; settings.vsync = true;
} }
if (args[i] == std::string("-fullscreen")) if (args[i] == std::string("-fullscreen")) {
{
settings.fullscreen = true; settings.fullscreen = true;
} }
if ((args[i] == std::string("-w")) || (args[i] == std::string("-width"))) if ((args[i] == std::string("-w")) || (args[i] == std::string("-width"))) {
{
char* endptr; char* endptr;
uint32_t w = strtol(args[i + 1], &endptr, 10); uint32_t w = strtol(args[i + 1], &endptr, 10);
if (endptr != args[i + 1]) { width = w; }; if (endptr != args[i + 1]) { width = w; };
} }
if ((args[i] == std::string("-h")) || (args[i] == std::string("-height"))) if ((args[i] == std::string("-h")) || (args[i] == std::string("-height"))) {
{
char* endptr; char* endptr;
uint32_t h = strtol(args[i + 1], &endptr, 10); uint32_t h = strtol(args[i + 1], &endptr, 10);
if (endptr != args[i + 1]) { height = h; }; if (endptr != args[i + 1]) { height = h; };
} }
if ((args[i] == std::string("-b")) || (args[i] == std::string("-benchmark"))) {
benchmark.active = true;
// Number of iterations as optional parameter
if (args.size() > i + 1) {
char* endptr;
uint32_t iterations = strtol(args[i + 1], &endptr, 10);
if (endptr != args[i + 1]) { benchmark.iterations = iterations; };
}
benchmark.iterationTime.resize(benchmark.iterations);
benchmark.frameTimes.min = std::numeric_limits<double>::max();
benchmark.frameTimes.max = std::numeric_limits<double>::min();
benchmark.frameTimes.avg = 0.0;
}
} }
#if defined(__ANDROID__) #if defined(__ANDROID__)
@ -1381,8 +1392,8 @@ void VulkanExampleBase::handleAppCommand(android_app * app, int32_t cmd)
#elif (defined(VK_USE_PLATFORM_IOS_MVK) || defined(VK_USE_PLATFORM_MACOS_MVK)) #elif (defined(VK_USE_PLATFORM_IOS_MVK) || defined(VK_USE_PLATFORM_MACOS_MVK))
void* VulkanExampleBase::setupWindow(void* view) void* VulkanExampleBase::setupWindow(void* view)
{ {
this->view = view; this->view = view;
return view; return view;
} }
#elif defined(_DIRECT2DISPLAY) #elif defined(_DIRECT2DISPLAY)
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR) #elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
@ -2149,7 +2160,7 @@ void VulkanExampleBase::initSwapchain()
#elif defined(__ANDROID__) #elif defined(__ANDROID__)
swapChain.initSurface(androidApp->window); swapChain.initSurface(androidApp->window);
#elif (defined(VK_USE_PLATFORM_IOS_MVK) || defined(VK_USE_PLATFORM_MACOS_MVK)) #elif (defined(VK_USE_PLATFORM_IOS_MVK) || defined(VK_USE_PLATFORM_MACOS_MVK))
swapChain.initSurface(view); swapChain.initSurface(view);
#elif defined(_DIRECT2DISPLAY) #elif defined(_DIRECT2DISPLAY)
swapChain.initSurface(width, height); swapChain.initSurface(width, height);
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR) #elif defined(VK_USE_PLATFORM_WAYLAND_KHR)

View file

@ -37,6 +37,7 @@
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <string> #include <string>
#include <array> #include <array>
#include <numeric>
#include "vulkan/vulkan.h" #include "vulkan/vulkan.h"
@ -150,6 +151,17 @@ public:
VkClearColorValue defaultClearColor = { { 0.025f, 0.025f, 0.025f, 1.0f } }; VkClearColorValue defaultClearColor = { { 0.025f, 0.025f, 0.025f, 1.0f } };
/** @brief Stores performance metrics for benchmark runs */
struct Benchmark {
bool active = false;
uint32_t iterations = 10;
uint32_t currIteration = 0;
std::vector<double> iterationTime;
struct FrameTimes {
double min, max, avg;
} frameTimes;
} benchmark;
float zoom = 0; float zoom = 0;
static std::vector<const char*> args; static std::vector<const char*> args;
@ -210,7 +222,7 @@ public:
/** @brief Product model and manufacturer of the Android device (via android.Product*) */ /** @brief Product model and manufacturer of the Android device (via android.Product*) */
std::string androidProduct; std::string androidProduct;
#elif (defined(VK_USE_PLATFORM_IOS_MVK) || defined(VK_USE_PLATFORM_MACOS_MVK)) #elif (defined(VK_USE_PLATFORM_IOS_MVK) || defined(VK_USE_PLATFORM_MACOS_MVK))
void* view; void* view;
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR) #elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
wl_display *display = nullptr; wl_display *display = nullptr;
wl_registry *registry = nullptr; wl_registry *registry = nullptr;
@ -259,7 +271,7 @@ public:
static int32_t handleAppInput(struct android_app* app, AInputEvent* event); static int32_t handleAppInput(struct android_app* app, AInputEvent* event);
static void handleAppCommand(android_app* app, int32_t cmd); static void handleAppCommand(android_app* app, int32_t cmd);
#elif (defined(VK_USE_PLATFORM_IOS_MVK) || defined(VK_USE_PLATFORM_MACOS_MVK)) #elif (defined(VK_USE_PLATFORM_IOS_MVK) || defined(VK_USE_PLATFORM_MACOS_MVK))
void* setupWindow(void* view); void* setupWindow(void* view);
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR) #elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
wl_shell_surface *setupWindow(); wl_shell_surface *setupWindow();
void initWaylandConnection(); void initWaylandConnection();
@ -379,8 +391,10 @@ public:
// Start the main render loop // Start the main render loop
void renderLoop(); void renderLoop();
// Render one frame of a render loop on platforms that sync rendering void benchmarkLoop();
void renderFrame();
// Render one frame of a render loop on platforms that sync rendering
void renderFrame();
void updateTextOverlay(); void updateTextOverlay();