Debugger: Make the time stamp recording option work for single items

Should help to drill down to individual expensive dumpers.

Change-Id: I983ba075231784f71dd9d5c3bda375a3ee508bf6
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
hjk
2019-04-09 08:23:24 +02:00
parent 57cac11e20
commit e95fd876aa
10 changed files with 53 additions and 18 deletions

View File

@@ -270,6 +270,7 @@ class DumperBase:
# Later set, or not set: # Later set, or not set:
self.stringCutOff = 10000 self.stringCutOff = 10000
self.displayStringLimit = 100 self.displayStringLimit = 100
self.useTimeStamps = False
self.typesReported = {} self.typesReported = {}
self.typesToReport = {} self.typesToReport = {}
@@ -329,6 +330,7 @@ class DumperBase:
self.showQObjectNames = int(args.get('qobjectnames', '1')) self.showQObjectNames = int(args.get('qobjectnames', '1'))
self.nativeMixed = int(args.get('nativemixed', '0')) self.nativeMixed = int(args.get('nativemixed', '0'))
self.autoDerefPointers = int(args.get('autoderef', '0')) self.autoDerefPointers = int(args.get('autoderef', '0'))
self.useTimeStamps = int(args.get('timestamps', '0'))
self.partialVariable = args.get('partialvar', '') self.partialVariable = args.get('partialvar', '')
self.uninitialized = args.get('uninitialized', []) self.uninitialized = args.get('uninitialized', [])
self.uninitialized = list(map(lambda x: self.hexdecode(x), self.uninitialized)) self.uninitialized = list(map(lambda x: self.hexdecode(x), self.uninitialized))
@@ -422,6 +424,8 @@ class DumperBase:
self.currentIName = item.iname self.currentIName = item.iname
self.currentValue = ReportItem(); self.currentValue = ReportItem();
self.currentType = ReportItem(); self.currentType = ReportItem();
if self.useTimeStamps:
item.startTime = time.time()
def exitSubItem(self, item, exType, exValue, exTraceBack): def exitSubItem(self, item, exType, exValue, exTraceBack):
#warn('CURRENT VALUE: %s: %s %s' % #warn('CURRENT VALUE: %s: %s %s' %
@@ -431,6 +435,8 @@ class DumperBase:
showException('SUBITEM', exType, exValue, exTraceBack) showException('SUBITEM', exType, exValue, exTraceBack)
self.putSpecialValue('notaccessible') self.putSpecialValue('notaccessible')
self.putNumChild(0) self.putNumChild(0)
if self.useTimeStamps:
self.put('time="%s",' % (time.time() - item.startTime))
if not self.isCli: if not self.isCli:
try: try:
if self.currentType.value: if self.currentType.value:

View File

@@ -1114,6 +1114,7 @@ void CdbEngine::doUpdateLocals(const UpdateParameters &updateParameters)
cmd.arg("dyntype", boolSetting(UseDynamicType)); cmd.arg("dyntype", boolSetting(UseDynamicType));
cmd.arg("partialvar", updateParameters.partialVariable); cmd.arg("partialvar", updateParameters.partialVariable);
cmd.arg("qobjectnames", boolSetting(ShowQObjectNames)); cmd.arg("qobjectnames", boolSetting(ShowQObjectNames));
cmd.arg("timestamps", boolSetting(LogTimeStamps));
StackFrame frame = stackHandler()->currentFrame(); StackFrame frame = stackHandler()->currentFrame();
cmd.arg("context", frame.context); cmd.arg("context", frame.context);

View File

@@ -4743,6 +4743,7 @@ void GdbEngine::doUpdateLocals(const UpdateParameters &params)
cmd.arg("autoderef", boolSetting(AutoDerefPointers)); cmd.arg("autoderef", boolSetting(AutoDerefPointers));
cmd.arg("dyntype", boolSetting(UseDynamicType)); cmd.arg("dyntype", boolSetting(UseDynamicType));
cmd.arg("qobjectnames", boolSetting(ShowQObjectNames)); cmd.arg("qobjectnames", boolSetting(ShowQObjectNames));
cmd.arg("timestamps", boolSetting(LogTimeStamps));
StackFrame frame = stackHandler()->currentFrame(); StackFrame frame = stackHandler()->currentFrame();
cmd.arg("context", frame.context); cmd.arg("context", frame.context);

View File

@@ -764,6 +764,7 @@ void LldbEngine::doUpdateLocals(const UpdateParameters &params)
cmd.arg("dyntype", boolSetting(UseDynamicType)); cmd.arg("dyntype", boolSetting(UseDynamicType));
cmd.arg("partialvar", params.partialVariable); cmd.arg("partialvar", params.partialVariable);
cmd.arg("qobjectnames", boolSetting(ShowQObjectNames)); cmd.arg("qobjectnames", boolSetting(ShowQObjectNames));
cmd.arg("timestamps", boolSetting(LogTimeStamps));
StackFrame frame = stackHandler()->currentFrame(); StackFrame frame = stackHandler()->currentFrame();
cmd.arg("context", frame.context); cmd.arg("context", frame.context);

