blob: e4c4735017ee3b2af1c56bf4dec8ac174a1d9e92 [file] [log] [blame]
Jose Fonseca9653f952015-05-19 16:32:43 +01001#pragma once
James Benton0b65a2b2012-09-07 18:38:15 +01002
3#include "graphing/heatmapview.h"
4#include "profiling.h"
5
6/**
7 * Data providers for a heatmap based off the trace::Profile call data
8 */
9
10class ProfileHeatmapRowIterator : public HeatmapRowIterator {
11public:
12 ProfileHeatmapRowIterator(const trace::Profile* profile, qint64 start, qint64 end, int steps, bool gpu, int program = -1) :
13 m_profile(profile),
14 m_step(-1),
15 m_stepWidth(1),
16 m_stepCount(steps),
17 m_index(0),
18 m_timeStart(start),
19 m_timeEnd(end),
20 m_useGpu(gpu),
21 m_program(program),
22 m_selected(false),
23 m_timeSelection(false),
24 m_programSelection(false)
25 {
26 m_timeWidth = m_timeEnd - m_timeStart;
27 }
28
Jose Fonseca010f9962016-03-05 14:45:41 +000029 virtual bool next() override
James Benton0b65a2b2012-09-07 18:38:15 +010030 {
31 unsigned maxIndex = m_program == -1 ? m_profile->calls.size() : m_profile->programs[m_program].calls.size();
32
33 if (m_index >= maxIndex) {
34 return false;
35 }
36
37 double dtds = m_timeWidth / (double)m_stepCount;
38
39 qint64 heatDuration = 0;
40 qint64 programHeatDuration = 0;
41 m_heat = 0.0f;
42 m_step += m_stepWidth;
43 m_stepWidth = 1;
44
45 m_selected = false;
46
47 /* Iterator through calls until step != lastStep */
48 for (; m_index < maxIndex; ++m_index)
49 {
50 const trace::Profile::Call* call;
51
52 if (m_program == -1) {
53 call = &m_profile->calls[m_index];
54 } else {
55 call = &m_profile->calls[ m_profile->programs[m_program].calls[m_index] ];
56 }
57
58 qint64 start, duration, end;
59
60 if (m_useGpu) {
61 start = call->gpuStart;
62 duration = call->gpuDuration;
63
64 if (call->pixels < 0) {
65 continue;
66 }
67 } else {
68 start = call->cpuStart;
69 duration = call->cpuDuration;
70 }
71
72 end = start + duration;
73
74 if (end < m_timeStart) {
75 continue;
76 }
77
78 if (start > m_timeEnd) {
79 m_index = m_profile->calls.size();
80 break;
81 }
82
83 double left = timeToStep(start);
84 double right = timeToStep(end);
85
86 int leftStep = left;
87 int rightStep = right;
88
89 if (leftStep > m_step) {
90 break;
91 }
92
93 if (m_programSelection && call->program == m_programSel) {
94 m_selected = true;
95 }
96
97 if (rightStep - leftStep > 1) {
98 m_label = QString::fromStdString(call->name);
99 m_step = left;
100 m_stepWidth = rightStep - leftStep;
101 heatDuration = dtds;
102 ++m_index;
103 break;
104 }
105
106 if (leftStep < m_step) {
107 qint64 rightTime = stepToTime(rightStep);
108 heatDuration += end - rightTime;
109
110 if (m_programSelection && call->program == m_programSel) {
111 programHeatDuration += end - rightTime;
112 }
113 } else if (leftStep == rightStep) {
114 heatDuration += duration;
115
116 if (m_programSelection && call->program == m_programSel) {
117 programHeatDuration += duration;
118 }
119 } else if (rightStep - leftStep == 1) {
120 qint64 rightTime = stepToTime(rightStep);
121 heatDuration += rightTime - start;
122
123 if (m_programSelection && call->program == m_programSel) {
124 programHeatDuration += rightTime - start;
125 }
126
127 break;
128 }
129 }
130
131 m_heat = heatDuration / dtds;
132 m_programHeat = programHeatDuration / dtds;
133
134 if (m_timeSelection) {
135 qint64 time = stepToTime(m_step);
136
137 if (time >= m_timeSelStart && time <= m_timeSelEnd) {
138 m_programHeat = 1.0;
139 }
140 }
141
142 if (m_programSelection && (m_program == m_programSel || (m_selected && m_stepWidth > 1))) {
143 m_programHeat = 1.0;
144 }
145
146 if (m_programHeat > 0) {
147 m_selected = true;
148 }
149
150 return true;
151 }
152
Jose Fonseca010f9962016-03-05 14:45:41 +0000153 virtual bool isGpu() const override
James Benton0b65a2b2012-09-07 18:38:15 +0100154 {
155 return m_useGpu;
156 }
157
Jose Fonseca010f9962016-03-05 14:45:41 +0000158 virtual float heat() const override
James Benton0b65a2b2012-09-07 18:38:15 +0100159 {
160 return m_heat;
161 }
162
Jose Fonseca010f9962016-03-05 14:45:41 +0000163 virtual float selectedHeat() const override
James Benton0b65a2b2012-09-07 18:38:15 +0100164 {
165 return m_programHeat;
166 }
167
Jose Fonseca010f9962016-03-05 14:45:41 +0000168 virtual int step() const override
James Benton0b65a2b2012-09-07 18:38:15 +0100169 {
170 return m_step;
171 }
172
Jose Fonseca010f9962016-03-05 14:45:41 +0000173 virtual int width() const override
James Benton0b65a2b2012-09-07 18:38:15 +0100174 {
175 return m_stepWidth;
176 }
177
Jose Fonseca010f9962016-03-05 14:45:41 +0000178 virtual QString label() const override
James Benton0b65a2b2012-09-07 18:38:15 +0100179 {
180 return m_label;
181 }
182
183 void setProgramSelection(int program)
184 {
185 m_programSelection = true;
186 m_programSel = program;
187 }
188
189 void setTimeSelection(qint64 start, qint64 end)
190 {
191 m_timeSelection = true;
192 m_timeSelStart = start;
193 m_timeSelEnd = end;
194 }
195
196private:
197 double timeToStep(qint64 time) const
198 {
199 double pos = time;
200 pos -= m_timeStart;
201 pos /= m_timeWidth;
202 pos *= m_stepCount;
203 return pos;
204 }
205
206 qint64 stepToTime(int pos) const
207 {
208 double time = pos;
209 time /= m_stepCount;
210 time *= m_timeWidth;
211 time += m_timeStart;
212 return (qint64)time;
213 }
214
215private:
216 const trace::Profile* m_profile;
217
218 int m_step;
219 int m_stepWidth;
220 int m_stepCount;
221
222 unsigned m_index;
223
224 float m_heat;
225
226 qint64 m_timeStart;
227 qint64 m_timeEnd;
228 qint64 m_timeWidth;
229
230 bool m_useGpu;
231 int m_program;
232
233 QString m_label;
234
235 bool m_selected;
236
237 bool m_timeSelection;
238 qint64 m_timeSelStart;
239 qint64 m_timeSelEnd;
240
241 bool m_programSelection;
242 int m_programSel;
243
244 float m_programHeat;
245};
246
247class ProfileHeatmapDataProvider : public HeatmapDataProvider {
248protected:
249 enum SelectionType {
250 None,
251 Time,
252 Program
253 };
254
255public:
256 ProfileHeatmapDataProvider(trace::Profile* profile) :
257 m_profile(profile),
258 m_selectionState(NULL)
259 {
260 sortRows();
261 }
262
Jose Fonseca010f9962016-03-05 14:45:41 +0000263 virtual qint64 start() const override
James Benton0b65a2b2012-09-07 18:38:15 +0100264 {
265 return m_profile->frames.front().cpuStart;
266 }
267
Jose Fonseca010f9962016-03-05 14:45:41 +0000268 virtual qint64 end() const override
James Benton0b65a2b2012-09-07 18:38:15 +0100269 {
270 return m_profile->frames.back().cpuStart + m_profile->frames.back().cpuDuration;
271 }
272
Jose Fonseca010f9962016-03-05 14:45:41 +0000273 virtual unsigned dataRows() const override
James Benton0b65a2b2012-09-07 18:38:15 +0100274 {
275 return m_rowPrograms.size();
276 }
277
Jose Fonseca010f9962016-03-05 14:45:41 +0000278 virtual QString dataLabel(unsigned row) const override
James Benton0b65a2b2012-09-07 18:38:15 +0100279 {
280 if (row >= m_rowPrograms.size()) {
281 return QString();
282 } else {
283 return QString("%1").arg(m_rowPrograms[row]);
284 }
285 }
286
Jose Fonseca010f9962016-03-05 14:45:41 +0000287 virtual qint64 dataRowAt(unsigned row) const override
James Benton0b65a2b2012-09-07 18:38:15 +0100288 {
289 if (row >= m_rowPrograms.size()) {
290 return 0;
291 } else {
292 return m_rowPrograms[row];
293 }
294 }
295
Jose Fonseca010f9962016-03-05 14:45:41 +0000296 virtual HeatmapRowIterator* dataRowIterator(int row, qint64 start, qint64 end, int steps) const override
James Benton0b65a2b2012-09-07 18:38:15 +0100297 {
298 ProfileHeatmapRowIterator* itr = new ProfileHeatmapRowIterator(m_profile, start, end, steps, true, m_rowPrograms[row]);
299
300 if (m_selectionState) {
301 if (m_selectionState->type == SelectionState::Horizontal) {
302 itr->setTimeSelection(m_selectionState->start, m_selectionState->end);
303 } else if (m_selectionState->type == SelectionState::Vertical) {
304 itr->setProgramSelection(m_selectionState->start);
305 }
306 }
307
308 return itr;
309 }
310
Jose Fonseca010f9962016-03-05 14:45:41 +0000311 virtual unsigned headerRows() const override
James Benton0b65a2b2012-09-07 18:38:15 +0100312 {
313 return 2;
314 }
315
Jose Fonseca010f9962016-03-05 14:45:41 +0000316 virtual qint64 headerRowAt(unsigned row) const override
James Benton0b65a2b2012-09-07 18:38:15 +0100317 {
318 return row;
319 }
320
Jose Fonseca010f9962016-03-05 14:45:41 +0000321 virtual QString headerLabel(unsigned row) const override
James Benton0b65a2b2012-09-07 18:38:15 +0100322 {
323 if (row == 0) {
324 return "CPU";
325 } else if (row == 1) {
326 return "GPU";
327 } else {
328 return QString();
329 }
330 }
331
Jose Fonseca010f9962016-03-05 14:45:41 +0000332 virtual HeatmapRowIterator* headerRowIterator(int row, qint64 start, qint64 end, int steps) const override
James Benton0b65a2b2012-09-07 18:38:15 +0100333 {
334 ProfileHeatmapRowIterator* itr = new ProfileHeatmapRowIterator(m_profile, start, end, steps, row != 0);
335
336 if (m_selectionState) {
337 if (m_selectionState->type == SelectionState::Horizontal) {
338 itr->setTimeSelection(m_selectionState->start, m_selectionState->end);
339 } else if (m_selectionState->type == SelectionState::Vertical) {
340 itr->setProgramSelection(m_selectionState->start);
341 }
342 }
343
344 return itr;
345 }
346
Jose Fonseca010f9962016-03-05 14:45:41 +0000347 virtual qint64 dataItemAt(unsigned row, qint64 time) const override
James Benton0b65a2b2012-09-07 18:38:15 +0100348 {
349 if (row >= m_rowPrograms.size()) {
350 return -1;
351 }
352
353 unsigned program = m_rowPrograms[row];
354
355 std::vector<unsigned>::const_iterator item =
356 Profiling::binarySearchTimespanIndexed
357 (m_profile->calls, m_profile->programs[program].calls.begin(), m_profile->programs[program].calls.end(), time);
358
359 if (item == m_profile->programs[program].calls.end()) {
360 return -1;
361 }
362
363 return *item;
364 }
365
Jose Fonseca010f9962016-03-05 14:45:41 +0000366 virtual qint64 headerItemAt(unsigned row, qint64 time) const override
James Benton0b65a2b2012-09-07 18:38:15 +0100367 {
368 if (row >= m_rowPrograms.size()) {
369 return -1;
370 }
371
372 if (row == 0) {
373 /* CPU */
374 std::vector<trace::Profile::Call>::const_iterator item =
375 Profiling::binarySearchTimespan<trace::Profile::Call,
376 &trace::Profile::Call::cpuStart,
377 &trace::Profile::Call::cpuDuration>
378 (m_profile->calls.begin(), m_profile->calls.end(), time);
379
380 if (item != m_profile->calls.end()) {
381 return item - m_profile->calls.begin();
382 }
383 } else if (row == 1) {
384 /* GPU */
385 for (unsigned i = 0; i < m_rowPrograms.size(); ++i) {
386 qint64 index = dataItemAt(i, time);
387
388 if (index != -1) {
389 return index;
390 }
391 }
392 }
393
394 return -1;
395 }
396
Jose Fonseca010f9962016-03-05 14:45:41 +0000397 virtual void itemDoubleClicked(qint64 index) const override
James Benton0b65a2b2012-09-07 18:38:15 +0100398 {
399 if (index < 0 || index >= m_profile->calls.size()) {
400 return;
401 }
402
403 const trace::Profile::Call& call = m_profile->calls[index];
404 Profiling::jumpToCall(call.no);
405 }
406
Jose Fonseca010f9962016-03-05 14:45:41 +0000407 virtual QString itemTooltip(qint64 index) const override
James Benton0b65a2b2012-09-07 18:38:15 +0100408 {
409 if (index >= m_profile->calls.size()) {
410 return QString();
411 }
412
413 const trace::Profile::Call& call = m_profile->calls[index];
414
415 QString text;
416 text = QString::fromStdString(call.name);
417
418 text += QString("\nCall: %1").arg(call.no);
Giuseppe D'Angeloe3418192015-02-22 22:56:53 +0100419 text += QString("\nCPU Start: %1").arg(Profiling::getTimeString(call.cpuStart, 1e3));
420 text += QString("\nCPU Duration: %1").arg(Profiling::getTimeString(call.cpuDuration, 1e3));
James Benton0b65a2b2012-09-07 18:38:15 +0100421
422 if (call.pixels >= 0) {
Giuseppe D'Angeloe3418192015-02-22 22:56:53 +0100423 text += QString("\nGPU Start: %1").arg(Profiling::getTimeString(call.gpuStart, 1e3));
424 text += QString("\nGPU Duration: %1").arg(Profiling::getTimeString(call.gpuDuration, 1e3));
James Benton0b65a2b2012-09-07 18:38:15 +0100425 text += QString("\nPixels Drawn: %1").arg(QLocale::system().toString((qlonglong)call.pixels));
426 }
427
428 return text;
429 }
430
Jose Fonseca010f9962016-03-05 14:45:41 +0000431 virtual void setSelectionState(SelectionState* state) override
James Benton0b65a2b2012-09-07 18:38:15 +0100432 {
433 m_selectionState = state;
434 }
435
436private:
437 void sortRows()
438 {
439 typedef QPair<quint64, unsigned> Pair;
440 std::vector<Pair> gpu;
441
442 /* Map shader to visible row */
443 for (std::vector<trace::Profile::Program>::const_iterator itr = m_profile->programs.begin(); itr != m_profile->programs.end(); ++itr) {
444 const trace::Profile::Program& program = *itr;
445 unsigned no = itr - m_profile->programs.begin();
446
447 if (program.gpuTotal > 0) {
448 gpu.push_back(Pair(program.gpuTotal, no));
449 }
450 }
451
452 /* Sort the shaders by most used gpu */
453 qSort(gpu);
454
455 /* Create row order */
456 m_rowPrograms.clear();
457
458 for (std::vector<Pair>::const_reverse_iterator itr = gpu.rbegin(); itr != gpu.rend(); ++itr) {
459 m_rowPrograms.push_back(itr->second);
460 }
461 }
462
463protected:
464 trace::Profile* m_profile;
465 std::vector<int> m_rowPrograms;
466 SelectionState* m_selectionState;
467};