From dfa583f410c538fbd717479fcbb1b158008f8496 Mon Sep 17 00:00:00 2001 From: Sergey Yagovtsev Date: Sun, 1 May 2016 23:32:46 +0300 Subject: [PATCH] Simple tree view --- .gitignore | 3 +- include/profiler/profiler.h | 5 + profiler_gui/CMakeLists.txt | 4 +- profiler_gui/main.cpp | 18 ++- profiler_gui/treeitem.cpp | 52 +++++++ profiler_gui/treeitem.h | 28 ++++ profiler_gui/treemodel.cpp | 264 ++++++++++++++++++++++++++++++++++++ profiler_gui/treemodel.h | 34 +++++ sample/main.cpp | 19 +++ 9 files changed, 419 insertions(+), 8 deletions(-) create mode 100644 profiler_gui/treeitem.cpp create mode 100644 profiler_gui/treeitem.h create mode 100644 profiler_gui/treemodel.cpp create mode 100644 profiler_gui/treemodel.h diff --git a/.gitignore b/.gitignore index a054091..e4373d3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ bin -build +*build* .idea +*.user diff --git a/include/profiler/profiler.h b/include/profiler/profiler.h index 557ae4b..db31e68 100644 --- a/include/profiler/profiler.h +++ b/include/profiler/profiler.h @@ -259,6 +259,11 @@ namespace profiler inline bool isCleared() const { return end >= begin; } inline void finish(){ tick(end); } timestamp_t duration() const { return (end - begin); } + + inline bool startsEarlierThan(const BaseBlockData& another) const {return this->begin < another.begin;} + inline bool endsEarlierThan(const BaseBlockData& another) const {return this->end < another.end;} + inline bool startsLaterThan(const BaseBlockData& another) const {return !this->startsEarlierThan(another);} + inline bool endsLaterThan(const BaseBlockData& another) const {return !this->endsEarlierThan(another);} }; #pragma pack(pop) diff --git a/profiler_gui/CMakeLists.txt b/profiler_gui/CMakeLists.txt index d1d2114..27a72fe 100644 --- a/profiler_gui/CMakeLists.txt +++ b/profiler_gui/CMakeLists.txt @@ -6,5 +6,5 @@ set(CMAKE_AUTOMOC ON) set(CMAKE_INCLUDE_CURRENT_DIR ON) find_package(Qt5Widgets REQUIRED) -add_executable(${PROJECT_NAME} main.cpp) -target_link_libraries(${PROJECT_NAME} Qt5::Widgets) \ No newline at end of file +add_executable(${PROJECT_NAME} main.cpp treemodel.h treemodel.cpp treeitem.h treeitem.cpp) +target_link_libraries(${PROJECT_NAME} Qt5::Widgets easy_profiler) diff --git a/profiler_gui/main.cpp b/profiler_gui/main.cpp index 3699b9a..ea4335d 100644 --- a/profiler_gui/main.cpp +++ b/profiler_gui/main.cpp @@ -1,18 +1,26 @@ #include #include #include +#include "treemodel.h" int main(int argc, char **argv) { QApplication app(argc, argv); - QFileSystemModel *model = new QFileSystemModel; - model->setRootPath(QDir::currentPath()); + //QFileSystemModel *model = new QFileSystemModel; + //model->setRootPath(QDir::currentPath()); + + QFile file("/home/yse/projects/easy_profiler/bin/test.prof"); + file.open(QIODevice::ReadOnly); + TreeModel model(file.readAll()); + file.close(); + + QTreeView *tree = new QTreeView(); - tree->setModel(model); + tree->setModel(&model); tree->show(); - return app.exec(); -} \ No newline at end of file + return app.exec( ); +} diff --git a/profiler_gui/treeitem.cpp b/profiler_gui/treeitem.cpp new file mode 100644 index 0000000..66daaef --- /dev/null +++ b/profiler_gui/treeitem.cpp @@ -0,0 +1,52 @@ +#include + +#include "treeitem.h" + +TreeItem::TreeItem(const QList &data, TreeItem *parent) +{ + m_parentItem = parent; + m_itemData = data; +} + +TreeItem::~TreeItem() +{ + qDeleteAll(m_childItems); +} + +void TreeItem::appendChild(TreeItem *item) +{ + m_childItems.append(item); +} + +TreeItem *TreeItem::child(int row) +{ + return m_childItems.value(row); +} + +int TreeItem::childCount() const +{ + return m_childItems.count(); +} + +int TreeItem::columnCount() const +{ + return m_itemData.count(); +} + +QVariant TreeItem::data(int column) const +{ + return m_itemData.value(column); +} + +TreeItem *TreeItem::parentItem() +{ + return m_parentItem; +} + +int TreeItem::row() const +{ + if (m_parentItem) + return m_parentItem->m_childItems.indexOf(const_cast(this)); + + return 0; +} \ No newline at end of file diff --git a/profiler_gui/treeitem.h b/profiler_gui/treeitem.h new file mode 100644 index 0000000..92802a5 --- /dev/null +++ b/profiler_gui/treeitem.h @@ -0,0 +1,28 @@ +#ifndef TREEITEM_H +#define TREEITEM_H + +#include +#include + +class TreeItem +{ +public: + explicit TreeItem(const QList &data, TreeItem *parentItem = 0); + ~TreeItem(); + + void appendChild(TreeItem *child); + + TreeItem *child(int row); + int childCount() const; + int columnCount() const; + QVariant data(int column) const; + int row() const; + TreeItem *parentItem(); + +private: + QList m_childItems; + QList m_itemData; + TreeItem *m_parentItem; +}; + +#endif // TREEITEM_H \ No newline at end of file diff --git a/profiler_gui/treemodel.cpp b/profiler_gui/treemodel.cpp new file mode 100644 index 0000000..6d0abd3 --- /dev/null +++ b/profiler_gui/treemodel.cpp @@ -0,0 +1,264 @@ +#include "treeitem.h" +#include "treemodel.h" +#include "profiler/profiler.h" +#include +#include +#include + +TreeModel::TreeModel(const QByteArray &data, QObject *parent) + : QAbstractItemModel(parent) +{ + QList rootData; + rootData << "Name" << "Duration usec" << "thread id" << "begin"; + m_rootItem = new TreeItem(rootData); + setupModelData(data, m_rootItem); +} + +TreeModel::~TreeModel() +{ + delete m_rootItem; +} + +int TreeModel::columnCount(const QModelIndex &parent) const +{ + if (parent.isValid()) + return static_cast(parent.internalPointer())->columnCount(); + else + return m_rootItem->columnCount(); +} + +QVariant TreeModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + if (role != Qt::DisplayRole) + return QVariant(); + + TreeItem *item = static_cast(index.internalPointer()); + + return item->data(index.column()); +} + +Qt::ItemFlags TreeModel::flags(const QModelIndex &index) const +{ + if (!index.isValid()) + return 0; + + return QAbstractItemModel::flags(index); +} + +QVariant TreeModel::headerData(int section, Qt::Orientation orientation, + int role) const +{ + if (orientation == Qt::Horizontal && role == Qt::DisplayRole) + return m_rootItem->data(section); + + return QVariant(); +} + +QModelIndex TreeModel::index(int row, int column, const QModelIndex &parent) +const +{ + if (!hasIndex(row, column, parent)) + return QModelIndex(); + + TreeItem *parentItem; + + if (!parent.isValid()) + parentItem = m_rootItem; + else + parentItem = static_cast(parent.internalPointer()); + + TreeItem *childItem = parentItem->child(row); + if (childItem) + return createIndex(row, column, childItem); + else + return QModelIndex(); +} + +QModelIndex TreeModel::parent(const QModelIndex &index) const +{ + if (!index.isValid()) + return QModelIndex(); + + TreeItem *childItem = static_cast(index.internalPointer()); + TreeItem *parentItem = childItem->parentItem(); + + if (parentItem == m_rootItem) + return QModelIndex(); + + return createIndex(parentItem->row(), 0, parentItem); +} + +int TreeModel::rowCount(const QModelIndex &parent) const +{ + TreeItem *parentItem; + if (parent.column() > 0) + return 0; + + if (!parent.isValid()) + parentItem = m_rootItem; + else + parentItem = static_cast(parent.internalPointer()); + + return parentItem->childCount(); +} + + + +void TreeModel::setupModelData(const QByteArray &lines, TreeItem *parent) +{ + QList parents; + QList indentations; + + indentations << 0; + + typedef std::map blocks_map_t; + typedef std::map thread_map_t; + thread_map_t blocksList; + QByteArray array(lines); + QDataStream io(&array,QIODevice::ReadOnly); + + + + + while(!io.atEnd()){ + uint16_t sz = 0; + io.readRawData((char*)&sz,sizeof(sz)); + char* data = new char[sz]; + io.readRawData(data,sz); + profiler::BaseBlockData* baseData = (profiler::BaseBlockData*)data; + blocksList[baseData->getThreadId()].emplace( + baseData->getBegin(), + std::move(profiler::SerilizedBlock(sz, data))); + } + + + + + for (auto& threads_list : blocksList){ + + std::list parents_blocks; + parents.clear(); + parents << parent; + + for (auto& i : threads_list.second){ + QList columnData; + const profiler::BaseBlockData * _block = i.second.block(); + + profiler::timestamp_t _end = _block->getEnd(); + profiler::timestamp_t _begin = _block->getBegin(); + + columnData << i.second.getBlockName(); + columnData << QVariant::fromValue(_block->duration()); + columnData << QVariant::fromValue(_block->getThreadId()); + + + + if(parents_blocks.empty()){ + parents_blocks.push_back(_block); + parents << parents.last(); + }else{ + + auto& last_block_in_stack = parents_blocks.back(); + auto last_block_end = last_block_in_stack->getEnd(); + + if(_begin >= last_block_end){ + parents_blocks.pop_back(); + parents.pop_back(); + + for(std::list::reverse_iterator it = parents_blocks.rbegin(); it != parents_blocks.rend();){ + last_block_end = (*it)->getEnd(); + + if(_end <= last_block_end){ + break; + }else{ + parents_blocks.erase( std::next(it).base() ); + parents.pop_back(); + } + } + + parents_blocks.push_back(_block); + if(parents.size() > 1){ + parents << parents.last()->child(parents.last()->childCount()-1); + }else{ + parents << parents.last(); + } + + + }else if(_end <= last_block_end){ + //child + + parents_blocks.push_back(_block); + if(parents.size() > 1){ + parents << parents.last()->child(parents.last()->childCount()-1); + }else{ + parents << parents.last(); + } + } + } + + + + + + + + + columnData << QVariant::fromValue(_block->getBegin() - _begin); + + if(_block->getType() == profiler::BLOCK_TYPE_BLOCK){ + parents.last()->appendChild(new TreeItem(columnData, parents.last())); + }else{ + //parents.last()->appendChild(new TreeItem(columnData, parent)); + } + + } + + } + + + + return; +/* + while (number < lines.count()) { + int position = 0; + while (position < lines[number].length()) { + if (lines[number].at(position) != ' ') + break; + position++; + } + + QString lineData = lines[number].mid(position).trimmed(); + + if (!lineData.isEmpty()) { + // Read the column data from the rest of the line. + QStringList columnStrings = lineData.split("\t", QString::SkipEmptyParts); + QList columnData; + for (int column = 0; column < columnStrings.count(); ++column) + columnData << columnStrings[column]; + + if (position > indentations.last()) { + // The last child of the current parent is now the new parent + // unless the current parent has no children. + + if (parents.last()->childCount() > 0) { + parents << parents.last()->child(parents.last()->childCount()-1); + indentations << position; + } + } else { + while (position < indentations.last() && parents.count() > 0) { + parents.pop_back(); + indentations.pop_back(); + } + } + + // Append a new item to the current parent's list of children. + parents.last()->appendChild(new TreeItem(columnData, parents.last())); + } + + ++number; + } + */ +} diff --git a/profiler_gui/treemodel.h b/profiler_gui/treemodel.h new file mode 100644 index 0000000..95856c9 --- /dev/null +++ b/profiler_gui/treemodel.h @@ -0,0 +1,34 @@ +#ifndef TREEMODEL_H +#define TREEMODEL_H + +#include +#include +#include + +class TreeItem; + +class TreeModel : public QAbstractItemModel +{ + Q_OBJECT + +public: + explicit TreeModel(const QByteArray &data, QObject *parent = 0); + ~TreeModel(); + + QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE; + Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE; + QVariant headerData(int section, Qt::Orientation orientation, + int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; + QModelIndex index(int row, int column, + const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; + QModelIndex parent(const QModelIndex &index) const Q_DECL_OVERRIDE; + int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; + int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; + +private: + void setupModelData(const QByteArray &lines, TreeItem *parent); + + TreeItem *m_rootItem; +}; + +#endif // TREEMODEL_H diff --git a/sample/main.cpp b/sample/main.cpp index 956bde4..4b40187 100644 --- a/sample/main.cpp +++ b/sample/main.cpp @@ -9,14 +9,33 @@ void loadingResources(){ std::this_thread::sleep_for(std::chrono::milliseconds(500)); } + + void prepareMath(){ PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Blue); std::this_thread::sleep_for(std::chrono::milliseconds(2)); } +void calcIntersect(){ + PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Blue); + std::this_thread::sleep_for(std::chrono::microseconds(700)); +} + +void calcPhys(){ + PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Blue); + calcIntersect(); +} + +void calcBrain(){ + PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Blue); + std::this_thread::sleep_for(std::chrono::microseconds(300)); +} + void calculateBehavior(){ PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Lightblue); std::this_thread::sleep_for(std::chrono::milliseconds(3)); + calcPhys(); + calcBrain(); } void modellingStep(){