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