Skip to content

Commit

Permalink
cabana: avoid dead locks and improve responsiveness (commaai#32740)
Browse files Browse the repository at this point in the history
avoid dead locks and improve responsive
  • Loading branch information
deanlee authored Jun 16, 2024
1 parent 02ed9c5 commit 865b98a
Show file tree
Hide file tree
Showing 16 changed files with 135 additions and 123 deletions.
2 changes: 1 addition & 1 deletion tools/cabana/chart/chart.cc
Original file line number Diff line number Diff line change
Expand Up @@ -513,7 +513,7 @@ void ChartView::mouseReleaseEvent(QMouseEvent *event) {
// no rubber dragged, seek to mouse position
can->seekTo(min);
} else if (rubber->width() > 10 && (max - min) > MIN_ZOOM_SECONDS) {
charts_widget->zoom_undo_stack->push(new ZoomCommand(charts_widget, {min, max}));
charts_widget->zoom_undo_stack->push(new ZoomCommand({min, max}));
} else {
viewport()->update();
}
Expand Down
24 changes: 11 additions & 13 deletions tools/cabana/chart/chartswidget.cc
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QFrame(parent) {
QObject::connect(dbc(), &DBCManager::DBCFileChanged, this, &ChartsWidget::removeAll);
QObject::connect(can, &AbstractStream::eventsMerged, this, &ChartsWidget::eventsMerged);
QObject::connect(can, &AbstractStream::msgsReceived, this, &ChartsWidget::updateState);
QObject::connect(can, &AbstractStream::seeking, this, &ChartsWidget::updateState);
QObject::connect(can, &AbstractStream::timeRangeChanged, this, &ChartsWidget::timeRangeChanged);
QObject::connect(range_slider, &QSlider::valueChanged, this, &ChartsWidget::setMaxChartRange);
QObject::connect(new_plot_btn, &QToolButton::clicked, this, &ChartsWidget::newChart);
QObject::connect(remove_all_btn, &QToolButton::clicked, this, &ChartsWidget::removeAll);
Expand Down Expand Up @@ -159,16 +161,13 @@ void ChartsWidget::eventsMerged(const MessageEventsMap &new_events) {
}
}

void ChartsWidget::setZoom(double min, double max) {
zoomed_range = {min, max};
is_zoomed = zoomed_range != display_range;
void ChartsWidget::timeRangeChanged(const std::optional<std::pair<double, double>> &time_range) {
updateToolBar();
updateState();
emit rangeChanged(min, max, is_zoomed);
}

void ChartsWidget::zoomReset() {
setZoom(display_range.first, display_range.second);
can->setTimeRange(std::nullopt);
zoom_undo_stack->clear();
}

Expand All @@ -186,22 +185,19 @@ void ChartsWidget::showValueTip(double sec) {
void ChartsWidget::updateState() {
if (charts.isEmpty()) return;

const auto &time_range = can->timeRange();
const double cur_sec = can->currentSec();
if (!is_zoomed) {
if (!time_range.has_value()) {
double pos = (cur_sec - display_range.first) / std::max<float>(1.0, max_chart_range);
if (pos < 0 || pos > 0.8) {
display_range.first = std::max(0.0, cur_sec - max_chart_range * 0.1);
}
double max_sec = std::min(display_range.first + max_chart_range, can->totalSeconds());
display_range.first = std::max(0.0, max_sec - max_chart_range);
display_range.second = display_range.first + max_chart_range;
} else if (cur_sec < (zoomed_range.first - 0.1) || cur_sec >= zoomed_range.second) {
// loop in zoomed range
QTimer::singleShot(0, [ts = zoomed_range.first]() { can->seekTo(ts);});
return;
}

const auto &range = is_zoomed ? zoomed_range : display_range;
const auto &range = time_range ? *time_range : display_range;
for (auto c : charts) {
c->updatePlot(cur_sec, range.first, range.second);
}
Expand All @@ -217,12 +213,14 @@ void ChartsWidget::updateToolBar() {
title_label->setText(tr("Charts: %1").arg(charts.size()));
columns_action->setText(tr("Column: %1").arg(column_count));
range_lb->setText(utils::formatSeconds(max_chart_range));

bool is_zoomed = can->timeRange().has_value();
range_lb_action->setVisible(!is_zoomed);
range_slider_action->setVisible(!is_zoomed);
undo_zoom_action->setVisible(is_zoomed);
redo_zoom_action->setVisible(is_zoomed);
reset_zoom_action->setVisible(is_zoomed);
reset_zoom_btn->setText(is_zoomed ? tr("%1-%2").arg(zoomed_range.first, 0, 'f', 2).arg(zoomed_range.second, 0, 'f', 2) : "");
reset_zoom_btn->setText(is_zoomed ? tr("%1-%2").arg(can->timeRange()->first, 0, 'f', 2).arg(can->timeRange()->second, 0, 'f', 2) : "");
remove_all_btn->setEnabled(!charts.isEmpty());
dock_btn->setIcon(docking ? "arrow-up-right-square" : "arrow-down-left-square");
dock_btn->setToolTip(docking ? tr("Undock charts") : tr("Dock charts"));
Expand Down Expand Up @@ -252,7 +250,7 @@ ChartView *ChartsWidget::findChart(const MessageId &id, const cabana::Signal *si
}

ChartView *ChartsWidget::createChart() {
auto chart = new ChartView(is_zoomed ? zoomed_range : display_range, this);
auto chart = new ChartView(can->timeRange().value_or(display_range), this);
chart->setFixedHeight(settings.chart_height);
chart->setMinimumWidth(CHART_MIN_WIDTH);
chart->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
Expand Down
16 changes: 6 additions & 10 deletions tools/cabana/chart/chartswidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,10 @@ class ChartsWidget : public QFrame {
public slots:
void setColumnCount(int n);
void removeAll();
void setZoom(double min, double max);
void timeRangeChanged(const std::optional<std::pair<double, double>> &time_range);

signals:
void dock(bool floating);
void rangeChanged(double min, double max, bool is_zommed);
void seriesChanged();

private:
Expand Down Expand Up @@ -102,9 +101,7 @@ public slots:
ChartsContainer *charts_container;
QScrollArea *charts_scroll;
uint32_t max_chart_range = 0;
bool is_zoomed = false;
std::pair<double, double> display_range;
std::pair<double, double> zoomed_range;
QAction *columns_action;
int column_count = 1;
int current_column_count = 0;
Expand All @@ -119,12 +116,11 @@ public slots:

class ZoomCommand : public QUndoCommand {
public:
ZoomCommand(ChartsWidget *charts, std::pair<double, double> range) : charts(charts), range(range), QUndoCommand() {
prev_range = charts->is_zoomed ? charts->zoomed_range : charts->display_range;
ZoomCommand(std::pair<double, double> range) : range(range), QUndoCommand() {
prev_range = can->timeRange();
setText(QObject::tr("Zoom to %1-%2").arg(range.first, 0, 'f', 2).arg(range.second, 0, 'f', 2));
}
void undo() override { charts->setZoom(prev_range.first, prev_range.second); }
void redo() override { charts->setZoom(range.first, range.second); }
ChartsWidget *charts;
std::pair<double, double> prev_range, range;
void undo() override { can->setTimeRange(prev_range); }
void redo() override { can->setTimeRange(range); }
std::optional<std::pair<double, double>> prev_range, range;
};
1 change: 0 additions & 1 deletion tools/cabana/mainwin.cc
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,6 @@ void MainWindow::createDockWidgets() {
video_splitter = new QSplitter(Qt::Vertical, this);
video_widget = new VideoWidget(this);
video_splitter->addWidget(video_widget);
QObject::connect(charts_widget, &ChartsWidget::rangeChanged, video_widget, &VideoWidget::updateTimeRange);

video_splitter->addWidget(charts_container);
video_splitter->setStretchFactor(1, 1);
Expand Down
22 changes: 20 additions & 2 deletions tools/cabana/streams/abstractstream.cc
Original file line number Diff line number Diff line change
Expand Up @@ -92,13 +92,23 @@ void AbstractStream::updateLastMessages() {
std::set<MessageId> msgs;
{
std::lock_guard lk(mutex_);
double max_sec = 0;
for (const auto &id : new_msgs_) {
const auto &can_data = messages_[id];
current_sec_ = std::max(current_sec_, can_data.ts);
max_sec = std::max(max_sec, can_data.ts);
last_msgs[id] = can_data;
sources.insert(id.source);
}
msgs = std::move(new_msgs_);

if (!new_msgs_.empty()) {
msgs = std::move(new_msgs_);
current_sec_ = max_sec;
}
}

if (time_range_ && (current_sec_ < time_range_->first || current_sec_ >= time_range_->second)) {
seekTo(time_range_->first);
return;
}

if (sources.size() != prev_src_size) {
Expand All @@ -108,6 +118,14 @@ void AbstractStream::updateLastMessages() {
emit msgsReceived(&msgs, prev_msg_size != last_msgs.size());
}

void AbstractStream::setTimeRange(const std::optional<std::pair<double, double>> &range) {
time_range_ = range;
if (time_range_ && (current_sec_ < time_range_->first || current_sec_ >= time_range_->second)) {
seekTo(time_range_->first);
}
emit timeRangeChanged(time_range_);
}

void AbstractStream::updateEvent(const MessageId &id, double sec, const uint8_t *data, uint8_t size) {
std::lock_guard lk(mutex_);
messages_[id].compute(id, data, size, sec, getSpeed(), masks_[id]);
Expand Down
8 changes: 7 additions & 1 deletion tools/cabana/streams/abstractstream.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
#include <array>
#include <memory>
#include <mutex>
#include <optional>
#include <set>
#include <unordered_map>
#include <utility>
#include <vector>

#include <QColor>
Expand Down Expand Up @@ -77,6 +79,8 @@ class AbstractStream : public QObject {
virtual double getSpeed() { return 1; }
virtual bool isPaused() const { return false; }
virtual void pause(bool pause) {}
void setTimeRange(const std::optional<std::pair<double, double>> &range);
const std::optional<std::pair<double, double>> &timeRange() const { return time_range_; }

inline const std::unordered_map<MessageId, CanData> &lastMessages() const { return last_msgs; }
inline const MessageEventsMap &eventsMap() const { return events_; }
Expand All @@ -91,8 +95,9 @@ class AbstractStream : public QObject {
signals:
void paused();
void resume();
void seekingTo(double sec);
void seeking(double sec);
void seekedTo(double sec);
void timeRangeChanged(const std::optional<std::pair<double, double>> &range);
void streamStarted();
void eventsMerged(const MessageEventsMap &events_map);
void msgsReceived(const std::set<MessageId> *new_msgs, bool has_new_ids);
Expand All @@ -110,6 +115,7 @@ class AbstractStream : public QObject {

std::vector<const CanEvent *> all_events_;
double current_sec_ = 0;
std::optional<std::pair<double, double>> time_range_;
uint64_t lastest_event_ts = 0;

private:
Expand Down
7 changes: 1 addition & 6 deletions tools/cabana/streams/replaystream.cc
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,9 @@ bool ReplayStream::loadRoute(const QString &route, const QString &data_dir, uint
{}, nullptr, replay_flags, data_dir, this));
replay->setSegmentCacheLimit(settings.max_cached_minutes);
replay->installEventFilter(event_filter, this);
QObject::connect(replay.get(), &Replay::seeking, this, &AbstractStream::seeking);
QObject::connect(replay.get(), &Replay::seekedTo, this, &AbstractStream::seekedTo);
QObject::connect(replay.get(), &Replay::segmentsMerged, this, &ReplayStream::mergeSegments);
QObject::connect(replay.get(), &Replay::qLogLoaded, this, &ReplayStream::qLogLoaded, Qt::QueuedConnection);
return replay->load();
}

Expand Down Expand Up @@ -92,12 +92,7 @@ bool ReplayStream::eventFilter(const Event *event) {
}

void ReplayStream::seekTo(double ts) {
// Update timestamp and notify receivers of the time change.
current_sec_ = ts;
std::set<MessageId> new_msgs;
msgsReceived(&new_msgs, false);

// Seek to the specified timestamp
replay->seekTo(std::max(double(0), ts), false);
}

Expand Down
3 changes: 0 additions & 3 deletions tools/cabana/streams/replaystream.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,6 @@ class ReplayStream : public AbstractStream {
void pause(bool pause) override;
static AbstractOpenStreamWidget *widget(AbstractStream **stream);

signals:
void qLogLoaded(int segnum, std::shared_ptr<LogReader> qlog);

private:
void mergeSegments();
std::unique_ptr<Replay> replay = nullptr;
Expand Down
23 changes: 11 additions & 12 deletions tools/cabana/videowidget.cc
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ VideoWidget::VideoWidget(QWidget *parent) : QFrame(parent) {
QObject::connect(can, &AbstractStream::paused, this, &VideoWidget::updatePlayBtnState);
QObject::connect(can, &AbstractStream::resume, this, &VideoWidget::updatePlayBtnState);
QObject::connect(can, &AbstractStream::msgsReceived, this, &VideoWidget::updateState);
QObject::connect(can, &AbstractStream::seeking, this, &VideoWidget::updateState);
QObject::connect(can, &AbstractStream::timeRangeChanged, this, &VideoWidget::timeRangeChanged);

updatePlayBtnState();
setWhatsThis(tr(R"(
Expand Down Expand Up @@ -150,14 +152,16 @@ QWidget *VideoWidget::createCameraWidget() {

setMaximumTime(can->totalSeconds());
QObject::connect(slider, &QSlider::sliderReleased, [this]() { can->seekTo(slider->currentSecond()); });
QObject::connect(slider, &Slider::updateMaximumTime, this, &VideoWidget::setMaximumTime, Qt::QueuedConnection);
QObject::connect(can, &AbstractStream::eventsMerged, this, [this]() { slider->update(); });
QObject::connect(static_cast<ReplayStream*>(can), &ReplayStream::qLogLoaded, slider, &Slider::parseQLog);
QObject::connect(cam_widget, &CameraWidget::clicked, []() { can->pause(!can->isPaused()); });
QObject::connect(cam_widget, &CameraWidget::vipcAvailableStreamsUpdated, this, &VideoWidget::vipcAvailableStreamsUpdated);
QObject::connect(camera_tab, &QTabBar::currentChanged, [this](int index) {
if (index != -1) cam_widget->setStreamType((VisionStreamType)camera_tab->tabData(index).toInt());
});

auto replay = static_cast<ReplayStream*>(can)->getReplay();
QObject::connect(replay, &Replay::qLogLoaded, slider, &Slider::parseQLog, Qt::QueuedConnection);
QObject::connect(replay, &Replay::totalSecondsUpdated, this, &VideoWidget::setMaximumTime, Qt::QueuedConnection);
return w;
}

Expand Down Expand Up @@ -198,13 +202,13 @@ void VideoWidget::setMaximumTime(double sec) {
slider->setTimeRange(0, sec);
}

void VideoWidget::updateTimeRange(double min, double max, bool is_zoomed) {
void VideoWidget::timeRangeChanged(const std::optional<std::pair<double, double>> &time_range) {
if (can->liveStreaming()) {
skip_to_end_btn->setEnabled(!is_zoomed);
skip_to_end_btn->setEnabled(!time_range.has_value());
return;
}
is_zoomed ? slider->setTimeRange(min, max)
: slider->setTimeRange(0, maximum_time);
time_range ? slider->setTimeRange(time_range->first, time_range->second)
: slider->setTimeRange(0, maximum_time);
}

QString VideoWidget::formatTime(double sec, bool include_milliseconds) {
Expand Down Expand Up @@ -255,12 +259,7 @@ void Slider::setTimeRange(double min, double max) {
setRange(min * factor, max * factor);
}

void Slider::parseQLog(int segnum, std::shared_ptr<LogReader> qlog) {
const auto &segments = qobject_cast<ReplayStream *>(can)->route()->segments();
if (segments.size() > 0 && segnum == segments.rbegin()->first && !qlog->events.empty()) {
emit updateMaximumTime(qlog->events.back().mono_time / 1e9 - can->routeStartTime());
}

void Slider::parseQLog(std::shared_ptr<LogReader> qlog) {
std::mutex mutex;
QtConcurrent::blockingMap(qlog->events.cbegin(), qlog->events.cend(), [&mutex, this](const Event &e) {
if (e.which == cereal::Event::Which::THUMBNAIL) {
Expand Down
8 changes: 3 additions & 5 deletions tools/cabana/videowidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <map>
#include <memory>
#include <set>
#include <utility>

#include <QHBoxLayout>
#include <QFrame>
Expand Down Expand Up @@ -40,13 +41,10 @@ class Slider : public QSlider {
void setTimeRange(double min, double max);
AlertInfo alertInfo(double sec);
QPixmap thumbnail(double sec);
void parseQLog(int segnum, std::shared_ptr<LogReader> qlog);
void parseQLog(std::shared_ptr<LogReader> qlog);

const double factor = 1000.0;

signals:
void updateMaximumTime(double);

private:
void mousePressEvent(QMouseEvent *e) override;
void mouseMoveEvent(QMouseEvent *e) override;
Expand All @@ -63,11 +61,11 @@ class VideoWidget : public QFrame {

public:
VideoWidget(QWidget *parnet = nullptr);
void updateTimeRange(double min, double max, bool is_zommed);
void setMaximumTime(double sec);

protected:
QString formatTime(double sec, bool include_milliseconds = false);
void timeRangeChanged(const std::optional<std::pair<double, double>> &time_range);
void updateState();
void updatePlayBtnState();
QWidget *createCameraWidget();
Expand Down
1 change: 0 additions & 1 deletion tools/replay/camera.cc
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ void CameraServer::cameraThread(Camera &cam) {
capnp::FlatArrayMessageReader reader(event->data);
auto evt = reader.getRoot<cereal::Event>();
auto eidx = capnp::AnyStruct::Reader(evt).getPointerSection()[0].getAs<cereal::EncodeIndex>();
if (eidx.getType() != cereal::EncodeIndex::Type::FULL_H_E_V_C) continue;

int segment_id = eidx.getSegmentId();
uint32_t frame_id = eidx.getFrameId();
Expand Down
6 changes: 3 additions & 3 deletions tools/replay/logreader.cc
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,10 @@ bool LogReader::load(const char *data, size_t size, std::atomic<bool> *abort) {
evt.which == cereal::Event::DRIVER_ENCODE_IDX ||
evt.which == cereal::Event::WIDE_ROAD_ENCODE_IDX) {
auto idx = capnp::AnyStruct::Reader(event).getPointerSection()[0].getAs<cereal::EncodeIndex>();
if (uint64_t sof = idx.getTimestampSof()) {
mono_time = sof;
if (idx.getType() == cereal::EncodeIndex::Type::FULL_H_E_V_C) {
uint64_t sof = idx.getTimestampSof();
events.emplace_back(which, sof ? sof : mono_time, event_data, idx.getSegmentNum());
}
events.emplace_back(which, mono_time, event_data, idx.getSegmentNum());
}
}
} catch (const kj::Exception &e) {
Expand Down
Loading

0 comments on commit 865b98a

Please sign in to comment.