Skip to content

Commit

Permalink
Latency (microsoft#1085)
Browse files Browse the repository at this point in the history
* Latency Measuring test was added

* Latency Test Added

* Added Test to IMU_ft to ensure IMU and color device timestamps measured up

* updated

* Test speed up

* Remove useless EXPECT_EQ comparing the same 64ints

* Fixing Clang breaks

* Fixing Clang breaks

Co-authored-by: Paul McElroy <[email protected]>
  • Loading branch information
wes-b and Greendogo authored Mar 5, 2020
1 parent 1d8878e commit 52cfb4a
Show file tree
Hide file tree
Showing 13 changed files with 1,167 additions and 43 deletions.
4 changes: 4 additions & 0 deletions include/k4ainternal/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ typedef struct _guid_t
#define MAX_SERIAL_NUMBER_LENGTH \
(13 * 2) // Current schema is for 12 digits plus NULL, the extra size is in case that grows in the future.

#define HZ_TO_PERIOD_MS(Hz) (1000 / Hz)
#define HZ_TO_PERIOD_US(Hz) (1000000 / Hz)
#define HZ_TO_PERIOD_NS(Hz) (1000000000 / Hz)

inline static uint32_t k4a_convert_fps_to_uint(k4a_fps_t fps)
{
uint32_t fps_int;
Expand Down
40 changes: 14 additions & 26 deletions src/capturesync/capturesync.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,6 @@ K4A_DECLARE_CONTEXT(capturesync_t, capturesync_context_t);
#define DEPTH_CAPTURE (false)
#define COLOR_CAPTURE (true)

#define MICRO_SECONDS(seconds) (seconds * 1000000)

/**
* This function is responsible for updating the information in either capturesync_context_t->depth_ir or in
* capturesync_context_t->color. capturesync_context_t holds the capture, image, and ts for the sample we are currenly
Expand Down Expand Up @@ -488,41 +486,31 @@ k4a_result_t capturesync_start(capturesync_t capturesync_handle, const k4a_devic
RETURN_VALUE_IF_HANDLE_INVALID(K4A_RESULT_FAILED, capturesync_t, capturesync_handle);
RETURN_VALUE_IF_ARG(K4A_RESULT_FAILED, config == NULL);
capturesync_context_t *sync = capturesync_t_get_context(capturesync_handle);
k4a_result_t result = K4A_RESULT_SUCCEEDED;

// Reset frames to drop
sync->waiting_for_clean_depth_ts = true;
sync->synchronized_images_only = config->synchronized_images_only;

uint32_t camera_fps = k4a_convert_fps_to_uint(config->camera_fps);
sync->fps_period = HZ_TO_PERIOD_US(k4a_convert_fps_to_uint(config->camera_fps));
sync->fps_1_quarter_period = sync->fps_period / 4;
sync->depth_delay_off_color_usec = config->depth_delay_off_color_usec;
sync->sync_captures = true;
sync->depth_captures_dropped = 0;

result = K4A_RESULT_FROM_BOOL(camera_fps > 0);
if (K4A_SUCCEEDED(result))
if (config->color_resolution == K4A_COLOR_RESOLUTION_OFF || config->depth_mode == K4A_DEPTH_MODE_OFF)
{
sync->fps_period = MICRO_SECONDS(1) / camera_fps;
sync->fps_1_quarter_period = sync->fps_period / 4;
sync->depth_delay_off_color_usec = config->depth_delay_off_color_usec;
sync->sync_captures = true;
sync->depth_captures_dropped = 0;

if (config->color_resolution == K4A_COLOR_RESOLUTION_OFF || config->depth_mode == K4A_DEPTH_MODE_OFF)
{
// Only 1 sensor is running, disable synchronization
sync->sync_captures = false;
}
// Only 1 sensor is running, disable synchronization
sync->sync_captures = false;
}

if (K4A_SUCCEEDED(result))
{
queue_enable(sync->color.queue);
queue_enable(sync->depth_ir.queue);
queue_enable(sync->sync_queue);
queue_enable(sync->color.queue);
queue_enable(sync->depth_ir.queue);
queue_enable(sync->sync_queue);

// Not taking the lock as we don't need to synchronize this on start
sync->running = true;
}
// Not taking the lock as we don't need to synchronize this on start
sync->running = true;

return result;
return K4A_RESULT_SUCCEEDED;
}

void capturesync_stop(capturesync_t capturesync_handle)
Expand Down
2 changes: 1 addition & 1 deletion src/dewrapper/dewrapper.c
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ static k4a_result_t depth_engine_start_helper(dewrapper_context_t *dewrapper,
assert(dewrapper->calibration_memory != NULL);

// Max comput time is the configured FPS
*depth_engine_max_compute_time_ms = 1000 / k4a_convert_fps_to_uint(fps);
*depth_engine_max_compute_time_ms = HZ_TO_PERIOD_MS(k4a_convert_fps_to_uint(fps));
result = K4A_RESULT_FROM_BOOL(*depth_engine_max_compute_time_ms != 0);

if (K4A_SUCCEEDED(result))
Expand Down
4 changes: 2 additions & 2 deletions src/sdk/k4a.c
Original file line number Diff line number Diff line change
Expand Up @@ -681,7 +681,7 @@ static k4a_result_t validate_configuration(k4a_context_t *device, const k4a_devi
if (config->wired_sync_mode == K4A_WIRED_SYNC_MODE_SUBORDINATE &&
config->subordinate_delay_off_master_usec != 0)
{
uint32_t fps_in_usec = 1000000 / k4a_convert_fps_to_uint(config->camera_fps);
uint32_t fps_in_usec = HZ_TO_PERIOD_US(k4a_convert_fps_to_uint(config->camera_fps));
if (config->subordinate_delay_off_master_usec > fps_in_usec)
{
result = K4A_RESULT_FAILED;
Expand Down Expand Up @@ -716,7 +716,7 @@ static k4a_result_t validate_configuration(k4a_context_t *device, const k4a_devi

if (depth_enabled && color_enabled)
{
int64_t fps = 1000000 / k4a_convert_fps_to_uint(config->camera_fps);
int64_t fps = HZ_TO_PERIOD_US(k4a_convert_fps_to_uint(config->camera_fps));
if (config->depth_delay_off_color_usec < -fps || config->depth_delay_off_color_usec > fps)
{
result = K4A_RESULT_FAILED;
Expand Down
1 change: 1 addition & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ add_subdirectory(executables)
add_subdirectory(ExternLibraries)
add_subdirectory(FirmwareTests)
add_subdirectory(global)
add_subdirectory(latency)
add_subdirectory(logging)
add_subdirectory(IMUTests)
add_subdirectory(multidevice)
Expand Down
2 changes: 1 addition & 1 deletion tests/ColorTests/FunctionalTest/color_ft.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -716,7 +716,7 @@ int32_t color_control_test::map_manual_exposure(int32_t value, bool sixty_hertz)
// Limit exposure setting based on FPS setting.
int32_t color_control_test::limit_exposure_to_fps_setting(int32_t value, bool sixty_hertz, k4a_fps_t fps)
{
int fps_usec = 1000000 / k4a_convert_fps_to_uint(fps);
int fps_usec = HZ_TO_PERIOD_US(k4a_convert_fps_to_uint(fps));
int last_exposure;

if (value < fps_usec)
Expand Down
45 changes: 44 additions & 1 deletion tests/IMUTests/FunctionalTest/imu_ft.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
//**************Symbolic Constant Macros (defines) *************
#define STREAM_RUN_TIME_SEC 4
#define ERROR_START_STREAM_TIME 10000
#define SECOND_TO_MICROSECONDS(sec) (sec * 1000 * 1000)

// Total ACC range is +/- 147.15 m/s^2.
#define MIN_ACC_READING -15.0f
Expand Down Expand Up @@ -85,6 +86,8 @@ static void RunStreamConfig(k4a_device_t device, uint32_t expected_fps)
tickcounter_ms_t end_ms;
tickcounter_ms_t delta_ms;
uint32_t error_tolerance;
int first_sample_inspected = 0;
uint64_t fps_period_us;

stream_count = STREAM_RUN_TIME_SEC * expected_fps;
tick_count = tickcounter_create();
Expand All @@ -95,8 +98,11 @@ static void RunStreamConfig(k4a_device_t device, uint32_t expected_fps)
config.color_resolution = K4A_COLOR_RESOLUTION_2160P;
config.depth_mode = K4A_DEPTH_MODE_NFOV_UNBINNED;
config.camera_fps = K4A_FRAMES_PER_SECOND_30;
config.synchronized_images_only = true;
ASSERT_EQ(K4A_RESULT_SUCCEEDED, k4a_device_start_cameras(device, &config));

fps_period_us = HZ_TO_PERIOD_US(k4a_convert_fps_to_uint(config.camera_fps));

// start streaming.
ASSERT_EQ(K4A_RESULT_SUCCEEDED, k4a_device_start_imu(device));

Expand All @@ -114,7 +120,16 @@ static void RunStreamConfig(k4a_device_t device, uint32_t expected_fps)
{
// get frames as available
ASSERT_EQ(K4A_WAIT_RESULT_SUCCEEDED, k4a_device_get_imu_sample(device, &imu_sample, timeout_ms));

if (!first_sample_inspected)
{
// Time stamps should not go backwards and the first time stamps should be around zero as the color camera
// staring will device time stamps reset to zero.
ASSERT_LT(imu_sample.acc_timestamp_usec, SECOND_TO_MICROSECONDS(2));
ASSERT_LT(imu_sample.gyro_timestamp_usec, SECOND_TO_MICROSECONDS(2));
std::cout << "Initial Timestamps are: " << imu_sample.gyro_timestamp_usec << " and "
<< imu_sample.gyro_timestamp_usec << "\n";
first_sample_inspected = 1;
}
ASSERT_GT(imu_sample.acc_timestamp_usec, last_acc_dev_ts);
last_acc_dev_ts = imu_sample.acc_timestamp_usec;
ASSERT_GT(imu_sample.gyro_timestamp_usec, last_gyro_dev_ts);
Expand All @@ -128,6 +143,34 @@ static void RunStreamConfig(k4a_device_t device, uint32_t expected_fps)
ASSERT_EQ(true, is_float_in_range(imu_sample.gyro_sample.xyz.y, MIN_GYRO_READING, MAX_GYRO_READING, "GYRO_Y"));
ASSERT_EQ(true, is_float_in_range(imu_sample.gyro_sample.xyz.z, MIN_GYRO_READING, MAX_GYRO_READING, "GYRO_Z"));

{
k4a_capture_t capture;
k4a_wait_result_t wresult;
ASSERT_NE(wresult = k4a_device_get_capture(device, &capture, 0), K4A_WAIT_RESULT_FAILED);
if (wresult == K4A_WAIT_RESULT_SUCCEEDED)
{
k4a_image_t image = k4a_capture_get_color_image(capture);
int64_t ts_c_dev = (int64_t)k4a_image_get_device_timestamp_usec(image);
EXPECT_LT(std::abs(ts_c_dev - (int64_t)imu_sample.gyro_timestamp_usec), (int64_t)fps_period_us * 4);
EXPECT_LT(std::abs(ts_c_dev - (int64_t)imu_sample.acc_timestamp_usec), (int64_t)fps_period_us * 4);
k4a_image_release(image);

image = k4a_capture_get_ir_image(capture);
int64_t ts_ir_dev = (int64_t)k4a_image_get_device_timestamp_usec(image);
EXPECT_LT(std::abs(ts_ir_dev - (int64_t)imu_sample.gyro_timestamp_usec), (int64_t)fps_period_us * 4);
EXPECT_LT(std::abs(ts_ir_dev - (int64_t)imu_sample.acc_timestamp_usec), (int64_t)fps_period_us * 4);
k4a_image_release(image);

// printf("IMU PTS delta %" PRId64 " %" PRId64 " %" PRId64 " %" PRId64 " \n",
// (int64_t)imu_sample.gyro_timestamp_usec - ts_c_dev,
// (int64_t)imu_sample.acc_timestamp_usec - ts_c_dev,
// (int64_t)imu_sample.gyro_timestamp_usec - ts_ir_dev,
// (int64_t)imu_sample.acc_timestamp_usec - ts_ir_dev);

k4a_capture_release(capture);
}
}

stream_count--;
};

Expand Down
10 changes: 5 additions & 5 deletions tests/RecordTests/UnitTest/playback_ut.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ TEST_F(playback_ut, open_large_file)
k4a_capture_t capture = NULL;
k4a_stream_result_t stream_result = K4A_STREAM_RESULT_FAILED;
uint64_t timestamps[3] = { 0, 1000, 1000 };
uint64_t timestamp_delta = 1000000 / k4a_convert_fps_to_uint(config.camera_fps);
uint64_t timestamp_delta = HZ_TO_PERIOD_US(k4a_convert_fps_to_uint(config.camera_fps));
size_t i = 0;
for (; i < 50; i++)
{
Expand Down Expand Up @@ -177,7 +177,7 @@ TEST_F(playback_ut, open_delay_offset_file)
k4a_capture_t capture = NULL;
k4a_stream_result_t stream_result = K4A_STREAM_RESULT_FAILED;
uint64_t timestamps[3] = { 0, 10000, 10000 };
uint64_t timestamp_delta = 1000000 / k4a_convert_fps_to_uint(config.camera_fps);
uint64_t timestamp_delta = HZ_TO_PERIOD_US(k4a_convert_fps_to_uint(config.camera_fps));

// Read forward
for (size_t i = 0; i < test_frame_count; i++)
Expand Down Expand Up @@ -281,7 +281,7 @@ TEST_F(playback_ut, playback_seek_test)
k4a_capture_t capture = NULL;
k4a_stream_result_t stream_result = K4A_STREAM_RESULT_FAILED;
uint64_t timestamps[3] = { 0, 1000, 1000 };
uint64_t timestamp_delta = 1000000 / k4a_convert_fps_to_uint(config.camera_fps);
uint64_t timestamp_delta = HZ_TO_PERIOD_US(k4a_convert_fps_to_uint(config.camera_fps));

k4a_imu_sample_t imu_sample = { 0 };
uint64_t imu_timestamp = 1150;
Expand Down Expand Up @@ -546,7 +546,7 @@ TEST_F(playback_ut, open_skipped_frames_file)
k4a_capture_t capture = NULL;
k4a_stream_result_t stream_result = K4A_STREAM_RESULT_FAILED;
uint64_t timestamps[3] = { 1000000, 1001000, 1001000 };
uint64_t timestamp_delta = 1000000 / k4a_convert_fps_to_uint(config.camera_fps);
uint64_t timestamp_delta = HZ_TO_PERIOD_US(k4a_convert_fps_to_uint(config.camera_fps));

// Test initial state
stream_result = k4a_playback_get_previous_capture(handle, &capture);
Expand Down Expand Up @@ -817,7 +817,7 @@ TEST_F(playback_ut, open_start_offset_file)
k4a_stream_result_t stream_result = K4A_STREAM_RESULT_FAILED;
uint64_t timestamps[3] = { 1000000, 1000000, 1000000 };
uint64_t imu_timestamp = 1001150;
uint64_t timestamp_delta = 1000000 / k4a_convert_fps_to_uint(config.camera_fps);
uint64_t timestamp_delta = HZ_TO_PERIOD_US(k4a_convert_fps_to_uint(config.camera_fps));
uint64_t last_timestamp = k4a_playback_get_recording_length_usec(handle) +
(uint64_t)config.start_timestamp_offset_usec;
ASSERT_EQ(last_timestamp, (uint64_t)config.start_timestamp_offset_usec + 3333150);
Expand Down
8 changes: 4 additions & 4 deletions tests/RecordTests/UnitTest/sample_recordings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ void SampleRecordings::SetUp()

uint64_t timestamps[3] = { 0, 1000, 1000 }; // Offset the Depth and IR tracks by 1ms to test
uint64_t imu_timestamp = 1150;
uint32_t timestamp_delta = 1000000 / k4a_convert_fps_to_uint(record_config_full.camera_fps);
uint32_t timestamp_delta = HZ_TO_PERIOD_US(k4a_convert_fps_to_uint(record_config_full.camera_fps));
k4a_capture_t capture = NULL;
for (size_t i = 0; i < test_frame_count; i++)
{
Expand Down Expand Up @@ -108,7 +108,7 @@ void SampleRecordings::SetUp()
uint64_t timestamps[3] = { 0,
(uint64_t)record_config_delay.depth_delay_off_color_usec,
(uint64_t)record_config_delay.depth_delay_off_color_usec };
uint32_t timestamp_delta = 1000000 / k4a_convert_fps_to_uint(record_config_delay.camera_fps);
uint32_t timestamp_delta = HZ_TO_PERIOD_US(k4a_convert_fps_to_uint(record_config_delay.camera_fps));
k4a_capture_t capture = NULL;
for (size_t i = 0; i < test_frame_count; i++)
{
Expand Down Expand Up @@ -169,7 +169,7 @@ void SampleRecordings::SetUp()
}

uint64_t timestamps[3] = { 1000000, 1001000, 1001000 }; // Start recording at 1s
uint32_t timestamp_delta = 1000000 / k4a_convert_fps_to_uint(record_config_full.camera_fps);
uint32_t timestamp_delta = HZ_TO_PERIOD_US(k4a_convert_fps_to_uint(record_config_full.camera_fps));
for (size_t i = 0; i < test_frame_count; i++)
{
// Create a known pattern of dropped / missing frames that can be tested against
Expand Down Expand Up @@ -235,7 +235,7 @@ void SampleRecordings::SetUp()

uint64_t timestamps[3] = { 1000000, 1000000, 1000000 };
uint64_t imu_timestamp = 1001150;
uint32_t timestamp_delta = 1000000 / k4a_convert_fps_to_uint(record_config_delay.camera_fps);
uint32_t timestamp_delta = HZ_TO_PERIOD_US(k4a_convert_fps_to_uint(record_config_delay.camera_fps));
k4a_capture_t capture = NULL;
for (size_t i = 0; i < test_frame_count; i++)
{
Expand Down
15 changes: 15 additions & 0 deletions tests/latency/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.

add_executable(latency_perf latency_perf.cpp)

target_compile_definitions(latency_perf PRIVATE _CRT_SECURE_NO_WARNINGS)

target_link_libraries(latency_perf PRIVATE
azure::aziotsharedutil
gtest::gtest
k4a::k4a
k4ainternal::logging
k4ainternal::utcommon)

k4a_add_tests(TARGET latency_perf HARDWARE_REQUIRED TEST_TYPE PERF)
Loading

0 comments on commit 52cfb4a

Please sign in to comment.