utilities: Update time/r methods for LINUX

Default to MONOTONIC clock for timer methods to avoid falling victim to
clock corrections.  Changed signatures from accepting pointers since
this is not needed an complicates calls and Java/JS/Python bindings.

    * Switched from nanosleep to clock_nanosleep to allow developers to
      provide a clock for LINUX
    * Default upm_clock_init to CLOCK_MONOTONIC
    * Updated logic to calculating delay and elapsed to be more readable
    * Added ns flavors for completeness
    * Refactored all upm_* delay/timer methods
    * Added #else for preprocessor cases w/o an #else
    * Added test for AQI
    * Added test fixture with logic to identify a minimum delay time
      which is used as a metric for testing all delay methods
    * Much more lenient unit testing of delays to minimize false CI
      failures

Signed-off-by: Noel Eck <noel.eck@intel.com>
This commit is contained in:
Noel Eck
2018-05-01 10:56:27 -07:00
parent be46240b8c
commit db3c73cbd1
10 changed files with 290 additions and 165 deletions

View File

@ -22,11 +22,29 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <chrono>
#include <thread>
#include "gtest/gtest.h"
#include "upm_utilities.h"
#include "upm_utilities.hpp"
/* Average over AVG_CNT iterations */
#define AVG_CNT 5
/* Specify a delay for all tests under 1s */
#define ms_50 std::chrono::milliseconds(50)
/* Specify a +/- value for all tests under 1s. Since the delay methods in
* non-realtime operating systems can vary greatly, use a lenient value for
* testing these methods. */
#define time_range std::chrono::milliseconds(5)
/* Helper defines */
#define to_ms std::chrono::duration_cast<std::chrono::milliseconds>
#define to_us std::chrono::duration_cast<std::chrono::microseconds>
#define to_ns std::chrono::duration_cast<std::chrono::nanoseconds>
/* Utilities test fixture */
class utilities_unit : public ::testing::Test
{
@ -44,44 +62,107 @@ class utilities_unit : public ::testing::Test
virtual void TearDown() {}
};
/* Sanity check on min_delay_ns */
TEST_F(utilities_unit, min_delay_LT_500us)
{
/* Determine a rough-average for the minimum delay using chrono */
std::chrono::nanoseconds min_delay_ns = std::chrono::nanoseconds::zero();
for (int i = 0; i < AVG_CNT; i++)
{
auto start = std::chrono::steady_clock::now();
std::this_thread::sleep_for(std::chrono::nanoseconds(1));
auto end = std::chrono::steady_clock::now();
min_delay_ns += to_ns(end-start);
}
min_delay_ns /= AVG_CNT;
ASSERT_LT(to_us(min_delay_ns).count(), 500);
}
/* Test the second delay method */
TEST_F(utilities_unit, test_upm_delay)
{
upm_clock_t clock;
upm_clock_init(&clock);
upm_clock_t clock = upm_clock_init();
/* Test a corner case */
upm_delay(0);
/* +- check for 0s */
EXPECT_EQ(upm_elapsed_ms(&clock), 0);
clock = upm_clock_init();
upm_delay(1);
/* +- check for 1s +/- 1ms */
ASSERT_NEAR(upm_elapsed_ms(&clock), 1000, 1);
/* +- check near 1s */
EXPECT_NEAR(upm_elapsed_ms(&clock), 1000, time_range.count());
}
/* Test the millisecond delay method */
TEST_F(utilities_unit, test_upm_delay_ms)
{
upm_clock_t clock;
upm_clock_init(&clock);
upm_clock_t clock = upm_clock_init();
/* Test a corner case */
upm_delay_ms(0);
upm_delay_ms(50);
/* +- check for 50ms +/- 1ms */
ASSERT_NEAR(upm_elapsed_ms(&clock), 50, 1);
/* +- check for 0ms */
EXPECT_EQ(upm_elapsed_ms(&clock), 0);
clock = upm_clock_init();
upm_delay_ms(ms_50.count() * AVG_CNT);
/* +- check near 50ms */
EXPECT_NEAR(upm_elapsed_ms(&clock)/AVG_CNT, ms_50.count(), time_range.count());
}
/* Test the microsecond delay method */
TEST_F(utilities_unit, test_upm_delay_us)
{
upm_clock_t clock;
upm_clock_init(&clock);
upm_clock_t clock = upm_clock_init();
/* Test a corner case */
upm_delay_us(0);
upm_delay_us(1000);
/* +- check for 1000us +/- 150us */
ASSERT_NEAR(upm_elapsed_us(&clock), 1000, 150);
/* +- check for 0us +/- 100us */
EXPECT_NEAR(upm_elapsed_us(&clock), 0, 100);
clock = upm_clock_init();
upm_delay_us(to_us(ms_50).count() * AVG_CNT);
/* +- check near 50ms */
EXPECT_NEAR(upm_elapsed_us(&clock)/AVG_CNT, to_us(ms_50).count(),
to_us(time_range).count());
}
/* Test the nanosecond delay method */
TEST_F(utilities_unit, test_upm_delay_ns)
{
upm_clock_t clock = upm_clock_init();
/* Test a corner case */
upm_delay_ns(0);
/* +- check for 0us +/- 100us */
EXPECT_NEAR(upm_elapsed_ns(&clock), 0, 100000);
clock = upm_clock_init();
upm_delay_ns(to_ns(ms_50).count() * AVG_CNT);
/* +- check near 50ms */
EXPECT_NEAR(upm_elapsed_ns(&clock)/AVG_CNT, to_ns(ms_50).count(),
to_ns(time_range).count());
}
/* Test the max us delay (default to disabled) */
TEST_F(utilities_unit, DISABLED_test_upm_delay_us_max)
{
upm_clock_t clock = upm_clock_init();
upm_delay_us(4294967295);
EXPECT_NEAR(upm_elapsed_us(&clock), 4294967295, 150);
}
/* Test the Air Quality Index method */
TEST_F(utilities_unit, test_upm_ugm3_to_aqi)
{
EXPECT_EQ(upm_ugm3_to_aqi(10), 41);
}