18c2ecf20Sopenharmony_ci/* set_timer latency test 28c2ecf20Sopenharmony_ci * John Stultz (john.stultz@linaro.org) 38c2ecf20Sopenharmony_ci * (C) Copyright Linaro 2014 48c2ecf20Sopenharmony_ci * Licensed under the GPLv2 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * This test makes sure the set_timer api is correct 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * To build: 98c2ecf20Sopenharmony_ci * $ gcc set-timer-lat.c -o set-timer-lat -lrt 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * This program is free software: you can redistribute it and/or modify 128c2ecf20Sopenharmony_ci * it under the terms of the GNU General Public License as published by 138c2ecf20Sopenharmony_ci * the Free Software Foundation, either version 2 of the License, or 148c2ecf20Sopenharmony_ci * (at your option) any later version. 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * This program is distributed in the hope that it will be useful, 178c2ecf20Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 188c2ecf20Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 198c2ecf20Sopenharmony_ci * GNU General Public License for more details. 208c2ecf20Sopenharmony_ci */ 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include <errno.h> 248c2ecf20Sopenharmony_ci#include <stdio.h> 258c2ecf20Sopenharmony_ci#include <unistd.h> 268c2ecf20Sopenharmony_ci#include <time.h> 278c2ecf20Sopenharmony_ci#include <string.h> 288c2ecf20Sopenharmony_ci#include <signal.h> 298c2ecf20Sopenharmony_ci#include <stdlib.h> 308c2ecf20Sopenharmony_ci#include <pthread.h> 318c2ecf20Sopenharmony_ci#include "../kselftest.h" 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#define CLOCK_REALTIME 0 348c2ecf20Sopenharmony_ci#define CLOCK_MONOTONIC 1 358c2ecf20Sopenharmony_ci#define CLOCK_PROCESS_CPUTIME_ID 2 368c2ecf20Sopenharmony_ci#define CLOCK_THREAD_CPUTIME_ID 3 378c2ecf20Sopenharmony_ci#define CLOCK_MONOTONIC_RAW 4 388c2ecf20Sopenharmony_ci#define CLOCK_REALTIME_COARSE 5 398c2ecf20Sopenharmony_ci#define CLOCK_MONOTONIC_COARSE 6 408c2ecf20Sopenharmony_ci#define CLOCK_BOOTTIME 7 418c2ecf20Sopenharmony_ci#define CLOCK_REALTIME_ALARM 8 428c2ecf20Sopenharmony_ci#define CLOCK_BOOTTIME_ALARM 9 438c2ecf20Sopenharmony_ci#define CLOCK_HWSPECIFIC 10 448c2ecf20Sopenharmony_ci#define CLOCK_TAI 11 458c2ecf20Sopenharmony_ci#define NR_CLOCKIDS 12 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci#define NSEC_PER_SEC 1000000000ULL 498c2ecf20Sopenharmony_ci#define UNRESONABLE_LATENCY 40000000 /* 40ms in nanosecs */ 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci#define TIMER_SECS 1 528c2ecf20Sopenharmony_ciint alarmcount; 538c2ecf20Sopenharmony_ciint clock_id; 548c2ecf20Sopenharmony_cistruct timespec start_time; 558c2ecf20Sopenharmony_cilong long max_latency_ns; 568c2ecf20Sopenharmony_ciint timer_fired_early; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cichar *clockstring(int clockid) 598c2ecf20Sopenharmony_ci{ 608c2ecf20Sopenharmony_ci switch (clockid) { 618c2ecf20Sopenharmony_ci case CLOCK_REALTIME: 628c2ecf20Sopenharmony_ci return "CLOCK_REALTIME"; 638c2ecf20Sopenharmony_ci case CLOCK_MONOTONIC: 648c2ecf20Sopenharmony_ci return "CLOCK_MONOTONIC"; 658c2ecf20Sopenharmony_ci case CLOCK_PROCESS_CPUTIME_ID: 668c2ecf20Sopenharmony_ci return "CLOCK_PROCESS_CPUTIME_ID"; 678c2ecf20Sopenharmony_ci case CLOCK_THREAD_CPUTIME_ID: 688c2ecf20Sopenharmony_ci return "CLOCK_THREAD_CPUTIME_ID"; 698c2ecf20Sopenharmony_ci case CLOCK_MONOTONIC_RAW: 708c2ecf20Sopenharmony_ci return "CLOCK_MONOTONIC_RAW"; 718c2ecf20Sopenharmony_ci case CLOCK_REALTIME_COARSE: 728c2ecf20Sopenharmony_ci return "CLOCK_REALTIME_COARSE"; 738c2ecf20Sopenharmony_ci case CLOCK_MONOTONIC_COARSE: 748c2ecf20Sopenharmony_ci return "CLOCK_MONOTONIC_COARSE"; 758c2ecf20Sopenharmony_ci case CLOCK_BOOTTIME: 768c2ecf20Sopenharmony_ci return "CLOCK_BOOTTIME"; 778c2ecf20Sopenharmony_ci case CLOCK_REALTIME_ALARM: 788c2ecf20Sopenharmony_ci return "CLOCK_REALTIME_ALARM"; 798c2ecf20Sopenharmony_ci case CLOCK_BOOTTIME_ALARM: 808c2ecf20Sopenharmony_ci return "CLOCK_BOOTTIME_ALARM"; 818c2ecf20Sopenharmony_ci case CLOCK_TAI: 828c2ecf20Sopenharmony_ci return "CLOCK_TAI"; 838c2ecf20Sopenharmony_ci }; 848c2ecf20Sopenharmony_ci return "UNKNOWN_CLOCKID"; 858c2ecf20Sopenharmony_ci} 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cilong long timespec_sub(struct timespec a, struct timespec b) 898c2ecf20Sopenharmony_ci{ 908c2ecf20Sopenharmony_ci long long ret = NSEC_PER_SEC * b.tv_sec + b.tv_nsec; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci ret -= NSEC_PER_SEC * a.tv_sec + a.tv_nsec; 938c2ecf20Sopenharmony_ci return ret; 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_civoid sigalarm(int signo) 988c2ecf20Sopenharmony_ci{ 998c2ecf20Sopenharmony_ci long long delta_ns; 1008c2ecf20Sopenharmony_ci struct timespec ts; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci clock_gettime(clock_id, &ts); 1038c2ecf20Sopenharmony_ci alarmcount++; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci delta_ns = timespec_sub(start_time, ts); 1068c2ecf20Sopenharmony_ci delta_ns -= NSEC_PER_SEC * TIMER_SECS * alarmcount; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci if (delta_ns < 0) 1098c2ecf20Sopenharmony_ci timer_fired_early = 1; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci if (delta_ns > max_latency_ns) 1128c2ecf20Sopenharmony_ci max_latency_ns = delta_ns; 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_civoid describe_timer(int flags, int interval) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci printf("%-22s %s %s ", 1188c2ecf20Sopenharmony_ci clockstring(clock_id), 1198c2ecf20Sopenharmony_ci flags ? "ABSTIME":"RELTIME", 1208c2ecf20Sopenharmony_ci interval ? "PERIODIC":"ONE-SHOT"); 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ciint setup_timer(int clock_id, int flags, int interval, timer_t *tm1) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci struct sigevent se; 1268c2ecf20Sopenharmony_ci struct itimerspec its1, its2; 1278c2ecf20Sopenharmony_ci int err; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci /* Set up timer: */ 1308c2ecf20Sopenharmony_ci memset(&se, 0, sizeof(se)); 1318c2ecf20Sopenharmony_ci se.sigev_notify = SIGEV_SIGNAL; 1328c2ecf20Sopenharmony_ci se.sigev_signo = SIGRTMAX; 1338c2ecf20Sopenharmony_ci se.sigev_value.sival_int = 0; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci max_latency_ns = 0; 1368c2ecf20Sopenharmony_ci alarmcount = 0; 1378c2ecf20Sopenharmony_ci timer_fired_early = 0; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci err = timer_create(clock_id, &se, tm1); 1408c2ecf20Sopenharmony_ci if (err) { 1418c2ecf20Sopenharmony_ci if ((clock_id == CLOCK_REALTIME_ALARM) || 1428c2ecf20Sopenharmony_ci (clock_id == CLOCK_BOOTTIME_ALARM)) { 1438c2ecf20Sopenharmony_ci printf("%-22s %s missing CAP_WAKE_ALARM? : [UNSUPPORTED]\n", 1448c2ecf20Sopenharmony_ci clockstring(clock_id), 1458c2ecf20Sopenharmony_ci flags ? "ABSTIME":"RELTIME"); 1468c2ecf20Sopenharmony_ci /* Indicate timer isn't set, so caller doesn't wait */ 1478c2ecf20Sopenharmony_ci return 1; 1488c2ecf20Sopenharmony_ci } 1498c2ecf20Sopenharmony_ci printf("%s - timer_create() failed\n", clockstring(clock_id)); 1508c2ecf20Sopenharmony_ci return -1; 1518c2ecf20Sopenharmony_ci } 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci clock_gettime(clock_id, &start_time); 1548c2ecf20Sopenharmony_ci if (flags) { 1558c2ecf20Sopenharmony_ci its1.it_value = start_time; 1568c2ecf20Sopenharmony_ci its1.it_value.tv_sec += TIMER_SECS; 1578c2ecf20Sopenharmony_ci } else { 1588c2ecf20Sopenharmony_ci its1.it_value.tv_sec = TIMER_SECS; 1598c2ecf20Sopenharmony_ci its1.it_value.tv_nsec = 0; 1608c2ecf20Sopenharmony_ci } 1618c2ecf20Sopenharmony_ci its1.it_interval.tv_sec = interval; 1628c2ecf20Sopenharmony_ci its1.it_interval.tv_nsec = 0; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci err = timer_settime(*tm1, flags, &its1, &its2); 1658c2ecf20Sopenharmony_ci if (err) { 1668c2ecf20Sopenharmony_ci printf("%s - timer_settime() failed\n", clockstring(clock_id)); 1678c2ecf20Sopenharmony_ci return -1; 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci return 0; 1718c2ecf20Sopenharmony_ci} 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ciint check_timer_latency(int flags, int interval) 1748c2ecf20Sopenharmony_ci{ 1758c2ecf20Sopenharmony_ci int err = 0; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci describe_timer(flags, interval); 1788c2ecf20Sopenharmony_ci printf("timer fired early: %7d : ", timer_fired_early); 1798c2ecf20Sopenharmony_ci if (!timer_fired_early) { 1808c2ecf20Sopenharmony_ci printf("[OK]\n"); 1818c2ecf20Sopenharmony_ci } else { 1828c2ecf20Sopenharmony_ci printf("[FAILED]\n"); 1838c2ecf20Sopenharmony_ci err = -1; 1848c2ecf20Sopenharmony_ci } 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci describe_timer(flags, interval); 1878c2ecf20Sopenharmony_ci printf("max latency: %10lld ns : ", max_latency_ns); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci if (max_latency_ns < UNRESONABLE_LATENCY) { 1908c2ecf20Sopenharmony_ci printf("[OK]\n"); 1918c2ecf20Sopenharmony_ci } else { 1928c2ecf20Sopenharmony_ci printf("[FAILED]\n"); 1938c2ecf20Sopenharmony_ci err = -1; 1948c2ecf20Sopenharmony_ci } 1958c2ecf20Sopenharmony_ci return err; 1968c2ecf20Sopenharmony_ci} 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ciint check_alarmcount(int flags, int interval) 1998c2ecf20Sopenharmony_ci{ 2008c2ecf20Sopenharmony_ci describe_timer(flags, interval); 2018c2ecf20Sopenharmony_ci printf("count: %19d : ", alarmcount); 2028c2ecf20Sopenharmony_ci if (alarmcount == 1) { 2038c2ecf20Sopenharmony_ci printf("[OK]\n"); 2048c2ecf20Sopenharmony_ci return 0; 2058c2ecf20Sopenharmony_ci } 2068c2ecf20Sopenharmony_ci printf("[FAILED]\n"); 2078c2ecf20Sopenharmony_ci return -1; 2088c2ecf20Sopenharmony_ci} 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ciint do_timer(int clock_id, int flags) 2118c2ecf20Sopenharmony_ci{ 2128c2ecf20Sopenharmony_ci timer_t tm1; 2138c2ecf20Sopenharmony_ci const int interval = TIMER_SECS; 2148c2ecf20Sopenharmony_ci int err; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci err = setup_timer(clock_id, flags, interval, &tm1); 2178c2ecf20Sopenharmony_ci /* Unsupported case - return 0 to not fail the test */ 2188c2ecf20Sopenharmony_ci if (err) 2198c2ecf20Sopenharmony_ci return err == 1 ? 0 : err; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci while (alarmcount < 5) 2228c2ecf20Sopenharmony_ci sleep(1); 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci timer_delete(tm1); 2258c2ecf20Sopenharmony_ci return check_timer_latency(flags, interval); 2268c2ecf20Sopenharmony_ci} 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ciint do_timer_oneshot(int clock_id, int flags) 2298c2ecf20Sopenharmony_ci{ 2308c2ecf20Sopenharmony_ci timer_t tm1; 2318c2ecf20Sopenharmony_ci const int interval = 0; 2328c2ecf20Sopenharmony_ci struct timeval timeout; 2338c2ecf20Sopenharmony_ci int err; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci err = setup_timer(clock_id, flags, interval, &tm1); 2368c2ecf20Sopenharmony_ci /* Unsupported case - return 0 to not fail the test */ 2378c2ecf20Sopenharmony_ci if (err) 2388c2ecf20Sopenharmony_ci return err == 1 ? 0 : err; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci memset(&timeout, 0, sizeof(timeout)); 2418c2ecf20Sopenharmony_ci timeout.tv_sec = 5; 2428c2ecf20Sopenharmony_ci do { 2438c2ecf20Sopenharmony_ci err = select(0, NULL, NULL, NULL, &timeout); 2448c2ecf20Sopenharmony_ci } while (err == -1 && errno == EINTR); 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci timer_delete(tm1); 2478c2ecf20Sopenharmony_ci err = check_timer_latency(flags, interval); 2488c2ecf20Sopenharmony_ci err |= check_alarmcount(flags, interval); 2498c2ecf20Sopenharmony_ci return err; 2508c2ecf20Sopenharmony_ci} 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ciint main(void) 2538c2ecf20Sopenharmony_ci{ 2548c2ecf20Sopenharmony_ci struct sigaction act; 2558c2ecf20Sopenharmony_ci int signum = SIGRTMAX; 2568c2ecf20Sopenharmony_ci int ret = 0; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci /* Set up signal handler: */ 2598c2ecf20Sopenharmony_ci sigfillset(&act.sa_mask); 2608c2ecf20Sopenharmony_ci act.sa_flags = 0; 2618c2ecf20Sopenharmony_ci act.sa_handler = sigalarm; 2628c2ecf20Sopenharmony_ci sigaction(signum, &act, NULL); 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci printf("Setting timers for every %i seconds\n", TIMER_SECS); 2658c2ecf20Sopenharmony_ci for (clock_id = 0; clock_id < NR_CLOCKIDS; clock_id++) { 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci if ((clock_id == CLOCK_PROCESS_CPUTIME_ID) || 2688c2ecf20Sopenharmony_ci (clock_id == CLOCK_THREAD_CPUTIME_ID) || 2698c2ecf20Sopenharmony_ci (clock_id == CLOCK_MONOTONIC_RAW) || 2708c2ecf20Sopenharmony_ci (clock_id == CLOCK_REALTIME_COARSE) || 2718c2ecf20Sopenharmony_ci (clock_id == CLOCK_MONOTONIC_COARSE) || 2728c2ecf20Sopenharmony_ci (clock_id == CLOCK_HWSPECIFIC)) 2738c2ecf20Sopenharmony_ci continue; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci ret |= do_timer(clock_id, TIMER_ABSTIME); 2768c2ecf20Sopenharmony_ci ret |= do_timer(clock_id, 0); 2778c2ecf20Sopenharmony_ci ret |= do_timer_oneshot(clock_id, TIMER_ABSTIME); 2788c2ecf20Sopenharmony_ci ret |= do_timer_oneshot(clock_id, 0); 2798c2ecf20Sopenharmony_ci } 2808c2ecf20Sopenharmony_ci if (ret) 2818c2ecf20Sopenharmony_ci return ksft_exit_fail(); 2828c2ecf20Sopenharmony_ci return ksft_exit_pass(); 2838c2ecf20Sopenharmony_ci} 284