CtfVisualizer: Do not crash on unexpected types again

And print a nicer error message.

Amends c05f9cacc6

Task-number: QTCREATORBUG-29659
Change-Id: I1db6bea0bedf1fae034fecbbbeae56bb2fee49ed
Reviewed-by: Jarek Kobus <jaroslaw.kobus@qt.io>
This commit is contained in:
Eike Ziller
2023-09-28 10:54:28 +02:00
parent 963ff4381d
commit 97518b3f6a
3 changed files with 59 additions and 41 deletions

View File

@@ -46,50 +46,56 @@ qint64 CtfTraceManager::traceEnd() const
void CtfTraceManager::addEvent(const json &event) void CtfTraceManager::addEvent(const json &event)
{ {
const double timestamp = event.value(CtfTracingClockTimestampKey, -1.0); try {
if (timestamp < 0) { const double timestamp = event.value(CtfTracingClockTimestampKey, -1.0);
// events without or with negative timestamp will be ignored if (timestamp < 0) {
return; // events without or with negative timestamp will be ignored
} return;
if (m_timeOffset < 0) {
// the timestamp of the first event is used as the global offset
m_timeOffset = timestamp;
}
static const auto getStringValue = [](const json &event, const char *key, const QString &def) {
if (!event.contains(key))
return def;
const json val = event[key];
if (val.is_string())
return QString::fromStdString(val);
if (val.is_number()) {
return QString::number(int(val));
} }
return def; if (m_timeOffset < 0) {
}; // the timestamp of the first event is used as the global offset
const QString processId = getStringValue(event, CtfProcessIdKey, "0"); m_timeOffset = timestamp;
const QString threadId = getStringValue(event, CtfThreadIdKey, processId);
if (!m_threadModels.contains(threadId)) {
addModelForThread(threadId, processId);
}
if (event.value(CtfEventPhaseKey, "") == CtfEventTypeMetadata) {
const std::string name = event[CtfEventNameKey];
if (name == "thread_name") {
m_threadNames[threadId] = QString::fromStdString(event["args"]["name"]);
} else if (name == "process_name") {
m_processNames[processId] = QString::fromStdString(event["args"]["name"]);
} }
}
const QPair<bool, qint64> result = m_threadModels[threadId]->addEvent(event, m_timeOffset); static const auto getStringValue =
const bool visibleOnTimeline = result.first; [](const json &event, const char *key, const QString &def) {
if (visibleOnTimeline) { if (!event.contains(key))
m_traceBegin = std::min(m_traceBegin, timestamp); return def;
m_traceEnd = std::max(m_traceEnd, timestamp); const json val = event[key];
} else if (m_timeOffset == timestamp) { if (val.is_string())
// this timestamp was used as the time offset but it is not a visible element return QString::fromStdString(val);
// -> reset the time offset again: if (val.is_number()) {
m_timeOffset = -1.0; return QString::number(int(val));
}
return def;
};
const QString processId = getStringValue(event, CtfProcessIdKey, "0");
const QString threadId = getStringValue(event, CtfThreadIdKey, processId);
if (!m_threadModels.contains(threadId)) {
addModelForThread(threadId, processId);
}
if (event.value(CtfEventPhaseKey, "") == CtfEventTypeMetadata) {
const std::string name = event[CtfEventNameKey];
if (name == "thread_name") {
m_threadNames[threadId] = QString::fromStdString(event["args"]["name"]);
} else if (name == "process_name") {
m_processNames[processId] = QString::fromStdString(event["args"]["name"]);
}
}
const QPair<bool, qint64> result = m_threadModels[threadId]->addEvent(event, m_timeOffset);
const bool visibleOnTimeline = result.first;
if (visibleOnTimeline) {
m_traceBegin = std::min(m_traceBegin, timestamp);
m_traceEnd = std::max(m_traceEnd, timestamp);
} else if (m_timeOffset == timestamp) {
// this timestamp was used as the time offset but it is not a visible element
// -> reset the time offset again:
m_timeOffset = -1.0;
}
} catch (...) {
m_errorString = Tr::tr("Error while parsing CTF data: %1.")
.arg("<pre>" + QString::fromStdString(event.dump()) + "</pre>");
} }
} }
@@ -216,6 +222,7 @@ void CtfTraceManager::updateStatistics()
void CtfTraceManager::clearAll() void CtfTraceManager::clearAll()
{ {
m_errorString.clear();
m_modelAggregator->clear(); m_modelAggregator->clear();
for (CtfTimelineModel *model: std::as_const(m_threadModels)) { for (CtfTimelineModel *model: std::as_const(m_threadModels)) {
model->deleteLater(); model->deleteLater();
@@ -226,6 +233,10 @@ void CtfTraceManager::clearAll()
m_timeOffset = -1; m_timeOffset = -1;
} }
QString CtfTraceManager::errorString() const
{
return m_errorString;
}
} // namespace Internal } // namespace Internal
} // namespace CtfVisualizer } // namespace CtfVisualizer

View File

@@ -46,6 +46,8 @@ public:
void updateStatistics(); void updateStatistics();
void clearAll(); void clearAll();
QString errorString() const;
signals: signals:
void detailsRequested(const QString &title); void detailsRequested(const QString &title);
@@ -66,6 +68,7 @@ protected:
double m_traceEnd = std::numeric_limits<double>::min(); double m_traceEnd = std::numeric_limits<double>::min();
double m_timeOffset = -1.0; double m_timeOffset = -1.0;
QString m_errorString;
}; };
} // namespace Internal } // namespace Internal

View File

@@ -231,6 +231,10 @@ void CtfVisualizerTool::loadJson(const QString &fileName)
QMessageBox::warning(Core::ICore::dialogParent(), QMessageBox::warning(Core::ICore::dialogParent(),
Tr::tr("CTF Visualizer"), Tr::tr("CTF Visualizer"),
Tr::tr("The file does not contain any trace data.")); Tr::tr("The file does not contain any trace data."));
} else if (!m_traceManager->errorString().isEmpty()) {
QMessageBox::warning(Core::ICore::dialogParent(),
Tr::tr("CTF Visualizer"),
m_traceManager->errorString());
} else { } else {
m_traceManager->finalize(); m_traceManager->finalize();
m_perspective.select(); m_perspective.select();