]> git.cworth.org Git - apitrace/blobdiff - gui/calldurationgraph.h
Rewrote profile graph drawing code.
[apitrace] / gui / calldurationgraph.h
diff --git a/gui/calldurationgraph.h b/gui/calldurationgraph.h
new file mode 100644 (file)
index 0000000..0c7e8c9
--- /dev/null
@@ -0,0 +1,173 @@
+#ifndef CALLDURATIONGRAPH_H
+#define CALLDURATIONGRAPH_H
+
+#include "graphing/graphwidget.h"
+#include "trace_profiler.hpp"
+#include "profiling.h"
+
+/**
+ * Wrapper for call duration graphs.
+ *
+ * This implements the transformSelectionIn and transformSelectionOut to
+ * allow sharing the selection between the graphs and the heatmap as they
+ * are using different scales. The duration graphs have call.no on the X-axis
+ * whereas the heatmap has time on the X axis.
+ */
+class CallDurationGraph : public GraphWidget {
+public:
+    CallDurationGraph(QWidget* parent = 0) :
+        GraphWidget(parent),
+        m_profile(NULL)
+    {
+    }
+
+    void setProfile(const trace::Profile* profile)
+    {
+        m_profile = profile;
+    }
+
+protected:
+    /* Transform from time-based horizontal selection to call no based. */
+    virtual SelectionState transformSelectionIn(SelectionState state)
+    {
+        if (!m_profile || state.type != SelectionState::Horizontal) {
+            return state;
+        }
+
+        qint64 timeStart = state.start;
+        qint64 timeEnd = state.end;
+
+        std::vector<trace::Profile::Call>::const_iterator itr;
+
+        itr =
+            Profiling::binarySearchTimespan<
+                trace::Profile::Call,
+                &trace::Profile::Call::cpuStart,
+                &trace::Profile::Call::cpuDuration>
+            (m_profile->calls.begin(), m_profile->calls.end(), timeStart, true);
+
+        state.start = itr - m_profile->calls.begin();
+
+        itr =
+            Profiling::binarySearchTimespan<
+                trace::Profile::Call,
+                &trace::Profile::Call::cpuStart,
+                &trace::Profile::Call::cpuDuration>
+            (m_profile->calls.begin(), m_profile->calls.end(), timeEnd, true);
+
+        state.end = itr - m_profile->calls.begin();
+
+        return state;
+    }
+
+    virtual SelectionState transformSelectionOut(SelectionState state)
+    {
+        if (!m_profile || state.type != SelectionState::Horizontal) {
+            return state;
+        }
+
+        qint64 start = qMax<qint64>(0, state.start);
+        qint64 end = qMin<qint64>(state.end, m_profile->calls.size());
+
+        /* Call based -> time based */
+        state.start = m_profile->calls[start].cpuStart;
+        state.end = m_profile->calls[end].cpuStart + m_profile->calls[end].cpuDuration;
+
+        return state;
+    }
+
+private:
+    const trace::Profile* m_profile;
+};
+
+/* Data provider for call duration graphs */
+class CallDurationDataProvider : public GraphDataProvider {
+public:
+    CallDurationDataProvider(const trace::Profile* profile, bool gpu) :
+        m_gpu(gpu),
+        m_profile(profile),
+        m_selectionState(NULL)
+    {
+    }
+
+    virtual qint64 size() const
+    {
+        return m_profile ? m_profile->calls.size() : 0;
+    }
+
+    virtual bool selected(qint64 index) const
+    {
+        if (m_selectionState) {
+            if (m_selectionState->type == SelectionState::Horizontal) {
+                if (m_selectionState->start <= index && index < m_selectionState->end) {
+                    return true;
+                }
+            } else if (m_selectionState->type == SelectionState::Vertical) {
+                return m_profile->calls[index].program == m_selectionState->start;
+            }
+        }
+
+        return false;
+    }
+
+    virtual void setSelectionState(SelectionState* state)
+    {
+        m_selectionState = state;
+    }
+
+    virtual qint64 value(qint64 index) const
+    {
+        if (m_gpu) {
+            return m_profile->calls[index].gpuDuration;
+        } else {
+            return m_profile->calls[index].cpuDuration;
+        }
+    }
+
+    virtual void itemDoubleClicked(qint64 index) const
+    {
+        if (!m_profile) {
+            return;
+        }
+
+        if (index < 0 || index >= m_profile->calls.size()) {
+            return;
+        }
+
+        const trace::Profile::Call& call = m_profile->calls[index];
+        Profiling::jumpToCall(call.no);
+    }
+
+    virtual QString itemTooltip(qint64 index) const
+    {
+        if (!m_profile) {
+            return QString();
+        }
+
+        if (index < 0 || index >= m_profile->calls.size()) {
+            return QString();
+        }
+
+        const trace::Profile::Call& call = m_profile->calls[index];
+
+        QString text;
+        text  = QString::fromStdString(call.name);
+        text += QString("\nCall: %1").arg(call.no);
+        text += QString("\nCPU Duration: %1").arg(Profiling::getTimeString(call.cpuDuration));
+
+        if (call.pixels >= 0) {
+            text += QString("\nGPU Duration: %1").arg(Profiling::getTimeString(call.gpuDuration));
+            text += QString("\nPixels Drawn: %1").arg(QLocale::system().toString((qlonglong)call.pixels));
+            text += QString("\nProgram: %1").arg(call.program);
+        }
+
+        return text;
+    }
+
+private:
+    bool m_gpu;
+    const trace::Profile* m_profile;
+    SelectionState* m_selectionState;
+};
+
+#endif