Determine the trajectory that is blocking progress. (#154)
When processing offline data determining which trajectory needs more data before processing can continue is surprisingly tricky. We thus expose this information at the map builder to avoid duplicating this logic.master
parent
ead4d03b16
commit
db45c4ef78
|
@ -108,6 +108,10 @@ void MapBuilder::FinishTrajectory(const int trajectory_id) {
|
||||||
sensor_collator_.FinishTrajectory(trajectory_id);
|
sensor_collator_.FinishTrajectory(trajectory_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int MapBuilder::GetBlockingTrajectoryId() const {
|
||||||
|
return sensor_collator_.GetBlockingTrajectoryId();
|
||||||
|
}
|
||||||
|
|
||||||
int MapBuilder::GetTrajectoryId(const Submaps* const trajectory) const {
|
int MapBuilder::GetTrajectoryId(const Submaps* const trajectory) const {
|
||||||
const auto trajectory_id = trajectory_ids_.find(trajectory);
|
const auto trajectory_id = trajectory_ids_.find(trajectory);
|
||||||
CHECK(trajectory_id != trajectory_ids_.end());
|
CHECK(trajectory_id != trajectory_ids_.end());
|
||||||
|
|
|
@ -67,6 +67,11 @@ class MapBuilder {
|
||||||
// i.e. no further sensor data is expected.
|
// i.e. no further sensor data is expected.
|
||||||
void FinishTrajectory(int trajectory_id);
|
void FinishTrajectory(int trajectory_id);
|
||||||
|
|
||||||
|
// Must only be called if at least one unfinished trajectory exists. Returns
|
||||||
|
// the ID of the trajectory that needs more data before the MapBuilder is
|
||||||
|
// unblocked.
|
||||||
|
int GetBlockingTrajectoryId() const;
|
||||||
|
|
||||||
// Returns the trajectory ID for 'trajectory'.
|
// Returns the trajectory ID for 'trajectory'.
|
||||||
int GetTrajectoryId(const mapping::Submaps* trajectory) const;
|
int GetTrajectoryId(const mapping::Submaps* trajectory) const;
|
||||||
|
|
||||||
|
|
|
@ -46,5 +46,9 @@ void Collator::AddSensorData(const int trajectory_id, const string& sensor_id,
|
||||||
|
|
||||||
void Collator::Flush() { queue_.Flush(); }
|
void Collator::Flush() { queue_.Flush(); }
|
||||||
|
|
||||||
|
int Collator::GetBlockingTrajectoryId() const {
|
||||||
|
return queue_.GetBlocker().trajectory_id;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace sensor
|
} // namespace sensor
|
||||||
} // namespace cartographer
|
} // namespace cartographer
|
||||||
|
|
|
@ -57,6 +57,11 @@ class Collator {
|
||||||
// AddSensorData may not be called after Flush.
|
// AddSensorData may not be called after Flush.
|
||||||
void Flush();
|
void Flush();
|
||||||
|
|
||||||
|
// Must only be called if at least one unfinished trajectory exists. Returns
|
||||||
|
// the ID of the trajectory that needs more data before the Collator is
|
||||||
|
// unblocked.
|
||||||
|
int GetBlockingTrajectoryId() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Queue keys are a pair of trajectory ID and sensor identifier.
|
// Queue keys are a pair of trajectory ID and sensor identifier.
|
||||||
OrderedMultiQueue queue_;
|
OrderedMultiQueue queue_;
|
||||||
|
|
|
@ -32,12 +32,12 @@ namespace {
|
||||||
// for data.
|
// for data.
|
||||||
const int kMaxQueueSize = 500;
|
const int kMaxQueueSize = 500;
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
inline std::ostream& operator<<(std::ostream& out, const QueueKey& key) {
|
inline std::ostream& operator<<(std::ostream& out, const QueueKey& key) {
|
||||||
return out << '(' << key.trajectory_id << ", " << key.sensor_id << ')';
|
return out << '(' << key.trajectory_id << ", " << key.sensor_id << ')';
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
OrderedMultiQueue::OrderedMultiQueue() {}
|
OrderedMultiQueue::OrderedMultiQueue() {}
|
||||||
|
|
||||||
OrderedMultiQueue::~OrderedMultiQueue() {
|
OrderedMultiQueue::~OrderedMultiQueue() {
|
||||||
|
@ -84,11 +84,16 @@ void OrderedMultiQueue::Flush() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QueueKey OrderedMultiQueue::GetBlocker() const {
|
||||||
|
CHECK(!queues_.empty());
|
||||||
|
return blocker_;
|
||||||
|
}
|
||||||
|
|
||||||
void OrderedMultiQueue::Dispatch() {
|
void OrderedMultiQueue::Dispatch() {
|
||||||
while (true) {
|
while (true) {
|
||||||
Queue* next_queue = nullptr;
|
|
||||||
const Data* next_data = nullptr;
|
const Data* next_data = nullptr;
|
||||||
int next_trajectory_id = -1;
|
Queue* next_queue = nullptr;
|
||||||
|
QueueKey next_queue_key;
|
||||||
for (auto it = queues_.begin(); it != queues_.end();) {
|
for (auto it = queues_.begin(); it != queues_.end();) {
|
||||||
const auto* data = it->second.queue.Peek<Data>();
|
const auto* data = it->second.queue.Peek<Data>();
|
||||||
if (data == nullptr) {
|
if (data == nullptr) {
|
||||||
|
@ -96,13 +101,13 @@ void OrderedMultiQueue::Dispatch() {
|
||||||
queues_.erase(it++);
|
queues_.erase(it++);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
CannotMakeProgress();
|
CannotMakeProgress(it->first);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (next_data == nullptr || data->time < next_data->time) {
|
if (next_data == nullptr || data->time < next_data->time) {
|
||||||
next_data = data;
|
next_data = data;
|
||||||
next_queue = &it->second;
|
next_queue = &it->second;
|
||||||
next_trajectory_id = it->first.trajectory_id;
|
next_queue_key = it->first;
|
||||||
}
|
}
|
||||||
CHECK_LE(last_dispatched_time_, next_data->time)
|
CHECK_LE(last_dispatched_time_, next_data->time)
|
||||||
<< "Non-sorted data added to queue: '" << it->first << "'";
|
<< "Non-sorted data added to queue: '" << it->first << "'";
|
||||||
|
@ -116,7 +121,7 @@ void OrderedMultiQueue::Dispatch() {
|
||||||
// If we haven't dispatched any data for this trajectory yet, fast forward
|
// If we haven't dispatched any data for this trajectory yet, fast forward
|
||||||
// all queues of this trajectory until a common start time has been reached.
|
// all queues of this trajectory until a common start time has been reached.
|
||||||
const common::Time common_start_time =
|
const common::Time common_start_time =
|
||||||
GetCommonStartTime(next_trajectory_id);
|
GetCommonStartTime(next_queue_key.trajectory_id);
|
||||||
|
|
||||||
if (next_data->time >= common_start_time) {
|
if (next_data->time >= common_start_time) {
|
||||||
// Happy case, we are beyond the 'common_start_time' already.
|
// Happy case, we are beyond the 'common_start_time' already.
|
||||||
|
@ -125,6 +130,7 @@ void OrderedMultiQueue::Dispatch() {
|
||||||
} else if (next_queue->queue.Size() < 2) {
|
} else if (next_queue->queue.Size() < 2) {
|
||||||
if (!next_queue->finished) {
|
if (!next_queue->finished) {
|
||||||
// We cannot decide whether to drop or dispatch this yet.
|
// We cannot decide whether to drop or dispatch this yet.
|
||||||
|
CannotMakeProgress(next_queue_key);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
last_dispatched_time_ = next_data->time;
|
last_dispatched_time_ = next_data->time;
|
||||||
|
@ -142,26 +148,16 @@ void OrderedMultiQueue::Dispatch() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OrderedMultiQueue::CannotMakeProgress() {
|
void OrderedMultiQueue::CannotMakeProgress(const QueueKey& queue_key) {
|
||||||
|
blocker_ = queue_key;
|
||||||
for (auto& entry : queues_) {
|
for (auto& entry : queues_) {
|
||||||
if (entry.second.queue.Size() > kMaxQueueSize) {
|
if (entry.second.queue.Size() > kMaxQueueSize) {
|
||||||
LOG_EVERY_N(WARNING, 60) << "Queues waiting for data: "
|
LOG_EVERY_N(WARNING, 60) << "Queue waiting for data: " << queue_key;
|
||||||
<< EmptyQueuesDebugString();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
string OrderedMultiQueue::EmptyQueuesDebugString() {
|
|
||||||
std::ostringstream empty_queues;
|
|
||||||
for (auto& entry : queues_) {
|
|
||||||
if (entry.second.queue.Size() == 0) {
|
|
||||||
empty_queues << (empty_queues.tellp() > 0 ? ", " : "") << entry.first;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return empty_queues.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
common::Time OrderedMultiQueue::GetCommonStartTime(const int trajectory_id) {
|
common::Time OrderedMultiQueue::GetCommonStartTime(const int trajectory_id) {
|
||||||
auto emplace_result = common_start_time_per_trajectory_.emplace(
|
auto emplace_result = common_start_time_per_trajectory_.emplace(
|
||||||
trajectory_id, common::Time::min());
|
trajectory_id, common::Time::min());
|
||||||
|
|
|
@ -69,6 +69,11 @@ class OrderedMultiQueue {
|
||||||
// queues.
|
// queues.
|
||||||
void Flush();
|
void Flush();
|
||||||
|
|
||||||
|
// Must only be called if at least one unfinished queue exists. Returns the
|
||||||
|
// key of a queue that needs more data before the OrderedMultiQueue can
|
||||||
|
// dispatch data.
|
||||||
|
QueueKey GetBlocker() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Queue {
|
struct Queue {
|
||||||
common::BlockingQueue<std::unique_ptr<Data>> queue;
|
common::BlockingQueue<std::unique_ptr<Data>> queue;
|
||||||
|
@ -77,8 +82,7 @@ class OrderedMultiQueue {
|
||||||
};
|
};
|
||||||
|
|
||||||
void Dispatch();
|
void Dispatch();
|
||||||
void CannotMakeProgress();
|
void CannotMakeProgress(const QueueKey& queue_key);
|
||||||
string EmptyQueuesDebugString();
|
|
||||||
common::Time GetCommonStartTime(int trajectory_id);
|
common::Time GetCommonStartTime(int trajectory_id);
|
||||||
|
|
||||||
// Used to verify that values are dispatched in sorted order.
|
// Used to verify that values are dispatched in sorted order.
|
||||||
|
@ -86,6 +90,7 @@ class OrderedMultiQueue {
|
||||||
|
|
||||||
std::map<int, common::Time> common_start_time_per_trajectory_;
|
std::map<int, common::Time> common_start_time_per_trajectory_;
|
||||||
std::map<QueueKey, Queue> queues_;
|
std::map<QueueKey, Queue> queues_;
|
||||||
|
QueueKey blocker_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace sensor
|
} // namespace sensor
|
||||||
|
|
Loading…
Reference in New Issue