diff options
Diffstat (limited to 'include')
-rw-r--r-- | include/mbgl/perf/runtime_metrics.hpp | 201 | ||||
-rw-r--r-- | include/mbgl/perf/trace_data.in | 34 | ||||
-rw-r--r-- | include/mbgl/util/chrono.hpp | 5 |
3 files changed, 240 insertions, 0 deletions
diff --git a/include/mbgl/perf/runtime_metrics.hpp b/include/mbgl/perf/runtime_metrics.hpp new file mode 100644 index 0000000000..73c2c7cf46 --- /dev/null +++ b/include/mbgl/perf/runtime_metrics.hpp @@ -0,0 +1,201 @@ +#pragma once + +#define MBGL_COLLECT_RUNTIME_METRICS + +#ifndef MBGL_COLLECT_RUNTIME_METRICS +#define MBGL_TRACE_RENDERER_BEGIN(range, ...) +#define MBGL_TRACE_RENDERER_END(range, ...) +#define MBGL_TRACE_RENDERER_BEGINRECORD(range, ...) +#define MBGL_TRACE_RENDERER_ENDRECORD(range, ...) +#define MBGL_IF_TRACING(x) +#else +#include <mutex> +#include <mbgl/util/chrono.hpp> +#include <mbgl/util/logging.hpp> +#include <vector> + +#define MBGL_IF_TRACING(x) x + +//#define MBGL_TRACER_USE_MUTEX +#ifndef MBGL_TRACER_USE_MUTEX +#define LOCK_RENDERER(t) +#define UNLOCK_RENDERER(t) +#define RENDERER_LOCKER() +#else +#define LOCK_RENDERER(t) t.frame_mutex.lock(); +#define UNLOCK_RENDERER(t) t.frame_mutex.unlock(); +#define RENDERER_LOCKER() std::unique_lock<std::mutex> locker(frame_mutex); +#endif + +// First argument intended to be rangeName +#define RANGE_NAME(X, ...) X +#define MBGL_TRACE_RENDERER_BEGIN(...) { \ + mbgl::util::Tracer &t = mbgl::util::Tracer::get(); \ + LOCK_RENDERER(t); \ + t.frameTrace.RANGE_NAME(__VA_ARGS__).scope = t.currentScope; \ + t.currentScope += 1; \ + t.frameTrace.RANGE_NAME(__VA_ARGS__).begin = mbgl::util::Tracer::nanoseconds(); \ + UNLOCK_RENDERER(t); \ + } +#define MBGL_TRACE_RENDERER_END(...) { \ + mbgl::util::Tracer &t = mbgl::util::Tracer::get(); \ + LOCK_RENDERER(t); \ + t.frameTrace.RANGE_NAME(__VA_ARGS__).end = mbgl::util::Tracer::nanoseconds(); \ + t.currentScope -= 1; \ + t.frameTrace.RANGE_NAME(__VA_ARGS__).totalCalls += 1; \ + t.frameTrace.RANGE_NAME(__VA_ARGS__).totalMs += t.frameTrace.RANGE_NAME(__VA_ARGS__).end - t.frameTrace.RANGE_NAME(__VA_ARGS__).begin; \ + UNLOCK_RENDERER(t); \ + } +#define MBGL_TRACE_RENDERER_BEGINRECORD(...) { \ + mbgl::util::Tracer &t = mbgl::util::Tracer::get(); \ + LOCK_RENDERER(t); \ + t.frameTraceReset(t.frameTrace); \ + t.frameTrace.RANGE_NAME(__VA_ARGS__).scope = t.currentScope; \ + t.currentScope += 1; \ + t.frameTrace.RANGE_NAME(__VA_ARGS__).begin = mbgl::util::Tracer::nanoseconds(); \ + UNLOCK_RENDERER(t); \ + } +#define MBGL_TRACE_RENDERER_ENDRECORD(...) { \ + mbgl::util::Tracer &t = mbgl::util::Tracer::get(); \ + LOCK_RENDERER(t); \ + t.frameTrace.RANGE_NAME(__VA_ARGS__).end = mbgl::util::Tracer::nanoseconds(); \ + t.currentScope -= 1; \ + t.frameTrace.RANGE_NAME(__VA_ARGS__).totalCalls += 1; \ + t.frameTrace.RANGE_NAME(__VA_ARGS__).totalMs += t.frameTrace.RANGE_NAME(__VA_ARGS__).end - t.frameTrace.RANGE_NAME(__VA_ARGS__).begin; \ + if (t.collectData) t.frameList.push_back(t.frameTrace); \ + UNLOCK_RENDERER(t); } + +#define MBGL_TRACE_APPSTART(...) { mbgl::util::Tracer::get().appStart = mbgl::util::Tracer::nanoseconds(); } + +#define NS2MS(x) ((x) * 0.000001) + +namespace mbgl { +namespace util { + +struct TraceInterval { + unsigned char scope = 0; // overwritten by each range + uint64_t begin = 0u; // overwritten by each range + uint64_t end = 0u; // overwritten by each range + uint64_t totalMs = 0u; + uint64_t totalCalls = 0u; +}; + +#define STRUCT_BEGIN(name) struct name { +#define STRUCT_END() }; +#define STRUCT_MEMBER_UINT64_RANGE(name, store_range, store_counter) TraceInterval name; +#include <mbgl/perf/trace_data.in> +#undef STRUCT_BEGIN +#undef STRUCT_END +#undef STRUCT_MEMBER_UINT64_RANGE + +// Instrumentation-less tracing implementation, possibly requiring mutexing +class Tracer +{ +public: + static uint64_t nanoseconds() { + return Clock::now().time_since_epoch().count(); + } + static Tracer& get() { + static Tracer i; // Guaranteed to be destroyed. + // Instantiated on first use. + return i; + } +private: + Tracer() {} + +public: + Tracer(Tracer const&) = delete; + void operator=(Tracer const&) = delete; + bool collectData = false; + + + std::mutex frame_mutex; + std::vector<mbgl::util::FrameTrace> frameList; + mbgl::util::FrameTrace frameTrace; + unsigned int currentScope = 0u; + unsigned int appStart = 0u; + +/* frameTraceReset */ +#define STRUCT_BEGIN(name) static void frameTraceReset(name &data) { data = name(); // clear it by assigning to a new struct +#define STRUCT_END() }; +#define STRUCT_MEMBER_UINT64_RANGE(name, store_range, store_counter) +#include <mbgl/perf/trace_data.in> +#undef STRUCT_BEGIN +#undef STRUCT_END +#undef STRUCT_MEMBER_UINT64_RANGE + +/* framesToJson */ +#define STRUCT_BEGIN(name) \ +static std::string frameToJson(const name &data) { \ + std::string res; \ + res += "{\n"; +// The following assumes that one of { store_range, store_counter } is true. +#define STRUCT_MEMBER_UINT64_RANGE(name, store_range, store_counter) \ +res += std::string("\"") + std::string(#name) + std::string("\" : { "); \ +if (store_range) { \ + res += std::string("\"scope\" : ") + std::to_string(data.name.scope) + std::string(" , ") \ + + std::string("\"begin\" : ") + std::to_string(data.name.begin) + std::string(" , ") \ + + std::string("\"end\" : ") + std::to_string(data.name.end); } \ +if (store_counter) { if (store_range) res += std::string(","); \ + res += std::string("\"totalMs\" : ") + std::to_string(data.name.totalMs) + std::string(" , ") \ + + std::string("\"totalCalls\" : ") + std::to_string(data.name.totalCalls); \ +} \ +res += std::string(" },"); +#define STRUCT_END() \ + res.pop_back(); res += "}"; \ + return res; \ +}; +#include <mbgl/perf/trace_data.in> +#undef STRUCT_BEGIN +#undef STRUCT_END +#undef STRUCT_MEMBER_UINT64_RANGE + + inline bool isCollectingData() const { + return collectData; + } + inline void setCollectData(bool enabled) { + collectData = enabled; + } + + inline std::string framesJson(bool steal = false) const { + LOCK_RENDERER(*this); + std::vector<mbgl::util::FrameTrace> frameList_; + if (steal) + frameList_ = std::move(frameList); + else + frameList_ = frameList; + UNLOCK_RENDERER(*this); + + std::string res; + res += "[\n"; + for (const auto &f: frameList) + res += frameToJson(f) + std::string(","); + res.pop_back(); + res += "]\n"; + return res; + } + + inline std::string dumpAll(bool steal = false) const { + std::string res; + res += "{\n"; + // meta + res += "\"global\": {\n"; + + res += "}\n"; + + // frames + res += ", \"frames\": "; + res += framesJson(steal); + + res += "}\n"; + return res; + } + + inline void clearFrames() { + RENDERER_LOCKER(); + frameList.clear(); + } +}; +} // namespace util +} // namespace mbgl +#endif diff --git a/include/mbgl/perf/trace_data.in b/include/mbgl/perf/trace_data.in new file mode 100644 index 0000000000..b2288fa9e7 --- /dev/null +++ b/include/mbgl/perf/trace_data.in @@ -0,0 +1,34 @@ +STRUCT_BEGIN(FrameTrace) + +STRUCT_MEMBER_UINT64_RANGE(update, true, false) // Before attaching render target +STRUCT_MEMBER_UINT64_RANGE(attach, true, false) +STRUCT_MEMBER_UINT64_RANGE(render, true, false) +STRUCT_MEMBER_UINT64_RANGE(orchestrate, true, false) // Before orchestration +STRUCT_MEMBER_UINT64_RANGE(prepare, true, false) // Before prepare -- This and below are not present IF (!isMapModeContinuous && !renderTreeParameters->loaded) +STRUCT_MEMBER_UINT64_RANGE(renderimpl, true, false) // Before Impl::render +STRUCT_MEMBER_UINT64_RANGE(waitrenderable, true, false) // Before wait on renderable +STRUCT_MEMBER_UINT64_RANGE(upload, true, false) // Before UPLOAD PASS +STRUCT_MEMBER_UINT64_RANGE(draw, true, false) +STRUCT_MEMBER_UINT64_RANGE(extrusions, true, false) // Before 3D pass (extrusions) +STRUCT_MEMBER_UINT64_RANGE(clear, true, false) // 1st draw stage +STRUCT_MEMBER_UINT64_RANGE(opaque, true, false) // 2 opaque should only have layer render items +STRUCT_MEMBER_UINT64_RANGE(translucent, true, false) // 3 same here +STRUCT_MEMBER_UINT64_RANGE(debug, true, false) // 4 debug only renders sourceRenderItems +STRUCT_MEMBER_UINT64_RANGE(flushencoder, true, false) // 5 --- + +STRUCT_MEMBER_UINT64_RANGE(imagesourcerenderdata, false, true) +STRUCT_MEMBER_UINT64_RANGE(layerrenderitem, false, true) +STRUCT_MEMBER_UINT64_RANGE(tilesourcerenderitem, false, true) + +STRUCT_MEMBER_UINT64_RANGE(fill_layer, false, true) +STRUCT_MEMBER_UINT64_RANGE(extrusion_layer, false, true) +STRUCT_MEMBER_UINT64_RANGE(line_layer, false, true) +STRUCT_MEMBER_UINT64_RANGE(circle_layer, false, true) +STRUCT_MEMBER_UINT64_RANGE(heatmap_layer, false, true) +STRUCT_MEMBER_UINT64_RANGE(background_layer, false, true) +STRUCT_MEMBER_UINT64_RANGE(raster_layer, false, true) +STRUCT_MEMBER_UINT64_RANGE(symbol_layer, false, true) +STRUCT_MEMBER_UINT64_RANGE(hillshade_layer, false, true) +STRUCT_MEMBER_UINT64_RANGE(custom_layer, false, true) + +STRUCT_END() diff --git a/include/mbgl/util/chrono.hpp b/include/mbgl/util/chrono.hpp index 723cd131e3..2b16e74b32 100644 --- a/include/mbgl/util/chrono.hpp +++ b/include/mbgl/util/chrono.hpp @@ -9,6 +9,7 @@ using Clock = std::chrono::steady_clock; using Seconds = std::chrono::seconds; using Milliseconds = std::chrono::milliseconds; +using Nanoseconds = std::chrono::nanoseconds; using TimePoint = Clock::time_point; using Duration = Clock::duration; @@ -22,6 +23,10 @@ inline Timestamp now() { return std::chrono::time_point_cast<Seconds>(std::chrono::system_clock::now()); } +inline uint64_t now_ns() { + return Clock::now().time_since_epoch().count(); +} + // Returns the RFC1123 formatted date. E.g. "Tue, 04 Nov 2014 02:13:24 GMT" std::string rfc1123(Timestamp); |