From 06e174dcbf63370ea802fe302e07250845bf74cf Mon Sep 17 00:00:00 2001 From: Hugues Evrard Date: Tue, 12 Mar 2019 18:52:26 +0100 Subject: Implement --log-graphics-calls-time flag (#351) Add the necessary Delegate methods to implement timing of graphics API calls. --- include/amber/amber.h | 4 +++ samples/Android.mk | 3 +- samples/CMakeLists.txt | 1 + samples/amber.cc | 28 +++++++++++++++++- samples/timestamp.cc | 69 +++++++++++++++++++++++++++++++++++++++++++++ samples/timestamp.h | 27 ++++++++++++++++++ src/vulkan/device.cc | 2 ++ tools/update_vk_wrappers.py | 17 ++++++++++- 8 files changed, 148 insertions(+), 3 deletions(-) create mode 100644 samples/timestamp.cc create mode 100644 samples/timestamp.h diff --git a/include/amber/amber.h b/include/amber/amber.h index 5a89b88..8e4b5a3 100644 --- a/include/amber/amber.h +++ b/include/amber/amber.h @@ -61,6 +61,10 @@ class Delegate { virtual void Log(const std::string& message) = 0; /// Tells whether to log the graphics API calls virtual bool LogGraphicsCalls() const = 0; + /// Tells whether to log the duration of graphics API calls + virtual bool LogGraphicsCallsTime() const = 0; + /// Returns the current timestamp in nanoseconds + virtual uint64_t GetTimestampNs() const = 0; }; struct Options { diff --git a/samples/Android.mk b/samples/Android.mk index 06f5fe9..bb8945f 100644 --- a/samples/Android.mk +++ b/samples/Android.mk @@ -23,7 +23,8 @@ LOCAL_SRC_FILES:= \ config_helper_vulkan.cc \ log.cc \ ppm.cc \ - png.cc + png.cc \ + timestamp.cc LOCAL_C_INCLUDES := $(LOCAL_PATH)/.. $(LOCAL_PATH)/../include LOCAL_LDLIBS:=-landroid -lvulkan -llog LOCAL_CXXFLAGS:=-std=c++11 -fno-exceptions -fno-rtti -Werror -Wno-unknown-pragmas -DAMBER_ENGINE_VULKAN=1 diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt index 213d4c3..1a3183d 100644 --- a/samples/CMakeLists.txt +++ b/samples/CMakeLists.txt @@ -20,6 +20,7 @@ set(AMBER_SOURCES log.cc ppm.cc png.cc + timestamp.cc ${CMAKE_BINARY_DIR}/src/build-versions.h.fake ) diff --git a/samples/amber.cc b/samples/amber.cc index 79d0cee..19c323f 100644 --- a/samples/amber.cc +++ b/samples/amber.cc @@ -26,6 +26,7 @@ #include "samples/config_helper.h" #include "samples/png.h" #include "samples/ppm.h" +#include "samples/timestamp.h" #include "src/build-versions.h" #include "src/make_unique.h" @@ -46,6 +47,7 @@ struct Options { bool show_help = false; bool show_version_info = false; bool log_graphics_calls = false; + bool log_graphics_calls_time = false; amber::EngineType engine = amber::kEngineTypeVulkan; std::string spv_env; }; @@ -66,6 +68,7 @@ const char kUsage[] = R"(Usage: amber [options] SCRIPT [SCRIPTS...] -v -- Engine version (eg, 1.1 for Vulkan). Default 1.0. -V, --version -- Output version information for Amber and libraries. --log-graphics-calls -- Log graphics API calls (only for Vulkan so far). + --log-graphics-calls-time -- Log timing of graphics API calls timing (Vulkan only). -h -- This help text. )"; @@ -161,6 +164,8 @@ bool ParseArgs(const std::vector& args, Options* opts) { opts->quiet = true; } else if (arg == "--log-graphics-calls") { opts->log_graphics_calls = true; + } else if (arg == "--log-graphics-calls-time") { + opts->log_graphics_calls_time = true; } else if (arg.size() > 0 && arg[0] == '-') { std::cerr << "Unrecognized option " << arg << std::endl; return false; @@ -209,7 +214,8 @@ std::string ReadFile(const std::string& input_file) { class SampleDelegate : public amber::Delegate { public: - SampleDelegate() : log_graphics_calls_(false) {} + SampleDelegate() + : log_graphics_calls_(false), log_graphics_calls_time_(false) {} ~SampleDelegate() override = default; void Log(const std::string& message) override { @@ -222,8 +228,25 @@ class SampleDelegate : public amber::Delegate { log_graphics_calls_ = log_graphics_calls; } + bool LogGraphicsCallsTime() const override { + return log_graphics_calls_time_; + } + + void SetLogGraphicsCallsTime(bool log_graphics_calls_time) { + log_graphics_calls_time_ = log_graphics_calls_time; + if (log_graphics_calls_time) { + // Make sure regular logging is also enabled + log_graphics_calls_ = true; + } + } + + uint64_t GetTimestampNs() const override { + return timestamp::SampleGetTimestampNs(); + } + private: bool log_graphics_calls_; + bool log_graphics_calls_time_; }; } // namespace @@ -291,6 +314,9 @@ int main(int argc, const char** argv) { if (options.log_graphics_calls) { delegate.SetLogGraphicsCalls(true); } + if (options.log_graphics_calls_time) { + delegate.SetLogGraphicsCallsTime(true); + } amber::Options amber_options; amber_options.engine = options.engine; diff --git a/samples/timestamp.cc b/samples/timestamp.cc new file mode 100644 index 0000000..50c6539 --- /dev/null +++ b/samples/timestamp.cc @@ -0,0 +1,69 @@ +// Copyright 2019 The Amber Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "samples/timestamp.h" + +#include + +#if defined(_WIN32) || defined(_WIN64) +#define SAMPLE_PLATFORM_WINDOWS 1 +#define SAMPLE_PLATFORM_POSIX 0 +#elif defined(__linux__) || defined(__APPLE__) +#define SAMPLE_PLATFORM_POSIX 1 +#define SAMPLE_PLATFORM_WINDOWS 0 +#endif + +#if SAMPLE_PLATFORM_WINDOWS +#include +#elif SAMPLE_PLATFORM_POSIX +#include +#else +#error "Unknown platform" +#endif + +namespace timestamp { + +uint64_t SampleGetTimestampNs() { + uint64_t timestamp = 0; + +#if SAMPLE_PLATFORM_WINDOWS + + LARGE_INTEGER tick_per_seconds; + if (!QueryPerformanceFrequency(&tick_per_seconds)) { + return 0; + } + LARGE_INTEGER ticks; + if (!QueryPerformanceCounter(&ticks)) { + return 0; + } + double tick_duration_ns = static_cast(1.0e9) / + static_cast(tick_per_seconds.QuadPart); + timestamp = uint64_t(static_cast(ticks.QuadPart) * tick_duration_ns); + +#elif SAMPLE_PLATFORM_POSIX + + struct timespec time; + if (clock_gettime(CLOCK_MONOTONIC, &time)) { + return 0; + } + timestamp = static_cast((time.tv_sec * 1000000000) + time.tv_nsec); + +#else +#error "Implement timestamp::SampleGetTimestampNs" +#endif + + return timestamp; +} + +} // namespace timestamp diff --git a/samples/timestamp.h b/samples/timestamp.h new file mode 100644 index 0000000..81b0f55 --- /dev/null +++ b/samples/timestamp.h @@ -0,0 +1,27 @@ +// Copyright 2019 The Amber Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SAMPLES_TIMESTAMP_H_ +#define SAMPLES_TIMESTAMP_H_ + +#include "amber/amber.h" + +namespace timestamp { + +/// Return a timestamp in nanoseconds. +uint64_t SampleGetTimestampNs(); + +} // namespace timestamp + +#endif // SAMPLES_TIMESTAMP_H_ diff --git a/src/vulkan/device.cc b/src/vulkan/device.cc index d2a7145..7059942 100644 --- a/src/vulkan/device.cc +++ b/src/vulkan/device.cc @@ -15,9 +15,11 @@ #include "src/vulkan/device.h" #include +#include // Vulkan wrappers: std::setw(), std::left/right #include #include #include +#include #include #include diff --git a/tools/update_vk_wrappers.py b/tools/update_vk_wrappers.py index bb7dd45..995558d 100755 --- a/tools/update_vk_wrappers.py +++ b/tools/update_vk_wrappers.py @@ -89,7 +89,6 @@ def gen_wrappers(methods, xml): return_variable = 'ret' call_prefix = return_type + ' ' + return_variable + ' = ' - template = Template(R'''{ PFN_${method} ptr = reinterpret_cast(getInstanceProcAddr(instance_, "${method}")); if (!ptr) { @@ -98,7 +97,23 @@ def gen_wrappers(methods, xml): if (delegate && delegate->LogGraphicsCalls()) { ptrs_.${method} = [ptr, delegate](${signature}) -> ${return_type} { delegate->Log("${method}"); + uint64_t timestamp_start = 0; + if (delegate->LogGraphicsCallsTime()) { + timestamp_start = delegate->GetTimestampNs(); + } ${call_prefix}ptr(${arguments}); + if (delegate->LogGraphicsCallsTime()) { + uint64_t timestamp_end = delegate->GetTimestampNs(); + uint64_t duration = timestamp_end - timestamp_start; + std::ostringstream out; + out << "time "; + // name of method on 40 characters + out << std::left << std::setw(40) << "${method}"; + // duration in nanoseconds on 12 characters, right-aligned + out << std::right << std::setw(12) << duration; + out << " ns"; + delegate->Log(out.str()); + } return ${return_variable}; }; } else { -- cgit v1.2.3