Update the constraints to enforce the worst case slew
When we have a period with no observations in a log file, we used to
assume that time slewed at a rate that connected the observations with a
line. For long enough periods of time, this ends up being pretty wrong.
We need to actually enforce what our guarentees are. That the solution
is bounded by the worst case slew, which is a V connecting the two
samples using the max slew rate as the slope. Anything crossing that V
is wrong by construction, and anything inside it is actually valid,
though it might be a bit weird.
Change-Id: I6ee1476ae7c218a15239e818393c7df43d8ba2dc
Signed-off-by: Austin Schuh <austin.linux@gmail.com>
diff --git a/aos/events/logging/boot_timestamp.h b/aos/events/logging/boot_timestamp.h
index e818fb9..0d68045 100644
--- a/aos/events/logging/boot_timestamp.h
+++ b/aos/events/logging/boot_timestamp.h
@@ -90,6 +90,11 @@
BootTimestamp operator+(monotonic_clock::duration d) const {
return {boot, time + d};
}
+
+ BootTimestamp operator+=(monotonic_clock::duration d) {
+ time += d;
+ return *this;
+ }
BootTimestamp operator-(monotonic_clock::duration d) const {
return {boot, time - d};
}
diff --git a/aos/network/timestamp_filter.cc b/aos/network/timestamp_filter.cc
index 336987c..4d6946d 100644
--- a/aos/network/timestamp_filter.cc
+++ b/aos/network/timestamp_filter.cc
@@ -491,15 +491,16 @@
std::pair<Pointer, std::pair<std::tuple<BootTimestamp, BootDuration>,
std::tuple<BootTimestamp, BootDuration>>>
NoncausalTimestampFilter::FindTimestamps(const NoncausalTimestampFilter *other,
- Pointer pointer, BootTimestamp ta_base,
- double ta, size_t sample_boot) const {
+ bool use_other, Pointer pointer,
+ BootTimestamp ta_base, double ta,
+ size_t sample_boot) const {
CHECK_GE(ta, 0.0);
CHECK_LT(ta, 1.0);
// Since ta is less than an integer, and timestamps should be at least 1 ns
// apart, we can ignore ta if we make sure that the end of the segment is
// strictly > than ta_base.
- return FindTimestamps(other, pointer, ta_base, sample_boot);
+ return FindTimestamps(other, use_other, pointer, ta_base, sample_boot);
}
std::pair<
@@ -507,7 +508,7 @@
std::pair<std::tuple<monotonic_clock::time_point, chrono::nanoseconds>,
std::tuple<monotonic_clock::time_point, chrono::nanoseconds>>>
NoncausalTimestampFilter::SingleFilter::FindTimestamps(
- const SingleFilter *other, Pointer pointer,
+ const SingleFilter *other, bool use_other, Pointer pointer,
monotonic_clock::time_point ta_base, double ta) const {
CHECK_GE(ta, 0.0);
CHECK_LT(ta, 1.0);
@@ -515,7 +516,7 @@
// Since ta is less than an integer, and timestamps should be at least 1 ns
// apart, we can ignore ta if we make sure that the end of the segment is
// strictly > than ta_base.
- return FindTimestamps(other, pointer, ta_base);
+ return FindTimestamps(other, use_other, pointer, ta_base);
}
std::pair<
@@ -523,9 +524,12 @@
std::pair<std::tuple<monotonic_clock::time_point, chrono::nanoseconds>,
std::tuple<monotonic_clock::time_point, chrono::nanoseconds>>>
NoncausalTimestampFilter::InterpolateWithOtherFilter(
- Pointer pointer, monotonic_clock::time_point ta,
+ Pointer pointer, bool use_other, monotonic_clock::time_point ta,
std::tuple<monotonic_clock::time_point, chrono::nanoseconds> t0,
std::tuple<monotonic_clock::time_point, chrono::nanoseconds> t1) {
+ if (!use_other) {
+ return std::make_pair(pointer, std::make_pair(t0, t1));
+ }
// We have 2 timestamps bookending everything, and a list of points in the
// middle.
//
@@ -576,7 +580,7 @@
std::pair<std::tuple<monotonic_clock::time_point, chrono::nanoseconds>,
std::tuple<monotonic_clock::time_point, chrono::nanoseconds>>>
NoncausalTimestampFilter::SingleFilter::FindTimestamps(
- const SingleFilter *other, Pointer pointer,
+ const SingleFilter *other, bool use_other, Pointer pointer,
monotonic_clock::time_point ta) const {
CHECK_GT(timestamps_size(), 1u);
@@ -638,7 +642,7 @@
<< ": Cache changed";
}
- return InterpolateWithOtherFilter(pointer, ta, t0, t1);
+ return InterpolateWithOtherFilter(pointer, use_other, ta, t0, t1);
}
}
}
@@ -707,7 +711,7 @@
}
if (pointer.other_points_.size() > 0) {
- return InterpolateWithOtherFilter(pointer, ta, t0, t1);
+ return InterpolateWithOtherFilter(pointer, use_other, ta, t0, t1);
}
}
}
@@ -936,7 +940,7 @@
Pointer,
std::pair<std::tuple<monotonic_clock::time_point, chrono::nanoseconds>,
std::tuple<monotonic_clock::time_point, chrono::nanoseconds>>>
- points = FindTimestamps(other, pointer, ta);
+ points = FindTimestamps(other, true, pointer, ta);
return std::make_pair(points.first,
NoncausalTimestampFilter::InterpolateOffset(
points.second.first, points.second.second, ta));
@@ -962,7 +966,7 @@
Pointer,
std::pair<std::tuple<monotonic_clock::time_point, chrono::nanoseconds>,
std::tuple<monotonic_clock::time_point, chrono::nanoseconds>>>
- points = FindTimestamps(other, pointer, ta_base, ta);
+ points = FindTimestamps(other, true, pointer, ta_base, ta);
CHECK_LT(std::get<0>(points.second.first), std::get<0>(points.second.second));
// Return both the integer and double portion together to save a timestamp
// lookup.
@@ -1026,7 +1030,7 @@
other == nullptr
? nullptr
: &other->filter(tb_base.boot, ta_base.boot)->filter,
- pointer, ta_base.time, ta)
+ true, pointer, ta_base.time, ta)
.second;
// As a reminder, our cost function is essentially:
@@ -1098,13 +1102,18 @@
return true;
}
+ // Honestly, here, we care about confirming that the worst case holds. This
+ // means that each solution is plausible based on the points that we have. The
+ // only thing we actually know is that time will slew by at most the max slew
+ // rate, so the candidate solution must be within the max slew rate from the
+ // samples.
std::pair<
Pointer,
std::pair<std::tuple<monotonic_clock::time_point, chrono::nanoseconds>,
std::tuple<monotonic_clock::time_point, chrono::nanoseconds>>>
- points = FindTimestamps(other, pointer, ta_base, ta);
+ points = FindTimestamps(other, false, pointer, ta_base, ta);
const std::pair<chrono::nanoseconds, double> offset =
- NoncausalTimestampFilter::InterpolateOffset(
+ NoncausalTimestampFilter::BoundOffset(
points.second.first, points.second.second, ta_base, ta);
// See below for why this is a >=
if (static_cast<double>((offset.first + ta_base - tb_base).count()) >=
@@ -1129,12 +1138,13 @@
<< ") is before the start and we have forgotten the answer.";
return false;
}
+
+ // The logic here mirrors the double variant above almost perfectly. See
+ // above for the comments.
+
if (IsOutsideSamples(ta, 0.)) {
- // Special case size = 1 or ta_base before first timestamp or
- // after last timestamp, so we need to extrapolate out
auto reference_timestamp = GetReferenceTimestamp(ta, 0.);
- // Special case size = 1 or ta before first timestamp, so we extrapolate
const chrono::nanoseconds offset =
NoncausalTimestampFilter::ExtrapolateOffset(reference_timestamp.second,
ta);
@@ -1153,10 +1163,9 @@
Pointer,
std::pair<std::tuple<monotonic_clock::time_point, chrono::nanoseconds>,
std::tuple<monotonic_clock::time_point, chrono::nanoseconds>>>
- points = FindTimestamps(other, pointer, ta);
- const chrono::nanoseconds offset =
- NoncausalTimestampFilter::InterpolateOffset(points.second.first,
- points.second.second, ta);
+ points = FindTimestamps(other, false, pointer, ta);
+ const chrono::nanoseconds offset = NoncausalTimestampFilter::BoundOffset(
+ points.second.first, points.second.second, ta);
// Note: this needs to be >=. The simulation code doesn't give us a good
// way to preserve order well enough to have causality preserved when things
diff --git a/aos/network/timestamp_filter.h b/aos/network/timestamp_filter.h
index 72ffb4f..1367f4c 100644
--- a/aos/network/timestamp_filter.h
+++ b/aos/network/timestamp_filter.h
@@ -535,8 +535,9 @@
std::pair<Pointer,
std::pair<std::tuple<logger::BootTimestamp, logger::BootDuration>,
std::tuple<logger::BootTimestamp, logger::BootDuration>>>
- FindTimestamps(const NoncausalTimestampFilter *other, Pointer pointer,
- logger::BootTimestamp ta, size_t sample_boot) const {
+ FindTimestamps(const NoncausalTimestampFilter *other, bool use_other,
+ Pointer pointer, logger::BootTimestamp ta,
+ size_t sample_boot) const {
const BootFilter *boot_filter = filter(ta.boot, sample_boot);
std::pair<
Pointer,
@@ -546,7 +547,7 @@
result = boot_filter->filter.FindTimestamps(
other == nullptr ? nullptr
: &other->filter(sample_boot, ta.boot)->filter,
- pointer, ta.time);
+ use_other, pointer, ta.time);
result.first.boot_filter_ = boot_filter;
return std::make_pair(
result.first,
@@ -565,8 +566,8 @@
std::pair<Pointer,
std::pair<std::tuple<logger::BootTimestamp, logger::BootDuration>,
std::tuple<logger::BootTimestamp, logger::BootDuration>>>
- FindTimestamps(const NoncausalTimestampFilter *other, Pointer pointer,
- logger::BootTimestamp ta_base, double ta,
+ FindTimestamps(const NoncausalTimestampFilter *other, bool use_other,
+ Pointer pointer, logger::BootTimestamp ta_base, double ta,
size_t sample_boot) const;
static std::chrono::nanoseconds InterpolateOffset(
@@ -628,14 +629,14 @@
std::pair<
std::tuple<monotonic_clock::time_point, std::chrono::nanoseconds>,
std::tuple<monotonic_clock::time_point, std::chrono::nanoseconds>>>
- FindTimestamps(const SingleFilter *other, Pointer pointer,
+ FindTimestamps(const SingleFilter *other, bool use_other, Pointer pointer,
monotonic_clock::time_point ta) const;
std::pair<
Pointer,
std::pair<
std::tuple<monotonic_clock::time_point, std::chrono::nanoseconds>,
std::tuple<monotonic_clock::time_point, std::chrono::nanoseconds>>>
- FindTimestamps(const SingleFilter *other, Pointer pointer,
+ FindTimestamps(const SingleFilter *other, bool use_other, Pointer pointer,
monotonic_clock::time_point ta_base, double ta) const;
// Check whether the given timestamp falls within our current samples
@@ -873,7 +874,7 @@
std::tuple<monotonic_clock::time_point, std::chrono::nanoseconds>,
std::tuple<monotonic_clock::time_point, std::chrono::nanoseconds>>>
InterpolateWithOtherFilter(
- Pointer pointer, monotonic_clock::time_point ta,
+ Pointer pointer, bool use_other, monotonic_clock::time_point ta,
std::tuple<monotonic_clock::time_point, std::chrono::nanoseconds> t0,
std::tuple<monotonic_clock::time_point, std::chrono::nanoseconds> t1);
diff --git a/aos/network/timestamp_filter_test.cc b/aos/network/timestamp_filter_test.cc
index b354d0e..4aa5377 100644
--- a/aos/network/timestamp_filter_test.cc
+++ b/aos/network/timestamp_filter_test.cc
@@ -1093,122 +1093,122 @@
filter.Sample(t2, o2);
filter.Sample(t3, o3);
- result = filter.FindTimestamps(nullptr, Pointer(),
+ result = filter.FindTimestamps(nullptr, true, Pointer(),
e - chrono::microseconds(10), 0);
EXPECT_THAT(result.second,
::testing::Pair(::testing::Eq(std::make_tuple(t1, o1)),
::testing::Eq(std::make_tuple(t2, o2))));
- EXPECT_EQ(result, filter.FindTimestamps(nullptr, result.first,
+ EXPECT_EQ(result, filter.FindTimestamps(nullptr, true, result.first,
e - chrono::microseconds(10), 0));
- result = filter.FindTimestamps(nullptr, Pointer(),
+ result = filter.FindTimestamps(nullptr, true, Pointer(),
e - chrono::microseconds(10), 0.9, 0);
EXPECT_THAT(result.second,
::testing::Pair(::testing::Eq(std::make_tuple(t1, o1)),
::testing::Eq(std::make_tuple(t2, o2))));
EXPECT_EQ(result,
- filter.FindTimestamps(nullptr, result.first,
+ filter.FindTimestamps(nullptr, true, result.first,
e - chrono::microseconds(10), 0.9, 0));
result =
- filter.FindTimestamps(nullptr, Pointer(), e + chrono::microseconds(0), 0);
+ filter.FindTimestamps(nullptr, true, Pointer(), e + chrono::microseconds(0), 0);
EXPECT_THAT(result.second,
::testing::Pair(::testing::Eq(std::make_tuple(t1, o1)),
::testing::Eq(std::make_tuple(t2, o2))));
- EXPECT_EQ(result, filter.FindTimestamps(nullptr, result.first,
+ EXPECT_EQ(result, filter.FindTimestamps(nullptr, true, result.first,
e + chrono::microseconds(0), 0));
- result = filter.FindTimestamps(nullptr, Pointer(),
+ result = filter.FindTimestamps(nullptr, true, Pointer(),
e + chrono::microseconds(0), 0.8, 0);
EXPECT_THAT(result.second,
::testing::Pair(::testing::Eq(std::make_tuple(t1, o1)),
::testing::Eq(std::make_tuple(t2, o2))));
- EXPECT_EQ(result, filter.FindTimestamps(nullptr, result.first,
+ EXPECT_EQ(result, filter.FindTimestamps(nullptr, true, result.first,
e + chrono::microseconds(0), 0.8, 0));
- result = filter.FindTimestamps(nullptr, Pointer(),
+ result = filter.FindTimestamps(nullptr, true, Pointer(),
e + chrono::microseconds(100), 0);
EXPECT_THAT(result.second,
::testing::Pair(::testing::Eq(std::make_tuple(t1, o1)),
::testing::Eq(std::make_tuple(t2, o2))));
- EXPECT_EQ(result, filter.FindTimestamps(nullptr, result.first,
+ EXPECT_EQ(result, filter.FindTimestamps(nullptr, true, result.first,
e + chrono::microseconds(100), 0));
- result = filter.FindTimestamps(nullptr, Pointer(),
+ result = filter.FindTimestamps(nullptr, true, Pointer(),
e + chrono::microseconds(100), 0.7, 0);
EXPECT_THAT(result.second,
::testing::Pair(::testing::Eq(std::make_tuple(t1, o1)),
::testing::Eq(std::make_tuple(t2, o2))));
EXPECT_EQ(result,
- filter.FindTimestamps(nullptr, result.first,
+ filter.FindTimestamps(nullptr, true, result.first,
e + chrono::microseconds(100), 0.7, 0));
- result = filter.FindTimestamps(nullptr, Pointer(),
+ result = filter.FindTimestamps(nullptr, true, Pointer(),
e + chrono::microseconds(1000), 0);
EXPECT_THAT(result.second,
::testing::Pair(::testing::Eq(std::make_tuple(t2, o2)),
::testing::Eq(std::make_tuple(t3, o3))));
- EXPECT_EQ(result, filter.FindTimestamps(nullptr, result.first,
+ EXPECT_EQ(result, filter.FindTimestamps(nullptr, true, result.first,
e + chrono::microseconds(1000), 0));
- result = filter.FindTimestamps(nullptr, Pointer(),
+ result = filter.FindTimestamps(nullptr, true, Pointer(),
e + chrono::microseconds(1000), 0.0, 0);
EXPECT_THAT(result.second,
::testing::Pair(::testing::Eq(std::make_tuple(t2, o2)),
::testing::Eq(std::make_tuple(t3, o3))));
EXPECT_EQ(result,
- filter.FindTimestamps(nullptr, result.first,
+ filter.FindTimestamps(nullptr, true, result.first,
e + chrono::microseconds(1000), 0.0, 0));
- result = filter.FindTimestamps(nullptr, Pointer(),
+ result = filter.FindTimestamps(nullptr, true, Pointer(),
e + chrono::microseconds(1500), 0);
EXPECT_THAT(result.second,
::testing::Pair(::testing::Eq(std::make_tuple(t2, o2)),
::testing::Eq(std::make_tuple(t3, o3))));
- EXPECT_EQ(result, filter.FindTimestamps(nullptr, result.first,
+ EXPECT_EQ(result, filter.FindTimestamps(nullptr, true, result.first,
e + chrono::microseconds(1500), 0));
- result = filter.FindTimestamps(nullptr, Pointer(),
+ result = filter.FindTimestamps(nullptr, true, Pointer(),
e + chrono::microseconds(1500), 0.0, 0);
EXPECT_THAT(result.second,
::testing::Pair(::testing::Eq(std::make_tuple(t2, o2)),
::testing::Eq(std::make_tuple(t3, o3))));
EXPECT_EQ(result,
- filter.FindTimestamps(nullptr, result.first,
+ filter.FindTimestamps(nullptr, true, result.first,
e + chrono::microseconds(1500), 0.0, 0));
- result = filter.FindTimestamps(nullptr, Pointer(),
+ result = filter.FindTimestamps(nullptr, true, Pointer(),
e + chrono::microseconds(2000), 0);
EXPECT_THAT(result.second,
::testing::Pair(::testing::Eq(std::make_tuple(t2, o2)),
::testing::Eq(std::make_tuple(t3, o3))));
- EXPECT_EQ(result, filter.FindTimestamps(nullptr, result.first,
+ EXPECT_EQ(result, filter.FindTimestamps(nullptr, true, result.first,
e + chrono::microseconds(2000), 0));
- result = filter.FindTimestamps(nullptr, Pointer(),
+ result = filter.FindTimestamps(nullptr, true, Pointer(),
e + chrono::microseconds(2000), 0.1, 0);
EXPECT_THAT(result.second,
::testing::Pair(::testing::Eq(std::make_tuple(t2, o2)),
::testing::Eq(std::make_tuple(t3, o3))));
EXPECT_EQ(result,
- filter.FindTimestamps(nullptr, result.first,
+ filter.FindTimestamps(nullptr, true, result.first,
e + chrono::microseconds(2000), 0.1, 0));
- result = filter.FindTimestamps(nullptr, Pointer(),
+ result = filter.FindTimestamps(nullptr, true, Pointer(),
e + chrono::microseconds(2500), 0);
EXPECT_THAT(result.second,
::testing::Pair(::testing::Eq(std::make_tuple(t2, o2)),
::testing::Eq(std::make_tuple(t3, o3))));
- EXPECT_EQ(result, filter.FindTimestamps(nullptr, result.first,
+ EXPECT_EQ(result, filter.FindTimestamps(nullptr, true, result.first,
e + chrono::microseconds(2500), 0));
- result = filter.FindTimestamps(nullptr, Pointer(),
+ result = filter.FindTimestamps(nullptr, true, Pointer(),
e + chrono::microseconds(2500), 0.0, 0);
EXPECT_THAT(result.second,
::testing::Pair(::testing::Eq(std::make_tuple(t2, o2)),
::testing::Eq(std::make_tuple(t3, o3))));
EXPECT_EQ(result,
- filter.FindTimestamps(nullptr, result.first,
+ filter.FindTimestamps(nullptr, true, result.first,
e + chrono::microseconds(2500), 0.0, 0));
}
@@ -1264,55 +1264,130 @@
t3_b + o3_b + chrono::nanoseconds(1)));
// Before the start
- result = filter_a.FindTimestamps(&filter_b, Pointer(),
+ result = filter_a.FindTimestamps(&filter_b, true, Pointer(),
e - chrono::microseconds(10), 0);
EXPECT_THAT(result.second,
::testing::Pair(::testing::Eq(std::make_tuple(t1_a, o1_a)),
::testing::Eq(std::make_tuple(
t2_b + o2_b, -o2_b - kMinNetworkDelay()))));
- EXPECT_EQ(result, filter_a.FindTimestamps(&filter_b, result.first,
+ EXPECT_EQ(result, filter_a.FindTimestamps(&filter_b, true, result.first,
e - chrono::microseconds(10), 0));
// Before the first opposite point.
- result = filter_a.FindTimestamps(&filter_b, Pointer(),
+ result = filter_a.FindTimestamps(&filter_b, true, Pointer(),
e + chrono::microseconds(10), 0);
EXPECT_THAT(result.second,
::testing::Pair(::testing::Eq(std::make_tuple(t1_a, o1_a)),
::testing::Eq(std::make_tuple(
t2_b + o2_b, -o2_b - kMinNetworkDelay()))));
- EXPECT_EQ(result, filter_a.FindTimestamps(&filter_b, result.first,
+ EXPECT_EQ(result, filter_a.FindTimestamps(&filter_b, true, result.first,
e + chrono::microseconds(10), 0));
// Between the two opposite points.
- result = filter_a.FindTimestamps(&filter_b, Pointer(),
+ result = filter_a.FindTimestamps(&filter_b, true, Pointer(),
e + chrono::microseconds(250), 0);
EXPECT_THAT(result.second,
::testing::Pair(::testing::Eq(std::make_tuple(
t2_b + o2_b, -o2_b - kMinNetworkDelay())),
::testing::Eq(std::make_tuple(
t3_b + o3_b, -o3_b - kMinNetworkDelay()))));
- EXPECT_EQ(result, filter_a.FindTimestamps(&filter_b, result.first,
+ EXPECT_EQ(result, filter_a.FindTimestamps(&filter_b, true, result.first,
e + chrono::microseconds(250), 0));
// After the last opposite point.
- result = filter_a.FindTimestamps(&filter_b, Pointer(),
+ result = filter_a.FindTimestamps(&filter_b, true, Pointer(),
e + chrono::microseconds(450), 0);
EXPECT_THAT(result.second,
::testing::Pair(::testing::Eq(std::make_tuple(
t3_b + o3_b, -o3_b - kMinNetworkDelay())),
::testing::Eq(std::make_tuple(t2_a, o2_a))));
- EXPECT_EQ(result, filter_a.FindTimestamps(&filter_b, result.first,
+ EXPECT_EQ(result, filter_a.FindTimestamps(&filter_b, true, result.first,
e + chrono::microseconds(450), 0));
// And after the end.
- result = filter_a.FindTimestamps(&filter_b, Pointer(),
+ result = filter_a.FindTimestamps(&filter_b, true, Pointer(),
e + chrono::microseconds(1100), 0);
EXPECT_THAT(result.second,
::testing::Pair(::testing::Eq(std::make_tuple(
t3_b + o3_b, -o3_b - kMinNetworkDelay())),
::testing::Eq(std::make_tuple(t2_a, o2_a))));
- EXPECT_EQ(result, filter_a.FindTimestamps(&filter_b, result.first,
+ EXPECT_EQ(result, filter_a.FindTimestamps(&filter_b, true, result.first,
e + chrono::microseconds(1100), 0));
+
+ // And make sure that the FindTimestamps with "use_other==false" flag will
+ // return the same answer as no filter.
+ for (BootTimestamp t = t1_a - chrono::microseconds(500);
+ t < t2_a + chrono::microseconds(500); t += chrono::microseconds(100)) {
+ EXPECT_EQ(filter_a.FindTimestamps(&filter_b, false, Pointer(), t, 0),
+ filter_a.FindTimestamps(nullptr, true, Pointer(), t, 0));
+ }
+}
+
+// Tests that we can validate a solution reasonably.
+TEST_F(NoncausalTimestampFilterTest, ValidateSolution) {
+ const BootTimestamp e{0, monotonic_clock::epoch()};
+ // Note: t1, t2, t3 need to be picked such that the slop is small so filter
+ // doesn't modify the timestamps.
+ const BootTimestamp t1_a = e + chrono::nanoseconds(0);
+ const BootDuration o1_a{0, chrono::nanoseconds(100)};
+ const BootTimestamp t2_a = e + chrono::microseconds(1000);
+ const BootDuration o2_a{0, chrono::nanoseconds(100)};
+
+ const BootTimestamp tmid_a = e + chrono::microseconds(500);
+ const BootDuration omid_a{0, chrono::nanoseconds(-400)};
+
+ const BootTimestamp tbefore_a = e - chrono::microseconds(500);
+ const BootDuration obefore_a{0, chrono::nanoseconds(-400)};
+ const BootTimestamp tafter_a = e + chrono::microseconds(1500);
+ const BootDuration oafter_a{0, chrono::nanoseconds(-400)};
+
+ TestingNoncausalTimestampFilter filter_a(node_a, node_b);
+ TestingNoncausalTimestampFilter filter_b(node_b, node_a);
+
+ std::pair<Pointer,
+ std::pair<std::tuple<logger::BootTimestamp, logger::BootDuration>,
+ std::tuple<logger::BootTimestamp, logger::BootDuration>>>
+ result;
+
+ filter_a.Sample(t1_a, o1_a);
+ filter_a.Sample(t2_a, o2_a);
+
+ // At the control points, we should see that the boundary is right at the
+ // edge.
+ EXPECT_TRUE(filter_a.ValidateSolution(&filter_b, Pointer(), t1_a,
+ t1_a + o1_a + chrono::nanoseconds(1)));
+ EXPECT_TRUE(filter_a.ValidateSolution(&filter_b, Pointer(), t1_a, 0.0,
+ t1_a + o1_a, 0.00001));
+ EXPECT_FALSE(filter_a.ValidateSolution(&filter_b, Pointer(), t1_a,
+ t1_a + o1_a - chrono::nanoseconds(1)));
+ EXPECT_FALSE(filter_a.ValidateSolution(&filter_b, Pointer(), t1_a, 0.0,
+ t1_a + o1_a, -0.0001));
+
+ EXPECT_TRUE(filter_a.ValidateSolution(&filter_b, Pointer(), t2_a,
+ t2_a + o2_a + chrono::nanoseconds(1)));
+ EXPECT_TRUE(filter_a.ValidateSolution(&filter_b, Pointer(), t2_a, 0.0,
+ t2_a + o2_a, 0.00001));
+ EXPECT_FALSE(filter_a.ValidateSolution(&filter_b, Pointer(), t2_a,
+ t2_a + o2_a - chrono::nanoseconds(1)));
+ EXPECT_FALSE(filter_a.ValidateSolution(&filter_b, Pointer(), t2_a, 0.0,
+ t2_a + o2_a, -0.00001));
+
+ // Now that we've checked the control points, check in the middle to confirm
+ // it looks like we are using BoundOffset rather than interpolate.
+ EXPECT_TRUE(filter_a.ValidateSolution(&filter_b, Pointer(), tmid_a,
+ tmid_a + omid_a + chrono::nanoseconds(1)));
+ EXPECT_TRUE(filter_a.ValidateSolution(&filter_b, Pointer(), tmid_a, 0.0,
+ tmid_a + omid_a, 0.00001));
+
+ EXPECT_FALSE(filter_a.ValidateSolution(&filter_b, Pointer(), tbefore_a,
+ tbefore_a + obefore_a - chrono::nanoseconds(1)));
+ EXPECT_FALSE(filter_a.ValidateSolution(&filter_b, Pointer(), tbefore_a, 0.0,
+ tbefore_a + obefore_a, -0.00001));
+
+ EXPECT_FALSE(filter_a.ValidateSolution(&filter_b, Pointer(), tafter_a,
+ tafter_a + oafter_a - chrono::nanoseconds(1)));
+ EXPECT_FALSE(filter_a.ValidateSolution(&filter_b, Pointer(), tafter_a, 0.0,
+ tafter_a + oafter_a, -0.00001));
}
// Tests that Offset returns results indicative of it calling InterpolateOffset