View File

@@ -363,6 +363,10 @@ void WatchItem::parseHelper(const GdbMi &input, bool maySort)
if (mi.isValid()) if (mi.isValid())
exp = mi.data(); exp = mi.data();
mi = input["time"];
if (mi.isValid())
time = mi.data().toFloat();
mi = input["sortgroup"]; mi = input["sortgroup"];
if (mi.isValid()) if (mi.isValid())
sortGroup = mi.toInt(); sortGroup = mi.toInt();
@@ -462,6 +466,8 @@ void WatchItem::parse(const GdbMi &data, bool maySort)
if (wname.isValid()) if (wname.isValid())
exp = name; exp = name;
time = data["time"].data().toFloat();
} }
// Format a tooltip row with aligned colon. // Format a tooltip row with aligned colon.
@@ -508,6 +514,7 @@ QString WatchItem::toToolTip() const
if (size) if (size)
formatToolTipRow(str, tr("Static Object Size"), tr("%n bytes", nullptr, size)); formatToolTipRow(str, tr("Static Object Size"), tr("%n bytes", nullptr, size));
formatToolTipRow(str, tr("Internal ID"), internalName()); formatToolTipRow(str, tr("Internal ID"), internalName());
formatToolTipRow(str, tr("Creation Time in ms"), QString::number(int(time * 1000)));
str << "</table></body></html>"; str << "</table></body></html>";
return res; return res;
} }

View File

@@ -99,6 +99,7 @@ public:
bool valueEnabled; // Value will be enabled or not bool valueEnabled; // Value will be enabled or not
bool valueEditable; // Value will be editable bool valueEditable; // Value will be editable
bool outdated; // \internal item is to be removed. bool outdated; // \internal item is to be removed.
double time = 0; // Time used on the dumper side to produce this item
private: private:
void parseHelper(const GdbMi &input, bool maySort); void parseHelper(const GdbMi &input, bool maySort);

View File

