cabana: remove the qlog parsing thread (#30319)

remove the qlog thread
old-commit-hash: e287a5f164
testing-closet
Dean Lee 2 years ago committed by GitHub
parent 47b9097674
commit 3fb329773e
  1. 1
      tools/cabana/streams/replaystream.cc
  2. 3
      tools/cabana/streams/replaystream.h
  3. 77
      tools/cabana/videowidget.cc
  4. 13
      tools/cabana/videowidget.h
  5. 10
      tools/replay/replay.cc
  6. 2
      tools/replay/replay.h

@ -40,6 +40,7 @@ bool ReplayStream::loadRoute(const QString &route, const QString &data_dir, uint
replay->installEventFilter(event_filter, this); replay->installEventFilter(event_filter, this);
QObject::connect(replay.get(), &Replay::seekedTo, this, &AbstractStream::seekedTo); QObject::connect(replay.get(), &Replay::seekedTo, this, &AbstractStream::seekedTo);
QObject::connect(replay.get(), &Replay::segmentsMerged, this, &ReplayStream::mergeSegments); QObject::connect(replay.get(), &Replay::segmentsMerged, this, &ReplayStream::mergeSegments);
QObject::connect(replay.get(), &Replay::qLogLoaded, this, &ReplayStream::qLogLoaded, Qt::QueuedConnection);
return replay->load(); return replay->load();
} }

@ -32,6 +32,9 @@ public:
inline const std::vector<std::tuple<double, double, TimelineType>> getTimeline() override { return replay->getTimeline(); } inline const std::vector<std::tuple<double, double, TimelineType>> getTimeline() override { return replay->getTimeline(); }
static AbstractOpenStreamWidget *widget(AbstractStream **stream); static AbstractOpenStreamWidget *widget(AbstractStream **stream);
signals:
void qLogLoaded(int segnum, std::shared_ptr<LogReader> qlog);
private: private:
void mergeSegments(); void mergeSegments();
std::unique_ptr<Replay> replay = nullptr; std::unique_ptr<Replay> replay = nullptr;

