1# Copyright (c) 2023-2024 Intel Corporation 2# 3# SPDX-License-Identifier: Apache-2.0 4 5import logging 6 7from math import ceil 8 9from twister_harness import DeviceAdapter 10 11logger = logging.getLogger(__name__) 12 13 14def do_analysis(test, stats, stats_count, config, sys_clock_hw_cycles_per_sec): 15 logger.info('====================================================') 16 logger.info(f'periodic timer behaviour using {test} mechanism:') 17 18 test_period = int(config['TIMER_TEST_PERIOD']) 19 test_samples = int(config['TIMER_TEST_SAMPLES']) 20 21 seconds = (test_period * test_samples) / 1_000_000 22 23 periods_sec = test_period / 1_000_000 24 ticks_per_sec = int(config['SYS_CLOCK_TICKS_PER_SEC']) 25 periods_tick = ceil(ticks_per_sec * periods_sec) 26 27 expected_period = test_period * sys_clock_hw_cycles_per_sec / 1_000_000 28 cyc_per_tick = sys_clock_hw_cycles_per_sec / ticks_per_sec 29 expected_period_drift = ((periods_tick * cyc_per_tick - expected_period) / 30 sys_clock_hw_cycles_per_sec * 1_000_000) 31 expected_total_drift = expected_period_drift * test_samples / 1_000_000 32 33 period_max_drift = (int(config['TIMER_EXTERNAL_TEST_PERIOD_MAX_DRIFT_PPM']) 34 / 1_000_000) 35 min_bound = (test_period - period_max_drift * test_period + 36 expected_period_drift) / 1_000_000 37 max_bound = (test_period + period_max_drift * test_period + 38 expected_period_drift) / 1_000_000 39 40 min_cyc = 1. / sys_clock_hw_cycles_per_sec 41 max_stddev = int(config['TIMER_TEST_MAX_STDDEV']) / 1_000_000 42 # Max STDDEV cannot be lower than clock single cycle 43 max_stddev = max(min_cyc, max_stddev) 44 45 max_drift_ppm = int(config['TIMER_EXTERNAL_TEST_MAX_DRIFT_PPM']) 46 time_diff = stats['total_time'] - seconds - expected_total_drift 47 48 logger.info(f'min: {stats["min"] * 1_000_000:.6f} us') 49 logger.info(f'max: {stats["max"] * 1_000_000:.6f} us') 50 logger.info(f'mean: {stats["mean"] * 1_000_000:.6f} us') 51 logger.info(f'variance: {stats["var"] * 1_000_000:.6f} us') 52 logger.info(f'stddev: {stats["stddev"] * 1_000_000:.6f} us') 53 logger.info(f'total time: {stats["total_time"] * 1_000_000:.6f} us') 54 logger.info(f'expected drift: {seconds * max_drift_ppm} us') 55 logger.info(f'real drift: {time_diff * 1_000_000:.6f} us') 56 logger.info('====================================================') 57 58 logger.info('RECORD: {' 59 f'"testcase":"jitter_drift_timer"' 60 f', "mechanism":"{test}_external", "stats_count": {stats_count}, ' + 61 ', '.join(['"{}_us":{:.6f}'.format(k, v * 1_000_000) for k,v in stats.items()]) + 62 f', "expected_total_time_us":{seconds * 1_000_000:.6f}' 63 f', "expected_total_drift_us":{seconds * max_drift_ppm:.6f}' 64 f', "total_drift_us": {time_diff * 1_000_000:.6f}' 65 f', "min_bound_us":{min_bound * 1_000_000:.6f}' 66 f', "max_bound_us":{max_bound * 1_000_000:.6f}' 67 f', "expected_period_cycles":{expected_period:.0f}' 68 f', "MAX_STD_DEV":{max_stddev * 1_000_000:.0f}' 69 f', "sys_clock_hw_cycles_per_sec":{sys_clock_hw_cycles_per_sec}, ' + 70 ', '.join(['"CONFIG_{}":{}'.format(k, str(config[k]).rstrip()) for k in [ 71 'SYS_CLOCK_HW_CYCLES_PER_SEC', 72 'SYS_CLOCK_TICKS_PER_SEC', 73 'TIMER_TEST_PERIOD', 74 'TIMER_TEST_SAMPLES', 75 'TIMER_EXTERNAL_TEST_PERIOD_MAX_DRIFT_PPM', 76 'TIMER_EXTERNAL_TEST_MAX_DRIFT_PPM' 77 ] 78 ]) + '}' 79 ) 80 81 assert stats['stddev'] < max_stddev 82 assert stats['min'] >= min_bound 83 assert stats['max'] <= max_bound 84 assert abs(time_diff) < seconds * max_drift_ppm / 1_000_000 85 86 87def wait_sync_point(dut: DeviceAdapter, point): 88 dut.readlines_until(regex=f"===== {point} =====") 89 90 91def test_flash(dut: DeviceAdapter, tool, tool_options, config, 92 sys_clock_hw_cycles_per_sec): 93 tool = __import__(tool) 94 95 test_period = int(config['TIMER_TEST_PERIOD']) 96 test_samples = int(config['TIMER_TEST_SAMPLES']) 97 seconds = (test_period * test_samples) / 1_000_000 98 99 tests = ["builtin", "startdelay"] 100 for test in tests: 101 wait_sync_point(dut, test) 102 stats, stats_count = tool.run(seconds, tool_options) 103 assert stats_count 104 do_analysis(test, stats, stats_count, config, sys_clock_hw_cycles_per_sec) 105 106 # Let the running test's image output to be fully captured from device. 107 dut.readlines() 108