summaryrefslogtreecommitdiff
path: root/retrace/daemon
diff options
context:
space:
mode:
Diffstat (limited to 'retrace/daemon')
-rw-r--r--retrace/daemon/CMakeLists.txt2
-rw-r--r--retrace/daemon/glframe_metrics.cpp496
-rw-r--r--retrace/daemon/glframe_metrics.hpp53
-rw-r--r--retrace/daemon/glframe_metrics_intel.cpp523
-rw-r--r--retrace/daemon/glframe_metrics_intel.hpp68
-rw-r--r--retrace/daemon/glframe_retrace.cpp4
6 files changed, 631 insertions, 515 deletions
diff --git a/retrace/daemon/CMakeLists.txt b/retrace/daemon/CMakeLists.txt
index 2833f239..237f60de 100644
--- a/retrace/daemon/CMakeLists.txt
+++ b/retrace/daemon/CMakeLists.txt
@@ -52,6 +52,8 @@ set (RETRACE_SOURCES
glframe_gpu_speed.hpp
glframe_metrics.cpp
glframe_metrics.hpp
+ glframe_metrics_intel.cpp
+ glframe_metrics_intel.hpp
glframe_os.hpp
glframe_logger.cpp
glframe_logger.hpp
diff --git a/retrace/daemon/glframe_metrics.cpp b/retrace/daemon/glframe_metrics.cpp
index 3e3b57e8..ddbae751 100644
--- a/retrace/daemon/glframe_metrics.cpp
+++ b/retrace/daemon/glframe_metrics.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) Intel Corp. 2015. All Rights Reserved.
+// Copyright (C) Intel Corp. 2017. All Rights Reserved.
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
@@ -25,498 +25,10 @@
// * Mark Janes <mark.a.janes@intel.com>
// **********************************************************************/
-#include "glframe_metrics.hpp"
+#include "glframe_metrics_intel.hpp"
-#include <GL/gl.h>
-#include <GL/glext.h>
-
-#include <string>
-#include <vector>
-#include <map>
-
-#include "glframe_glhelper.hpp"
-#include "glframe_logger.hpp"
-#include "glretrace.hpp"
-
-using glretrace::ExperimentId;
-using glretrace::GlFunctions;
-using glretrace::MetricId;
-using glretrace::NoAssign;
-using glretrace::NoCopy;
-using glretrace::OnFrameRetrace;
using glretrace::PerfMetrics;
-using glretrace::PerfMetricsContext;
-using glretrace::RenderId;
-using glretrace::SelectionId;
-using glretrace::GL;
-using glretrace::glretrace_delay;
-using glretrace::ID_PREFIX_MASK;
-
-namespace {
-
-struct MetricDescription {
- MetricId id;
- std::string name;
- std::string description;
- MetricDescription() {}
- MetricDescription(MetricId i,
- const std::string &n,
- const std::string &d)
- : id(i), name(n), description(d) {}
-};
-
-class PerfMetric : public NoCopy, NoAssign {
- public:
- PerfMetric(int query_id, int counter_num);
- MetricId id() const;
- const std::string &name() const;
- const std::string &description() const;
- float getMetric(const std::vector<unsigned char> &data) const;
- private:
- const int m_query_id, m_counter_num;
- GLuint m_offset, m_data_size, m_type,
- m_data_type;
- std::string m_name, m_description;
-};
-
-
-class PerfMetricGroup : public NoCopy, NoAssign {
- public:
- explicit PerfMetricGroup(int query_id);
- ~PerfMetricGroup();
- const std::string &name() const { return m_query_name; }
- void metrics(std::vector<MetricDescription> *m) const;
- void begin(RenderId render);
- void end(RenderId render);
- void publish(MetricId metric, PerfMetrics::MetricMap *m);
-
- private:
- std::string m_query_name;
- const int m_query_id;
- unsigned int m_data_size;
- std::vector<unsigned char> m_data_buf;
-
- std::map<MetricId, PerfMetric *> m_metrics;
-
- // represent queries that have not produced results
- std::map<RenderId, int> m_extant_query_handles;
-
- // represent query handles that can be reused
- std::vector<unsigned int> m_free_query_handles;
-};
-
-} // namespace
-
-namespace glretrace {
-
-class PerfMetricsContext : public NoCopy, NoAssign {
- public:
- explicit PerfMetricsContext(OnFrameRetrace *cb);
- ~PerfMetricsContext();
- int groupCount() const;
- void selectMetric(MetricId metric);
- void selectGroup(int index);
- void begin(RenderId render);
- void end();
- void publish(PerfMetrics::MetricMap *metrics);
- private:
- std::vector<PerfMetricGroup *> groups;
- // indicates offset in groups of PerfMetricGroup reporting MetricId
- std::map<MetricId, int> metric_map;
- // indicates the group that will handle subsequent begin/end calls
- PerfMetricGroup *current_group;
- MetricId current_metric;
- RenderId current_render;
-};
-
-} // namespace glretrace
-
-PerfMetricsContext::PerfMetricsContext(OnFrameRetrace *cb)
- : current_group(NULL) {
- GLuint query_id;
- GLint count;
- bool has_metrics = false;
- GlFunctions::GetIntegerv(GL_NUM_EXTENSIONS, &count);
- for (int i = 0; i < count; ++i) {
- const GLubyte *name = GlFunctions::GetStringi(GL_EXTENSIONS, i);
- if (strcmp((const char*)name, "GL_INTEL_performance_query") == 0)
- has_metrics = true;
- }
- if (!has_metrics)
- return;
-
- GlFunctions::GetFirstPerfQueryIdINTEL(&query_id);
- if (query_id == GLuint(-1))
- return;
-
- if (query_id == 0)
- return;
- std::vector<unsigned int> query_ids;
- query_ids.push_back(query_id);
-
- while (true) {
- GlFunctions::GetNextPerfQueryIdINTEL(query_id, &query_id);
- if (!query_id)
- break;
- query_ids.push_back(query_id);
- }
-
- std::map<std::string, MetricDescription> known_metrics;
-
- std::vector<MetricDescription> metrics;
- int group_index = 0;
- for (auto i : query_ids) {
- PerfMetricGroup *g = new PerfMetricGroup(i);
- if (g->name() == "Compute Metrics Extended Gen9") {
- // SKL metrics bug. Queries on this group crash.
- delete g;
- continue;
- }
-
- groups.push_back(g);
- metrics.clear();
- g->metrics(&metrics);
- for (auto &d : metrics) {
- if (known_metrics.find(d.name) == known_metrics.end()) {
- known_metrics[d.name] = d;
- metric_map[d.id] = group_index;
- }
- }
- ++group_index;
- }
- std::vector<MetricId> ids;
- std::vector<std::string> names;
- std::vector<std::string> descriptions;
- for (auto &i : known_metrics) {
- names.push_back(i.second.name);
- ids.push_back(i.second.id);
- descriptions.push_back(i.second.description);
- }
- if (cb)
- // only send metrics list on first context
- cb->onMetricList(ids, names, descriptions);
-}
-
-PerfMetricsContext::~PerfMetricsContext() {
- for (auto g : groups)
- delete g;
- groups.clear();
-}
-
-PerfMetricGroup::PerfMetricGroup(int query_id) : m_query_id(query_id) {
- static GLint max_name_len = 0;
- if (max_name_len == 0)
- GlFunctions::GetIntegerv(GL_PERFQUERY_QUERY_NAME_LENGTH_MAX_INTEL,
- &max_name_len);
-
- std::vector<GLchar> query_name(max_name_len);
- unsigned int number_instances, capabilities_mask, number_counters;
- GlFunctions::GetPerfQueryInfoINTEL(m_query_id,
- query_name.size(), query_name.data(),
- &m_data_size, &number_counters,
- &number_instances, &capabilities_mask);
- m_data_buf.resize(m_data_size);
- m_query_name = query_name.data();
- for (unsigned int counter_num = 1; counter_num <= number_counters;
- ++counter_num) {
- PerfMetric *p = new PerfMetric(m_query_id, counter_num);
- m_metrics[p->id()] = p;
- }
-}
-
-PerfMetricGroup::~PerfMetricGroup() {
- for (auto free_query : m_free_query_handles) {
- GlFunctions::DeletePerfQueryINTEL(free_query);
- }
- m_free_query_handles.clear();
- assert(m_extant_query_handles.empty());
- for (auto m : m_metrics)
- delete m.second;
- m_metrics.clear();
-}
-
-void
-PerfMetricGroup::metrics(std::vector<MetricDescription> *m) const {
- for (auto &i : m_metrics) {
- m->push_back(MetricDescription(i.first,
- i.second->name(),
- i.second->description()));
- }
-}
-
-void
-PerfMetricGroup::begin(RenderId render) {
- if (m_free_query_handles.empty()) {
- GLuint query_handle;
- GlFunctions::CreatePerfQueryINTEL(m_query_id, &query_handle);
- m_free_query_handles.push_back(query_handle);
- }
- GLuint query_handle = m_free_query_handles.back();
- m_free_query_handles.pop_back();
-
- // When more than one process requests metrics concurrently,
- // BeginPerfQueryINTEL fails.
- int retry = 0;
- GL::GetError();
- while (true) {
- GlFunctions::BeginPerfQueryINTEL(query_handle);
- if (GL_NO_ERROR == GL::GetError())
- break;
- if (++retry > 20) {
- GRLOG(glretrace::ERR, "failed to begin metrics query, aborting");
- assert(false);
- exit(-1);
- }
- GRLOG(glretrace::WARN, "failed to begin metrics query");
- glretrace_delay(200);
- }
- m_extant_query_handles[render] = query_handle;
-}
-
-static const MetricId ALL_METRICS_IN_GROUP = MetricId(~ID_PREFIX_MASK);
-
-void
-PerfMetricGroup::publish(MetricId metric,
- PerfMetrics::MetricMap *out_metrics) {
- const bool publish_all = (metric == ALL_METRICS_IN_GROUP);
- for (auto extant_query : m_extant_query_handles) {
- memset(m_data_buf.data(), 0, m_data_buf.size());
- GLuint bytes_written;
- GlFunctions::GetPerfQueryDataINTEL(extant_query.second,
- GL_PERFQUERY_WAIT_INTEL,
- m_data_size, m_data_buf.data(),
- &bytes_written);
- assert(bytes_written == m_data_size);
-
- if (publish_all) {
- for (auto desired_metric : m_metrics) {
- MetricId met_id = desired_metric.first;
- (*out_metrics)[met_id][extant_query.first] =
- desired_metric.second->getMetric(m_data_buf);
- }
- } else {
- (*out_metrics)[metric][extant_query.first] =
- m_metrics[metric]->getMetric(m_data_buf);
- }
- m_free_query_handles.push_back(extant_query.second);
- }
- m_extant_query_handles.clear();
- for (auto free_query : m_free_query_handles) {
- GlFunctions::DeletePerfQueryINTEL(free_query);
- }
- m_free_query_handles.clear();
-}
-
-void
-PerfMetricGroup::end(RenderId render) {
- if (m_extant_query_handles.find(render) != m_extant_query_handles.end())
- GlFunctions::EndPerfQueryINTEL(m_extant_query_handles[render]);
-}
-
-
-PerfMetric::PerfMetric(int query_id,
- int counter_num) : m_query_id(query_id),
- m_counter_num(counter_num) {
- static GLint max_name_len = 0, max_desc_len = 0;
- if (max_name_len == 0)
- GlFunctions::GetIntegerv(GL_PERFQUERY_COUNTER_NAME_LENGTH_MAX_INTEL,
- &max_name_len);
- if (max_desc_len == 0)
- GlFunctions::GetIntegerv(GL_PERFQUERY_COUNTER_DESC_LENGTH_MAX_INTEL,
- &max_desc_len);
- std::vector<GLchar> counter_name(max_name_len);
- std::vector<GLchar> counter_description(max_desc_len);
- GLuint64 max_value;
- GlFunctions::GetPerfCounterInfoINTEL(m_query_id, m_counter_num,
- counter_name.size(), counter_name.data(),
- counter_description.size(),
- counter_description.data(),
- &m_offset, &m_data_size, &m_type,
- &m_data_type, &max_value);
- m_name = counter_name.data();
- m_description = counter_description.data();
-}
-
-MetricId
-PerfMetric::id() const {
- return MetricId(m_query_id, m_counter_num);
-}
-
-const std::string &
-PerfMetric::name() const {
- return m_name;
-}
-
-const std::string &
-PerfMetric::description() const {
- return m_description;
-}
-
-float
-PerfMetric::getMetric(const std::vector<unsigned char> &data) const {
- const unsigned char *p_value = data.data() + m_offset;
- float fval;
- switch (m_data_type) {
- case GL_PERFQUERY_COUNTER_DATA_UINT32_INTEL: {
- assert(m_data_size == 4);
- const uint32_t val = *reinterpret_cast<const uint32_t *>(p_value);
- fval = static_cast<float>(val);
- break;
- }
- case GL_PERFQUERY_COUNTER_DATA_UINT64_INTEL: {
- assert(m_data_size == 8);
- const uint64_t val = *reinterpret_cast<const uint64_t *>(p_value);
- fval = static_cast<float>(val);
- break;
- }
- case GL_PERFQUERY_COUNTER_DATA_FLOAT_INTEL: {
- assert(m_data_size == 4);
- fval = *reinterpret_cast<const float *>(p_value);
- break;
- }
- case GL_PERFQUERY_COUNTER_DATA_DOUBLE_INTEL: {
- assert(m_data_size == 8);
- const double val = *reinterpret_cast<const double *>(p_value);
- fval = static_cast<float>(val);
- break;
- }
- case GL_PERFQUERY_COUNTER_DATA_BOOL32_INTEL: {
- assert(m_data_size == 4);
- const bool val = *reinterpret_cast<const bool*>(p_value);
- fval = val ? 1.0 : 0.0;
- break;
- }
- default:
- assert(false);
- }
- return fval;
-}
-
-void
-PerfMetricsContext::selectMetric(MetricId metric) {
- assert(metric_map.find(metric) != metric_map.end());
- current_metric = metric;
- current_group = groups[metric_map[metric]];
-}
-
-void
-PerfMetricsContext::publish(PerfMetrics::MetricMap *metrics) {
- current_group->publish(current_metric, metrics);
-}
-
-void
-PerfMetricsContext::begin(RenderId render) {
- current_group->begin(render);
- current_render = render;
-}
-
-void
-PerfMetricsContext::end() {
- current_group->end(current_render);
-}
-
-int
-PerfMetricsContext::groupCount() const {
- return groups.size();
-}
-
-void
-PerfMetricsContext::selectGroup(int index) {
- current_group = groups[index];
- current_metric = ALL_METRICS_IN_GROUP;
-}
-
-PerfMetrics::PerfMetrics(OnFrameRetrace *cb)
- : m_current_group(0) {
- Context *c = getCurrentContext();
- m_current_context = new PerfMetricsContext(cb);
- m_contexts[c] = m_current_context;
-}
-
-PerfMetrics::~PerfMetrics() {
- for (auto i : m_contexts) {
- delete i.second;
- }
- m_contexts.clear();
-}
-
-int
-PerfMetrics::groupCount() const {
- assert(!m_contexts.empty());
- return m_contexts.begin()->second->groupCount();
-}
-
-void
-PerfMetrics::selectMetric(MetricId metric) {
- m_data.clear();
- m_current_metric = metric;
- for (auto i : m_contexts)
- i.second->selectMetric(metric);
-}
-
-void
-PerfMetrics::selectGroup(int index) {
- m_current_group = index;
- m_current_metric = ALL_METRICS_IN_GROUP;
- for (auto i : m_contexts)
- i.second->selectGroup(index);
-}
-
-void
-PerfMetrics::begin(RenderId render) {
- if (!m_current_context) {
- beginContext();
- }
- m_current_context->begin(render);
-}
-
-void
-PerfMetrics::end() {
- if (m_current_context)
- m_current_context->end();
-}
-
-void
-PerfMetrics::publish(ExperimentId experimentCount,
- SelectionId selectionCount,
- OnFrameRetrace *callback) {
- for (auto i : m_contexts)
- i.second->publish(&m_data);
-
- for (auto i : m_data) {
- MetricSeries s;
- s.metric = i.first;
- s.data.resize(i.second.rbegin()->first.index() + 1);
- for (auto datapoint : i.second)
- s.data[datapoint.first.index()] = datapoint.second;
- callback->onMetrics(s, experimentCount, selectionCount);
- }
- m_data.clear();
-}
-
-void
-PerfMetrics::beginContext() {
- Context *c = getCurrentContext();
- auto entry = m_contexts.find(c);
- if (entry != m_contexts.end()) {
- m_current_context = entry->second;
- } else {
- // create a new metrics context
- GRLOG(glretrace::WARN, "new context in frame");
- m_current_context = new PerfMetricsContext(NULL);
- m_contexts[c] = m_current_context;
- }
- m_current_context->selectGroup(m_current_group);
- if (m_current_metric() &&
- (m_current_metric != ALL_METRICS_IN_GROUP))
- m_current_context->selectMetric(m_current_metric);
-}
-void
-PerfMetrics::endContext() {
- if (m_current_context) {
- m_current_context->end();
- m_current_context->publish(&m_data);
- }
- m_current_context = NULL;
+PerfMetrics *PerfMetrics::Create(OnFrameRetrace *callback) {
+ return new PerfMetricsIntel(callback);
}
diff --git a/retrace/daemon/glframe_metrics.hpp b/retrace/daemon/glframe_metrics.hpp
index 41180f64..ab3ab78f 100644
--- a/retrace/daemon/glframe_metrics.hpp
+++ b/retrace/daemon/glframe_metrics.hpp
@@ -32,35 +32,46 @@
#include <vector>
#include "glframe_traits.hpp"
-#include "glframe_retrace.hpp"
+#include "glframe_retrace_interface.hpp"
namespace glretrace {
class PerfMetricsContext;
struct Context;
-class PerfMetrics : public NoCopy, NoAssign {
+class PerfMetrics {
public:
- explicit PerfMetrics(OnFrameRetrace *cb);
- ~PerfMetrics();
- int groupCount() const;
- void selectMetric(MetricId metric);
- void selectGroup(int index);
- void begin(RenderId render);
- void end();
- void publish(ExperimentId experimentCount,
+ // Constructor accepts OnFrameRetrace callback pointer, and calls
+ // onMetricList before returning.
+ static PerfMetrics *Create(OnFrameRetrace *callback);
+ virtual ~PerfMetrics() {}
+
+ // Indicates the number of passes a metrics retrace must make to
+ // collect the full metric set
+ virtual int groupCount() const = 0;
+
+ // Subsequent begin/end will collect data for all counters in the group
+ virtual void selectGroup(int index) = 0;
+
+ // Subsequent begin/end will collect data for the metric associated
+ // with the id
+ virtual void selectMetric(MetricId metric) = 0;
+
+ // Begin collection for selected metrics. When reported, the
+ // counter values will be associated with the specified render.
+ virtual void begin(RenderId render) = 0;
+
+ // End collection for the selected metrics.
+ virtual void end() = 0;
+
+ // Flush and call onMetrics, providing all queried metric data.
+ virtual void publish(ExperimentId experimentCount,
SelectionId selectionCount,
- OnFrameRetrace *callback);
- // call before changing to another context
- void endContext();
- void beginContext();
- typedef std::map<MetricId, std::map<RenderId, float>> MetricMap;
- private:
- PerfMetricsContext* m_current_context;
- std::map<Context*, PerfMetricsContext*> m_contexts;
- MetricMap m_data;
- int m_current_group;
- MetricId m_current_metric;
+ OnFrameRetrace *callback) = 0;
+
+ // Call before changing to another context
+ virtual void endContext() = 0;
+ virtual void beginContext() = 0;
};
} // namespace glretrace
diff --git a/retrace/daemon/glframe_metrics_intel.cpp b/retrace/daemon/glframe_metrics_intel.cpp
new file mode 100644
index 00000000..f199ff1b
--- /dev/null
+++ b/retrace/daemon/glframe_metrics_intel.cpp
@@ -0,0 +1,523 @@
+// Copyright (C) Intel Corp. 2015. All Rights Reserved.
+
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+
+// The above copyright notice and this permission notice (including the
+// next paragraph) shall be included in all copies or substantial
+// portions of the Software.
+
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// **********************************************************************/
+// * Authors:
+// * Mark Janes <mark.a.janes@intel.com>
+// **********************************************************************/
+
+#include "glframe_metrics_intel.hpp"
+
+#include <GL/gl.h>
+#include <GL/glext.h>
+
+#include <string>
+#include <vector>
+#include <map>
+
+#include "glframe_glhelper.hpp"
+#include "glframe_logger.hpp"
+#include "glretrace.hpp"
+
+using glretrace::ExperimentId;
+using glretrace::GlFunctions;
+using glretrace::MetricId;
+using glretrace::NoAssign;
+using glretrace::NoCopy;
+using glretrace::OnFrameRetrace;
+using glretrace::PerfMetrics;
+using glretrace::PerfMetricsIntel;
+using glretrace::PerfMetricsContext;
+using glretrace::RenderId;
+using glretrace::SelectionId;
+using glretrace::GL;
+using glretrace::glretrace_delay;
+using glretrace::ID_PREFIX_MASK;
+
+namespace {
+
+struct MetricDescription {
+ MetricId id;
+ std::string name;
+ std::string description;
+ MetricDescription() {}
+ MetricDescription(MetricId i,
+ const std::string &n,
+ const std::string &d)
+ : id(i), name(n), description(d) {}
+};
+
+class PerfMetric : public NoCopy, NoAssign {
+ public:
+ PerfMetric(int query_id, int counter_num);
+ MetricId id() const;
+ const std::string &name() const;
+ const std::string &description() const;
+ float getMetric(const std::vector<unsigned char> &data) const;
+ private:
+ const int m_query_id, m_counter_num;
+ GLuint m_offset, m_data_size, m_type,
+ m_data_type;
+ std::string m_name, m_description;
+};
+
+
+class PerfMetricGroup : public NoCopy, NoAssign {
+ public:
+ explicit PerfMetricGroup(int query_id);
+ ~PerfMetricGroup();
+ const std::string &name() const { return m_query_name; }
+ void metrics(std::vector<MetricDescription> *m) const;
+ void begin(RenderId render);
+ void end(RenderId render);
+ void publish(MetricId metric, PerfMetricsIntel::MetricMap *m);
+
+ private:
+ std::string m_query_name;
+ const int m_query_id;
+ unsigned int m_data_size;
+ std::vector<unsigned char> m_data_buf;
+
+ std::map<MetricId, PerfMetric *> m_metrics;
+
+ // represent queries that have not produced results
+ std::map<RenderId, int> m_extant_query_handles;
+
+ // represent query handles that can be reused
+ std::vector<unsigned int> m_free_query_handles;
+};
+
+} // namespace
+
+namespace glretrace {
+
+class PerfMetricsContext : public NoCopy, NoAssign {
+ public:
+ explicit PerfMetricsContext(OnFrameRetrace *cb);
+ ~PerfMetricsContext();
+ int groupCount() const;
+ void selectMetric(MetricId metric);
+ void selectGroup(int index);
+ void begin(RenderId render);
+ void end();
+ void publish(PerfMetricsIntel::MetricMap *metrics);
+ private:
+ std::vector<PerfMetricGroup *> groups;
+ // indicates offset in groups of PerfMetricGroup reporting MetricId
+ std::map<MetricId, int> metric_map;
+ // indicates the group that will handle subsequent begin/end calls
+ PerfMetricGroup *current_group;
+ MetricId current_metric;
+ RenderId current_render;
+};
+
+} // namespace glretrace
+
+PerfMetricsContext::PerfMetricsContext(OnFrameRetrace *cb)
+ : current_group(NULL) {
+ GLuint query_id;
+ GLint count;
+ bool has_metrics = false;
+ GlFunctions::GetIntegerv(GL_NUM_EXTENSIONS, &count);
+ for (int i = 0; i < count; ++i) {
+ const GLubyte *name = GlFunctions::GetStringi(GL_EXTENSIONS, i);
+ if (strcmp((const char*)name, "GL_INTEL_performance_query") == 0)
+ has_metrics = true;
+ }
+ if (!has_metrics)
+ return;
+
+ GlFunctions::GetFirstPerfQueryIdINTEL(&query_id);
+ if (query_id == GLuint(-1))
+ return;
+
+ if (query_id == 0)
+ return;
+ std::vector<unsigned int> query_ids;
+ query_ids.push_back(query_id);
+
+ while (true) {
+ GlFunctions::GetNextPerfQueryIdINTEL(query_id, &query_id);
+ if (!query_id)
+ break;
+ query_ids.push_back(query_id);
+ }
+
+ std::map<std::string, MetricDescription> known_metrics;
+
+ std::vector<MetricDescription> metrics;
+ int group_index = 0;
+ for (auto i : query_ids) {
+ PerfMetricGroup *g = new PerfMetricGroup(i);
+ if (g->name() == "Compute Metrics Extended Gen9") {
+ // SKL metrics bug. Queries on this group crash.
+ delete g;
+ continue;
+ }
+
+ groups.push_back(g);
+ metrics.clear();
+ g->metrics(&metrics);
+ for (auto &d : metrics) {
+ if (known_metrics.find(d.name) == known_metrics.end()) {
+ known_metrics[d.name] = d;
+ metric_map[d.id] = group_index;
+ }
+ }
+ ++group_index;
+ }
+ std::vector<MetricId> ids;
+ std::vector<std::string> names;
+ std::vector<std::string> descriptions;
+ for (auto &i : known_metrics) {
+ names.push_back(i.second.name);
+ ids.push_back(i.second.id);
+ descriptions.push_back(i.second.description);
+ }
+ if (cb)
+ // only send metrics list on first context
+ cb->onMetricList(ids, names, descriptions);
+}
+
+PerfMetricsContext::~PerfMetricsContext() {
+ for (auto g : groups)
+ delete g;
+ groups.clear();
+}
+
+PerfMetricGroup::PerfMetricGroup(int query_id) : m_query_id(query_id) {
+ static GLint max_name_len = 0;
+ if (max_name_len == 0)
+ GlFunctions::GetIntegerv(GL_PERFQUERY_QUERY_NAME_LENGTH_MAX_INTEL,
+ &max_name_len);
+
+ std::vector<GLchar> query_name(max_name_len);
+ unsigned int number_instances, capabilities_mask, number_counters;
+ GlFunctions::GetPerfQueryInfoINTEL(m_query_id,
+ query_name.size(), query_name.data(),
+ &m_data_size, &number_counters,
+ &number_instances, &capabilities_mask);
+ m_data_buf.resize(m_data_size);
+ m_query_name = query_name.data();
+ for (unsigned int counter_num = 1; counter_num <= number_counters;
+ ++counter_num) {
+ PerfMetric *p = new PerfMetric(m_query_id, counter_num);
+ m_metrics[p->id()] = p;
+ }
+}
+
+PerfMetricGroup::~PerfMetricGroup() {
+ for (auto free_query : m_free_query_handles) {
+ GlFunctions::DeletePerfQueryINTEL(free_query);
+ }
+ m_free_query_handles.clear();
+ assert(m_extant_query_handles.empty());
+ for (auto m : m_metrics)
+ delete m.second;
+ m_metrics.clear();
+}
+
+void
+PerfMetricGroup::metrics(std::vector<MetricDescription> *m) const {
+ for (auto &i : m_metrics) {
+ m->push_back(MetricDescription(i.first,
+ i.second->name(),
+ i.second->description()));
+ }
+}
+
+void
+PerfMetricGroup::begin(RenderId render) {
+ if (m_free_query_handles.empty()) {
+ GLuint query_handle;
+ GlFunctions::CreatePerfQueryINTEL(m_query_id, &query_handle);
+ m_free_query_handles.push_back(query_handle);
+ }
+ GLuint query_handle = m_free_query_handles.back();
+ m_free_query_handles.pop_back();
+
+ // When more than one process requests metrics concurrently,
+ // BeginPerfQueryINTEL fails.
+ int retry = 0;
+ GL::GetError();
+ while (true) {
+ GlFunctions::BeginPerfQueryINTEL(query_handle);
+ if (GL_NO_ERROR == GL::GetError())
+ break;
+ if (++retry > 20) {
+ GRLOG(glretrace::ERR, "failed to begin metrics query, aborting");
+ assert(false);
+ exit(-1);
+ }
+ GRLOG(glretrace::WARN, "failed to begin metrics query");
+ glretrace_delay(200);
+ }
+ m_extant_query_handles[render] = query_handle;
+}
+
+static const MetricId ALL_METRICS_IN_GROUP = MetricId(~ID_PREFIX_MASK);
+
+void
+PerfMetricGroup::publish(MetricId metric,
+ PerfMetricsIntel::MetricMap *out_metrics) {
+ const bool publish_all = (metric == ALL_METRICS_IN_GROUP);
+ for (auto extant_query : m_extant_query_handles) {
+ memset(m_data_buf.data(), 0, m_data_buf.size());
+ GLuint bytes_written;
+ GlFunctions::GetPerfQueryDataINTEL(extant_query.second,
+ GL_PERFQUERY_WAIT_INTEL,
+ m_data_size, m_data_buf.data(),
+ &bytes_written);
+ assert(bytes_written == m_data_size);
+
+ if (publish_all) {
+ for (auto desired_metric : m_metrics) {
+ MetricId met_id = desired_metric.first;
+ (*out_metrics)[met_id][extant_query.first] =
+ desired_metric.second->getMetric(m_data_buf);
+ }
+ } else {
+ (*out_metrics)[metric][extant_query.first] =
+ m_metrics[metric]->getMetric(m_data_buf);
+ }
+ m_free_query_handles.push_back(extant_query.second);
+ }
+ m_extant_query_handles.clear();
+ for (auto free_query : m_free_query_handles) {
+ GlFunctions::DeletePerfQueryINTEL(free_query);
+ }
+ m_free_query_handles.clear();
+}
+
+void
+PerfMetricGroup::end(RenderId render) {
+ if (m_extant_query_handles.find(render) != m_extant_query_handles.end())
+ GlFunctions::EndPerfQueryINTEL(m_extant_query_handles[render]);
+}
+
+
+PerfMetric::PerfMetric(int query_id,
+ int counter_num) : m_query_id(query_id),
+ m_counter_num(counter_num) {
+ static GLint max_name_len = 0, max_desc_len = 0;
+ if (max_name_len == 0)
+ GlFunctions::GetIntegerv(GL_PERFQUERY_COUNTER_NAME_LENGTH_MAX_INTEL,
+ &max_name_len);
+ if (max_desc_len == 0)
+ GlFunctions::GetIntegerv(GL_PERFQUERY_COUNTER_DESC_LENGTH_MAX_INTEL,
+ &max_desc_len);
+ std::vector<GLchar> counter_name(max_name_len);
+ std::vector<GLchar> counter_description(max_desc_len);
+ GLuint64 max_value;
+ GlFunctions::GetPerfCounterInfoINTEL(m_query_id, m_counter_num,
+ counter_name.size(), counter_name.data(),
+ counter_description.size(),
+ counter_description.data(),
+ &m_offset, &m_data_size, &m_type,
+ &m_data_type, &max_value);
+ m_name = counter_name.data();
+ m_description = counter_description.data();
+}
+
+MetricId
+PerfMetric::id() const {
+ return MetricId(m_query_id, m_counter_num);
+}
+
+const std::string &
+PerfMetric::name() const {
+ return m_name;
+}
+
+const std::string &
+PerfMetric::description() const {
+ return m_description;
+}
+
+float
+PerfMetric::getMetric(const std::vector<unsigned char> &data) const {
+ const unsigned char *p_value = data.data() + m_offset;
+ float fval;
+ switch (m_data_type) {
+ case GL_PERFQUERY_COUNTER_DATA_UINT32_INTEL: {
+ assert(m_data_size == 4);
+ const uint32_t val = *reinterpret_cast<const uint32_t *>(p_value);
+ fval = static_cast<float>(val);
+ break;
+ }
+ case GL_PERFQUERY_COUNTER_DATA_UINT64_INTEL: {
+ assert(m_data_size == 8);
+ const uint64_t val = *reinterpret_cast<const uint64_t *>(p_value);
+ fval = static_cast<float>(val);
+ break;
+ }
+ case GL_PERFQUERY_COUNTER_DATA_FLOAT_INTEL: {
+ assert(m_data_size == 4);
+ fval = *reinterpret_cast<const float *>(p_value);
+ break;
+ }
+ case GL_PERFQUERY_COUNTER_DATA_DOUBLE_INTEL: {
+ assert(m_data_size == 8);
+ const double val = *reinterpret_cast<const double *>(p_value);
+ fval = static_cast<float>(val);
+ break;
+ }
+ case GL_PERFQUERY_COUNTER_DATA_BOOL32_INTEL: {
+ assert(m_data_size == 4);
+ const bool val = *reinterpret_cast<const bool*>(p_value);
+ fval = val ? 1.0 : 0.0;
+ break;
+ }
+ default:
+ assert(false);
+ }
+ return fval;
+}
+
+void
+PerfMetricsContext::selectMetric(MetricId metric) {
+ assert(metric_map.find(metric) != metric_map.end());
+ current_metric = metric;
+ current_group = groups[metric_map[metric]];
+}
+
+void
+PerfMetricsContext::publish(PerfMetricsIntel::MetricMap *metrics) {
+ current_group->publish(current_metric, metrics);
+}
+
+void
+PerfMetricsContext::begin(RenderId render) {
+ current_group->begin(render);
+ current_render = render;
+}
+
+void
+PerfMetricsContext::end() {
+ current_group->end(current_render);
+}
+
+int
+PerfMetricsContext::groupCount() const {
+ return groups.size();
+}
+
+void
+PerfMetricsContext::selectGroup(int index) {
+ current_group = groups[index];
+ current_metric = ALL_METRICS_IN_GROUP;
+}
+
+PerfMetricsIntel::PerfMetricsIntel(OnFrameRetrace *cb)
+ : m_current_group(0) {
+ Context *c = getCurrentContext();
+ m_current_context = new PerfMetricsContext(cb);
+ m_contexts[c] = m_current_context;
+}
+
+PerfMetricsIntel::~PerfMetricsIntel() {
+ for (auto i : m_contexts) {
+ delete i.second;
+ }
+ m_contexts.clear();
+}
+
+int
+PerfMetricsIntel::groupCount() const {
+ assert(!m_contexts.empty());
+ return m_contexts.begin()->second->groupCount();
+}
+
+void
+PerfMetricsIntel::selectMetric(MetricId metric) {
+ m_data.clear();
+ m_current_metric = metric;
+ for (auto i : m_contexts)
+ i.second->selectMetric(metric);
+}
+
+void
+PerfMetricsIntel::selectGroup(int index) {
+ m_current_group = index;
+ m_current_metric = ALL_METRICS_IN_GROUP;
+ for (auto i : m_contexts)
+ i.second->selectGroup(index);
+}
+
+void
+PerfMetricsIntel::begin(RenderId render) {
+ if (!m_current_context) {
+ beginContext();
+ }
+ m_current_context->begin(render);
+}
+
+void
+PerfMetricsIntel::end() {
+ if (m_current_context)
+ m_current_context->end();
+}
+
+void
+PerfMetricsIntel::publish(ExperimentId experimentCount,
+ SelectionId selectionCount,
+ OnFrameRetrace *callback) {
+ for (auto i : m_contexts)
+ i.second->publish(&m_data);
+
+ for (auto i : m_data) {
+ MetricSeries s;
+ s.metric = i.first;
+ s.data.resize(i.second.rbegin()->first.index() + 1);
+ for (auto datapoint : i.second)
+ s.data[datapoint.first.index()] = datapoint.second;
+ callback->onMetrics(s, experimentCount, selectionCount);
+ }
+ m_data.clear();
+}
+
+void
+PerfMetricsIntel::beginContext() {
+ Context *c = getCurrentContext();
+ auto entry = m_contexts.find(c);
+ if (entry != m_contexts.end()) {
+ m_current_context = entry->second;
+ } else {
+ // create a new metrics context
+ GRLOG(glretrace::WARN, "new context in frame");
+ m_current_context = new PerfMetricsContext(NULL);
+ m_contexts[c] = m_current_context;
+ }
+ m_current_context->selectGroup(m_current_group);
+ if (m_current_metric() &&
+ (m_current_metric != ALL_METRICS_IN_GROUP))
+ m_current_context->selectMetric(m_current_metric);
+}
+
+void
+PerfMetricsIntel::endContext() {
+ if (m_current_context) {
+ m_current_context->end();
+ m_current_context->publish(&m_data);
+ }
+ m_current_context = NULL;
+}
diff --git a/retrace/daemon/glframe_metrics_intel.hpp b/retrace/daemon/glframe_metrics_intel.hpp
new file mode 100644
index 00000000..3ab47c77
--- /dev/null
+++ b/retrace/daemon/glframe_metrics_intel.hpp
@@ -0,0 +1,68 @@
+// Copyright (C) Intel Corp. 2015. All Rights Reserved.
+
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+
+// The above copyright notice and this permission notice (including the
+// next paragraph) shall be included in all copies or substantial
+// portions of the Software.
+
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// **********************************************************************/
+// * Authors:
+// * Mark Janes <mark.a.janes@intel.com>
+// **********************************************************************/
+
+#ifndef _GLFRAME_METRICS_INTEL_HPP_
+#define _GLFRAME_METRICS_INTEL_HPP_
+
+#include <map>
+#include <vector>
+
+#include "glframe_metrics.hpp"
+#include "glframe_traits.hpp"
+#include "glframe_retrace.hpp"
+
+namespace glretrace {
+
+class PerfMetricsContext;
+struct Context;
+
+class PerfMetricsIntel : public PerfMetrics, NoCopy, NoAssign {
+ public:
+ explicit PerfMetricsIntel(OnFrameRetrace *cb);
+ ~PerfMetricsIntel();
+ int groupCount() const;
+ void selectMetric(MetricId metric);
+ void selectGroup(int index);
+ void begin(RenderId render);
+ void end();
+ void publish(ExperimentId experimentCount,
+ SelectionId selectionCount,
+ OnFrameRetrace *callback);
+ void endContext();
+ void beginContext();
+ typedef std::map<MetricId, std::map<RenderId, float>> MetricMap;
+ private:
+ PerfMetricsContext* m_current_context;
+ std::map<Context*, PerfMetricsContext*> m_contexts;
+ MetricMap m_data;
+ int m_current_group;
+ MetricId m_current_metric;
+};
+
+} // namespace glretrace
+
+#endif /* _GLFRAME_METRICS_INTEL_HPP__ */
diff --git a/retrace/daemon/glframe_retrace.cpp b/retrace/daemon/glframe_retrace.cpp
index 0f340312..5e04d1f3 100644
--- a/retrace/daemon/glframe_retrace.cpp
+++ b/retrace/daemon/glframe_retrace.cpp
@@ -163,7 +163,7 @@ FrameRetrace::openFile(const std::string &filename,
}
// sends list of available metrics to ui
- m_metrics = new PerfMetrics(callback);
+ m_metrics = PerfMetrics::Create(callback);
parser->getBookmark(frame_start.start);
// play through the frame, recording each context
@@ -277,7 +277,7 @@ FrameRetrace::retraceMetrics(const std::vector<MetricId> &ids,
i->retraceMetrics(m_metrics, m_tracker);
m_metrics->publish(experimentCount,
SelectionId(0), // this use case is not based
- // on render selection
+ // on render selection
callback);
}
}