@ -1,8 +1,6 @@
#include "tools/cabana/videowidget.h" #include "tools/cabana/videowidget.h"
#include <algorithm> #include <algorithm>
#include <memory>
#include <string>
#include <utility> #include <utility>
#include <QButtonGroup> #include <QButtonGroup>
@ -11,7 +9,6 @@
#include <QPainter> #include <QPainter>
#include <QStackedLayout> #include <QStackedLayout>
#include <QStyleOptionSlider> #include <QStyleOptionSlider>
#include <QTimer>
#include <QVBoxLayout> #include <QVBoxLayout>
#include <QtConcurrent> #include <QtConcurrent>
@ -125,6 +122,7 @@ QWidget *VideoWidget::createCameraWidget() {
QObject::connect(slider, &QSlider::valueChanged, [=](int value) { time_label->setText(utils::formatSeconds(slider->currentSecond())); }); QObject::connect(slider, &QSlider::valueChanged, [=](int value) { time_label->setText(utils::formatSeconds(slider->currentSecond())); });
QObject::connect(slider, &Slider::updateMaximumTime, this, &VideoWidget::setMaximumTime, Qt::QueuedConnection); QObject::connect(slider, &Slider::updateMaximumTime, this, &VideoWidget::setMaximumTime, Qt::QueuedConnection);
QObject::connect(cam_widget, &CameraWidget::clicked, []() { can->pause(!can->isPaused()); }); QObject::connect(cam_widget, &CameraWidget::clicked, []() { can->pause(!can->isPaused()); });
QObject::connect(static_cast<ReplayStream*>(can), &ReplayStream::qLogLoaded, slider, &Slider::parseQLog);
QObject::connect(can, &AbstractStream::updated, this, &VideoWidget::updateState); QObject::connect(can, &AbstractStream::updated, this, &VideoWidget::updateState);
return w; return w;
} }
@ -165,29 +163,9 @@ void VideoWidget::updatePlayBtnState() {
Slider::Slider(QWidget *parent) : thumbnail_label(parent), QSlider(Qt::Horizontal, parent) { Slider::Slider(QWidget *parent) : thumbnail_label(parent), QSlider(Qt::Horizontal, parent) {
setMouseTracking(true); setMouseTracking(true);
auto timer = new QTimer(this);
timer->callOnTimeout([this]() {
timeline = can->getTimeline();
std::sort(timeline.begin(), timeline.end(), [](auto &l, auto &r) { return std::get<2>(l) < std::get<2>(r); });
update();
});
timer->start(2000);
QObject::connect(can, &AbstractStream::eventsMerged, [this]() {
if (!qlog_future) {
qlog_future = std::make_unique<QFuture<void>>(QtConcurrent::run(this, &Slider::parseQLog));
}
});
QObject::connect(qApp, &QApplication::aboutToQuit, [this]() {
abort_parse_qlog = true;
if (qlog_future && qlog_future->isRunning()) {
qDebug() << "stopping thumbnail thread";
qlog_future->waitForFinished();
}
});
} }
AlertInfo Slider::alertInfo(double seconds) { AlertInfo Slider::alertInfo(double seconds) {
std::lock_guard lk(thumbnail_lock);
uint64_t mono_time = (seconds + can->routeStartTime()) * 1e9; uint64_t mono_time = (seconds + can->routeStartTime()) * 1e9;
auto alert_it = alerts.lower_bound(mono_time); auto alert_it = alerts.lower_bound(mono_time);
bool has_alert = (alert_it != alerts.end()) && ((alert_it->first - mono_time) <= 1e8); bool has_alert = (alert_it != alerts.end()) && ((alert_it->first - mono_time) <= 1e8);
@ -195,7 +173,6 @@ AlertInfo Slider::alertInfo(double seconds) {
} }
QPixmap Slider::thumbnail(double seconds) { QPixmap Slider::thumbnail(double seconds) {
std::lock_guard lk(thumbnail_lock);
uint64_t mono_time = (seconds + can->routeStartTime()) * 1e9; uint64_t mono_time = (seconds + can->routeStartTime()) * 1e9;
auto it = thumbnails.lowerBound(mono_time); auto it = thumbnails.lowerBound(mono_time);
return it != thumbnails.end() ? it.value() : QPixmap(); return it != thumbnails.end() ? it.value() : QPixmap();
@ -206,36 +183,32 @@ void Slider::setTimeRange(double min, double max) {
setRange(min * factor, max * factor); setRange(min * factor, max * factor);
} }
void Slider::parseQLog() { void Slider::parseQLog(int segnum, std::shared_ptr<LogReader> qlog) {
const auto &segments = can->route()->segments(); const auto &segments = qobject_cast<ReplayStream *>(can)->route()->segments();
for (auto it = segments.rbegin(); it != segments.rend() && !abort_parse_qlog; ++it) { if (segments.size() > 0 && segnum == segments.rbegin()->first && !qlog->events.empty()) {
LogReader log; emit updateMaximumTime(qlog->events.back()->mono_time / 1e9 - can->routeStartTime());
std::string qlog = it->second.qlog.toStdString(); }
if (!qlog.empty() && log.load(qlog, &abort_parse_qlog, {cereal::Event::Which::THUMBNAIL, cereal::Event::Which::CONTROLS_STATE}, true, 0, 3)) {
if (it == segments.rbegin() && !log.events.empty()) { std::mutex mutex;
double max_time = log.events.back()->mono_time / 1e9 - can->routeStartTime(); QtConcurrent::blockingMap(qlog->events.cbegin(), qlog->events.cend(), [&mutex, this](const Event *e) {
emit updateMaximumTime(max_time); if (e->which == cereal::Event::Which::THUMBNAIL) {
auto thumb = e->event.getThumbnail();
auto data = thumb.getThumbnail();
if (QPixmap pm; pm.loadFromData(data.begin(), data.size(), "jpeg")) {
QPixmap scaled = pm.scaledToHeight(MIN_VIDEO_HEIGHT - THUMBNAIL_MARGIN * 2, Qt::SmoothTransformation);
std::lock_guard lk(mutex);
thumbnails[thumb.getTimestampEof()] = scaled;
} }
for (auto ev = log.events.cbegin(); ev != log.events.cend() && !abort_parse_qlog; ++ev) { } else if (e->which == cereal::Event::Which::CONTROLS_STATE) {
if ((*ev)->which == cereal::Event::Which::THUMBNAIL) { auto cs = e->event.getControlsState();
auto thumb = (*ev)->event.getThumbnail(); if (cs.getAlertType().size() > 0 && cs.getAlertText1().size() > 0 &&
auto data = thumb.getThumbnail(); cs.getAlertSize() != cereal::ControlsState::AlertSize::NONE) {
if (QPixmap pm; pm.loadFromData(data.begin(), data.size(), "jpeg")) { std::lock_guard lk(mutex);
pm = pm.scaledToHeight(MIN_VIDEO_HEIGHT - THUMBNAIL_MARGIN * 2, Qt::SmoothTransformation); alerts.emplace(e->mono_time, AlertInfo{cs.getAlertStatus(), cs.getAlertText1().cStr(), cs.getAlertText2().cStr()});
std::lock_guard lk(thumbnail_lock);
thumbnails[thumb.getTimestampEof()] = pm;
}
} else if ((*ev)->which == cereal::Event::Which::CONTROLS_STATE) {
auto cs = (*ev)->event.getControlsState();
if (cs.getAlertType().size() > 0 && cs.getAlertText1().size() > 0 &&
cs.getAlertSize() != cereal::ControlsState::AlertSize::NONE) {
std::lock_guard lk(thumbnail_lock);
alerts.emplace((*ev)->mono_time, AlertInfo{cs.getAlertStatus(), cs.getAlertText1().cStr(), cs.getAlertText2().cStr()});
}
}
} }
} }
} });
update();
} }
void Slider::paintEvent(QPaintEvent *ev) { void Slider::paintEvent(QPaintEvent *ev) {
@ -245,7 +218,7 @@ void Slider::paintEvent(QPaintEvent *ev) {
double min = minimum() / factor; double min = minimum() / factor;
double max = maximum() / factor; double max = maximum() / factor;
for (auto [begin, end, type] : timeline) { for (auto [begin, end, type] : qobject_cast<ReplayStream *>(can)->getTimeline()) {
if (begin > max || end < min) if (begin > max || end < min)
continue; continue;
r.setLeft(((std::max(min, begin) - min) / (max - min)) * width()); r.setLeft(((std::max(min, begin) - min) / (max - min)) * width());

@ -1,19 +1,14 @@
#pragma once #pragma once
#include <atomic>
#include <map> #include <map>
#include <memory> #include <memory>
#include <mutex>
#include <tuple>
#include <vector>
#include <QFuture>
#include <QLabel> #include <QLabel>
#include <QSlider> #include <QSlider>
#include <QToolButton> #include <QToolButton>
#include "selfdrive/ui/qt/widgets/cameraview.h" #include "selfdrive/ui/qt/widgets/cameraview.h"
#include "tools/cabana/streams/abstractstream.h" #include "tools/cabana/streams/replaystream.h"
struct AlertInfo { struct AlertInfo {
cereal::ControlsState::AlertStatus status; cereal::ControlsState::AlertStatus status;
@ -42,6 +37,7 @@ public:
void setTimeRange(double min, double max); void setTimeRange(double min, double max);
AlertInfo alertInfo(double sec); AlertInfo alertInfo(double sec);
QPixmap thumbnail(double sec); QPixmap thumbnail(double sec);
void parseQLog(int segnum, std::shared_ptr<LogReader> qlog);
signals: signals:
void updateMaximumTime(double); void updateMaximumTime(double);
@ -51,15 +47,10 @@ private:
void mouseMoveEvent(QMouseEvent *e) override; void mouseMoveEvent(QMouseEvent *e) override;
bool event(QEvent *event) override; bool event(QEvent *event) override;
void paintEvent(QPaintEvent *ev) override; void paintEvent(QPaintEvent *ev) override;
void parseQLog();
const double factor = 1000.0; const double factor = 1000.0;
std::vector<std::tuple<double, double, TimelineType>> timeline;
std::mutex thumbnail_lock;
std::atomic<bool> abort_parse_qlog = false;
QMap<uint64_t, QPixmap> thumbnails; QMap<uint64_t, QPixmap> thumbnails;
std::map<uint64_t, AlertInfo> alerts; std::map<uint64_t, AlertInfo> alerts;
std::unique_ptr<QFuture<void>> qlog_future;
InfoLabel thumbnail_label; InfoLabel thumbnail_label;
}; };

@ -153,12 +153,10 @@ void Replay::buildTimeline() {
const auto &route_segments = route_->segments(); const auto &route_segments = route_->segments();
for (auto it = route_segments.cbegin(); it != route_segments.cend() && !exit_; ++it) { for (auto it = route_segments.cbegin(); it != route_segments.cend() && !exit_; ++it) {
LogReader log; std::shared_ptr<LogReader> log(new LogReader());
if (!log.load(it->second.qlog.toStdString(), &exit_, if (!log->load(it->second.qlog.toStdString(), &exit_, {}, !hasFlag(REPLAY_FLAG_NO_FILE_CACHE), 0, 3)) continue;
{cereal::Event::Which::CONTROLS_STATE, cereal::Event::Which::USER_FLAG},
!hasFlag(REPLAY_FLAG_NO_FILE_CACHE), 0, 3)) continue;
for (const Event *e : log.events) { for (const Event *e : log->events) {
if (e->which == cereal::Event::Which::CONTROLS_STATE) { if (e->which == cereal::Event::Which::CONTROLS_STATE) {
auto cs = e->event.getControlsState(); auto cs = e->event.getControlsState();
@ -186,6 +184,8 @@ void Replay::buildTimeline() {
timeline.push_back({toSeconds(e->mono_time), toSeconds(e->mono_time), TimelineType::UserFlag}); timeline.push_back({toSeconds(e->mono_time), toSeconds(e->mono_time), TimelineType::UserFlag});
} }
} }
std::sort(timeline.begin(), timeline.end(), [](auto &l, auto &r) { return std::get<2>(l) < std::get<2>(r); });
emit qLogLoaded(it->first, log);
} }
} }

@ -44,6 +44,7 @@ enum class FindFlag {
enum class TimelineType { None, Engaged, AlertInfo, AlertWarning, AlertCritical, UserFlag }; enum class TimelineType { None, Engaged, AlertInfo, AlertWarning, AlertCritical, UserFlag };
typedef bool (*replayEventFilter)(const Event *, void *); typedef bool (*replayEventFilter)(const Event *, void *);
Q_DECLARE_METATYPE(std::shared_ptr<LogReader>);
class Replay : public QObject { class Replay : public QObject {
Q_OBJECT Q_OBJECT
@ -91,6 +92,7 @@ signals:
void streamStarted(); void streamStarted();
void segmentsMerged(); void segmentsMerged();
void seekedTo(double sec); void seekedTo(double sec);
void qLogLoaded(int segnum, std::shared_ptr<LogReader> qlog);
protected slots: protected slots:
void segmentLoadFinished(bool success); void segmentLoadFinished(bool success);

Loading…
Cancel
Save