1 Star 0 Fork 2

HoperunHarmony/stress-ng

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
stress-clock.c 14.79 KB
一键复制 编辑 原始数据 按行查看 历史
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581
/*
* Copyright (C) 2013-2021 Canonical, Ltd.
* Copyright (C) 2022 Colin Ian King.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "stress-ng.h"
#include "core-capabilities.h"
#if defined(HAVE_POLL_H)
#include <poll.h>
#endif
#if defined(HAVE_SYS_TIMEX_H)
#include <sys/timex.h>
#endif
static const stress_help_t help[] = {
{ NULL, "clock N", "start N workers thrashing clocks and POSIX timers" },
{ NULL, "clock-ops N", "stop clock workers after N bogo operations" },
{ NULL, NULL, NULL }
};
#if defined(HAVE_SYS_TIMEX_H)
#define shim_timex timex
#else
struct shim_timex {
char data[128];
};
#endif
#if defined(HAVE_LIB_RT) && \
defined(HAVE_CLOCK_GETTIME) && \
defined(HAVE_CLOCK_SETTIME)
typedef struct {
const int id; /* Clock ID */
const char *name; /* Clock name */
} stress_clock_info_t;
#define CLOCK_INFO(x) { x, #x }
static const stress_clock_info_t clocks[] = {
#if defined(CLOCK_REALTIME)
CLOCK_INFO(CLOCK_REALTIME),
#endif
#if defined(CLOCK_REALTIME_COARSE)
CLOCK_INFO(CLOCK_REALTIME_COARSE),
#endif
#if defined(CLOCK_MONOTONIC)
CLOCK_INFO(CLOCK_MONOTONIC),
#endif
#if defined(CLOCK_MONOTONIC_RAW)
CLOCK_INFO(CLOCK_MONOTONIC_RAW),
#endif
#if defined(CLOCK_MONOTONIC_ACTIVE)
CLOCK_INFO(CLOCK_MONOTONIC_ACTIVE),
#endif
#if defined(CLOCK_BOOTTIME)
CLOCK_INFO(CLOCK_BOOTTIME),
#endif
#if defined(CLOCK_PROCESS_CPUTIME_ID)
CLOCK_INFO(CLOCK_PROCESS_CPUTIME_ID),
#endif
#if defined(CLOCK_THREAD_CPUTIME_ID)
CLOCK_INFO(CLOCK_THREAD_CPUTIME_ID),
#endif
#if defined(CLOCK_MONOTONIC_ACTIVE)
CLOCK_INFO(CLOCK_MONOTONIC_ACTIVE),
#endif
#if defined(CLOCK_TAI)
CLOCK_INFO(CLOCK_TAI)
#endif
};
#if defined(HAVE_CLOCK_NANOSLEEP)
static const int clocks_nanosleep[] = {
#if defined(CLOCK_REALTIME)
CLOCK_REALTIME,
#endif
#if defined(CLOCK_MONOTONIC)
CLOCK_MONOTONIC,
#endif
#if defined(CLOCK_THREAD_CPUTIME_ID)
CLOCK_THREAD_CPUTIME_ID
#endif
};
#endif
#if defined(HAVE_TIMER_CREATE) && \
defined(HAVE_TIMER_DELETE) && \
defined(HAVE_TIMER_GETTIME) && \
defined(HAVE_TIMER_GETOVERRUN) && \
defined(HAVE_TIMER_SETTIME)
static const int timers[] = {
#if defined(CLOCK_REALTIME)
CLOCK_REALTIME,
#endif
#if defined(CLOCK_MONOTONIC)
CLOCK_MONOTONIC,
#endif
#if defined(CLOCK_THREAD_CPUTIME_ID)
CLOCK_THREAD_CPUTIME_ID
#endif
};
#endif
#if defined(HAVE_CLOCK_NANOSLEEP) || \
(defined(HAVE_TIMER_CREATE) && \
defined(HAVE_TIMER_DELETE) && \
defined(HAVE_TIMER_GETTIME) && \
defined(HAVE_TIMER_GETOVERRUN) && \
defined(HAVE_TIMER_SETTIME))
/*
* stress_clock_name()
* clock id to name
*/
static const char *stress_clock_name(int id)
{
size_t i;
for (i = 0; i < SIZEOF_ARRAY(clocks); i++) {
if (clocks[i].id == id)
return clocks[i].name;
}
return "(unknown clock)";
}
#endif
#if (defined(__NR_clock_adjtime) && \
defined(HAVE_SYS_TIMEX_H) && \
defined(ADJ_SETOFFSET)) || \
(defined(HAVE_CLOCK_NANOSLEEP) && \
defined(TIMER_ABSTIME))
#define CHECK_INVALID_CLOCK_ID (1)
#endif
#if defined(CHECK_INVALID_CLOCK_ID)
/*
* check_invalid_clock_id()
* function to check if given clock_id is valid
*/
static inline bool check_invalid_clock_id(const clockid_t id) {
struct timespec tp;
(void)memset(&tp, 0, sizeof(tp));
return (clock_gettime(id, &tp) != 0);
}
#endif
#define FD_TO_CLOCKID(fd) ((~(clockid_t)(fd) << 3) | 3)
#if defined(__NR_clock_adjtime) && \
defined(HAVE_SYS_TIMEX_H) && \
defined(CLOCK_THREAD_CPUTIME_ID) && \
defined(ADJ_SETOFFSET)
/*
* shim_clock_adjtime
* wrapper for linux clock_adjtime system call
*/
static int shim_clock_adjtime(clockid_t clk_id, struct shim_timex *tx)
{
return (int)syscall(__NR_clock_adjtime, clk_id, tx);
}
#endif
/*
* stress_clock()
* stress system by rapid clocking system calls
*/
static int stress_clock(const stress_args_t *args)
{
/*
* Use same random number seed for each
* test run to ensure predictable repeatable
* 'random' sleep duration timings
*/
stress_mwc_set_seed(0xf238, 0x1872);
bool test_invalid_timespec = true;
const bool is_root = stress_check_capability(SHIM_CAP_IS_ROOT);
#if defined(CHECK_INVALID_CLOCK_ID)
const bool invalid_clock_id = check_invalid_clock_id(INT_MAX);
#endif
stress_set_proc_state(args->name, STRESS_STATE_RUN);
do {
#if defined(CLOCK_THREAD_CPUTIME_ID) && \
defined(HAVE_CLOCK_GETTIME) && \
defined(HAVE_CLOCK_SETTIME)
{
int ret;
struct timespec t;
/*
* Exercise setting local thread CPU timer
*/
ret = shim_clock_gettime(CLOCK_THREAD_CPUTIME_ID, &t);
if ((ret < 0) && (g_opt_flags & OPT_FLAGS_VERIFY) &&
(errno != EINVAL) && (errno != ENOSYS))
pr_fail("%s: clock_gettime failed for timer 'CLOCK_THREAD_CPUTIME_ID', errno=%d (%s)\n",
args->name, errno, strerror(errno));
/* Exercise clock_settime with illegal clockid */
(void)shim_clock_settime((clockid_t)-1, &t);
/*
* According to clock_settime(2), setting the timer
* CLOCK_THREAD_CPUTIME_ID is not possible on Linux.
* Try to set it and ignore the result because it will
* currently return -EINVAL, but it may not do so in the
* future.
*/
ret = clock_settime(CLOCK_THREAD_CPUTIME_ID, &t);
(void)ret;
}
#else
UNEXPECTED
#endif
#if defined(HAVE_CLOCK_GETRES)
{
size_t i;
struct timespec t;
/* Exercise clock_getres with illegal clockid */
(void)shim_clock_getres((clockid_t)-1, &t);
/* Exercise clock_gettime with illegal clockid */
(void)shim_clock_gettime((clockid_t)-1, &t);
/*
* Exercise clock_getres and clock_gettime for each clock
*/
for (i = 0; i < SIZEOF_ARRAY(clocks); i++) {
int ret;
ret = shim_clock_getres(clocks[i].id, &t);
if ((ret < 0) && (g_opt_flags & OPT_FLAGS_VERIFY) &&
(errno != EINVAL) && (errno != ENOSYS))
pr_fail("%s: clock_getres failed for timer '%s', errno=%d (%s)\n",
args->name, clocks[i].name, errno, strerror(errno));
ret = shim_clock_gettime(clocks[i].id, &t);
if ((ret < 0) && (g_opt_flags & OPT_FLAGS_VERIFY) &&
(errno != EINVAL) && (errno != ENOSYS))
pr_fail("%s: clock_gettime failed for timer '%s', errno=%d (%s)\n",
args->name, clocks[i].name, errno, strerror(errno));
}
}
#else
UNEXPECTED
#endif
#if defined(HAVE_CLOCK_GETTIME) && \
defined(HAVE_CLOCK_SETTIME)
if (test_invalid_timespec) {
size_t i;
for (i = 0; i < SIZEOF_ARRAY(clocks); i++) {
struct timespec t, t1;
int ret;
/* Save current time to reset later if required */
ret = shim_clock_gettime(clocks[i].id, &t1);
if ((ret < 0) && (g_opt_flags & OPT_FLAGS_VERIFY) &&
(errno != EINVAL) && (errno != ENOSYS)) {
pr_fail("%s: clock_getres failed for timer '%s', errno=%d (%s)\n",
args->name, clocks[i].name, errno, strerror(errno));
}
if (ret < 0)
continue;
/* Ensuring clock_settime cannot succeed without privilege */
if (!is_root) {
ret = shim_clock_settime(clocks[i].id, &t1);
if (ret != -EPERM) {
/* This is an error, report it! */
pr_fail("%s: clock_settime failed, did not have privilege to "
"set time, expected -EPERM, instead got errno=%d (%s)\n",
args->name, errno, strerror(errno));
}
}
/*
* Exercise clock_settime with illegal tv sec
* and nsec values
*/
t.tv_sec = -1;
t.tv_nsec = -1;
/*
* Test only if time fields are invalid
* negative values (some systems may
* represent tv_* files as unsigned hence
* this sanity check)
*/
if ((t.tv_sec < 0) && (t.tv_nsec < 0)) { /* cppcheck-suppress knownConditionTrueFalse */
ret = shim_clock_settime(clocks[i].id, &t);
if (ret < 0)
continue;
/* Expected a failure, but it succeeded(!) */
pr_fail("%s: clock_settime was able to set an "
"invalid negative time for timer '%s'\n",
args->name, clocks[i].name);
/* Restore the correct time */
ret = shim_clock_settime(clocks[i].id, &t1);
if ((ret < 0) && (errno != EINVAL) && (errno != ENOSYS)) {
pr_fail("%s: clock_gettime failed for timer '%s', errno=%d (%s)\n",
args->name, clocks[i].name, errno, strerror(errno));
}
/*
* Ensuring invalid clock_settime runs
* only single time to minimize time lag
*/
test_invalid_timespec = false;
}
}
}
#else
UNEXPECTED
#endif
#if defined(HAVE_CLOCK_NANOSLEEP) && \
defined(TIMER_ABSTIME)
{
size_t i;
struct timespec t;
static int n = 0;
if (n++ >= 1024) {
n = 0;
int ret_st;
/* Exercise clock_nanosleep on invalid clock id */
if (invalid_clock_id) {
(void)memset(&t, 0, sizeof(t));
ret_st = clock_nanosleep(INT_MAX, TIMER_ABSTIME, &t, NULL);
(void)ret_st;
}
(void)memset(&t, 0, sizeof(t));
t.tv_sec = -1;
ret_st = clock_nanosleep(clocks_nanosleep[0], TIMER_ABSTIME, &t, NULL);
(void)ret_st;
(void)memset(&t, 0, sizeof(t));
t.tv_nsec = STRESS_NANOSECOND;
ret_st = clock_nanosleep(clocks_nanosleep[0], TIMER_ABSTIME, &t, NULL);
(void)ret_st;
}
/*
* Exercise clock_nanosleep for each clock
*/
for (i = 0; i < SIZEOF_ARRAY(clocks_nanosleep); i++) {
int ret;
t.tv_sec = 0;
t.tv_nsec = (stress_mwc32() % 2500) + 1;
/*
* Calling with TIMER_ABSTIME will force
* clock_nanosleep() to return immediately
*/
ret = clock_nanosleep(clocks_nanosleep[i], TIMER_ABSTIME, &t, NULL);
if ((ret < 0) && (g_opt_flags & OPT_FLAGS_VERIFY))
pr_fail("%s: clock_nanosleep failed for timer '%s', errno=%d (%s)\n",
args->name,
stress_clock_name(clocks_nanosleep[i]),
errno, strerror(errno));
}
}
#else
UNEXPECTED
#endif
#if defined(__NR_clock_adjtime) && \
defined(HAVE_SYS_TIMEX_H) && \
defined(CLOCK_THREAD_CPUTIME_ID) && \
defined(ADJ_SETOFFSET)
{
size_t i;
struct shim_timex tx;
/* Exercise clock_adjtime on invalid clock id */
if (invalid_clock_id) {
int ret_st;
(void)memset(&tx, 0, sizeof(tx));
ret_st = shim_clock_adjtime(INT_MAX, &tx);
(void)ret_st;
}
/*
* Exercise clock_adjtime
*/
for (i = 0; i < SIZEOF_ARRAY(clocks); i++) {
int ret;
(void)memset(&tx, 0, sizeof(tx));
tx.modes = ADJ_SETOFFSET;
tx.time.tv_sec = 0;
tx.time.tv_usec = 0;
ret = shim_clock_adjtime(clocks[i].id, &tx);
if ((ret < 0) && (g_opt_flags & OPT_FLAGS_VERIFY) &&
(errno != EINVAL) && (errno != ENOSYS) &&
(errno != EPERM) && (errno != EOPNOTSUPP)) {
pr_fail("%s: clock_adjtime failed for timer '%s', errno=%d (%s)\n",
args->name, clocks[i].name, errno, strerror(errno));
}
}
}
#else
UNEXPECTED
#endif
#if defined(HAVE_TIMER_CREATE) && \
defined(HAVE_TIMER_DELETE) && \
defined(HAVE_TIMER_GETTIME) && \
defined(HAVE_TIMER_GETOVERRUN) && \
defined(HAVE_TIMER_SETTIME)
{
size_t i;
const size_t n = SIZEOF_ARRAY(timers);
bool timer_fail[n];
timer_t timer_id[n];
struct itimerspec its;
int ret;
/*
* Stress the timers
*/
for (i = 0; i < n; i++) {
struct sigevent sevp;
timer_fail[i] = false;
timer_id[i] = (timer_t)-1;
(void)memset(&sevp, 0, sizeof(sevp));
sevp.sigev_notify = SIGEV_NONE;
ret = timer_create(timers[i], &sevp, &timer_id[i]);
if (ret < 0) {
timer_fail[i] = true;
if (g_opt_flags & OPT_FLAGS_VERIFY) {
if ((errno == EINVAL) || (errno == EPERM))
continue;
pr_fail("%s: timer_create failed for timer '%s', errno=%d (%s)\n",
args->name,
stress_clock_name(timers[i]),
errno, strerror(errno));
}
continue;
}
/* One shot mode, for random time 0..5000 ns */
its.it_value.tv_sec = 0;
its.it_value.tv_nsec = (stress_mwc32() % 5000) + 1;
its.it_interval.tv_sec = 0;
its.it_interval.tv_nsec = 0;
ret = timer_settime(timer_id[i], 0, &its, NULL);
if ((ret < 0) && (g_opt_flags & OPT_FLAGS_VERIFY)) {
pr_fail("%s: timer_settime failed for timer '%s', errno=%d (%s)\n",
args->name,
stress_clock_name(timers[i]),
errno, strerror(errno));
}
}
for (i = 0; i < n; i++) {
if (timer_fail[i] || (timer_id[i] == (timer_t)-1))
continue;
ret = timer_gettime(timer_id[i], &its);
if ((ret < 0) && (g_opt_flags & OPT_FLAGS_VERIFY)) {
pr_fail("%s: timer_gettime failed for timer '%s', errno=%d (%s)\n",
args->name,
stress_clock_name(timers[i]),
errno, strerror(errno));
break;
}
ret = timer_getoverrun(timer_id[i]);
(void)ret;
}
for (i = 0; i < n; i++) {
if (timer_fail[i] || (timer_id[i] == (timer_t)-1))
continue;
ret = timer_delete(timer_id[i]);
if ((ret < 0) && (g_opt_flags & OPT_FLAGS_VERIFY)) {
pr_fail("%s: timer_delete failed for timer '%s', errno=%d (%s)\n",
args->name,
stress_clock_name(timers[i]),
errno, strerror(errno));
break;
}
}
}
#else
UNEXPECTED
#endif
#if defined(__linux__)
{
int fd;
fd = open("/dev/ptp0", O_RDWR);
if (fd >= 0) {
struct timespec t;
int ret, clkid = FD_TO_CLOCKID(fd);
#if defined(HAVE_POLL_H)
struct pollfd pollfds[1];
pollfds[0].fd = fd;
pollfds[0].events = POLLIN;
pollfds[0].revents = 0;
ret = poll(pollfds, 1, 0);
(void)ret;
#else
UNEXPECTED
#endif
ret = clock_gettime(clkid, &t);
if ((ret < 0) && (g_opt_flags & OPT_FLAGS_VERIFY) &&
(errno != EINVAL) && (errno != ENOSYS)) {
pr_fail("%s: clock_gettime failed for /dev/ptp0, errno=%d (%s)",
args->name, errno, strerror(errno));
}
#if defined(HAVE_CLOCK_GETRES)
ret = shim_clock_getres(clkid, &t);
if ((ret < 0) && (g_opt_flags & OPT_FLAGS_VERIFY) &&
(errno != EINVAL) && (errno != ENOSYS)) {
pr_fail("%s: clock_getres failed for /dev/ptp0, errno=%d (%s)",
args->name, errno, strerror(errno));
}
#else
UNEXPECTED
#endif
(void)close(fd);
}
}
#endif
inc_counter(args);
} while (keep_stressing(args));
stress_set_proc_state(args->name, STRESS_STATE_DEINIT);
return EXIT_SUCCESS;
}
stressor_info_t stress_clock_info = {
.stressor = stress_clock,
.class = CLASS_INTERRUPT | CLASS_OS,
.verify = VERIFY_OPTIONAL,
.help = help
};
#else
stressor_info_t stress_clock_info = {
.stressor = stress_not_implemented,
.class = CLASS_INTERRUPT | CLASS_OS,
.help = help
};
#endif
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/hoperun_harmony/stress-ng.git
[email protected]:hoperun_harmony/stress-ng.git
hoperun_harmony
stress-ng
stress-ng
master

搜索帮助