summaryrefslogtreecommitdiff
path: root/include/mbgl
diff options
context:
space:
mode:
Diffstat (limited to 'include/mbgl')
-rw-r--r--include/mbgl/perf/runtime_metrics.hpp201
-rw-r--r--include/mbgl/perf/trace_data.in34
-rw-r--r--include/mbgl/util/chrono.hpp5
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);