@@ -484,7 +484,7 @@ WatchModel::WatchModel(WatchHandler *handler, DebuggerEngine *engine)
m_contentsValid = true; m_contentsValid = true;
setHeader({tr("Name"), tr("Value"), tr("Type")}); setHeader({tr("Name"), tr("Time"), tr("Value"), tr("Type")});
m_localsRoot = new WatchItem; m_localsRoot = new WatchItem;
m_localsRoot->iname = "local"; m_localsRoot->iname = "local";
m_localsRoot->name = tr("Locals"); m_localsRoot->name = tr("Locals");
@@ -901,7 +901,7 @@ static QColor valueColor(const WatchItem *item, int column)
if (const WatchModel *model = watchModel(item)) { if (const WatchModel *model = watchModel(item)) {
if (!model->m_contentsValid && !item->isInspect()) { if (!model->m_contentsValid && !item->isInspect()) {
color = Theme::Debugger_WatchItem_ValueInvalid; color = Theme::Debugger_WatchItem_ValueInvalid;
} else if (column == 1) { } else if (column == WatchModel::ValueColumn) {
if (!item->valueEnabled) if (!item->valueEnabled)
color = Theme::Debugger_WatchItem_ValueInvalid; color = Theme::Debugger_WatchItem_ValueInvalid;
else if (!model->m_contentsValid && !item->isInspect()) else if (!model->m_contentsValid && !item->isInspect())
@@ -1011,11 +1011,13 @@ QVariant WatchModel::data(const QModelIndex &idx, int role) const
case Qt::EditRole: { case Qt::EditRole: {
switch (column) { switch (column) {
case 0: case TimeColumn:
return item->time;
case NameColumn:
return item->expression(); return item->expression();
case 1: case ValueColumn:
return item->editValue(); return item->editValue();
case 2: case TypeColumn:
return item->type; return item->type;
} }
break; break;
@@ -1023,11 +1025,13 @@ QVariant WatchModel::data(const QModelIndex &idx, int role) const
case Qt::DisplayRole: { case Qt::DisplayRole: {
switch (column) { switch (column) {
case 0: case TimeColumn:
return int(1000 * item->time);
case NameColumn:
return displayName(item); return displayName(item);
case 1: case ValueColumn:
return displayValue(item); return displayValue(item);
case 2: case TypeColumn:
return displayType(item); return displayType(item);
} }
break; break;
@@ -1129,14 +1133,14 @@ bool WatchModel::setData(const QModelIndex &idx, const QVariant &value, int role
switch (role) { switch (role) {
case Qt::EditRole: case Qt::EditRole:
switch (idx.column()) { switch (idx.column()) {
case 0: { case NameColumn: {
m_handler->updateWatchExpression(item, value.toString().trimmed()); m_handler->updateWatchExpression(item, value.toString().trimmed());
break; break;
} }
case 1: // Change value case ValueColumn: // Change value
m_engine->assignValueInDebugger(item, item->expression(), value); m_engine->assignValueInDebugger(item, item->expression(), value);
break; break;
case 2: // TODO: Implement change type. case TypeColumn: // TODO: Implement change type.
m_engine->assignValueInDebugger(item, item->expression(), value); m_engine->assignValueInDebugger(item, item->expression(), value);
break; break;
} }
@@ -1206,20 +1210,20 @@ Qt::ItemFlags WatchModel::flags(const QModelIndex &idx) const
if (item->isWatcher()) { if (item->isWatcher()) {
if (state == InferiorUnrunnable) if (state == InferiorUnrunnable)
return (column == 0 && item->iname.count('.') == 1) ? editable : notEditable; return (column == NameColumn && item->iname.count('.') == 1) ? editable : notEditable;
if (isRunning && !m_engine->hasCapability(AddWatcherWhileRunningCapability)) if (isRunning && !m_engine->hasCapability(AddWatcherWhileRunningCapability))
return notEditable; return notEditable;
if (column == 0 && item->iname.count('.') == 1) if (column == NameColumn && item->iname.count('.') == 1)
return editable; // Watcher names are editable. return editable; // Watcher names are editable.
if (column == 1 && item->arrayIndex >= 0) if (column == ValueColumn && item->arrayIndex >= 0)
return editable; return editable;
if (!item->name.isEmpty()) { if (!item->name.isEmpty()) {
// FIXME: Forcing types is not implemented yet. // FIXME: Forcing types is not implemented yet.
//if (idx.column() == 2) //if (idx.column() == 2)
// return editable; // Watcher types can be set by force. // return editable; // Watcher types can be set by force.
if (column == 1 && item->valueEditable && !item->elided) if (column == ValueColumn && item->valueEditable && !item->elided)
return editable; // Watcher values are sometimes editable. return editable; // Watcher values are sometimes editable.
} }
} else if (item->isLocal()) { } else if (item->isLocal()) {
@@ -1227,12 +1231,12 @@ Qt::ItemFlags WatchModel::flags(const QModelIndex &idx) const
return notEditable; return notEditable;
if (isRunning && !m_engine->hasCapability(AddWatcherWhileRunningCapability)) if (isRunning && !m_engine->hasCapability(AddWatcherWhileRunningCapability))
return notEditable; return notEditable;
if (column == 1 && item->valueEditable && !item->elided) if (column == ValueColumn && item->valueEditable && !item->elided)
return editable; // Locals values are sometimes editable. return editable; // Locals values are sometimes editable.
if (column == 1 && item->arrayIndex >= 0) if (column == ValueColumn && item->arrayIndex >= 0)
return editable; return editable;
} else if (item->isInspect()) { } else if (item->isInspect()) {
if (column == 1 && item->valueEditable) if (column == ValueColumn && item->valueEditable)
return editable; // Inspector values are sometimes editable. return editable; // Inspector values are sometimes editable.
} }
return notEditable; return notEditable;

View File

@@ -46,6 +46,8 @@ class WatchModelBase : public Utils::TreeModel<WatchItem, WatchItem>
public: public:
WatchModelBase() = default; WatchModelBase() = default;
enum { NameColumn, TimeColumn, ValueColumn, TypeColumn };
signals: signals:
void currentIndexRequested(const QModelIndex &idx); void currentIndexRequested(const QModelIndex &idx);
void itemIsExpanded(const QModelIndex &idx); void itemIsExpanded(const QModelIndex &idx);

View File

@@ -53,6 +53,9 @@ WatchTreeView::WatchTreeView(WatchType type)
connect(this, &QTreeView::expanded, this, &WatchTreeView::expandNode); connect(this, &QTreeView::expanded, this, &WatchTreeView::expandNode);
connect(this, &QTreeView::collapsed, this, &WatchTreeView::collapseNode); connect(this, &QTreeView::collapsed, this, &WatchTreeView::collapseNode);
connect(action(LogTimeStamps), &QAction::triggered,
this, &WatchTreeView::updateTimeColumn);
} }
void WatchTreeView::expandNode(const QModelIndex &idx) void WatchTreeView::expandNode(const QModelIndex &idx)
@@ -96,6 +99,14 @@ void WatchTreeView::setModel(QAbstractItemModel *model)
connect(watchModel, &WatchModelBase::updateFinished, connect(watchModel, &WatchModelBase::updateFinished,
this, &WatchTreeView::hideProgressIndicator); this, &WatchTreeView::hideProgressIndicator);
} }
updateTimeColumn();
}
void WatchTreeView::updateTimeColumn()
{
if (header())
header()->setSectionHidden(WatchModelBase::TimeColumn, !boolSetting(LogTimeStamps));
} }
void WatchTreeView::handleItemIsExpanded(const QModelIndex &idx) void WatchTreeView::handleItemIsExpanded(const QModelIndex &idx)

View File

@@ -56,6 +56,7 @@ private:
void resetHelper(); void resetHelper();
void expandNode(const QModelIndex &idx); void expandNode(const QModelIndex &idx);
void collapseNode(const QModelIndex &idx); void collapseNode(const QModelIndex &idx);
void updateTimeColumn();
void adjustSlider(); void adjustSlider();
void doItemsLayout() override; void doItemsLayout() override;