]> git.cworth.org Git - apitrace/blob - gui/profiletablemodel.cpp
Combine timeline and histogram tabs.
[apitrace] / gui / profiletablemodel.cpp
1 #include "profiletablemodel.h"
2 #include "profiledialog.h"
3
4 #include <QLocale>
5
6 typedef trace::Profile::Call Call;
7 typedef trace::Profile::Frame Frame;
8 typedef trace::Profile::Program Program;
9
10 enum {
11     COLUMN_PROGRAM,
12     COLUMN_USAGES,
13     COLUMN_GPU_TIME,
14     COLUMN_CPU_TIME,
15     COLUMN_PIXELS_DRAWN,
16     COLUMN_GPU_AVERAGE,
17     COLUMN_CPU_AVERAGE,
18     COLUMN_PIXELS_AVERAGE,
19     MAX_COLUMN
20 };
21
22 static QString columnNames[] = {
23     QString("Program"),
24     QString("Calls"),
25     QString("Total GPU Time"),
26     QString("Total CPU Time"),
27     QString("Total Pixels Drawn"),
28     QString("Avg GPU Time"),
29     QString("Avg CPU Time"),
30     QString("Avg Pixels Drawn")
31 };
32
33 ProfileTableModel::ProfileTableModel(QObject *parent)
34     : QAbstractTableModel(parent),
35       m_profile(0),
36       m_sortColumn(COLUMN_GPU_TIME),
37       m_sortOrder(Qt::DescendingOrder)
38 {
39 }
40
41
42 void ProfileTableModel::setProfile(trace::Profile* profile)
43 {
44     m_profile = profile;
45     m_timeMin = m_profile->frames.front().cpuStart;
46     m_timeMax = m_profile->frames.back().cpuStart + m_profile->frames.back().cpuDuration;
47     updateModel();
48 }
49
50
51 /**
52  * Set selection to nothing
53  */
54 void ProfileTableModel::selectNone()
55 {
56     m_timeMin = m_timeMax = 0;
57     updateModel();
58     sort(m_sortColumn, m_sortOrder);
59 }
60
61
62 /**
63  * Set selection to program
64  */
65 void ProfileTableModel::selectProgram(unsigned /*program*/)
66 {
67     /* We have no program based selection for table */
68     selectNone();
69 }
70
71
72 /**
73  * Set selection to a period of time
74  */
75 void ProfileTableModel::selectTime(int64_t start, int64_t end)
76 {
77     m_timeMin = start;
78     m_timeMax = end;
79
80     updateModel();
81     sort(m_sortColumn, m_sortOrder);
82 }
83
84
85 /**
86  * Creates the row data from trace profile
87  */
88 void ProfileTableModel::updateModel()
89 {
90     if (m_timeMin == m_timeMax) {
91         m_timeMin = m_profile->frames.front().cpuStart;
92         m_timeMax = m_profile->frames.back().cpuStart + m_profile->frames.back().cpuDuration;
93     }
94
95     for (QList<ProfileTableRow>::iterator itr = m_rowData.begin(); itr != m_rowData.end(); ++itr) {
96         ProfileTableRow& row = *itr;
97
98         row.uses = 0;
99         row.pixels = 0;
100         row.gpuTime = 0;
101         row.cpuTime = 0;
102         row.longestCpu = NULL;
103         row.longestGpu = NULL;
104         row.longestPixel = NULL;
105     }
106
107     for (std::vector<Program>::const_iterator itr = m_profile->programs.begin(); itr != m_profile->programs.end(); ++itr) {
108         ProfileTableRow* row = NULL;
109         const Program& program = *itr;
110
111         for (std::vector<unsigned>::const_iterator jtr = program.calls.begin(); jtr != program.calls.end(); ++jtr) {
112             const Call& call = m_profile->calls[*jtr];
113
114             if (call.cpuStart > m_timeMax) {
115                 break;
116             }
117
118             if (call.cpuStart + call.cpuDuration < m_timeMin) {
119                 continue;
120             }
121
122             if (!row) {
123                 row = getRow(itr - m_profile->programs.begin());
124             }
125
126             row->uses++;
127             row->pixels  += call.pixels;
128             row->gpuTime += call.gpuDuration;
129             row->cpuTime += call.cpuDuration;
130
131             if (!row->longestGpu || row->longestGpu->gpuDuration < call.gpuDuration) {
132                 row->longestGpu = &call;
133             }
134
135             if (!row->longestCpu || row->longestCpu->cpuDuration < call.cpuDuration) {
136                 row->longestCpu = &call;
137             }
138
139             if (!row->longestPixel || row->longestPixel->pixels < call.pixels) {
140                 row->longestPixel = &call;
141             }
142         }
143     }
144 }
145
146
147 /**
148  * Get the appropriate call associated with an item in the table
149  */
150 const trace::Profile::Call *ProfileTableModel::getJumpCall(const QModelIndex & index) const {
151     const ProfileTableRow& row = m_rowData[index.row()];
152
153     switch(index.column()) {
154     case COLUMN_GPU_TIME:
155     case COLUMN_GPU_AVERAGE:
156         return row.longestGpu;
157     case COLUMN_CPU_TIME:
158     case COLUMN_CPU_AVERAGE:
159         return row.longestCpu;
160     case COLUMN_PIXELS_DRAWN:
161     case COLUMN_PIXELS_AVERAGE:
162         return row.longestPixel;
163     }
164
165     return NULL;
166 }
167
168
169 /**
170  * Get the shader program associated with an item in the table
171  */
172 unsigned ProfileTableModel::getProgram(const QModelIndex & index) const
173 {
174     const ProfileTableRow& row = m_rowData[index.row()];
175     return row.program;
176 }
177
178
179 /**
180  * Get the row index for a shader program
181  */
182 int ProfileTableModel::getRowIndex(unsigned program) const
183 {
184     for (int i = 0; i < m_rowData.size(); ++i) {
185         if (m_rowData[i].program == program)
186             return i;
187     }
188
189     return -1;
190 }
191
192
193 /**
194  * Get the row data for a shader program
195  */
196 ProfileTableRow* ProfileTableModel::getRow(unsigned program) {
197     for (QList<ProfileTableRow>::iterator itr = m_rowData.begin(); itr != m_rowData.end(); ++itr) {
198         if (itr->program == program)
199             return &*itr;
200     }
201
202     m_rowData.append(ProfileTableRow(program));
203     return &m_rowData.back();
204 }
205
206
207 int ProfileTableModel::rowCount(const QModelIndex & parent) const
208 {
209     if (!parent.isValid()) {
210         return m_rowData.size();
211     } else {
212         return 0;
213     }
214 }
215
216
217 int ProfileTableModel::columnCount(const QModelIndex & /*parent*/) const
218 {
219     return MAX_COLUMN;
220 }
221
222
223 QVariant ProfileTableModel::data(const QModelIndex &index, int role) const
224 {
225     if (!index.isValid()) {
226         return QVariant();
227     }
228
229     if (role == Qt::DisplayRole) {
230         const ProfileTableRow& row = m_rowData[index.row()];
231
232         switch(index.column()) {
233         case COLUMN_PROGRAM:
234             return row.program;
235         case COLUMN_USAGES:
236             return QLocale::system().toString(row.uses);
237         case COLUMN_GPU_TIME:
238             return getTimeString(row.gpuTime);
239         case COLUMN_CPU_TIME:
240             return getTimeString(row.cpuTime);
241         case COLUMN_PIXELS_DRAWN:
242             return QLocale::system().toString((qlonglong)row.pixels);
243         case COLUMN_GPU_AVERAGE:
244             return getTimeString((row.uses <= 0) ? 0 : (row.gpuTime / row.uses));
245         case COLUMN_CPU_AVERAGE:
246             return getTimeString((row.uses <= 0) ? 0 : (row.cpuTime / row.uses));
247         case COLUMN_PIXELS_AVERAGE:
248             return QLocale::system().toString((row.uses <= 0) ? 0 : (row.pixels / row.uses));
249         }
250     } else if (role == Qt::TextAlignmentRole) {
251         return Qt::AlignRight;
252     }
253
254     return QVariant();
255 }
256
257
258 QVariant ProfileTableModel::headerData(int section, Qt::Orientation orientation, int role) const
259 {
260     if (role == Qt::DisplayRole && orientation == Qt::Horizontal) {
261         if (section >= 0 && section < MAX_COLUMN) {
262             return columnNames[section];
263         }
264     }
265
266     return QVariant();
267 }
268
269
270 class ProgramSorter {
271 public:
272     ProgramSorter(int column, Qt::SortOrder order)
273         : mSortColumn(column),
274           mSortOrder(order)
275     {
276     }
277
278     bool operator()(const ProfileTableRow &p1, const ProfileTableRow &p2) const
279     {
280         bool result = true;
281
282         switch(mSortColumn) {
283         case COLUMN_PROGRAM:
284             result = p1.program < p2.program;
285             break;
286         case COLUMN_USAGES:
287             result = p1.uses < p2.uses;
288             break;
289         case COLUMN_GPU_TIME:
290             result = p1.gpuTime < p2.gpuTime;
291             break;
292         case COLUMN_CPU_TIME:
293             result = p1.cpuTime < p2.cpuTime;
294             break;
295         case COLUMN_PIXELS_DRAWN:
296             result = p1.pixels < p2.pixels;
297             break;
298         case COLUMN_GPU_AVERAGE:
299             result = ((p1.uses <= 0) ? 0 : (p1.gpuTime / p1.uses)) < ((p2.uses <= 0) ? 0 : (p2.gpuTime / p2.uses));
300             break;
301         case COLUMN_CPU_AVERAGE:
302             result = ((p1.uses <= 0) ? 0 : (p1.cpuTime / p1.uses)) < ((p2.uses <= 0) ? 0 : (p2.cpuTime / p2.uses));
303             break;
304         case COLUMN_PIXELS_AVERAGE:
305             result = ((p1.uses <= 0) ? 0 : (p1.pixels / p1.uses)) < ((p2.uses <= 0) ? 0 : (p2.pixels / p2.uses));
306             break;
307         }
308
309         if (mSortOrder == Qt::DescendingOrder) {
310             return !result;
311         } else {
312             return result;
313         }
314     }
315
316 private:
317     int mSortColumn;
318     Qt::SortOrder mSortOrder;
319 };
320
321
322 void ProfileTableModel::sort(int column, Qt::SortOrder order) {
323     m_sortColumn = column;
324     m_sortOrder = order;
325     qSort(m_rowData.begin(), m_rowData.end(), ProgramSorter(column, order));
326     emit dataChanged(createIndex(0, 0), createIndex(m_rowData.size(), MAX_COLUMN));
327 }
328
329
330 #include "profiletablemodel.moc"