#include "profiletablemodel.h" #include "profiledialog.h" #include "profiling.h" #include typedef trace::Profile::Call Call; typedef trace::Profile::Frame Frame; typedef trace::Profile::Program Program; enum { COLUMN_PROGRAM, COLUMN_USAGES, COLUMN_GPU_TIME, COLUMN_CPU_TIME, COLUMN_PIXELS_DRAWN, COLUMN_GPU_AVERAGE, COLUMN_CPU_AVERAGE, COLUMN_PIXELS_AVERAGE, MAX_COLUMN }; static QString columnNames[] = { QString("Program"), QString("Calls"), QString("Total GPU Time"), QString("Total CPU Time"), QString("Total Pixels Drawn"), QString("Avg GPU Time"), QString("Avg CPU Time"), QString("Avg Pixels Drawn") }; ProfileTableModel::ProfileTableModel(QObject *parent) : QAbstractTableModel(parent), m_profile(0), m_sortColumn(COLUMN_GPU_TIME), m_sortOrder(Qt::DescendingOrder) { } void ProfileTableModel::setProfile(trace::Profile* profile) { m_profile = profile; m_timeMin = m_profile->frames.front().cpuStart; m_timeMax = m_profile->frames.back().cpuStart + m_profile->frames.back().cpuDuration; updateModel(); } /** * Set selection to nothing */ void ProfileTableModel::selectNone() { m_timeMin = m_timeMax = 0; updateModel(); sort(m_sortColumn, m_sortOrder); } /** * Set selection to program */ void ProfileTableModel::selectProgram(unsigned /*program*/) { /* We have no program based selection for table */ selectNone(); } /** * Set selection to a period of time */ void ProfileTableModel::selectTime(int64_t start, int64_t end) { m_timeMin = start; m_timeMax = end; updateModel(); sort(m_sortColumn, m_sortOrder); } /** * Creates the row data from trace profile */ void ProfileTableModel::updateModel() { if (m_timeMin == m_timeMax) { m_timeMin = m_profile->frames.front().cpuStart; m_timeMax = m_profile->frames.back().cpuStart + m_profile->frames.back().cpuDuration; } for (auto & row : m_rowData) { row.uses = 0; row.pixels = 0; row.gpuTime = 0; row.cpuTime = 0; row.longestCpu = NULL; row.longestGpu = NULL; row.longestPixel = NULL; } for (std::vector::const_iterator itr = m_profile->programs.begin(); itr != m_profile->programs.end(); ++itr) { ProfileTableRow* row = NULL; const Program& program = *itr; for (const auto & callNo : program.calls) { const Call& call = m_profile->calls[callNo]; if (call.cpuStart > m_timeMax) { break; } if (call.cpuStart + call.cpuDuration < m_timeMin) { continue; } if (!row) { row = getRow(itr - m_profile->programs.begin()); } row->uses++; row->pixels += call.pixels; row->gpuTime += call.gpuDuration; row->cpuTime += call.cpuDuration; if (!row->longestGpu || row->longestGpu->gpuDuration < call.gpuDuration) { row->longestGpu = &call; } if (!row->longestCpu || row->longestCpu->cpuDuration < call.cpuDuration) { row->longestCpu = &call; } if (!row->longestPixel || row->longestPixel->pixels < call.pixels) { row->longestPixel = &call; } } } } /** * Get the appropriate call associated with an item in the table */ const trace::Profile::Call *ProfileTableModel::getJumpCall(const QModelIndex & index) const { const ProfileTableRow& row = m_rowData[index.row()]; switch(index.column()) { case COLUMN_GPU_TIME: case COLUMN_GPU_AVERAGE: return row.longestGpu; case COLUMN_CPU_TIME: case COLUMN_CPU_AVERAGE: return row.longestCpu; case COLUMN_PIXELS_DRAWN: case COLUMN_PIXELS_AVERAGE: return row.longestPixel; } return NULL; } /** * Get the shader program associated with an item in the table */ unsigned ProfileTableModel::getProgram(const QModelIndex & index) const { const ProfileTableRow& row = m_rowData[index.row()]; return row.program; } /** * Get the row index for a shader program */ int ProfileTableModel::getRowIndex(unsigned program) const { for (int i = 0; i < m_rowData.size(); ++i) { if (m_rowData[i].program == program) return i; } return -1; } /** * Get the row data for a shader program */ ProfileTableRow* ProfileTableModel::getRow(unsigned program) { for (auto & row : m_rowData) { if (row.program == program) return &row; } m_rowData.append(ProfileTableRow(program)); return &m_rowData.back(); } int ProfileTableModel::rowCount(const QModelIndex & parent) const { if (!parent.isValid()) { return m_rowData.size(); } else { return 0; } } int ProfileTableModel::columnCount(const QModelIndex & /*parent*/) const { return MAX_COLUMN; } QVariant ProfileTableModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { return QVariant(); } if (role == Qt::DisplayRole) { const ProfileTableRow& row = m_rowData[index.row()]; switch(index.column()) { case COLUMN_PROGRAM: return row.program; case COLUMN_USAGES: return QLocale::system().toString(row.uses); case COLUMN_GPU_TIME: return Profiling::getTimeString(row.gpuTime); case COLUMN_CPU_TIME: return Profiling::getTimeString(row.cpuTime); case COLUMN_PIXELS_DRAWN: return QLocale::system().toString((qlonglong)row.pixels); case COLUMN_GPU_AVERAGE: return Profiling::getTimeString((row.uses <= 0) ? 0 : (row.gpuTime / row.uses)); case COLUMN_CPU_AVERAGE: return Profiling::getTimeString((row.uses <= 0) ? 0 : (row.cpuTime / row.uses)); case COLUMN_PIXELS_AVERAGE: return QLocale::system().toString((row.uses <= 0) ? 0 : (row.pixels / row.uses)); } } else if (role == Qt::TextAlignmentRole) { return Qt::AlignRight; } return QVariant(); } QVariant ProfileTableModel::headerData(int section, Qt::Orientation orientation, int role) const { if (role == Qt::DisplayRole && orientation == Qt::Horizontal) { if (section >= 0 && section < MAX_COLUMN) { return columnNames[section]; } } return QVariant(); } class ProgramSorter { public: ProgramSorter(int column, Qt::SortOrder order) : mSortColumn(column), mSortOrder(order) { } bool operator()(const ProfileTableRow &p1, const ProfileTableRow &p2) const { bool result = true; switch(mSortColumn) { case COLUMN_PROGRAM: result = p1.program < p2.program; break; case COLUMN_USAGES: result = p1.uses < p2.uses; break; case COLUMN_GPU_TIME: result = p1.gpuTime < p2.gpuTime; break; case COLUMN_CPU_TIME: result = p1.cpuTime < p2.cpuTime; break; case COLUMN_PIXELS_DRAWN: result = p1.pixels < p2.pixels; break; case COLUMN_GPU_AVERAGE: result = ((p1.uses <= 0) ? 0 : (p1.gpuTime / p1.uses)) < ((p2.uses <= 0) ? 0 : (p2.gpuTime / p2.uses)); break; case COLUMN_CPU_AVERAGE: result = ((p1.uses <= 0) ? 0 : (p1.cpuTime / p1.uses)) < ((p2.uses <= 0) ? 0 : (p2.cpuTime / p2.uses)); break; case COLUMN_PIXELS_AVERAGE: result = ((p1.uses <= 0) ? 0 : (p1.pixels / p1.uses)) < ((p2.uses <= 0) ? 0 : (p2.pixels / p2.uses)); break; } if (mSortOrder == Qt::DescendingOrder) { return !result; } else { return result; } } private: int mSortColumn; Qt::SortOrder mSortOrder; }; void ProfileTableModel::sort(int column, Qt::SortOrder order) { m_sortColumn = column; m_sortOrder = order; qSort(m_rowData.begin(), m_rowData.end(), ProgramSorter(column, order)); emit dataChanged(createIndex(0, 0), createIndex(m_rowData.size(), MAX_COLUMN)); } #include "profiletablemodel.moc"