-
Notifications
You must be signed in to change notification settings - Fork 4
Bugfix: increase performances of filter function
#372
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #372 +/- ##
==========================================
+ Coverage 83.20% 83.22% +0.02%
==========================================
Files 52 52
Lines 5233 5240 +7
Branches 596 599 +3
==========================================
+ Hits 4354 4361 +7
Misses 867 867
Partials 12 12
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR attempts to improve the performance of the filter function in TrajectoryCollection by optimizing lambda captures, but introduces critical bugs in the loop iteration logic that break the filtering functionality.
Key Changes:
- Changed lambda captures from by-value to by-reference to reduce copying overhead
- Modified loop structure to use pre-increment in the condition check
- Split timestamp validation into separate cases for strictly decreasing (error) vs equal (warning)
Comments suppressed due to low confidence (3)
src/dsf/mdt/TrajectoryCollection.cpp:165
- The loop increment bug (where every other point is skipped) is not caught by existing tests. The tests only verify that the filter doesn't crash, not that it processes all points correctly. Consider adding a test that:
- Creates a trajectory with an even number of points where consecutive pairs alternate between passing and failing the max speed check
- Verifies that all expected violations are detected, not just half of them
This would catch the bug where ++i in the loop condition causes the loop to skip processing every other point.
for (std::size_t i = 0; i < nPoints;) {
auto const& currentCluster = points[i];
if (!check_min_duration(currentCluster)) {
to_split.insert(uid);
return;
}
if (++i < nPoints) {
auto const& nextCluster = points[i];
if (!check_max_speed(nextCluster, currentCluster)) {
to_split.insert(uid);
return;
}
}
src/dsf/mdt/TrajectoryCollection.cpp:165
- The loop increment logic is incorrect. The variable
iis incremented in the loop condition check (++i < nPoints), but the loop body also processespoints[i]after the increment. This causes the loop to skip every other point.
When the loop executes:
- Iteration 1:
i=0, processespoints[0]ascurrentCluster, increments toi=1, processespoints[1]asnextCluster - Iteration 2: Loop condition increments
ito 2, skipspoints[1]processing, processespoints[2]ascurrentCluster, etc.
The original code with i > 0 correctly checked the previous cluster without skipping points. If the intent is to check consecutive pairs, the increment should happen at the end of the loop body, not in the condition.
for (std::size_t i = 0; i < nPoints;) {
auto const& currentCluster = points[i];
if (!check_min_duration(currentCluster)) {
to_split.insert(uid);
return;
}
if (++i < nPoints) {
auto const& nextCluster = points[i];
if (!check_max_speed(nextCluster, currentCluster)) {
to_split.insert(uid);
return;
}
}
src/dsf/mdt/TrajectoryCollection.cpp:212
- The same loop increment bug exists here. The loop increments
iin the condition check (++i < nPoints), but then continues to processpoints[i]asnextCluster. This means:
- The loop skips every other point for processing
- After adding
currentClusterat index 0, incrementing to 1, and checking speed between points[1] and points[0], the next iteration jumps to index 2, never properly processing point 1 as acurrentCluster
This breaks the trajectory splitting logic and causes incorrect behavior.
for (std::size_t i = 0; i < nPoints;) {
auto const& currentCluster = points[i];
newTrajectory.addCluster(currentCluster);
bool bShouldSplit = false;
if (++i < nPoints) {
auto const& nextCluster = points[i];
bShouldSplit = !check_max_speed(nextCluster, currentCluster);
}
if (!bShouldSplit) {
bShouldSplit = !check_min_duration(currentCluster);
}
// If constraint violated (max speed or min duration) - finalize current trajectory and start a new one
if (bShouldSplit && !newTrajectory.empty()) {
if (newTrajectory.size() >= min_points_per_trajectory) {
trajectories.emplace_back(std::move(newTrajectory));
}
newTrajectory = Trajectory();
newTrajectory.addCluster(currentCluster);
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| "Timestamps are not in increasing order within the trajectory."); | ||
| } | ||
| if (current_time == previous_time) { | ||
| spdlog::debug( |
Copilot
AI
Nov 27, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] Changing the log level from warn to debug for equal timestamps reduces visibility of data quality issues. Non-increasing timestamps could indicate data quality problems that should be surfaced to users, not hidden in debug logs. Consider keeping this as a warning or making the log level configurable.
| spdlog::debug( | |
| spdlog::warn( |
| if (current_time < previous_time) { | ||
| // Should never happen if data is clean | ||
| throw std::runtime_error( | ||
| "Timestamps are not in increasing order within the trajectory."); |
Copilot
AI
Nov 27, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Throwing an exception for non-increasing timestamps in a parallel loop can cause resource leaks or incomplete cleanup. The tbb::parallel_for_each may have multiple threads processing trajectories, and an exception from one thread could leave the concurrent sets (to_remove, to_split) in an inconsistent state.
Consider either:
- Collecting problematic trajectory IDs to remove/handle after the parallel section
- Using
spdlog::error()and marking the trajectory for removal instead of throwing - Documenting that input data must be pre-validated for timestamp ordering
| auto check_max_speed = [](PointsCluster const& currentCluster, | ||
| PointsCluster const& previousCluster, | ||
| double const max_speed_kph) { | ||
| auto check_max_speed = [&max_speed_kph](PointsCluster const& currentCluster, |
Check notice
Code scanning / Cppcheck (reported by Codacy)
MISRA 12.3 rule Note
| PointsCluster const& previousCluster, | ||
| double const max_speed_kph) { | ||
| auto check_max_speed = [&max_speed_kph](PointsCluster const& currentCluster, | ||
| PointsCluster const& previousCluster) { |
Check notice
Code scanning / Cppcheck (reported by Codacy)
MISRA 13.1 rule Note
| auto check_min_duration = | ||
| [&min_duration_min](dsf::mdt::PointsCluster const& cluster) { | ||
| if (!min_duration_min.has_value()) { | ||
| return true; |
Check notice
Code scanning / Cppcheck (reported by Codacy)
MISRA 15.5 rule Note
| if (!min_duration_min.has_value()) { | ||
| return true; | ||
| } | ||
| return cluster.duration() < min_duration_min.value() * SECONDS_IN_MINUTE; |
Check notice
Code scanning / Cppcheck (reported by Codacy)
MISRA 15.5 rule Note
| &to_split, | ||
| check_max_speed, | ||
| check_min_duration, | ||
| &check_max_speed, |
Check notice
Code scanning / Cppcheck (reported by Codacy)
MISRA 12.3 rule Note
| check_max_speed, | ||
| check_min_duration, | ||
| &check_max_speed, | ||
| &check_min_duration, |
Check notice
Code scanning / Cppcheck (reported by Codacy)
MISRA 12.3 rule Note
41f37af to
0ce9542
Compare
No description provided.