diff --git a/piqt_utils/piintrospector/containers_view.cpp b/piqt_utils/piintrospector/containers_view.cpp index a3d6ac5..db84dde 100644 --- a/piqt_utils/piintrospector/containers_view.cpp +++ b/piqt_utils/piintrospector/containers_view.cpp @@ -4,18 +4,10 @@ #include #include -#include -const QString demangle(const char * name) { - int status = -4; - char * res = abi::__cxa_demangle(name, NULL, NULL, &status); - QString ret((status == 0) ? res : name); - free(res); - return ret; -} - enum ColumnContainers { ccType, + ccItemSize, ccCount, ccBytesAllocated, ccBytesUsed, @@ -32,43 +24,41 @@ ContainersModel::ContainersModel() { } -void ContainersModel::update(const PIMap & td, const PIMap & tn) { - prev_typedata = typedata; - typedata = td; - typenames = tn; - PIVector ntypeids = tn.keys(); - for (int i = 0; i < ntypeids.size_s(); ++i) { - if (typeids.size_s() > i) - if (typeids[i] == ntypeids[i]) continue; - beginInsertRows(QModelIndex(), i, i); - typeids.insert(i, ntypeids[i]); +void ContainersModel::update(const PIVector & t) { + prev_data.clear(); + all.fill(0U); + piForeachC (PIIntrospectionContainers::TypeInfo & i, t) { + prev_data[i.id] = i; + all[ccCount] += i.count; + all[ccBytesAllocated] += i.allocated * i.item_size; + all[ccBytesUsed] += i.used * i.item_size; + } + int pts = cur_data.size_s(); + cur_data = t; + if (t.size_s() > pts) { + beginInsertRows(QModelIndex(), pts, t.size_s() - 1); endInsertRows(); } - prev_all = all; - all.fill(0U); - for (auto i = td.constBegin(); i != td.constEnd(); ++i) { - all[ccCount] += i.value().count; - all[ccBytesAllocated] += i.value().bytes_allocated; - all[ccBytesUsed] += i.value().bytes_used; + if (t.size_s() < pts) { + beginRemoveRows(QModelIndex(), t.size_s(), pts - 1); + endRemoveRows(); } - dataChanged(index(0, ccCount), index(typeids.size_s() - 1, columnCount())); + dataChanged(index(0, 0), index(cur_data.size_s() - 1, columnCount())); emit headerDataChanged(Qt::Horizontal, ccCount, columnCount()); } void ContainersModel::clear() { - beginRemoveRows(QModelIndex(), 0, typeids.size_s() - 1); - typedata.clear(); - prev_typedata.clear(); - typenames.clear(); - typeids.clear(); + beginRemoveRows(QModelIndex(), 0, cur_data.size_s() - 1); + cur_data.clear(); + prev_data.clear(); all.fill(0L); endRemoveRows(); } int ContainersModel::rowCount(const QModelIndex & parent) const { - return typeids.size_s(); + return cur_data.size_s(); } @@ -78,8 +68,8 @@ int ContainersModel::columnCount(const QModelIndex & parent) const { QModelIndex ContainersModel::index(int row, int column, const QModelIndex & parent) const { - if (row >= typenames.size_s() || row >= typedata.size_s()) return QModelIndex(); - return createIndex(row, column, typeids[row]); + if (row >= cur_data.size_s() || row >= cur_data.size_s()) return QModelIndex(); + return createIndex(row, column, cur_data[row].id); } @@ -98,6 +88,7 @@ QVariant ContainersModel::headerData(int section, Qt::Orientation orientation, i } switch (section) { case ccType : return tr("Type"); + case ccItemSize : return tr("Item size"); case ccCount : return tr("Count (%1)").arg(ret[ccCount]); case ccBytesAllocated: return tr("Allocated (%1)").arg(PI2QString(PIString::readableSize(ret[ccBytesAllocated]))); case ccBytesUsed : return tr("Used (%1)").arg(PI2QString(PIString::readableSize(ret[ccBytesUsed]))); @@ -110,40 +101,46 @@ QVariant ContainersModel::headerData(int section, Qt::Orientation orientation, i QVariant ContainersModel::data(const QModelIndex & index, int role) const { if (role != Qt::DisplayRole && role != Qt::UserRole && role != (Qt::UserRole+1)) return QVariant(); uint id = uint(index.internalId()); + const PIIntrospectionContainers::TypeInfo & t(cur_data[index.row()]); llong v = 0L; if (role == Qt::DisplayRole || role == Qt::UserRole) { + switch (index.column()) { + case ccType: return PI2QString(t.name); + case ccItemSize: return PI2QString(PIString::readableSize(t.item_size)); + default: break; + } if (mode_changes) { switch (index.column()) { - case ccType: return demangle(typenames.value(id).dataAscii()); - case ccCount: return int(typedata.value(id).count) - int(prev_typedata.value(id).count); + case ccCount: return int(t.count) - int(prev_data.value(id).count); case ccBytesAllocated: - v = typedata.value(id).bytes_allocated; - v -= prev_typedata.value(id).bytes_allocated; + v = t.allocated; + v -= prev_data.value(id).allocated; + v *= t.item_size; if (role == Qt::UserRole) return piAbs(v); return PI2QString(PIString::readableSize(v)); case ccBytesUsed: - v = typedata.value(id).bytes_used; - v -= prev_typedata.value(id).bytes_used; + v = t.used; + v -= prev_data.value(id).used; + v *= t.item_size; if (role == Qt::UserRole) return piAbs(v); return PI2QString(PIString::readableSize(v)); } } else { switch (index.column()) { - case ccType: return demangle(typenames.value(id).dataAscii()); - case ccCount: return typedata.value(id).count; + case ccCount: return t.count; case ccBytesAllocated: - v = typedata.value(id).bytes_allocated; + v = t.allocated * t.item_size; if (role == Qt::UserRole) return v; return PI2QString(PIString::readableSize(v)); case ccBytesUsed: - v = typedata.value(id).bytes_used; + v = t.used * t.item_size; if (role == Qt::UserRole) return v; return PI2QString(PIString::readableSize(v)); } } } if (role == (Qt::UserRole+1) && (index.column() == ccCount)) { - return typedata.value(id).count; + return t.count; } return QVariant(); } @@ -156,8 +153,8 @@ Qt::ItemFlags ContainersModel::flags(const QModelIndex & index) const { void ContainersModel::setChangesMode(bool yes) { mode_changes = yes; - if (typeids.isEmpty()) return; - dataChanged(index(0, ccCount), index(typeids.size_s() - 1, columnCount())); + if (cur_data.isEmpty()) return; + dataChanged(index(0, ccCount), index(cur_data.size_s() - 1, columnCount())); emit headerDataChanged(Qt::Horizontal, ccCount, columnCount()); } @@ -212,8 +209,8 @@ void ContainersView::changeEvent(QEvent * e) { } -void ContainersView::showContainers(const PIMap & data, const PIMap & typenames) { - model->update(data, typenames); +void ContainersView::showContainers(const PIVector & t) { + model->update(t); } diff --git a/piqt_utils/piintrospector/containers_view.h b/piqt_utils/piintrospector/containers_view.h index e0a29ea..d66c83c 100644 --- a/piqt_utils/piintrospector/containers_view.h +++ b/piqt_utils/piintrospector/containers_view.h @@ -14,7 +14,7 @@ class ContainersModel: public QAbstractItemModel { public: ContainersModel(); - void update(const PIMap & td, const PIMap & tn); + void update(const PIVector & t); void clear(); int rowCount(const QModelIndex & parent = QModelIndex()) const override; @@ -27,9 +27,8 @@ public: Qt::ItemFlags flags(const QModelIndex & index) const override; protected: - PIMap typedata, prev_typedata; - PIMap typenames; - PIVector typeids; + PIVector cur_data; + PIMap prev_data; PIVector all, prev_all; bool mode_changes; @@ -55,7 +54,7 @@ class ContainersView: public QWidget, private Ui::ContainersView public: ContainersView(QWidget * parent = 0); ~ContainersView(); - void showContainers(const PIMap & data, const PIMap & typenames); + void showContainers(const PIVector & t); void clear(); protected: void changeEvent(QEvent * e); diff --git a/piqt_utils/piintrospector/piintrospector.cpp b/piqt_utils/piintrospector/piintrospector.cpp index c813201..0afdc54 100644 --- a/piqt_utils/piintrospector/piintrospector.cpp +++ b/piqt_utils/piintrospector/piintrospector.cpp @@ -179,10 +179,9 @@ void QPIIntrospector::peerReceived(const PIString & from, const PIByteArray & da } break; case PIIntrospection::itContainers: { cs.get(pba); - PIMap data; - PIMap typenames; - PIIntrospection::unpackContainers(pba, data, typenames); - widgetContainers->showContainers(data, typenames); + PIVector data; + PIIntrospection::unpackContainers(pba, data); + widgetContainers->showContainers(data); } break; case PIIntrospection::itObjects: { cs.get(pba); diff --git a/piqt_utils/piintrospector/threads_view.cpp b/piqt_utils/piintrospector/threads_view.cpp new file mode 100644 index 0000000..0fcd09b --- /dev/null +++ b/piqt_utils/piintrospector/threads_view.cpp @@ -0,0 +1,230 @@ +#include "threads_view.h" +#include +#include +#include +#include +#include "ccm_piintrospector.h" + + +enum ColumnThreads { + ctClassname, + ctName, + ctID, + ctDelay, + ctState, + ctLoad, + ctRunCost, + ctRunCount, + ctColumnCount, +}; + + + + +ThreadsModel::ThreadsModel() { + PICodeInfo::EnumInfo * ei = PICodeInfo::enumsInfo->value("PIIntrospectionThreads::ThreadState"); + if (ei) { + piForeachC (PICodeInfo::EnumeratorInfo & e, ei->members) { + state_names[e.value] = PI2QString(e.name.mid(1)); + } + } + state_colors[PIIntrospectionThreads::sStopped] = QColor(Qt::red).lighter(150); + state_colors[PIIntrospectionThreads::sStarting] = QColor(Qt::blue).lighter(150); + state_colors[PIIntrospectionThreads::sRunning] = QColor(Qt::green).lighter(120); + state_colors[PIIntrospectionThreads::sWaiting] = QColor(Qt::yellow).lighter(110); +} + + +void ThreadsModel::update(const PIVector & t) { + int pts = threads.size_s(); + threads = t; + if (t.size_s() > pts) { + beginInsertRows(QModelIndex(), pts, t.size_s() - 1); + endInsertRows(); + } + if (t.size_s() < pts) { + beginRemoveRows(QModelIndex(), t.size_s(), pts - 1); + endRemoveRows(); + } + dataChanged(index(0, 0), index(threads.size_s() - 1, columnCount())); + //emit headerDataChanged(Qt::Horizontal, ccCount, columnCount()); +} + + +void ThreadsModel::setStat(const PIVector & s) { + stat = s; + dataChanged(index(0, ctLoad), index(threads.size_s() - 1, ctLoad)); +} + + +void ThreadsModel::clear() { + beginRemoveRows(QModelIndex(), 0, threads.size_s() - 1); + threads.clear(); + endRemoveRows(); +} + + +int ThreadsModel::rowCount(const QModelIndex & parent) const { + return threads.size_s(); +} + + +int ThreadsModel::columnCount(const QModelIndex & parent) const { + return ctColumnCount; +} + + +QModelIndex ThreadsModel::index(int row, int column, const QModelIndex & parent) const { + if (row >= threads.size_s() || row >= threads.size_s()) return QModelIndex(); + return createIndex(row, column, quintptr(0)); +} + + +bool ThreadsModel::hasChildren(const QModelIndex & parent) const { + if (!parent.isValid()) return true; + return false; +} + + +QVariant ThreadsModel::headerData(int section, Qt::Orientation orientation, int role) const { + if (orientation != Qt::Horizontal || role != Qt::DisplayRole) return QVariant(); + switch (section) { + case ctClassname: return tr("Classname"); + case ctName : return tr("Name"); + case ctID : return tr("pID (pri)"); + case ctDelay : return tr("Delay, ms"); + case ctState : return tr("State"); + case ctLoad : return tr("CPU, %"); + case ctRunCost : return tr("Run cost, avg"); + case ctRunCount : return tr("Run counts"); + default: break; + } + return QVariant(); +} + + +QVariant ThreadsModel::data(const QModelIndex & index, int role) const { + if (role != Qt::DisplayRole && role != Qt::DecorationRole && role != Qt::UserRole) return QVariant(); + const PIIntrospectionThreads::ThreadInfo & ti(threads[index.row()]); + if (role == Qt::DisplayRole) { + switch (index.column()) { + case ctClassname: return PI2QString(ti.classname); + case ctName : return PI2QString(ti.name); + case ctID : return QString("%1 (%2)").arg(ti.id).arg(ti.priority); + case ctDelay : return QString::number(ti.delay); + case ctState : return state_names.value(ti.state); + case ctLoad : { + piForeachC (PISystemMonitor::ThreadStats & s, stat) { + if (s.id == llong(ti.id)) { + return QString::number(s.cpu_load_kernel + s.cpu_load_user, 'f', 2) + " %"; + } + } + return "-"; + } + case ctRunCost : { + double v = ti.run_us; + QByteArray suff = " us"; + if (v > 1000.) {v /= 1000.; suff = " ms";} + if (v > 1000.) {v /= 1000.; suff = " s";} + return QString::number(v, 'f', 1) + suff; + } + case ctRunCount : return QString::number(ti.run_count); + } + } + if (index.column() == ctState) { + if (role == Qt::DecorationRole) { + return state_colors.value(ti.state); + } + if (role == Qt::UserRole) { + return int(ti.state); + } + } + return QVariant(); +} + + +Qt::ItemFlags ThreadsModel::flags(const QModelIndex & index) const { + return Qt::ItemIsEnabled | Qt::ItemIsSelectable; +} + + + +/* +void ContainersDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const { + QStyledItemDelegate::paint(painter, option, index); + if (model->index(index.row(), ccCount).data(Qt::UserRole+1).toInt() == 0) { + QColor col; + if (option.state == QStyle::State_Enabled || + option.state == QStyle::State_HasFocus) + col = option.palette.color(QPalette::Active, QPalette::WindowText); + else + col = option.palette.color(QPalette::Disabled, QPalette::WindowText); + col.setAlphaF(0.5); + int y = option.rect.center().y() + (option.fontMetrics.height() / 2.5) - option.fontMetrics.strikeOutPos(); + painter->setPen(QPen(col, lineThickness())); + painter->drawLine(QPoint(option.rect.left(), y), QPoint(option.rect.right(), y)); + } +} +*/ + + + + +ThreadsView::ThreadsView(QWidget * parent): QWidget(parent) { + setupUi(this); + model = new ThreadsModel(); + QSortFilterProxyModel * proxy = new QSortFilterProxyModel(); + proxy->setSourceModel(model); + proxy->setSortRole(Qt::UserRole); + proxy->setDynamicSortFilter(false); + treeThreads->setModel(model); + connect(checkHideStopped, SIGNAL(toggled(bool)), this, SLOT(updateHidden())); + //treeContainers->setItemDelegate(new ContainersDelegate(model)); +} + + +ThreadsView::~ThreadsView() { +} + + +void ThreadsView::setStat(const PIVector & stat) { + model->setStat(stat); +} + + +void ThreadsView::changeEvent(QEvent * e) { + QWidget::changeEvent(e); + switch (e->type()) { + case QEvent::LanguageChange: + retranslateUi(this); + break; + default: + break; + } +} + + +void ThreadsView::updateHidden() { + bool hide_stopped = checkHideStopped->isChecked(); + QModelIndex root = treeThreads->rootIndex(); + for (int i = 0; i < model->rowCount(); ++i) { + if (!hide_stopped) treeThreads->setRowHidden(i, root, false); + else { + if (model->index(i, ctState).data(Qt::UserRole).toInt() == PIIntrospectionThreads::sStopped) + treeThreads->setRowHidden(i, root, true); + else + treeThreads->setRowHidden(i, root, false); + } + } +} + + +void ThreadsView::showThreads(const PIVector & threads) { + model->update(threads); + updateHidden(); +} + + +void ThreadsView::clear() { + model->clear(); +} diff --git a/piqt_utils/piintrospector/threads_view.h b/piqt_utils/piintrospector/threads_view.h new file mode 100644 index 0000000..67cda5c --- /dev/null +++ b/piqt_utils/piintrospector/threads_view.h @@ -0,0 +1,79 @@ +#ifndef THREADS_VIEW_H +#define THREADS_VIEW_H + +#include "ui_threads_view.h" +#include +#include +#include +#include +#include +#include +#include "piqt.h" +#include "pisystemmonitor.h" +#include "piintrospection_threads_p.h" + + +class ThreadsModel: public QAbstractItemModel { + Q_OBJECT +public: + ThreadsModel(); + + void update(const PIVector & t); + void setStat(const PIVector & s); + void clear(); + + int rowCount(const QModelIndex & parent = QModelIndex()) const override; + int columnCount(const QModelIndex & parent = QModelIndex()) const override; + QModelIndex parent(const QModelIndex & child) const override {return QModelIndex();} + QModelIndex index(int row, int column, const QModelIndex & parent = QModelIndex()) const override; + bool hasChildren(const QModelIndex & parent = QModelIndex()) const override; + QVariant headerData(int section, Qt::Orientation orientation, int role) const override; + QVariant data(const QModelIndex & index, int role) const override; + Qt::ItemFlags flags(const QModelIndex & index) const override; + +protected: + PIVector threads; + PIVector stat; + QHash state_names; + QHash state_colors; + +}; + + + +/* +class ContainersDelegate: public QStyledItemDelegate { + Q_OBJECT +public: + ContainersDelegate(QAbstractItemModel * m) {model = m;} + void paint(QPainter *painter, const QStyleOptionViewItem & option, const QModelIndex &index) const override; + QAbstractItemModel * model; +}; +*/ + + +class ThreadsView: public QWidget, private Ui::ThreadsView +{ + Q_OBJECT +public: + ThreadsView(QWidget * parent = 0); + ~ThreadsView(); + + void setStat(const PIVector & stat); + void showThreads(const PIVector & threads); + void clear(); + +protected: + void changeEvent(QEvent * e); + + ThreadsModel * model; + +private slots: + void updateHidden(); + +public slots: + +}; + + +#endif // CONTAINERS_VIEW_H diff --git a/piqt_utils/piintrospector/threads_view.ui b/piqt_utils/piintrospector/threads_view.ui new file mode 100644 index 0000000..10210d0 --- /dev/null +++ b/piqt_utils/piintrospector/threads_view.ui @@ -0,0 +1,51 @@ + + + ThreadsView + + + + 0 + 0 + 513 + 365 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + Hide stopped + + + + + + + + + QAbstractItemView::NoEditTriggers + + + QAbstractItemView::ScrollPerPixel + + + + + + + +