blob: 7a3145543b221d35717d2c41be6dcc21e7a1ea38 [file] [log] [blame]
#pragma once
#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) override
{
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) override
{
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 override
{
return m_profile ? m_profile->calls.size() : 0;
}
virtual bool selected(qint64 index) const override
{
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) override
{
m_selectionState = state;
}
virtual qint64 value(qint64 index) const override
{
if (m_gpu) {
return m_profile->calls[index].gpuDuration;
} else {
return m_profile->calls[index].cpuDuration;
}
}
virtual void itemDoubleClicked(qint64 index) const override
{
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 override
{
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;
};