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