26 std::string Payload(
const std::string &bytes, uint32_t &size) {
27 std::memcpy(&size, bytes.data() + 1,
sizeof(size));
33TEST(MultiGpuSensorSync, ticks_round_trip_with_bit_exact_deltas) {
37 std::ostringstream out;
39 const std::string bytes = out.str();
43 std::istringstream in(Payload(bytes, size));
45 ASSERT_TRUE(got.
Read(in, size));
46 ASSERT_EQ(got.
ticks.size(), 2u);
47 EXPECT_EQ(got.
ticks[0].actor_id, 7u);
48 EXPECT_EQ(got.
ticks[0].delta_seconds, 0.05f);
49 EXPECT_EQ(got.
ticks[1].delta_seconds, 0.1f + 1e-7f);
52TEST(MultiGpuSensorSync, empty_ticks_are_still_a_packet) {
54 std::ostringstream out;
57 std::istringstream in(Payload(out.str(), size));
60 ASSERT_TRUE(got.
Read(in, size));
61 EXPECT_TRUE(got.
ticks.empty());
64TEST(MultiGpuSensorSync, states_round_trip_every_field) {
78 imu.
imu_local_rotation = std::array<double, 4>{0.0, -0.25881904510252074, 0.0, 0.96592582628906831};
82 sent.
states = {lidar, imu, radar};
84 std::ostringstream out;
87 std::istringstream in(Payload(out.str(), size));
89 ASSERT_TRUE(got.
Read(in, size));
90 ASSERT_EQ(got.
states.size(), 3u);
93 EXPECT_FALSE(got.
states[0].imu_history.has_value());
94 ASSERT_TRUE(got.
states[1].imu_history.has_value());
95 EXPECT_EQ(got.
states[1].imu_history->last_location[2], 6.000001);
96 EXPECT_EQ(got.
states[1].imu_history->last_delta_seconds, 0.05f);
97 ASSERT_TRUE(got.
states[1].imu_local_rotation.has_value());
99 EXPECT_FALSE(got.
states[0].imu_local_rotation.has_value());
100 ASSERT_TRUE(got.
states[2].radar_previous_location.has_value());
101 EXPECT_EQ((*got.
states[2].radar_previous_location)[1], 20.25);
102 EXPECT_FALSE(got.
states[2].random_engine.has_value());
105TEST(MultiGpuSensorSync, unknown_and_longer_fields_are_skipped) {
107 std::ostringstream record;
108 const uint32_t
id = 8u;
109 record.write(
reinterpret_cast<const char *
>(&
id),
sizeof(
id));
111 std::string engine(
sizeof(uint32_t) + 2u,
'\0');
112 const uint32_t state = 777u;
113 std::memcpy(engine.data(), &state,
sizeof(state));
115 std::ostringstream payload;
116 const uint32_t count = 1u;
117 payload.write(
reinterpret_cast<const char *
>(&count),
sizeof(count));
120 const std::string body = payload.str();
121 std::istringstream in(body);
123 ASSERT_TRUE(got.
Read(in,
static_cast<uint32_t
>(body.size())));
124 ASSERT_EQ(got.
states.size(), 1u);
125 EXPECT_EQ(got.
states[0].actor_id, 8u);
126 EXPECT_EQ(got.
states[0].random_engine, std::optional<uint32_t>(777u));
129TEST(MultiGpuSensorSync, truncated_records_fail) {
135 std::ostringstream out;
138 const std::string payload = Payload(out.str(), size);
139 const std::string cut = payload.substr(0u, payload.size() - 4u);
140 std::istringstream in(cut);
142 EXPECT_FALSE(got.
Read(in,
static_cast<uint32_t
>(cut.size())));
145TEST(MultiGpuSensorSync, minstd_resumes_the_same_draws) {
147 std::minstd_rand primary(1234u);
148 for (
int i = 0; i < 17; ++i) {
149 (void)std::uniform_real_distribution<float>()(primary);
151 std::minstd_rand mirror(99u);
152 ASSERT_TRUE(SetEngineState(mirror, GetEngineState(primary)));
153 for (
int i = 0; i < 50; ++i) {
154 EXPECT_EQ(std::uniform_real_distribution<float>()(mirror), std::uniform_real_distribution<float>()(primary));
155 EXPECT_EQ(std::normal_distribution<float>(0.0f, 2.0f)(mirror), std::normal_distribution<float>(0.0f, 2.0f)(primary));
156 EXPECT_EQ(std::uniform_int_distribution<int32_t>(0, 1000)(mirror), std::uniform_int_distribution<int32_t>(0, 1000)(primary));
160TEST(MultiGpuSensorSync, impossible_engine_states_are_refused) {
161 std::minstd_rand engine;
162 EXPECT_FALSE(SetEngineState(engine, 0u));
163 EXPECT_FALSE(SetEngineState(engine, 2147483647u));
164 EXPECT_TRUE(SetEngineState(engine, 1u));
uint32_t GetEngineState(const std::minstd_rand &engine)
The state of a minstd_rand: the value its next draw is computed from.
constexpr std::size_t kFrameDataHeaderSize
Frame data (the SEND_FRAME payload) is a sequence of packets [uint8 id][uint32 payload size][payload]...
bool SetEngineState(std::minstd_rand &engine, uint32_t state)
Makes engine continue from state, as GetEngineState returned it.
void WriteField(std::ostream &out, uint8_t kind, const std::string &value)
void WriteSizedBytes(std::ostream &out, const std::string &bytes)
One [u32 size][bytes] entry: a variable-size record or, after a kind byte, a TLV value.
An IMU's history: its two previous locations (world, cm) and the delta between them; its acceleromete...
std::array< double, 3 > last_location
std::array< double, 3 > older_location
One record of frame data packet 27: the runtime state a sensor of the primary starts this frame's tic...
std::optional< ImuHistory > imu_history
std::optional< float > lidar_horizontal_angle
Ray-cast lidars: where this tick's sweep starts (radians).
std::optional< std::array< double, 4 > > imu_local_rotation
IMU: its rotation relative to its parent (x, y, z, w), which turns the parent's angular velocity into...
std::optional< std::array< double, 3 > > radar_previous_location
Radar: its previous location (world, cm), for its own velocity.
std::optional< uint32_t > random_engine
URandomEngine (noise, lidar drop-off, radar ray directions).
Frame data packet 27, for the sensors of packet 26 that carry state.
std::vector< SensorState > states
void Write(std::ostream &out) const
bool Read(std::istream &in, uint32_t size)
One record of frame data packet 26: a sensor of the primary that ticks in this frame,...
Frame data packet 26: every sensor of the primary that ticks in this frame.
static constexpr uint8_t kPacketId
std::vector< SensorTick > ticks
void Write(std::ostream &out) const
bool Read(std::istream &in, uint32_t size)
TEST(MultiGpuSensorSync, ticks_round_trip_with_bit_exact_deltas)