1 #include "profiledialog.h"
2 #include "profiletablemodel.h"
3 #include <QSortFilterProxyModel>
4 
5 #include "graphing/histogramview.h"
6 #include "graphing/timeaxiswidget.h"
7 #include "graphing/frameaxiswidget.h"
8 #include "graphing/heatmapverticalaxiswidget.h"
9 #include "profileheatmap.h"
10 
11 /* Handy function to allow selection of a call in main window */
12 ProfileDialog* g_profileDialog = 0;
13 
jumpToCall(int index)14 void Profiling::jumpToCall(int index)
15 {
16     if (g_profileDialog) {
17         g_profileDialog->showCall(index);
18     }
19 }
20 
21 /* Provides frame numbers based off call index */
22 class FrameCallDataProvider : public FrameDataProvider {
23 public:
FrameCallDataProvider(const trace::Profile * profile)24     FrameCallDataProvider(const trace::Profile* profile)
25     {
26         m_profile = profile;
27     }
28 
size() const29     unsigned size() const override {
30         return m_profile->frames.size();
31     }
32 
frameStart(unsigned index) const33     qint64 frameStart(unsigned index) const override {
34         return m_profile->frames[index].calls.begin;
35     }
36 
frameEnd(unsigned index) const37     qint64 frameEnd(unsigned index) const override {
38         return m_profile->frames[index].calls.end;
39     }
40 
41 private:
42     const trace::Profile* m_profile;
43 };
44 
45 /* Provides frame numbers based off time */
46 class FrameTimeDataProvider : public FrameDataProvider {
47 public:
FrameTimeDataProvider(const trace::Profile * profile)48     FrameTimeDataProvider(const trace::Profile* profile)
49     {
50         m_profile = profile;
51     }
52 
size() const53     unsigned size() const override {
54         return m_profile->frames.size();
55     }
56 
frameStart(unsigned index) const57     qint64 frameStart(unsigned index) const override {
58         return m_profile->frames[index].cpuStart;
59     }
60 
frameEnd(unsigned index) const61     qint64 frameEnd(unsigned index) const override {
62         return m_profile->frames[index].cpuStart + m_profile->frames[index].cpuDuration;
63     }
64 
65 private:
66     const trace::Profile* m_profile;
67 };
68 
ProfileDialog(QWidget * parent)69 ProfileDialog::ProfileDialog(QWidget *parent)
70     : QDialog(parent),
71       m_profile(0)
72 {
73     setupUi(this);
74     g_profileDialog = this;
75 
76     /* Gradients for call duration histograms */
77     QLinearGradient cpuGradient;
78     cpuGradient.setColorAt(0.9, QColor(0, 0, 210));
79     cpuGradient.setColorAt(0.0, QColor(130, 130, 255));
80 
81     QLinearGradient gpuGradient;
82     gpuGradient.setColorAt(0.9, QColor(210, 0, 0));
83     gpuGradient.setColorAt(0.0, QColor(255, 130, 130));
84 
85 
86     /* Setup heatmap timeline */
87     m_timeline->setLabel(new GraphLabelWidget("Frames ", m_timeline));
88     m_timeline->label()->setFlags(Qt::AlignVCenter | Qt::AlignRight);
89 
90     m_timeline->setView(new HeatmapView(m_timeline));
91 
92     m_timeline->setAxis(GraphWidget::AxisTop, new FrameAxisWidget(m_timeline));
93     m_timeline->setAxis(GraphWidget::AxisLeft, new HeatmapVerticalAxisWidget(m_timeline));
94     m_timeline->axis(GraphWidget::AxisLeft)->resize(80, 0);
95 
96     m_timeline->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
97     m_timeline->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
98 
99 
100     /* Setup Cpu call duration histogram */
101     m_cpuGraph->setLabel(new GraphLabelWidget("CPU", m_cpuGraph));
102 
103     m_cpuGraph->setAxis(GraphWidget::AxisTop, new FrameAxisWidget(m_cpuGraph));
104     m_cpuGraph->setAxis(GraphWidget::AxisLeft, new TimeAxisWidget(m_cpuGraph));
105     m_cpuGraph->axis(GraphWidget::AxisLeft)->resize(80, 0);
106 
107     HistogramView* cpuView = new HistogramView(m_cpuGraph);
108     cpuView->setSelectedGradient(cpuGradient);
109     m_cpuGraph->setView(cpuView);
110 
111 
112     /* Setup Gpu call duration histogram */
113     m_gpuGraph->setLabel(new GraphLabelWidget("GPU", m_gpuGraph));
114 
115     m_gpuGraph->setAxis(GraphWidget::AxisTop, new FrameAxisWidget(m_gpuGraph));
116     m_gpuGraph->setAxis(GraphWidget::AxisLeft, new TimeAxisWidget(m_gpuGraph));
117     m_gpuGraph->axis(GraphWidget::AxisLeft)->resize(80, 0);
118 
119     HistogramView* gpuView = new HistogramView(m_gpuGraph);
120     gpuView->setSelectedGradient(gpuGradient);
121     m_gpuGraph->setView(gpuView);
122 
123 
124     /* Synchronise selections */
125     connect(m_timeline, SIGNAL(selectionChanged(SelectionState)), m_cpuGraph, SLOT(setSelection(SelectionState)));
126     connect(m_timeline, SIGNAL(selectionChanged(SelectionState)), m_gpuGraph, SLOT(setSelection(SelectionState)));
127 
128     connect(m_cpuGraph, SIGNAL(selectionChanged(SelectionState)), m_timeline, SLOT(setSelection(SelectionState)));
129     connect(m_cpuGraph, SIGNAL(selectionChanged(SelectionState)), m_gpuGraph, SLOT(setSelection(SelectionState)));
130 
131     connect(m_gpuGraph, SIGNAL(selectionChanged(SelectionState)), m_timeline, SLOT(setSelection(SelectionState)));
132     connect(m_gpuGraph, SIGNAL(selectionChanged(SelectionState)), m_cpuGraph, SLOT(setSelection(SelectionState)));
133 
134     connect(m_timeline, SIGNAL(selectionChanged(SelectionState)), this, SLOT(graphSelectionChanged(SelectionState)));
135     connect(m_cpuGraph, SIGNAL(selectionChanged(SelectionState)), this, SLOT(graphSelectionChanged(SelectionState)));
136     connect(m_gpuGraph, SIGNAL(selectionChanged(SelectionState)), this, SLOT(graphSelectionChanged(SelectionState)));
137 
138 
139     /* Synchronise views between cpuGraph and gpuGraph */
140     connect(m_cpuGraph, SIGNAL(horizontalViewChanged(qint64,qint64)), m_gpuGraph, SLOT(setHorizontalView(qint64,qint64)));
141     connect(m_gpuGraph, SIGNAL(horizontalViewChanged(qint64,qint64)), m_cpuGraph, SLOT(setHorizontalView(qint64,qint64)));
142 }
143 
144 
~ProfileDialog()145 ProfileDialog::~ProfileDialog()
146 {
147     delete m_profile;
148 }
149 
150 
showCall(int call)151 void ProfileDialog::showCall(int call)
152 {
153     emit jumpToCall(call);
154 }
155 
156 
tableDoubleClicked(const QModelIndex & index)157 void ProfileDialog::tableDoubleClicked(const QModelIndex& index)
158 {
159     ProfileTableModel* model = (ProfileTableModel*)m_table->model();
160 
161     if (!model) {
162         return;
163     }
164 
165     const trace::Profile::Call* call = model->getJumpCall(index);
166 
167     if (call) {
168         emit jumpToCall(call->no);
169     } else {
170         unsigned program = model->getProgram(index);
171 
172         SelectionState state;
173         state.type = SelectionState::Vertical;
174         state.end = state.start = program;
175 
176         m_timeline->setSelection(state);
177         m_cpuGraph->setSelection(state);
178         m_gpuGraph->setSelection(state);
179     }
180 }
181 
182 
setProfile(trace::Profile * profile)183 void ProfileDialog::setProfile(trace::Profile* profile)
184 {
185 
186     if (profile && profile->frames.size()) {
187         HeatmapVerticalAxisWidget* programAxis;
188         FrameAxisWidget* frameAxis;
189         HistogramView* histogram;
190         HeatmapView* heatmap;
191 
192 
193         /* Setup data providers for Cpu graph */
194         m_cpuGraph->setProfile(profile);
195         histogram = (HistogramView*)m_cpuGraph->view();
196         frameAxis = (FrameAxisWidget*)m_cpuGraph->axis(GraphWidget::AxisTop);
197 
198         histogram->setDataProvider(new CallDurationDataProvider(profile, false));
199         frameAxis->setDataProvider(new FrameCallDataProvider(profile));
200 
201         /* Setup data provider for Gpu graph */
202         m_gpuGraph->setProfile(profile);
203         histogram = (HistogramView*)m_gpuGraph->view();
204         frameAxis = (FrameAxisWidget*)m_gpuGraph->axis(GraphWidget::AxisTop);
205 
206         histogram->setDataProvider(new CallDurationDataProvider(profile, true));
207         frameAxis->setDataProvider(new FrameCallDataProvider(profile));
208 
209         /* Setup data provider for heatmap timeline */
210         heatmap = (HeatmapView*)m_timeline->view();
211         frameAxis = (FrameAxisWidget*)m_timeline->axis(GraphWidget::AxisTop);
212         programAxis = (HeatmapVerticalAxisWidget*)m_timeline->axis(GraphWidget::AxisLeft);
213 
214         heatmap->setDataProvider(new ProfileHeatmapDataProvider(profile));
215         frameAxis->setDataProvider(new FrameTimeDataProvider(profile));
216         programAxis->setDataProvider(new ProfileHeatmapDataProvider(profile));
217 
218         /* Setup data model for table view */
219         ProfileTableModel* model = new ProfileTableModel(m_table);
220         model->setProfile(profile);
221 
222         delete m_table->model();
223         m_table->setModel(model);
224         m_table->update(QModelIndex());
225         m_table->sortByColumn(2, Qt::DescendingOrder);
226         m_table->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
227         m_table->resizeColumnsToContents();
228 
229         /* Reset selection */
230         SelectionState emptySelection;
231         emptySelection.type = SelectionState::None;
232         m_cpuGraph->setSelection(emptySelection);
233         m_gpuGraph->setSelection(emptySelection);
234         m_timeline->setSelection(emptySelection);
235     }
236 
237     delete m_profile;
238     m_profile = profile;
239 }
240 
241 
graphSelectionChanged(SelectionState state)242 void ProfileDialog::graphSelectionChanged(SelectionState state)
243 {
244     ProfileTableModel* model = (ProfileTableModel*)m_table->model();
245 
246     if (!model) {
247         return;
248     }
249 
250     if (state.type == SelectionState::None) {
251         model->selectNone();
252     } else if (state.type == SelectionState::Horizontal) {
253         model->selectTime(state.start, state.end);
254     } else if (state.type == SelectionState::Vertical) {
255         model->selectProgram(state.start);
256     }
257 
258     m_table->reset();
259 
260     if (state.type == SelectionState::Vertical) {
261         m_table->selectRow(model->getRowIndex(state.start));
262     }
263 }
264 
265 #include "profiledialog.moc"
266