mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 01:32:21 +02:00
RTLA patches for v7.2
- Fix discrepancy in --dump-tasks option Due to a mistake, rtla-timerlat-hist used the CLI syntax "--dump-task" instead of the documented "--dump-tasks". Change the option to match both documentation and the other timerlat tool, rtla-timerlat-top. - Extend coverage of runtime tests Cover both top and hist tools in all applicable test cases, add tests for a few uncovered options, and extend checks for some existing tests. - Add unit tests for actions rtla's actions feature is implemented in its source file and contains non-trivial parsing logic. Cover it with unit tests. - Stop record trace on interrupt Fix a bug where an interval exists after receiving a signal in which the main instance is stopped but the record instance is not, leading to discrepancies in reported results and sometimes rtla hanging. - Restore continue flag in actions_perform() Fix a bug where rtla always continues tracing after hitting a threshold even if the continue action was triggered just once, and add tests verifying that the flag is reset properly. - Migrate command line interface to libsubcmd Replace rtla's argument parsing using getopt_long() with libsubcmd, used by perf and objtool, to reuse existing code and auto-generate better help messages. Extensive unit tests are included to detect regressions. - Add -A/--aligned option to timerlat tools Add an option to align timerlat threads, based on the recently introduced TIMERLAT_ALIGN option of the timerlat tracer, together with unit tests and documentation. - Document tests in README Document how to run unit and runtime tests in rtla's README.txt, including the dependencies needed to run them. -----BEGIN PGP SIGNATURE----- iIoEABYKADIWIQRRSw7ePDh/lE+zeZMp5XQQmuv6qgUCajBedhQccm9zdGVkdEBn b29kbWlzLm9yZwAKCRAp5XQQmuv6qoCyAQCdWOebZIJmDbuIPaJFXNlpF0JWg6ly /1fHtM/TXA9l3gD+P4RrfWqwNzk1B1/jOfTma6kpIVW3rIWE+Kts1X3Dswk= =4CXs -----END PGP SIGNATURE----- Merge tag 'trace-tools-v7.2' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace Pull RTLA tool updates from Steven Rostedt: - Fix discrepancy in --dump-tasks option Due to a mistake, rtla-timerlat-hist used the CLI syntax "--dump-task" instead of the documented "--dump-tasks". Change the option to match both documentation and the other timerlat tool, rtla-timerlat-top. - Extend coverage of runtime tests Cover both top and hist tools in all applicable test cases, add tests for a few uncovered options, and extend checks for some existing tests. - Add unit tests for actions rtla's actions feature is implemented in its source file and contains non-trivial parsing logic. Cover it with unit tests. - Stop record trace on interrupt Fix a bug where an interval exists after receiving a signal in which the main instance is stopped but the record instance is not, leading to discrepancies in reported results and sometimes rtla hanging. - Restore continue flag in actions_perform() Fix a bug where rtla always continues tracing after hitting a threshold even if the continue action was triggered just once, and add tests verifying that the flag is reset properly. - Migrate command line interface to libsubcmd Replace rtla's argument parsing using getopt_long() with libsubcmd, used by perf and objtool, to reuse existing code and auto-generate better help messages. Extensive unit tests are included to detect regressions. - Add -A/--aligned option to timerlat tools Add an option to align timerlat threads, based on the recently introduced TIMERLAT_ALIGN option of the timerlat tracer, together with unit tests and documentation. - Document tests in README Document how to run unit and runtime tests in rtla's README.txt, including the dependencies needed to run them. * tag 'trace-tools-v7.2' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace: (26 commits) rtla: Document tests in README Documentation/rtla: Add -A/--aligned option rtla/tests: Add unit tests for -A/--aligned option rtla/timerlat: Add -A/--aligned CLI option rtla/tests: Add unit tests for CLI option callbacks rtla/tests: Add unit tests for _parse_args() functions rtla: Parse cmdline using libsubcmd tools subcmd: allow parsing distinct --opt and --no-opt tools subcmd: support optarg as separate argument rtla: Add libsubcmd dependency rtla/tests: Add runtime tests for restoring continue flag rtla/tests: Run runtime tests in temporary directory rtla/tests: Add unit test for restoring continue flag rtla/actions: Restore continue flag in actions_perform() rtla: Stop the record trace on interrupt rtla/tests: Add unit tests for actions module rtla/tests: Add runtime tests for -C/--cgroup rtla/tests: Add runtime test for -k and -u options rtla/tests: Add runtime test for -H/--house-keeping rtla/tests: Cover all hist options in runtime tests ...
This commit is contained in:
commit
6b5a2b7d9b
|
|
@ -26,9 +26,10 @@ EXIT STATUS
|
|||
|
||||
::
|
||||
|
||||
0 Passed: the test did not hit the stop tracing condition
|
||||
1 Error: invalid argument
|
||||
2 Failed: the test hit the stop tracing condition
|
||||
0 Passed: the test did not hit the stop tracing condition
|
||||
1 Error: invalid argument
|
||||
2 Failed: the test hit the stop tracing condition
|
||||
129 Help: either user requested help or incorrect option was specified
|
||||
|
||||
REPORTING BUGS
|
||||
==============
|
||||
|
|
|
|||
|
|
@ -95,3 +95,14 @@
|
|||
* **full** Print the entire stack trace, including unknown addresses.
|
||||
|
||||
For unknown addresses, the raw pointer is printed.
|
||||
|
||||
**-A**, **--aligned** *us*
|
||||
|
||||
Align wake-up of timerlat threads to a set offset in microseconds.
|
||||
|
||||
The alignment will be applied when the threads wake up at the start of tracing while
|
||||
the timer for the first cycle is armed. Each thread sets its timer to the wake-up time
|
||||
of the previous thread plus the alignment.
|
||||
|
||||
This option may be used with any non-negative argument, including zero, which will
|
||||
align threads so that they wake up all at the same time.
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@ static int get_value(struct parse_opt_ctx_t *p,
|
|||
const char *s, *arg = NULL;
|
||||
const int unset = flags & OPT_UNSET;
|
||||
int err;
|
||||
bool force_defval = false;
|
||||
|
||||
if (unset && p->opt)
|
||||
return opterror(opt, "takes no value", flags);
|
||||
|
|
@ -123,6 +124,42 @@ static int get_value(struct parse_opt_ctx_t *p,
|
|||
}
|
||||
}
|
||||
|
||||
if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
|
||||
if (!(p->flags & PARSE_OPT_OPTARG_ALLOW_NEXT)) {
|
||||
/*
|
||||
* If the option has an optional argument, and the argument is not
|
||||
* provided in the option itself, do not attempt to get it from
|
||||
* the next argument, unless PARSE_OPT_OPTARG_ALLOW_NEXT is set.
|
||||
*
|
||||
* This prevents a non-option argument from being interpreted as an
|
||||
* optional argument of a preceding option, for example:
|
||||
*
|
||||
* $ cmd --opt val
|
||||
* -> is "val" argument of "--opt" or a separate non-option
|
||||
* argument?
|
||||
*
|
||||
* With PARSE_OPT_OPTARG_ALLOW_NEXT, "val" is interpreted as
|
||||
* the argument of "--opt", i.e. the same as "--opt=val".
|
||||
* Without PARSE_OPT_OPTARG_ALLOW_NEXT, --opt is interpreted
|
||||
* as having the default value, and "val" as a separate non-option
|
||||
* argument.
|
||||
*
|
||||
* PARSE_OPT_OPTARG_ALLOW_NEXT is useful for commands that take no
|
||||
* non-option arguments and want to allow more flexibility in
|
||||
* optional argument passing.
|
||||
*/
|
||||
force_defval = true;
|
||||
}
|
||||
|
||||
if (p->argc <= 1 || p->argv[1][0] == '-') {
|
||||
/*
|
||||
* If next argument is an option or does not exist,
|
||||
* use the default value.
|
||||
*/
|
||||
force_defval = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (opt->flags & PARSE_OPT_NOBUILD) {
|
||||
char reason[128];
|
||||
bool noarg = false;
|
||||
|
|
@ -148,7 +185,7 @@ static int get_value(struct parse_opt_ctx_t *p,
|
|||
noarg = true;
|
||||
if (opt->flags & PARSE_OPT_NOARG)
|
||||
noarg = true;
|
||||
if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
|
||||
if (force_defval)
|
||||
noarg = true;
|
||||
|
||||
switch (opt->type) {
|
||||
|
|
@ -212,7 +249,7 @@ static int get_value(struct parse_opt_ctx_t *p,
|
|||
err = 0;
|
||||
if (unset)
|
||||
*(const char **)opt->value = NULL;
|
||||
else if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
|
||||
else if (force_defval)
|
||||
*(const char **)opt->value = (const char *)opt->defval;
|
||||
else
|
||||
err = get_arg(p, opt, flags, (const char **)opt->value);
|
||||
|
|
@ -244,7 +281,7 @@ static int get_value(struct parse_opt_ctx_t *p,
|
|||
return (*opt->callback)(opt, NULL, 1) ? (-1) : 0;
|
||||
if (opt->flags & PARSE_OPT_NOARG)
|
||||
return (*opt->callback)(opt, NULL, 0) ? (-1) : 0;
|
||||
if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
|
||||
if (force_defval)
|
||||
return (*opt->callback)(opt, NULL, 0) ? (-1) : 0;
|
||||
if (get_arg(p, opt, flags, &arg))
|
||||
return -1;
|
||||
|
|
@ -255,7 +292,7 @@ static int get_value(struct parse_opt_ctx_t *p,
|
|||
*(int *)opt->value = 0;
|
||||
return 0;
|
||||
}
|
||||
if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
|
||||
if (force_defval) {
|
||||
*(int *)opt->value = opt->defval;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -271,7 +308,7 @@ static int get_value(struct parse_opt_ctx_t *p,
|
|||
*(unsigned int *)opt->value = 0;
|
||||
return 0;
|
||||
}
|
||||
if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
|
||||
if (force_defval) {
|
||||
*(unsigned int *)opt->value = opt->defval;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -289,7 +326,7 @@ static int get_value(struct parse_opt_ctx_t *p,
|
|||
*(long *)opt->value = 0;
|
||||
return 0;
|
||||
}
|
||||
if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
|
||||
if (force_defval) {
|
||||
*(long *)opt->value = opt->defval;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -305,7 +342,7 @@ static int get_value(struct parse_opt_ctx_t *p,
|
|||
*(unsigned long *)opt->value = 0;
|
||||
return 0;
|
||||
}
|
||||
if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
|
||||
if (force_defval) {
|
||||
*(unsigned long *)opt->value = opt->defval;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -321,7 +358,7 @@ static int get_value(struct parse_opt_ctx_t *p,
|
|||
*(u64 *)opt->value = 0;
|
||||
return 0;
|
||||
}
|
||||
if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
|
||||
if (force_defval) {
|
||||
*(u64 *)opt->value = opt->defval;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -390,7 +427,8 @@ static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg,
|
|||
return 0;
|
||||
}
|
||||
if (!rest) {
|
||||
if (strstarts(options->long_name, "no-")) {
|
||||
if (strstarts(options->long_name, "no-") &&
|
||||
!(options->flags & PARSE_OPT_NOAUTONEG)) {
|
||||
/*
|
||||
* The long name itself starts with "no-", so
|
||||
* accept the option without "no-" so that users
|
||||
|
|
@ -428,12 +466,12 @@ static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg,
|
|||
continue;
|
||||
}
|
||||
/* negated and abbreviated very much? */
|
||||
if (strstarts("no-", arg)) {
|
||||
if (strstarts("no-", arg) && !(options->flags & PARSE_OPT_NOAUTONEG)) {
|
||||
flags |= OPT_UNSET;
|
||||
goto is_abbreviated;
|
||||
}
|
||||
/* negated? */
|
||||
if (strncmp(arg, "no-", 3))
|
||||
if (strncmp(arg, "no-", 3) || (options->flags & PARSE_OPT_NOAUTONEG))
|
||||
continue;
|
||||
flags |= OPT_UNSET;
|
||||
rest = skip_prefix(arg + 3, options->long_name);
|
||||
|
|
@ -982,7 +1020,8 @@ int parse_options_usage(const char * const *usagestr,
|
|||
if (strstarts(opts->long_name, optstr))
|
||||
print_option_help(opts, 0);
|
||||
if (strstarts("no-", optstr) &&
|
||||
strstarts(opts->long_name, optstr + 3))
|
||||
strstarts(opts->long_name, optstr + 3) &&
|
||||
!(opts->flags & PARSE_OPT_NOAUTONEG))
|
||||
print_option_help(opts, 0);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ enum parse_opt_flags {
|
|||
PARSE_OPT_KEEP_ARGV0 = 4,
|
||||
PARSE_OPT_KEEP_UNKNOWN = 8,
|
||||
PARSE_OPT_NO_INTERNAL_HELP = 16,
|
||||
PARSE_OPT_OPTARG_ALLOW_NEXT = 32,
|
||||
};
|
||||
|
||||
enum parse_opt_option_flags {
|
||||
|
|
@ -46,6 +47,7 @@ enum parse_opt_option_flags {
|
|||
PARSE_OPT_NOEMPTY = 128,
|
||||
PARSE_OPT_NOBUILD = 256,
|
||||
PARSE_OPT_CANSKIP = 512,
|
||||
PARSE_OPT_NOAUTONEG = 1024,
|
||||
};
|
||||
|
||||
struct option;
|
||||
|
|
@ -148,6 +150,8 @@ struct option {
|
|||
{ .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), .argh = "time", .help = (h), .callback = parse_opt_approxidate_cb }
|
||||
#define OPT_CALLBACK(s, l, v, a, h, f) \
|
||||
{ .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), .argh = (a), .help = (h), .callback = (f) }
|
||||
#define OPT_CALLBACK_FLAG(s, l, v, a, h, f, fl) \
|
||||
{ .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), .argh = (a), .help = (h), .callback = (f), .flags = (fl) }
|
||||
#define OPT_CALLBACK_SET(s, l, v, os, a, h, f) \
|
||||
{ .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), .argh = (a), .help = (h), .callback = (f), .set = check_vtype(os, bool *)}
|
||||
#define OPT_CALLBACK_NOOPT(s, l, v, a, h, f) \
|
||||
|
|
|
|||
3
tools/tracing/rtla/.gitignore
vendored
3
tools/tracing/rtla/.gitignore
vendored
|
|
@ -1,6 +1,7 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
rtla
|
||||
rtla-static
|
||||
unit_tests
|
||||
fixdep
|
||||
feature
|
||||
FEATURE-DUMP
|
||||
|
|
@ -9,3 +10,5 @@ custom_filename.txt
|
|||
osnoise_irq_noise_hist.txt
|
||||
osnoise_trace.txt
|
||||
timerlat_trace.txt
|
||||
libsubcmd/
|
||||
lib/
|
||||
|
|
|
|||
|
|
@ -27,6 +27,30 @@ endif
|
|||
RTLA := $(OUTPUT)rtla
|
||||
RTLA_IN := $(RTLA)-in.o
|
||||
|
||||
LIBSUBCMD_DIR = $(srctree)/tools/lib/subcmd/
|
||||
ifneq ($(OUTPUT),)
|
||||
LIBSUBCMD_OUTPUT = $(abspath $(OUTPUT))/libsubcmd
|
||||
else
|
||||
LIBSUBCMD_OUTPUT = $(CURDIR)/libsubcmd
|
||||
endif
|
||||
LIBSUBCMD = $(LIBSUBCMD_OUTPUT)/libsubcmd.a
|
||||
LIBSUBCMD_INCLUDES = $(LIBSUBCMD_OUTPUT)/include
|
||||
LIBSUBCMD_MAKEFLAGS = O=$(LIBSUBCMD_OUTPUT) DESTDIR=$(LIBSUBCMD_OUTPUT) prefix= subdir=
|
||||
|
||||
TOOLS_INCLUDES = -I$(srctree)/tools/include
|
||||
|
||||
ifneq ($(OUTPUT),)
|
||||
LIB_OUTPUT = $(abspath $(OUTPUT))/lib
|
||||
else
|
||||
LIB_OUTPUT = $(CURDIR)/lib
|
||||
endif
|
||||
|
||||
LIB_STRING = $(LIB_OUTPUT)/string.o
|
||||
LIB_STRING_SRC = $(srctree)/tools/lib/string.c
|
||||
|
||||
LIB_STR_ERROR_R = $(LIB_OUTPUT)/str_error_r.o
|
||||
LIB_STR_ERROR_R_SRC = $(srctree)/tools/lib/str_error_r.c
|
||||
|
||||
VERSION := $(shell sh -c "make -sC ../../.. kernelversion | grep -v make")
|
||||
DOCSRC := ../../../Documentation/tools/rtla/
|
||||
|
||||
|
|
@ -66,7 +90,7 @@ ifeq ($(config),1)
|
|||
include Makefile.config
|
||||
endif
|
||||
|
||||
CFLAGS += $(INCLUDES) $(LIB_INCLUDES)
|
||||
CFLAGS += $(INCLUDES) $(LIB_INCLUDES) $(TOOLS_INCLUDES) -I$(LIBSUBCMD_INCLUDES)
|
||||
|
||||
export CFLAGS OUTPUT srctree
|
||||
|
||||
|
|
@ -93,20 +117,48 @@ tests/bpf/bpf_action_map.o: tests/bpf/bpf_action_map.c
|
|||
$(Q)echo "BPF skeleton support is disabled, skipping tests/bpf/bpf_action_map.o"
|
||||
endif
|
||||
|
||||
$(RTLA): $(RTLA_IN)
|
||||
$(QUIET_LINK)$(CC) $(LDFLAGS) -o $(RTLA) $(RTLA_IN) $(EXTLIBS)
|
||||
$(RTLA): $(RTLA_IN) $(LIBSUBCMD) $(LIB_STRING) $(LIB_STR_ERROR_R)
|
||||
$(QUIET_LINK)$(CC) $(LDFLAGS) -o $(RTLA) $(RTLA_IN) $(LIBSUBCMD) $(LIB_STRING) $(LIB_STR_ERROR_R) $(EXTLIBS)
|
||||
|
||||
static: $(RTLA_IN)
|
||||
static: $(RTLA_IN) $(LIBSUBCMD) $(LIB_STRING) $(LIB_STR_ERROR_R)
|
||||
$(eval LDFLAGS += -static)
|
||||
$(QUIET_LINK)$(CC) -static $(LDFLAGS) -o $(RTLA)-static $(RTLA_IN) $(EXTLIBS)
|
||||
$(QUIET_LINK)$(CC) -static $(LDFLAGS) -o $(RTLA)-static $(RTLA_IN) $(LIBSUBCMD) $(LIB_STRING) $(LIB_STR_ERROR_R) $(EXTLIBS)
|
||||
|
||||
rtla.%: fixdep FORCE
|
||||
make -f $(srctree)/tools/build/Makefile.build dir=. $@
|
||||
|
||||
$(RTLA_IN): fixdep FORCE src/timerlat.skel.h
|
||||
$(RTLA_IN): fixdep FORCE src/timerlat.skel.h $(LIBSUBCMD_INCLUDES)
|
||||
make $(build)=rtla
|
||||
|
||||
clean: doc_clean fixdep-clean
|
||||
$(LIBSUBCMD_OUTPUT):
|
||||
$(Q)$(MKDIR) -p $@
|
||||
|
||||
$(LIBSUBCMD_INCLUDES): FORCE | $(LIBSUBCMD_OUTPUT)
|
||||
$(Q)$(MAKE) -C $(LIBSUBCMD_DIR) $(LIBSUBCMD_MAKEFLAGS) \
|
||||
install_headers
|
||||
|
||||
$(LIBSUBCMD): FORCE | $(LIBSUBCMD_OUTPUT)
|
||||
$(Q)$(MAKE) -C $(LIBSUBCMD_DIR) $(LIBSUBCMD_MAKEFLAGS) \
|
||||
$@
|
||||
|
||||
$(LIB_OUTPUT):
|
||||
$(Q)$(MKDIR) -p $@
|
||||
|
||||
$(LIB_STR_ERROR_R): $(LIB_STR_ERROR_R_SRC) | $(LIB_OUTPUT)
|
||||
$(QUIET_CC)$(CC) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
$(LIB_STRING): $(LIB_STRING_SRC) | $(LIB_OUTPUT)
|
||||
$(QUIET_CC)$(CC) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
libsubcmd-clean:
|
||||
$(call QUIET_CLEAN, libsubcmd)
|
||||
$(Q)$(RM) -r -- $(LIBSUBCMD_OUTPUT)
|
||||
|
||||
lib-clean:
|
||||
$(call QUIET_CLEAN, lib)
|
||||
$(Q)$(RM) -r -- $(LIB_OUTPUT)
|
||||
|
||||
clean: doc_clean fixdep-clean libsubcmd-clean lib-clean
|
||||
$(call QUIET_CLEAN, rtla)
|
||||
$(Q)find . -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete
|
||||
$(Q)rm -f rtla rtla-static fixdep FEATURE-DUMP rtla-*
|
||||
|
|
|
|||
|
|
@ -42,4 +42,34 @@ For development, we suggest the following steps for compiling rtla:
|
|||
$ make
|
||||
$ sudo make install
|
||||
|
||||
Running tests
|
||||
|
||||
RTLA has two test suites: a runtime test suite and a unit test suite.
|
||||
|
||||
The runtime test suite is available as "make check" (root required) and has
|
||||
the following dependencies, in addition to RTLA build dependencies:
|
||||
|
||||
- Perl
|
||||
- Test::Harness (libtest-harness-perl on Debian/Ubuntu, perl-Test-Harness on Fedora/RHEL)
|
||||
- bash
|
||||
- coreutils
|
||||
- ldd
|
||||
- util-linux
|
||||
- procps(-ng)
|
||||
- bpftool (if rtla is built against libbpf)
|
||||
|
||||
as well as the following required system configuration:
|
||||
|
||||
- CONFIG_OSNOISE_TRACER=y
|
||||
- CONFIG_TIMERLAT_TRACER=y
|
||||
- tracefs mounted and readable at /sys/kernel/tracing
|
||||
|
||||
The unit test suite is available as "make unit-tests" and has the following
|
||||
dependencies:
|
||||
|
||||
- libcheck
|
||||
|
||||
Unlike the runtime test suite, root is not required to run unit tests, nor is
|
||||
a tracefs/osnoise/timerlat-capable kernel required.
|
||||
|
||||
For further information, please refer to the rtla man page.
|
||||
|
|
|
|||
|
|
@ -11,4 +11,4 @@ rtla-y += timerlat_hist.o
|
|||
rtla-y += timerlat_u.o
|
||||
rtla-y += timerlat_aa.o
|
||||
rtla-y += timerlat_bpf.o
|
||||
rtla-y += rtla.o
|
||||
rtla-y += cli.o
|
||||
|
|
|
|||
|
|
@ -247,6 +247,8 @@ actions_perform(struct actions *self)
|
|||
int pid, retval;
|
||||
const struct action *action;
|
||||
|
||||
self->continue_flag = false;
|
||||
|
||||
for_each_action(self, action) {
|
||||
switch (action->type) {
|
||||
case ACTION_TRACE_OUTPUT:
|
||||
|
|
|
|||
539
tools/tracing/rtla/src/cli.c
Normal file
539
tools/tracing/rtla/src/cli.c
Normal file
|
|
@ -0,0 +1,539 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2021 Red Hat Inc, Daniel Bristot de Oliveira <bristot@kernel.org>
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <linux/compiler.h>
|
||||
|
||||
#define RTLA_ALLOW_CLI_P_H
|
||||
#include "cli_p.h"
|
||||
|
||||
static const char * const osnoise_top_usage[] = {
|
||||
"rtla osnoise [top] [<options>] [-h|--help]",
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const char * const osnoise_hist_usage[] = {
|
||||
"rtla osnoise hist [<options>] [-h|--help]",
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const char * const timerlat_top_usage[] = {
|
||||
"rtla timerlat [top] [<options>] [-h|--help]",
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const char * const timerlat_hist_usage[] = {
|
||||
"rtla timerlat hist [<options>] [-h|--help]",
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const char * const hwnoise_usage[] = {
|
||||
"rtla hwnoise [<options>] [-h|--help]",
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const int common_parse_options_flags = PARSE_OPT_OPTARG_ALLOW_NEXT;
|
||||
|
||||
bool in_unit_test;
|
||||
|
||||
/*
|
||||
* osnoise_top_parse_args - allocs, parse and fill the cmd line parameters
|
||||
*/
|
||||
struct common_params *osnoise_top_parse_args(int argc, char **argv)
|
||||
{
|
||||
struct osnoise_params *params;
|
||||
struct osnoise_cb_data cb_data;
|
||||
const char * const *usage;
|
||||
|
||||
params = calloc_fatal(1, sizeof(*params));
|
||||
|
||||
cb_data.params = params;
|
||||
cb_data.trace_output = NULL;
|
||||
|
||||
if (strcmp(argv[0], "hwnoise") == 0) {
|
||||
params->mode = MODE_HWNOISE;
|
||||
/*
|
||||
* Reduce CPU usage for 75% to avoid killing the system.
|
||||
*/
|
||||
params->runtime = 750000;
|
||||
params->period = 1000000;
|
||||
usage = hwnoise_usage;
|
||||
} else {
|
||||
usage = osnoise_top_usage;
|
||||
}
|
||||
|
||||
const struct option osnoise_top_options[] = {
|
||||
OPT_GROUP("Tracing Options:"),
|
||||
OSNOISE_OPT_PERIOD,
|
||||
OSNOISE_OPT_RUNTIME,
|
||||
RTLA_OPT_STOP('s', "stop", "single sample"),
|
||||
RTLA_OPT_STOP_TOTAL('S', "stop-total", "total sample"),
|
||||
OSNOISE_OPT_THRESHOLD,
|
||||
RTLA_OPT_TRACE_OUTPUT("osnoise", opt_osnoise_trace_output_cb),
|
||||
|
||||
OPT_GROUP("Event Configuration:"),
|
||||
RTLA_OPT_EVENT,
|
||||
RTLA_OPT_FILTER,
|
||||
RTLA_OPT_TRIGGER,
|
||||
|
||||
OPT_GROUP("CPU Configuration:"),
|
||||
RTLA_OPT_CPUS,
|
||||
RTLA_OPT_HOUSEKEEPING,
|
||||
|
||||
OPT_GROUP("Thread Configuration:"),
|
||||
RTLA_OPT_PRIORITY,
|
||||
RTLA_OPT_CGROUP,
|
||||
|
||||
OPT_GROUP("Output:"),
|
||||
RTLA_OPT_QUIET,
|
||||
|
||||
OPT_GROUP("System Tuning:"),
|
||||
RTLA_OPT_TRACE_BUFFER_SIZE,
|
||||
RTLA_OPT_WARM_UP,
|
||||
|
||||
OPT_GROUP("Auto Analysis and Actions:"),
|
||||
RTLA_OPT_AUTO(opt_osnoise_auto_cb),
|
||||
RTLA_OPT_ON_THRESHOLD("stop-total", opt_osnoise_on_threshold_cb),
|
||||
RTLA_OPT_ON_END(opt_osnoise_on_end_cb),
|
||||
|
||||
OPT_GROUP("General:"),
|
||||
RTLA_OPT_DURATION,
|
||||
RTLA_OPT_DEBUG,
|
||||
|
||||
OPT_END(),
|
||||
};
|
||||
|
||||
actions_init(¶ms->common.threshold_actions);
|
||||
actions_init(¶ms->common.end_actions);
|
||||
|
||||
argc = parse_options(argc, (const char **)argv,
|
||||
osnoise_top_options,
|
||||
usage,
|
||||
common_parse_options_flags);
|
||||
if (argc < 0)
|
||||
return NULL;
|
||||
|
||||
if (cb_data.trace_output)
|
||||
actions_add_trace_output(¶ms->common.threshold_actions, cb_data.trace_output);
|
||||
|
||||
if (geteuid() && !in_unit_test)
|
||||
fatal("osnoise needs root permission");
|
||||
|
||||
return ¶ms->common;
|
||||
}
|
||||
|
||||
/*
|
||||
* osnoise_hist_parse_args - allocs, parse and fill the cmd line parameters
|
||||
*/
|
||||
struct common_params *osnoise_hist_parse_args(int argc, char **argv)
|
||||
{
|
||||
struct osnoise_params *params;
|
||||
struct osnoise_cb_data cb_data;
|
||||
|
||||
params = calloc_fatal(1, sizeof(*params));
|
||||
|
||||
cb_data.params = params;
|
||||
cb_data.trace_output = NULL;
|
||||
|
||||
const struct option osnoise_hist_options[] = {
|
||||
OPT_GROUP("Tracing Options:"),
|
||||
OSNOISE_OPT_PERIOD,
|
||||
OSNOISE_OPT_RUNTIME,
|
||||
RTLA_OPT_STOP('s', "stop", "single sample"),
|
||||
RTLA_OPT_STOP_TOTAL('S', "stop-total", "total sample"),
|
||||
OSNOISE_OPT_THRESHOLD,
|
||||
RTLA_OPT_TRACE_OUTPUT("osnoise", opt_osnoise_trace_output_cb),
|
||||
|
||||
OPT_GROUP("Event Configuration:"),
|
||||
RTLA_OPT_EVENT,
|
||||
RTLA_OPT_FILTER,
|
||||
RTLA_OPT_TRIGGER,
|
||||
|
||||
OPT_GROUP("CPU Configuration:"),
|
||||
RTLA_OPT_CPUS,
|
||||
RTLA_OPT_HOUSEKEEPING,
|
||||
|
||||
OPT_GROUP("Thread Configuration:"),
|
||||
RTLA_OPT_PRIORITY,
|
||||
RTLA_OPT_CGROUP,
|
||||
|
||||
OPT_GROUP("Histogram Options:"),
|
||||
HIST_OPT_BUCKET_SIZE,
|
||||
HIST_OPT_ENTRIES,
|
||||
HIST_OPT_NO_HEADER,
|
||||
HIST_OPT_NO_SUMMARY,
|
||||
HIST_OPT_NO_INDEX,
|
||||
HIST_OPT_WITH_ZEROS,
|
||||
|
||||
OPT_GROUP("System Tuning:"),
|
||||
RTLA_OPT_TRACE_BUFFER_SIZE,
|
||||
RTLA_OPT_WARM_UP,
|
||||
|
||||
OPT_GROUP("Auto Analysis and Actions:"),
|
||||
RTLA_OPT_AUTO(opt_osnoise_auto_cb),
|
||||
RTLA_OPT_ON_THRESHOLD("stop-total", opt_osnoise_on_threshold_cb),
|
||||
RTLA_OPT_ON_END(opt_osnoise_on_end_cb),
|
||||
|
||||
OPT_GROUP("General:"),
|
||||
RTLA_OPT_DURATION,
|
||||
RTLA_OPT_DEBUG,
|
||||
|
||||
OPT_END(),
|
||||
};
|
||||
|
||||
actions_init(¶ms->common.threshold_actions);
|
||||
actions_init(¶ms->common.end_actions);
|
||||
|
||||
/* display data in microseconds */
|
||||
params->common.output_divisor = 1000;
|
||||
params->common.hist.bucket_size = 1;
|
||||
params->common.hist.entries = 256;
|
||||
|
||||
argc = parse_options(argc, (const char **)argv,
|
||||
osnoise_hist_options, osnoise_hist_usage,
|
||||
common_parse_options_flags);
|
||||
if (argc < 0)
|
||||
return NULL;
|
||||
|
||||
if (cb_data.trace_output)
|
||||
actions_add_trace_output(¶ms->common.threshold_actions, cb_data.trace_output);
|
||||
|
||||
if (geteuid() && !in_unit_test)
|
||||
fatal("rtla needs root permission");
|
||||
|
||||
if (params->common.hist.no_index && !params->common.hist.with_zeros)
|
||||
fatal("no-index set and with-zeros not set - it does not make sense");
|
||||
|
||||
return ¶ms->common;
|
||||
}
|
||||
|
||||
struct common_params *timerlat_top_parse_args(int argc, char **argv)
|
||||
{
|
||||
struct timerlat_params *params;
|
||||
struct timerlat_cb_data cb_data;
|
||||
|
||||
params = calloc_fatal(1, sizeof(*params));
|
||||
|
||||
cb_data.params = params;
|
||||
cb_data.trace_output = NULL;
|
||||
|
||||
const struct option timerlat_top_options[] = {
|
||||
OPT_GROUP("Tracing Options:"),
|
||||
TIMERLAT_OPT_PERIOD,
|
||||
RTLA_OPT_STOP('i', "irq", "irq latency"),
|
||||
RTLA_OPT_STOP_TOTAL('T', "thread", "thread latency"),
|
||||
TIMERLAT_OPT_STACK,
|
||||
RTLA_OPT_TRACE_OUTPUT("timerlat", opt_timerlat_trace_output_cb),
|
||||
|
||||
OPT_GROUP("Event Configuration:"),
|
||||
RTLA_OPT_EVENT,
|
||||
RTLA_OPT_FILTER,
|
||||
RTLA_OPT_TRIGGER,
|
||||
|
||||
OPT_GROUP("CPU Configuration:"),
|
||||
RTLA_OPT_CPUS,
|
||||
RTLA_OPT_HOUSEKEEPING,
|
||||
|
||||
OPT_GROUP("Thread Configuration:"),
|
||||
RTLA_OPT_PRIORITY,
|
||||
RTLA_OPT_CGROUP,
|
||||
RTLA_OPT_USER_THREADS,
|
||||
RTLA_OPT_KERNEL_THREADS,
|
||||
RTLA_OPT_USER_LOAD,
|
||||
TIMERLAT_OPT_ALIGNED,
|
||||
|
||||
OPT_GROUP("Output:"),
|
||||
TIMERLAT_OPT_NANO,
|
||||
RTLA_OPT_QUIET,
|
||||
|
||||
OPT_GROUP("System Tuning:"),
|
||||
TIMERLAT_OPT_DMA_LATENCY,
|
||||
TIMERLAT_OPT_DEEPEST_IDLE_STATE,
|
||||
RTLA_OPT_TRACE_BUFFER_SIZE,
|
||||
RTLA_OPT_WARM_UP,
|
||||
|
||||
OPT_GROUP("Auto Analysis and Actions:"),
|
||||
RTLA_OPT_AUTO(opt_timerlat_auto_cb),
|
||||
TIMERLAT_OPT_AA_ONLY,
|
||||
TIMERLAT_OPT_NO_AA,
|
||||
TIMERLAT_OPT_DUMPS_TASKS,
|
||||
RTLA_OPT_ON_THRESHOLD("latency", opt_timerlat_on_threshold_cb),
|
||||
RTLA_OPT_ON_END(opt_timerlat_on_end_cb),
|
||||
TIMERLAT_OPT_BPF_ACTION,
|
||||
TIMERLAT_OPT_STACK_FORMAT,
|
||||
|
||||
OPT_GROUP("General:"),
|
||||
RTLA_OPT_DURATION,
|
||||
RTLA_OPT_DEBUG,
|
||||
|
||||
OPT_END(),
|
||||
};
|
||||
|
||||
actions_init(¶ms->common.threshold_actions);
|
||||
actions_init(¶ms->common.end_actions);
|
||||
|
||||
/* disabled by default */
|
||||
params->dma_latency = -1;
|
||||
params->deepest_idle_state = -2;
|
||||
|
||||
/* display data in microseconds */
|
||||
params->common.output_divisor = 1000;
|
||||
|
||||
/* default to BPF mode */
|
||||
params->mode = TRACING_MODE_BPF;
|
||||
|
||||
/* default to truncate stack format */
|
||||
params->stack_format = STACK_FORMAT_TRUNCATE;
|
||||
|
||||
argc = parse_options(argc, (const char **)argv,
|
||||
timerlat_top_options, timerlat_top_usage,
|
||||
common_parse_options_flags);
|
||||
if (argc < 0)
|
||||
return NULL;
|
||||
|
||||
if (cb_data.trace_output)
|
||||
actions_add_trace_output(¶ms->common.threshold_actions, cb_data.trace_output);
|
||||
|
||||
if (geteuid() && !in_unit_test)
|
||||
fatal("rtla needs root permission");
|
||||
|
||||
/*
|
||||
* Auto analysis only happens if stop tracing, thus:
|
||||
*/
|
||||
if (!params->common.stop_us && !params->common.stop_total_us)
|
||||
params->no_aa = 1;
|
||||
|
||||
if (params->no_aa && params->common.aa_only)
|
||||
fatal("--no-aa and --aa-only are mutually exclusive!");
|
||||
|
||||
if (params->common.kernel_workload && params->common.user_workload)
|
||||
fatal("--kernel-threads and --user-threads are mutually exclusive!");
|
||||
|
||||
/*
|
||||
* If auto-analysis or trace output is enabled, switch from BPF mode to
|
||||
* mixed mode
|
||||
*/
|
||||
if (params->mode == TRACING_MODE_BPF &&
|
||||
(params->common.threshold_actions.present[ACTION_TRACE_OUTPUT] ||
|
||||
params->common.end_actions.present[ACTION_TRACE_OUTPUT] ||
|
||||
!params->no_aa))
|
||||
params->mode = TRACING_MODE_MIXED;
|
||||
|
||||
return ¶ms->common;
|
||||
}
|
||||
|
||||
struct common_params *timerlat_hist_parse_args(int argc, char **argv)
|
||||
{
|
||||
struct timerlat_params *params;
|
||||
struct timerlat_cb_data cb_data;
|
||||
|
||||
params = calloc_fatal(1, sizeof(*params));
|
||||
|
||||
cb_data.params = params;
|
||||
cb_data.trace_output = NULL;
|
||||
|
||||
const struct option timerlat_hist_options[] = {
|
||||
OPT_GROUP("Tracing Options:"),
|
||||
TIMERLAT_OPT_PERIOD,
|
||||
RTLA_OPT_STOP('i', "irq", "irq latency"),
|
||||
RTLA_OPT_STOP_TOTAL('T', "thread", "thread latency"),
|
||||
TIMERLAT_OPT_STACK,
|
||||
RTLA_OPT_TRACE_OUTPUT("timerlat", opt_timerlat_trace_output_cb),
|
||||
|
||||
OPT_GROUP("Event Configuration:"),
|
||||
RTLA_OPT_EVENT,
|
||||
RTLA_OPT_FILTER,
|
||||
RTLA_OPT_TRIGGER,
|
||||
|
||||
OPT_GROUP("CPU Configuration:"),
|
||||
RTLA_OPT_CPUS,
|
||||
RTLA_OPT_HOUSEKEEPING,
|
||||
|
||||
OPT_GROUP("Thread Configuration:"),
|
||||
RTLA_OPT_PRIORITY,
|
||||
RTLA_OPT_CGROUP,
|
||||
RTLA_OPT_USER_THREADS,
|
||||
RTLA_OPT_KERNEL_THREADS,
|
||||
RTLA_OPT_USER_LOAD,
|
||||
TIMERLAT_OPT_ALIGNED,
|
||||
|
||||
OPT_GROUP("Histogram Options:"),
|
||||
HIST_OPT_BUCKET_SIZE,
|
||||
HIST_OPT_ENTRIES,
|
||||
HIST_OPT_NO_IRQ,
|
||||
HIST_OPT_NO_THREAD,
|
||||
HIST_OPT_NO_HEADER,
|
||||
HIST_OPT_NO_SUMMARY,
|
||||
HIST_OPT_NO_INDEX,
|
||||
HIST_OPT_WITH_ZEROS,
|
||||
|
||||
OPT_GROUP("Output:"),
|
||||
TIMERLAT_OPT_NANO,
|
||||
|
||||
OPT_GROUP("System Tuning:"),
|
||||
TIMERLAT_OPT_DMA_LATENCY,
|
||||
TIMERLAT_OPT_DEEPEST_IDLE_STATE,
|
||||
RTLA_OPT_TRACE_BUFFER_SIZE,
|
||||
RTLA_OPT_WARM_UP,
|
||||
|
||||
OPT_GROUP("Auto Analysis and Actions:"),
|
||||
RTLA_OPT_AUTO(opt_timerlat_auto_cb),
|
||||
TIMERLAT_OPT_NO_AA,
|
||||
TIMERLAT_OPT_DUMPS_TASKS,
|
||||
RTLA_OPT_ON_THRESHOLD("latency", opt_timerlat_on_threshold_cb),
|
||||
RTLA_OPT_ON_END(opt_timerlat_on_end_cb),
|
||||
TIMERLAT_OPT_BPF_ACTION,
|
||||
TIMERLAT_OPT_STACK_FORMAT,
|
||||
|
||||
OPT_GROUP("General:"),
|
||||
RTLA_OPT_DURATION,
|
||||
RTLA_OPT_DEBUG,
|
||||
|
||||
OPT_END(),
|
||||
};
|
||||
|
||||
actions_init(¶ms->common.threshold_actions);
|
||||
actions_init(¶ms->common.end_actions);
|
||||
|
||||
/* disabled by default */
|
||||
params->dma_latency = -1;
|
||||
|
||||
/* disabled by default */
|
||||
params->deepest_idle_state = -2;
|
||||
|
||||
/* display data in microseconds */
|
||||
params->common.output_divisor = 1000;
|
||||
params->common.hist.bucket_size = 1;
|
||||
params->common.hist.entries = 256;
|
||||
|
||||
/* default to BPF mode */
|
||||
params->mode = TRACING_MODE_BPF;
|
||||
|
||||
/* default to truncate stack format */
|
||||
params->stack_format = STACK_FORMAT_TRUNCATE;
|
||||
|
||||
argc = parse_options(argc, (const char **)argv,
|
||||
timerlat_hist_options, timerlat_hist_usage,
|
||||
common_parse_options_flags);
|
||||
if (argc < 0)
|
||||
return NULL;
|
||||
|
||||
if (cb_data.trace_output)
|
||||
actions_add_trace_output(¶ms->common.threshold_actions, cb_data.trace_output);
|
||||
|
||||
if (geteuid() && !in_unit_test)
|
||||
fatal("rtla needs root permission");
|
||||
|
||||
if (params->common.hist.no_irq && params->common.hist.no_thread)
|
||||
fatal("no-irq and no-thread set, there is nothing to do here");
|
||||
|
||||
if (params->common.hist.no_index && !params->common.hist.with_zeros)
|
||||
fatal("no-index set with with-zeros is not set - it does not make sense");
|
||||
|
||||
/*
|
||||
* Auto analysis only happens if stop tracing, thus:
|
||||
*/
|
||||
if (!params->common.stop_us && !params->common.stop_total_us)
|
||||
params->no_aa = 1;
|
||||
|
||||
if (params->common.kernel_workload && params->common.user_workload)
|
||||
fatal("--kernel-threads and --user-threads are mutually exclusive!");
|
||||
|
||||
/*
|
||||
* If auto-analysis or trace output is enabled, switch from BPF mode to
|
||||
* mixed mode
|
||||
*/
|
||||
if (params->mode == TRACING_MODE_BPF &&
|
||||
(params->common.threshold_actions.present[ACTION_TRACE_OUTPUT] ||
|
||||
params->common.end_actions.present[ACTION_TRACE_OUTPUT] ||
|
||||
!params->no_aa))
|
||||
params->mode = TRACING_MODE_MIXED;
|
||||
|
||||
return ¶ms->common;
|
||||
}
|
||||
|
||||
/*
|
||||
* rtla_usage - print rtla usage
|
||||
*/
|
||||
__noreturn static void rtla_usage(int err)
|
||||
{
|
||||
int i;
|
||||
|
||||
static const char * const msg[] = {
|
||||
"",
|
||||
"rtla version " VERSION,
|
||||
"",
|
||||
" usage: rtla COMMAND ...",
|
||||
"",
|
||||
" commands:",
|
||||
" osnoise - gives information about the operating system noise (osnoise)",
|
||||
" hwnoise - gives information about hardware-related noise",
|
||||
" timerlat - measures the timer irq and thread latency",
|
||||
"",
|
||||
NULL,
|
||||
};
|
||||
|
||||
for (i = 0; msg[i]; i++)
|
||||
fprintf(stderr, "%s\n", msg[i]);
|
||||
exit(err);
|
||||
}
|
||||
|
||||
/*
|
||||
* run_tool_command - try to run a rtla tool command
|
||||
*
|
||||
* It returns 0 if it fails. The tool's main will generally not
|
||||
* return as they should call exit().
|
||||
*/
|
||||
int run_tool_command(int argc, char **argv, int start_position)
|
||||
{
|
||||
if (strcmp(argv[start_position], "osnoise") == 0) {
|
||||
osnoise_main(argc-start_position, &argv[start_position]);
|
||||
goto ran;
|
||||
} else if (strcmp(argv[start_position], "hwnoise") == 0) {
|
||||
hwnoise_main(argc-start_position, &argv[start_position]);
|
||||
goto ran;
|
||||
} else if (strcmp(argv[start_position], "timerlat") == 0) {
|
||||
timerlat_main(argc-start_position, &argv[start_position]);
|
||||
goto ran;
|
||||
}
|
||||
|
||||
return 0;
|
||||
ran:
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Set main as weak to allow overriding it for building unit test binary */
|
||||
#pragma weak main
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int retval;
|
||||
|
||||
/* is it an alias? */
|
||||
retval = run_tool_command(argc, argv, 0);
|
||||
if (retval)
|
||||
exit(0);
|
||||
|
||||
if (argc < 2)
|
||||
goto usage;
|
||||
|
||||
if (strcmp(argv[1], "-h") == 0)
|
||||
rtla_usage(129);
|
||||
else if (strcmp(argv[1], "--help") == 0)
|
||||
rtla_usage(129);
|
||||
|
||||
retval = run_tool_command(argc, argv, 1);
|
||||
if (retval)
|
||||
exit(0);
|
||||
|
||||
usage:
|
||||
rtla_usage(129);
|
||||
}
|
||||
9
tools/tracing/rtla/src/cli.h
Normal file
9
tools/tracing/rtla/src/cli.h
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#pragma once
|
||||
|
||||
struct common_params *osnoise_top_parse_args(int argc, char **argv);
|
||||
struct common_params *osnoise_hist_parse_args(int argc, char **argv);
|
||||
struct common_params *timerlat_top_parse_args(int argc, char **argv);
|
||||
struct common_params *timerlat_hist_parse_args(int argc, char **argv);
|
||||
|
||||
extern bool in_unit_test;
|
||||
687
tools/tracing/rtla/src/cli_p.h
Normal file
687
tools/tracing/rtla/src/cli_p.h
Normal file
|
|
@ -0,0 +1,687 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#pragma once
|
||||
|
||||
#ifndef RTLA_ALLOW_CLI_P_H
|
||||
#error "Private header file included outside of cli.c module"
|
||||
#endif
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <subcmd/parse-options.h>
|
||||
|
||||
#include "cli.h"
|
||||
#include "osnoise.h"
|
||||
#include "timerlat.h"
|
||||
|
||||
struct osnoise_cb_data {
|
||||
struct osnoise_params *params;
|
||||
char *trace_output;
|
||||
};
|
||||
|
||||
struct timerlat_cb_data {
|
||||
struct timerlat_params *params;
|
||||
char *trace_output;
|
||||
};
|
||||
|
||||
/*
|
||||
* Macros for command line options common to all tools
|
||||
*
|
||||
* Note: Some of the options are common to both timerlat and osnoise, but
|
||||
* have a slightly different meaning. Such options take additional arguments
|
||||
* that have to be provided by the *_parse_args() function of the corresponding
|
||||
* tool.
|
||||
*
|
||||
* All macros defined here assume the presence of a params variable of
|
||||
* the corresponding tool type (i.e struct timerlat_params or struct osnoise_params)
|
||||
* and a cb_data variable of the matching type.
|
||||
*/
|
||||
|
||||
#define RTLA_OPT_STOP(short, long, name) OPT_CALLBACK_FLAG(short, long, \
|
||||
¶ms->common.stop_us, \
|
||||
"us", \
|
||||
"stop trace if " name " is higher than the argument in us", \
|
||||
opt_llong_callback, PARSE_OPT_NOAUTONEG)
|
||||
|
||||
#define RTLA_OPT_STOP_TOTAL(short, long, name) OPT_CALLBACK_FLAG(short, long, \
|
||||
¶ms->common.stop_total_us, \
|
||||
"us", \
|
||||
"stop trace if " name " is higher than the argument in us", \
|
||||
opt_llong_callback, PARSE_OPT_NOAUTONEG)
|
||||
|
||||
#define RTLA_OPT_TRACE_OUTPUT(tracer, cb) OPT_CALLBACK_OPTARG('t', "trace", \
|
||||
(const char **)&cb_data.trace_output, \
|
||||
tracer "_trace.txt", \
|
||||
"[file]", \
|
||||
"save the stopped trace to [file|" tracer "_trace.txt]", \
|
||||
cb)
|
||||
|
||||
#define RTLA_OPT_CPUS OPT_CALLBACK('c', "cpus", ¶ms->common, \
|
||||
"cpu-list", \
|
||||
"run the tracer only on the given cpus", \
|
||||
opt_cpus_cb)
|
||||
|
||||
#define RTLA_OPT_CGROUP OPT_CALLBACK_OPTARG('C', "cgroup", ¶ms->common, \
|
||||
"[cgroup_name]", NULL, \
|
||||
"set cgroup, no argument means rtla's cgroup will be inherited", \
|
||||
opt_cgroup_cb)
|
||||
|
||||
#define RTLA_OPT_USER_THREADS OPT_CALLBACK_NOOPT('u', "user-threads", params, NULL, \
|
||||
"use rtla user-space threads instead of kernel-space timerlat threads", \
|
||||
opt_user_threads_cb)
|
||||
|
||||
#define RTLA_OPT_KERNEL_THREADS OPT_BOOLEAN('k', "kernel-threads", \
|
||||
¶ms->common.kernel_workload, \
|
||||
"use timerlat kernel-space threads instead of rtla user-space threads")
|
||||
|
||||
#define RTLA_OPT_USER_LOAD OPT_BOOLEAN('U', "user-load", ¶ms->common.user_data, \
|
||||
"enable timerlat for user-defined user-space workload")
|
||||
|
||||
#define RTLA_OPT_DURATION OPT_CALLBACK('d', "duration", ¶ms->common, \
|
||||
"time[s|m|h|d]", \
|
||||
"set the duration of the session", \
|
||||
opt_duration_cb)
|
||||
|
||||
#define RTLA_OPT_EVENT OPT_CALLBACK('e', "event", ¶ms->common.events, \
|
||||
"sys:event", \
|
||||
"enable the <sys:event> in the trace instance, multiple -e are allowed", \
|
||||
opt_event_cb)
|
||||
|
||||
#define RTLA_OPT_HOUSEKEEPING OPT_CALLBACK('H', "house-keeping", ¶ms->common, \
|
||||
"cpu-list", \
|
||||
"run rtla control threads only on the given cpus", \
|
||||
opt_housekeeping_cb)
|
||||
|
||||
#define RTLA_OPT_PRIORITY OPT_CALLBACK('P', "priority", ¶ms->common, \
|
||||
"o:prio|r:prio|f:prio|d:runtime:period", \
|
||||
"set scheduling parameters", \
|
||||
opt_priority_cb)
|
||||
|
||||
#define RTLA_OPT_TRIGGER OPT_CALLBACK(0, "trigger", ¶ms->common.events, \
|
||||
"trigger", \
|
||||
"enable a trace event trigger to the previous -e event", \
|
||||
opt_trigger_cb)
|
||||
|
||||
#define RTLA_OPT_FILTER OPT_CALLBACK(0, "filter", ¶ms->common.events, \
|
||||
"filter", \
|
||||
"enable a trace event filter to the previous -e event", \
|
||||
opt_filter_cb)
|
||||
|
||||
#define RTLA_OPT_QUIET OPT_BOOLEAN('q', "quiet", ¶ms->common.quiet, \
|
||||
"print only a summary at the end")
|
||||
|
||||
#define RTLA_OPT_TRACE_BUFFER_SIZE OPT_CALLBACK(0, "trace-buffer-size", \
|
||||
¶ms->common.buffer_size, "kB", \
|
||||
"set the per-cpu trace buffer size in kB", \
|
||||
opt_int_callback)
|
||||
|
||||
#define RTLA_OPT_WARM_UP OPT_CALLBACK(0, "warm-up", ¶ms->common.warmup, "s", \
|
||||
"let the workload run for s seconds before collecting data", \
|
||||
opt_int_callback)
|
||||
|
||||
#define RTLA_OPT_AUTO(cb) OPT_CALLBACK('a', "auto", &cb_data, "us", \
|
||||
"set automatic trace mode, stopping the session if argument in us sample is hit", \
|
||||
cb)
|
||||
|
||||
#define RTLA_OPT_ON_THRESHOLD(threshold, cb) OPT_CALLBACK(0, "on-threshold", \
|
||||
¶ms->common.threshold_actions, \
|
||||
"action", \
|
||||
"define action to be executed at " threshold " threshold, multiple are allowed", \
|
||||
cb)
|
||||
|
||||
#define RTLA_OPT_ON_END(cb) OPT_CALLBACK(0, "on-end", ¶ms->common.end_actions, \
|
||||
"action", \
|
||||
"define action to be executed at measurement end, multiple are allowed", \
|
||||
cb)
|
||||
|
||||
#define RTLA_OPT_DEBUG OPT_BOOLEAN('D', "debug", &config_debug, \
|
||||
"print debug info")
|
||||
|
||||
/*
|
||||
* Common callback functions for command line options
|
||||
*/
|
||||
|
||||
static int opt_llong_callback(const struct option *opt, const char *arg, int unset)
|
||||
{
|
||||
long long *value = opt->value;
|
||||
|
||||
if (unset || !arg)
|
||||
return -1;
|
||||
|
||||
*value = get_llong_from_str((char *)arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opt_int_callback(const struct option *opt, const char *arg, int unset)
|
||||
{
|
||||
int *value = opt->value;
|
||||
|
||||
if (unset || !arg)
|
||||
return -1;
|
||||
|
||||
if (strtoi(arg, value))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opt_cpus_cb(const struct option *opt, const char *arg, int unset)
|
||||
{
|
||||
struct common_params *params = opt->value;
|
||||
int retval;
|
||||
|
||||
if (unset || !arg)
|
||||
return -1;
|
||||
|
||||
retval = parse_cpu_set((char *)arg, ¶ms->monitored_cpus);
|
||||
if (retval)
|
||||
fatal("Invalid -c cpu list");
|
||||
params->cpus = (char *)arg;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opt_cgroup_cb(const struct option *opt, const char *arg, int unset)
|
||||
{
|
||||
struct common_params *params = opt->value;
|
||||
|
||||
if (unset)
|
||||
return -1;
|
||||
|
||||
params->cgroup = 1;
|
||||
params->cgroup_name = (char *)arg;
|
||||
if (params->cgroup_name && params->cgroup_name[0] == '=')
|
||||
/* Allow -C=<cgroup_name> next to -C[ ]<cgroup_name> */
|
||||
++params->cgroup_name;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opt_duration_cb(const struct option *opt, const char *arg, int unset)
|
||||
{
|
||||
struct common_params *params = opt->value;
|
||||
|
||||
if (unset || !arg)
|
||||
return -1;
|
||||
|
||||
params->duration = parse_seconds_duration((char *)arg);
|
||||
if (!params->duration)
|
||||
fatal("Invalid -d duration");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opt_event_cb(const struct option *opt, const char *arg, int unset)
|
||||
{
|
||||
struct trace_events **events = opt->value;
|
||||
struct trace_events *tevent;
|
||||
|
||||
if (unset || !arg)
|
||||
return -1;
|
||||
|
||||
tevent = trace_event_alloc((char *)arg);
|
||||
if (!tevent)
|
||||
fatal("Error alloc trace event");
|
||||
|
||||
if (*events)
|
||||
tevent->next = *events;
|
||||
*events = tevent;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opt_housekeeping_cb(const struct option *opt, const char *arg, int unset)
|
||||
{
|
||||
struct common_params *params = opt->value;
|
||||
int retval;
|
||||
|
||||
if (unset || !arg)
|
||||
return -1;
|
||||
|
||||
params->hk_cpus = 1;
|
||||
retval = parse_cpu_set((char *)arg, ¶ms->hk_cpu_set);
|
||||
if (retval)
|
||||
fatal("Error parsing house keeping CPUs");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opt_priority_cb(const struct option *opt, const char *arg, int unset)
|
||||
{
|
||||
struct common_params *params = opt->value;
|
||||
int retval;
|
||||
|
||||
if (unset || !arg)
|
||||
return -1;
|
||||
|
||||
retval = parse_prio((char *)arg, ¶ms->sched_param);
|
||||
if (retval == -1)
|
||||
fatal("Invalid -P priority");
|
||||
params->set_sched = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opt_trigger_cb(const struct option *opt, const char *arg, int unset)
|
||||
{
|
||||
struct trace_events **events = opt->value;
|
||||
|
||||
if (unset || !arg)
|
||||
return -1;
|
||||
|
||||
if (!*events)
|
||||
fatal("--trigger requires a previous -e");
|
||||
|
||||
trace_event_add_trigger(*events, (char *)arg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opt_filter_cb(const struct option *opt, const char *arg, int unset)
|
||||
{
|
||||
struct trace_events **events = opt->value;
|
||||
|
||||
if (unset || !arg)
|
||||
return -1;
|
||||
|
||||
if (!*events)
|
||||
fatal("--filter requires a previous -e");
|
||||
|
||||
trace_event_add_filter(*events, (char *)arg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Macros for command line options specific to osnoise
|
||||
*/
|
||||
#define OSNOISE_OPT_PERIOD OPT_CALLBACK('p', "period", ¶ms->period, "us", \
|
||||
"osnoise period in us", \
|
||||
opt_osnoise_period_cb)
|
||||
|
||||
#define OSNOISE_OPT_RUNTIME OPT_CALLBACK('r', "runtime", ¶ms->runtime, "us", \
|
||||
"osnoise runtime in us", \
|
||||
opt_osnoise_runtime_cb)
|
||||
|
||||
#define OSNOISE_OPT_THRESHOLD OPT_CALLBACK('T', "threshold", ¶ms->threshold, "us", \
|
||||
"the minimum delta to be considered a noise", \
|
||||
opt_llong_callback)
|
||||
|
||||
/*
|
||||
* Callback functions for command line options for osnoise tools
|
||||
*/
|
||||
|
||||
static int opt_osnoise_auto_cb(const struct option *opt, const char *arg, int unset)
|
||||
{
|
||||
struct osnoise_cb_data *cb_data = opt->value;
|
||||
struct osnoise_params *params = cb_data->params;
|
||||
long long auto_thresh;
|
||||
|
||||
if (unset || !arg)
|
||||
return -1;
|
||||
|
||||
auto_thresh = get_llong_from_str((char *)arg);
|
||||
params->common.stop_us = auto_thresh;
|
||||
params->threshold = 1;
|
||||
|
||||
if (!cb_data->trace_output)
|
||||
cb_data->trace_output = "osnoise_trace.txt";
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opt_osnoise_period_cb(const struct option *opt, const char *arg, int unset)
|
||||
{
|
||||
unsigned long long *period = opt->value;
|
||||
|
||||
if (unset || !arg)
|
||||
return -1;
|
||||
|
||||
*period = get_llong_from_str((char *)arg);
|
||||
if (*period > 10000000)
|
||||
fatal("Period longer than 10 s");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opt_osnoise_runtime_cb(const struct option *opt, const char *arg, int unset)
|
||||
{
|
||||
unsigned long long *runtime = opt->value;
|
||||
|
||||
if (unset || !arg)
|
||||
return -1;
|
||||
|
||||
*runtime = get_llong_from_str((char *)arg);
|
||||
if (*runtime < 100)
|
||||
fatal("Runtime shorter than 100 us");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opt_osnoise_trace_output_cb(const struct option *opt, const char *arg, int unset)
|
||||
{
|
||||
const char **trace_output = opt->value;
|
||||
|
||||
if (unset)
|
||||
return -1;
|
||||
|
||||
if (!arg) {
|
||||
*trace_output = "osnoise_trace.txt";
|
||||
} else {
|
||||
*trace_output = (char *)arg;
|
||||
if (*trace_output && (*trace_output)[0] == '=')
|
||||
/* Allow -t=<trace_output> next to -t[ ]<trace_output> */
|
||||
++*trace_output;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opt_osnoise_on_threshold_cb(const struct option *opt, const char *arg, int unset)
|
||||
{
|
||||
struct actions *actions = opt->value;
|
||||
int retval;
|
||||
|
||||
if (unset || !arg)
|
||||
return -1;
|
||||
|
||||
retval = actions_parse(actions, (char *)arg, "osnoise_trace.txt");
|
||||
if (retval)
|
||||
fatal("Invalid action %s", arg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opt_osnoise_on_end_cb(const struct option *opt, const char *arg, int unset)
|
||||
{
|
||||
struct actions *actions = opt->value;
|
||||
int retval;
|
||||
|
||||
if (unset || !arg)
|
||||
return -1;
|
||||
|
||||
retval = actions_parse(actions, (char *)arg, "osnoise_trace.txt");
|
||||
if (retval)
|
||||
fatal("Invalid action %s", arg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Macros for command line options specific to timerlat
|
||||
*/
|
||||
#define TIMERLAT_OPT_PERIOD OPT_CALLBACK('p', "period", ¶ms->timerlat_period_us, "us", \
|
||||
"timerlat period in us", \
|
||||
opt_timerlat_period_cb)
|
||||
|
||||
#define TIMERLAT_OPT_STACK OPT_CALLBACK('s', "stack", ¶ms->print_stack, "us", \
|
||||
"save the stack trace at the IRQ if a thread latency is higher than the argument in us", \
|
||||
opt_llong_callback)
|
||||
|
||||
#define TIMERLAT_OPT_NANO OPT_CALLBACK_NOOPT('n', "nano", params, NULL, \
|
||||
"display data in nanoseconds", \
|
||||
opt_nano_cb)
|
||||
|
||||
#define TIMERLAT_OPT_DMA_LATENCY OPT_CALLBACK(0, "dma-latency", ¶ms->dma_latency, "us", \
|
||||
"set /dev/cpu_dma_latency latency <us> to reduce exit from idle latency", \
|
||||
opt_dma_latency_cb)
|
||||
|
||||
#define TIMERLAT_OPT_DEEPEST_IDLE_STATE OPT_CALLBACK(0, "deepest-idle-state", \
|
||||
¶ms->deepest_idle_state, "n", \
|
||||
"only go down to idle state n on cpus used by timerlat to reduce exit from idle latency", \
|
||||
opt_int_callback)
|
||||
|
||||
#define TIMERLAT_OPT_AA_ONLY OPT_CALLBACK(0, "aa-only", params, "us", \
|
||||
"stop if <us> latency is hit, only printing the auto analysis (reduces CPU usage)", \
|
||||
opt_aa_only_cb)
|
||||
|
||||
#define TIMERLAT_OPT_NO_AA OPT_BOOLEAN(0, "no-aa", ¶ms->no_aa, \
|
||||
"disable auto-analysis, reducing rtla timerlat cpu usage")
|
||||
|
||||
#define TIMERLAT_OPT_DUMPS_TASKS OPT_BOOLEAN(0, "dump-tasks", ¶ms->dump_tasks, \
|
||||
"prints the task running on all CPUs if stop conditions are met (depends on !--no-aa)")
|
||||
|
||||
#define TIMERLAT_OPT_BPF_ACTION OPT_STRING(0, "bpf-action", ¶ms->bpf_action_program, \
|
||||
"program", \
|
||||
"load and execute BPF program when latency threshold is exceeded")
|
||||
|
||||
#define TIMERLAT_OPT_STACK_FORMAT OPT_CALLBACK(0, "stack-format", ¶ms->stack_format, "format", \
|
||||
"set the stack format (truncate, skip, full)", \
|
||||
opt_stack_format_cb)
|
||||
|
||||
#define TIMERLAT_OPT_ALIGNED OPT_CALLBACK('A', "aligned", params, "us", \
|
||||
"align thread wakeups to a specific offset", \
|
||||
opt_timerlat_align_cb)
|
||||
|
||||
/*
|
||||
* Callback functions for command line options for timerlat tools
|
||||
*/
|
||||
|
||||
static int opt_timerlat_period_cb(const struct option *opt, const char *arg, int unset)
|
||||
{
|
||||
long long *period = opt->value;
|
||||
|
||||
if (unset || !arg)
|
||||
return -1;
|
||||
|
||||
*period = get_llong_from_str((char *)arg);
|
||||
if (*period > 1000000)
|
||||
fatal("Period longer than 1 s");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opt_timerlat_auto_cb(const struct option *opt, const char *arg, int unset)
|
||||
{
|
||||
struct timerlat_cb_data *cb_data = opt->value;
|
||||
struct timerlat_params *params = cb_data->params;
|
||||
long long auto_thresh;
|
||||
|
||||
if (unset || !arg)
|
||||
return -1;
|
||||
|
||||
auto_thresh = get_llong_from_str((char *)arg);
|
||||
params->common.stop_total_us = auto_thresh;
|
||||
params->common.stop_us = auto_thresh;
|
||||
params->print_stack = auto_thresh;
|
||||
|
||||
if (!cb_data->trace_output)
|
||||
cb_data->trace_output = "timerlat_trace.txt";
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opt_dma_latency_cb(const struct option *opt, const char *arg, int unset)
|
||||
{
|
||||
int *dma_latency = opt->value;
|
||||
int retval;
|
||||
|
||||
if (unset || !arg)
|
||||
return -1;
|
||||
|
||||
retval = strtoi((char *)arg, dma_latency);
|
||||
if (retval)
|
||||
fatal("Invalid -dma-latency %s", arg);
|
||||
if (*dma_latency < 0 || *dma_latency > 10000)
|
||||
fatal("--dma-latency needs to be >= 0 and <= 10000");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opt_aa_only_cb(const struct option *opt, const char *arg, int unset)
|
||||
{
|
||||
struct timerlat_params *params = opt->value;
|
||||
long long auto_thresh;
|
||||
|
||||
if (unset || !arg)
|
||||
return -1;
|
||||
|
||||
auto_thresh = get_llong_from_str((char *)arg);
|
||||
params->common.stop_total_us = auto_thresh;
|
||||
params->common.stop_us = auto_thresh;
|
||||
params->print_stack = auto_thresh;
|
||||
params->common.aa_only = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opt_timerlat_trace_output_cb(const struct option *opt, const char *arg, int unset)
|
||||
{
|
||||
const char **trace_output = opt->value;
|
||||
|
||||
if (unset)
|
||||
return -1;
|
||||
|
||||
if (!arg) {
|
||||
*trace_output = "timerlat_trace.txt";
|
||||
} else {
|
||||
*trace_output = (char *)arg;
|
||||
if (*trace_output && (*trace_output)[0] == '=')
|
||||
/* Allow -t=<trace_output> next to -t[ ]<trace_output> */
|
||||
++*trace_output;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opt_timerlat_on_threshold_cb(const struct option *opt, const char *arg, int unset)
|
||||
{
|
||||
struct actions *actions = opt->value;
|
||||
int retval;
|
||||
|
||||
if (unset || !arg)
|
||||
return -1;
|
||||
|
||||
retval = actions_parse(actions, (char *)arg, "timerlat_trace.txt");
|
||||
if (retval)
|
||||
fatal("Invalid action %s", arg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opt_timerlat_on_end_cb(const struct option *opt, const char *arg, int unset)
|
||||
{
|
||||
struct actions *actions = opt->value;
|
||||
int retval;
|
||||
|
||||
if (unset || !arg)
|
||||
return -1;
|
||||
|
||||
retval = actions_parse(actions, (char *)arg, "timerlat_trace.txt");
|
||||
if (retval)
|
||||
fatal("Invalid action %s", arg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opt_user_threads_cb(const struct option *opt, const char *arg, int unset)
|
||||
{
|
||||
struct timerlat_params *params = opt->value;
|
||||
|
||||
if (unset)
|
||||
return -1;
|
||||
|
||||
params->common.user_workload = true;
|
||||
params->common.user_data = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opt_nano_cb(const struct option *opt, const char *arg, int unset)
|
||||
{
|
||||
struct timerlat_params *params = opt->value;
|
||||
|
||||
if (unset)
|
||||
return -1;
|
||||
|
||||
params->common.output_divisor = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opt_stack_format_cb(const struct option *opt, const char *arg, int unset)
|
||||
{
|
||||
int *format = opt->value;
|
||||
|
||||
if (unset || !arg)
|
||||
return -1;
|
||||
|
||||
*format = parse_stack_format((char *)arg);
|
||||
|
||||
if (*format == -1)
|
||||
fatal("Invalid --stack-format option");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opt_timerlat_align_cb(const struct option *opt, const char *arg, int unset)
|
||||
{
|
||||
struct timerlat_params *params = opt->value;
|
||||
|
||||
if (unset || !arg)
|
||||
return -1;
|
||||
|
||||
params->timerlat_align = true;
|
||||
params->timerlat_align_us = get_llong_from_str((char *)arg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Macros for command line options specific to histogram-based tools
|
||||
*/
|
||||
|
||||
#define HIST_OPT_BUCKET_SIZE OPT_CALLBACK('b', "bucket-size", \
|
||||
¶ms->common.hist.bucket_size, "N", \
|
||||
"set the histogram bucket size (default 1)", \
|
||||
opt_bucket_size_cb)
|
||||
|
||||
#define HIST_OPT_ENTRIES OPT_CALLBACK('E', "entries", ¶ms->common.hist.entries, "N", \
|
||||
"set the number of entries of the histogram (default 256)", \
|
||||
opt_entries_cb)
|
||||
|
||||
#define HIST_OPT_NO_IRQ OPT_BOOLEAN_FLAG(0, "no-irq", ¶ms->common.hist.no_irq, \
|
||||
"ignore IRQ latencies", PARSE_OPT_NOAUTONEG)
|
||||
|
||||
#define HIST_OPT_NO_THREAD OPT_BOOLEAN_FLAG(0, "no-thread", ¶ms->common.hist.no_thread, \
|
||||
"ignore thread latencies", PARSE_OPT_NOAUTONEG)
|
||||
|
||||
#define HIST_OPT_NO_HEADER OPT_BOOLEAN(0, "no-header", ¶ms->common.hist.no_header, \
|
||||
"do not print header")
|
||||
|
||||
#define HIST_OPT_NO_SUMMARY OPT_BOOLEAN(0, "no-summary", ¶ms->common.hist.no_summary, \
|
||||
"do not print summary")
|
||||
|
||||
#define HIST_OPT_NO_INDEX OPT_BOOLEAN(0, "no-index", ¶ms->common.hist.no_index, \
|
||||
"do not print index")
|
||||
|
||||
#define HIST_OPT_WITH_ZEROS OPT_BOOLEAN(0, "with-zeros", ¶ms->common.hist.with_zeros, \
|
||||
"print zero only entries")
|
||||
|
||||
/* Histogram-specific callbacks */
|
||||
|
||||
static int opt_bucket_size_cb(const struct option *opt, const char *arg, int unset)
|
||||
{
|
||||
int *bucket_size = opt->value;
|
||||
|
||||
if (unset || !arg)
|
||||
return -1;
|
||||
|
||||
*bucket_size = get_llong_from_str((char *)arg);
|
||||
if (*bucket_size == 0 || *bucket_size >= 1000000)
|
||||
fatal("Bucket size needs to be > 0 and <= 1000000");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opt_entries_cb(const struct option *opt, const char *arg, int unset)
|
||||
{
|
||||
int *entries = opt->value;
|
||||
|
||||
if (unset || !arg)
|
||||
return -1;
|
||||
|
||||
*entries = get_llong_from_str((char *)arg);
|
||||
if (*entries < 10 || *entries > 9999999)
|
||||
fatal("Entries must be > 10 and < 10000000");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -5,12 +5,11 @@
|
|||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <getopt.h>
|
||||
#include <sys/sysinfo.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
struct trace_instance *trace_inst;
|
||||
struct osnoise_tool *trace_tool;
|
||||
volatile int stop_tracing;
|
||||
int nr_cpus;
|
||||
|
||||
|
|
@ -21,12 +20,16 @@ static void stop_trace(int sig)
|
|||
* Stop requested twice in a row; abort event processing and
|
||||
* exit immediately
|
||||
*/
|
||||
tracefs_iterate_stop(trace_inst->inst);
|
||||
if (trace_tool)
|
||||
tracefs_iterate_stop(trace_tool->trace.inst);
|
||||
return;
|
||||
}
|
||||
stop_tracing = 1;
|
||||
if (trace_inst)
|
||||
trace_instance_stop(trace_inst);
|
||||
if (trace_tool) {
|
||||
trace_instance_stop(&trace_tool->trace);
|
||||
if (trace_tool->record)
|
||||
trace_instance_stop(&trace_tool->record->trace);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -53,96 +56,6 @@ static void unset_signals(struct common_params *params)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* getopt_auto - auto-generates optstring from long_options
|
||||
*/
|
||||
int getopt_auto(int argc, char **argv, const struct option *long_opts)
|
||||
{
|
||||
char opts[256];
|
||||
int n = 0;
|
||||
|
||||
for (int i = 0; long_opts[i].name; i++) {
|
||||
if (long_opts[i].val < 32 || long_opts[i].val > 127)
|
||||
continue;
|
||||
|
||||
if (n + 4 >= sizeof(opts))
|
||||
fatal("optstring buffer overflow");
|
||||
|
||||
opts[n++] = long_opts[i].val;
|
||||
|
||||
if (long_opts[i].has_arg == required_argument)
|
||||
opts[n++] = ':';
|
||||
else if (long_opts[i].has_arg == optional_argument) {
|
||||
opts[n++] = ':';
|
||||
opts[n++] = ':';
|
||||
}
|
||||
}
|
||||
|
||||
opts[n] = '\0';
|
||||
|
||||
return getopt_long(argc, argv, opts, long_opts, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* set_common_option - set common options
|
||||
*
|
||||
* @c: option character
|
||||
* @argc: argument count
|
||||
* @argv: argument vector
|
||||
* @common: common parameters structure
|
||||
*
|
||||
* Parse command line options that are common to all rtla tools.
|
||||
*
|
||||
* Returns: 1 if the option was set, 0 otherwise.
|
||||
*/
|
||||
int set_common_option(int c, int argc, char **argv, struct common_params *common)
|
||||
{
|
||||
struct trace_events *tevent;
|
||||
|
||||
switch (c) {
|
||||
case 'c':
|
||||
if (parse_cpu_set(optarg, &common->monitored_cpus))
|
||||
fatal("Invalid -c cpu list");
|
||||
common->cpus = optarg;
|
||||
break;
|
||||
case 'C':
|
||||
common->cgroup = 1;
|
||||
common->cgroup_name = parse_optional_arg(argc, argv);
|
||||
break;
|
||||
case 'D':
|
||||
config_debug = 1;
|
||||
break;
|
||||
case 'd':
|
||||
common->duration = parse_seconds_duration(optarg);
|
||||
if (!common->duration)
|
||||
fatal("Invalid -d duration");
|
||||
break;
|
||||
case 'e':
|
||||
tevent = trace_event_alloc(optarg);
|
||||
if (!tevent)
|
||||
fatal("Error alloc trace event");
|
||||
|
||||
if (common->events)
|
||||
tevent->next = common->events;
|
||||
common->events = tevent;
|
||||
break;
|
||||
case 'H':
|
||||
common->hk_cpus = 1;
|
||||
if (parse_cpu_set(optarg, &common->hk_cpu_set))
|
||||
fatal("Error parsing house keeping CPUs");
|
||||
break;
|
||||
case 'P':
|
||||
if (parse_prio(optarg, &common->sched_param) == -1)
|
||||
fatal("Invalid -P priority");
|
||||
common->set_sched = 1;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* common_apply_config - apply common configs to the initialized tool
|
||||
*/
|
||||
|
|
@ -255,11 +168,10 @@ int run_tool(struct tool_ops *ops, int argc, char *argv[])
|
|||
tool->params = params;
|
||||
|
||||
/*
|
||||
* Save trace instance into global variable so that SIGINT can stop
|
||||
* the timerlat tracer.
|
||||
* Expose the tool to signal handlers so they can stop the trace.
|
||||
* Otherwise, rtla could loop indefinitely when overloaded.
|
||||
*/
|
||||
trace_inst = &tool->trace;
|
||||
trace_tool = tool;
|
||||
|
||||
retval = ops->apply_config(tool);
|
||||
if (retval) {
|
||||
|
|
@ -267,7 +179,7 @@ int run_tool(struct tool_ops *ops, int argc, char *argv[])
|
|||
goto out_free;
|
||||
}
|
||||
|
||||
retval = enable_tracer_by_name(trace_inst->inst, ops->tracer);
|
||||
retval = enable_tracer_by_name(tool->trace.inst, ops->tracer);
|
||||
if (retval) {
|
||||
err_msg("Failed to enable %s tracer\n", ops->tracer);
|
||||
goto out_free;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#pragma once
|
||||
|
||||
#include <getopt.h>
|
||||
#include "actions.h"
|
||||
#include "timerlat_u.h"
|
||||
#include "trace.h"
|
||||
|
|
@ -52,18 +51,25 @@ struct osnoise_context {
|
|||
/* -1 as init value because 0 is off */
|
||||
int orig_opt_workload;
|
||||
int opt_workload;
|
||||
|
||||
/* -1 as init value because 0 is off */
|
||||
int orig_opt_timerlat_align;
|
||||
int opt_timerlat_align;
|
||||
|
||||
/* 0 as init value */
|
||||
unsigned long long orig_timerlat_align_us;
|
||||
unsigned long long timerlat_align_us;
|
||||
};
|
||||
|
||||
extern struct trace_instance *trace_inst;
|
||||
extern volatile int stop_tracing;
|
||||
|
||||
struct hist_params {
|
||||
char no_irq;
|
||||
char no_thread;
|
||||
char no_header;
|
||||
char no_summary;
|
||||
char no_index;
|
||||
char with_zeros;
|
||||
bool no_irq;
|
||||
bool no_thread;
|
||||
bool no_header;
|
||||
bool no_summary;
|
||||
bool no_index;
|
||||
bool with_zeros;
|
||||
int bucket_size;
|
||||
int entries;
|
||||
};
|
||||
|
|
@ -96,12 +102,12 @@ struct common_params {
|
|||
/* Other parameters */
|
||||
struct hist_params hist;
|
||||
int output_divisor;
|
||||
int pretty_output;
|
||||
int quiet;
|
||||
int user_workload;
|
||||
int kernel_workload;
|
||||
int user_data;
|
||||
int aa_only;
|
||||
bool pretty_output;
|
||||
bool quiet;
|
||||
bool user_workload;
|
||||
bool kernel_workload;
|
||||
bool user_data;
|
||||
bool aa_only;
|
||||
|
||||
struct actions threshold_actions;
|
||||
struct actions end_actions;
|
||||
|
|
@ -177,18 +183,6 @@ int osnoise_set_stop_us(struct osnoise_context *context, long long stop_us);
|
|||
int osnoise_set_stop_total_us(struct osnoise_context *context,
|
||||
long long stop_total_us);
|
||||
|
||||
int getopt_auto(int argc, char **argv, const struct option *long_opts);
|
||||
|
||||
#define COMMON_OPTIONS \
|
||||
{"cpus", required_argument, 0, 'c'},\
|
||||
{"cgroup", optional_argument, 0, 'C'},\
|
||||
{"debug", no_argument, 0, 'D'},\
|
||||
{"duration", required_argument, 0, 'd'},\
|
||||
{"event", required_argument, 0, 'e'},\
|
||||
{"house-keeping", required_argument, 0, 'H'},\
|
||||
{"priority", required_argument, 0, 'P'}
|
||||
int set_common_option(int c, int argc, char **argv, struct common_params *common);
|
||||
|
||||
int common_apply_config(struct osnoise_tool *tool, struct common_params *params);
|
||||
int top_main_loop(struct osnoise_tool *tool);
|
||||
int hist_main_loop(struct osnoise_tool *tool);
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@
|
|||
#include <stdio.h>
|
||||
#include <sched.h>
|
||||
|
||||
#include <linux/compiler.h>
|
||||
|
||||
#include "osnoise.h"
|
||||
|
||||
#define DEFAULT_SAMPLE_PERIOD 1000000 /* 1s */
|
||||
|
|
@ -421,6 +423,86 @@ void osnoise_put_timerlat_period_us(struct osnoise_context *context)
|
|||
context->orig_timerlat_period_us = OSNOISE_TIME_INIT_VAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* osnoise_get_timerlat_align_us - read and save the original "timerlat_align_us"
|
||||
*/
|
||||
static long long
|
||||
osnoise_get_timerlat_align_us(struct osnoise_context *context)
|
||||
{
|
||||
long long timerlat_align_us;
|
||||
|
||||
if (context->timerlat_align_us != OSNOISE_OPTION_INIT_VAL)
|
||||
return context->timerlat_align_us;
|
||||
|
||||
if (context->orig_timerlat_align_us != OSNOISE_OPTION_INIT_VAL)
|
||||
return context->orig_timerlat_align_us;
|
||||
|
||||
timerlat_align_us = osnoise_read_ll_config("osnoise/timerlat_align_us");
|
||||
if (timerlat_align_us < 0)
|
||||
goto out_err;
|
||||
|
||||
context->orig_timerlat_align_us = timerlat_align_us;
|
||||
return timerlat_align_us;
|
||||
|
||||
out_err:
|
||||
return OSNOISE_OPTION_INIT_VAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* osnoise_set_timerlat_align_us - set "timerlat_align_us"
|
||||
*/
|
||||
int osnoise_set_timerlat_align_us(struct osnoise_context *context, long long timerlat_align_us)
|
||||
{
|
||||
long long curr_timerlat_align_us = osnoise_get_timerlat_align_us(context);
|
||||
int retval;
|
||||
|
||||
if (curr_timerlat_align_us == OSNOISE_OPTION_INIT_VAL)
|
||||
return -1;
|
||||
|
||||
retval = osnoise_write_ll_config("osnoise/timerlat_align_us", timerlat_align_us);
|
||||
if (retval < 0)
|
||||
return -1;
|
||||
|
||||
context->timerlat_align_us = timerlat_align_us;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* osnoise_restore_timerlat_align_us - restore "timerlat_align_us"
|
||||
*/
|
||||
void osnoise_restore_timerlat_align_us(struct osnoise_context *context)
|
||||
{
|
||||
int retval;
|
||||
|
||||
if (context->orig_timerlat_align_us == OSNOISE_OPTION_INIT_VAL)
|
||||
return;
|
||||
|
||||
if (context->orig_timerlat_align_us == context->timerlat_align_us)
|
||||
goto out_done;
|
||||
|
||||
retval = osnoise_write_ll_config("osnoise/timerlat_align_us",
|
||||
context->orig_timerlat_align_us);
|
||||
if (retval < 0)
|
||||
err_msg("Could not restore original osnoise timerlat_align_us\n");
|
||||
|
||||
out_done:
|
||||
context->timerlat_align_us = OSNOISE_OPTION_INIT_VAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* osnoise_put_timerlat_align_us - restore original values and cleanup data
|
||||
*/
|
||||
void osnoise_put_timerlat_align_us(struct osnoise_context *context)
|
||||
{
|
||||
osnoise_restore_timerlat_align_us(context);
|
||||
|
||||
if (context->orig_timerlat_align_us == OSNOISE_OPTION_INIT_VAL)
|
||||
return;
|
||||
|
||||
context->orig_timerlat_align_us = OSNOISE_OPTION_INIT_VAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* osnoise_get_stop_us - read and save the original "stop_tracing_us"
|
||||
*/
|
||||
|
|
@ -906,6 +988,67 @@ static void osnoise_put_workload(struct osnoise_context *context)
|
|||
context->orig_opt_workload = OSNOISE_OPTION_INIT_VAL;
|
||||
}
|
||||
|
||||
static int osnoise_get_timerlat_align(struct osnoise_context *context)
|
||||
{
|
||||
if (context->opt_timerlat_align != OSNOISE_OPTION_INIT_VAL)
|
||||
return context->opt_timerlat_align;
|
||||
|
||||
if (context->orig_opt_timerlat_align != OSNOISE_OPTION_INIT_VAL)
|
||||
return context->orig_opt_timerlat_align;
|
||||
|
||||
context->orig_opt_timerlat_align = osnoise_options_get_option("TIMERLAT_ALIGN");
|
||||
|
||||
return context->orig_opt_timerlat_align;
|
||||
}
|
||||
|
||||
int osnoise_set_timerlat_align(struct osnoise_context *context, bool onoff)
|
||||
{
|
||||
int opt_timerlat_align = osnoise_get_timerlat_align(context);
|
||||
int retval;
|
||||
|
||||
if (opt_timerlat_align == OSNOISE_OPTION_INIT_VAL)
|
||||
return -1;
|
||||
|
||||
if (opt_timerlat_align == onoff)
|
||||
return 0;
|
||||
|
||||
retval = osnoise_options_set_option("TIMERLAT_ALIGN", onoff);
|
||||
if (retval < 0)
|
||||
return -2;
|
||||
|
||||
context->opt_timerlat_align = onoff;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void osnoise_restore_timerlat_align(struct osnoise_context *context)
|
||||
{
|
||||
int retval;
|
||||
|
||||
if (context->orig_opt_timerlat_align == OSNOISE_OPTION_INIT_VAL)
|
||||
return;
|
||||
|
||||
if (context->orig_opt_timerlat_align == context->opt_timerlat_align)
|
||||
goto out_done;
|
||||
|
||||
retval = osnoise_options_set_option("TIMERLAT_ALIGN", context->orig_opt_timerlat_align);
|
||||
if (retval < 0)
|
||||
err_msg("Could not restore original TIMERLAT_ALIGN option\n");
|
||||
|
||||
out_done:
|
||||
context->orig_opt_timerlat_align = OSNOISE_OPTION_INIT_VAL;
|
||||
}
|
||||
|
||||
static void osnoise_put_timerlat_align(struct osnoise_context *context)
|
||||
{
|
||||
osnoise_restore_timerlat_align(context);
|
||||
|
||||
if (context->orig_opt_timerlat_align == OSNOISE_OPTION_INIT_VAL)
|
||||
return;
|
||||
|
||||
context->orig_opt_timerlat_align = OSNOISE_OPTION_INIT_VAL;
|
||||
}
|
||||
|
||||
enum {
|
||||
FLAG_CONTEXT_NEWLY_CREATED = (1 << 0),
|
||||
FLAG_CONTEXT_DELETED = (1 << 1),
|
||||
|
|
@ -958,6 +1101,12 @@ struct osnoise_context *osnoise_context_alloc(void)
|
|||
context->orig_opt_workload = OSNOISE_OPTION_INIT_VAL;
|
||||
context->opt_workload = OSNOISE_OPTION_INIT_VAL;
|
||||
|
||||
context->orig_opt_timerlat_align = OSNOISE_OPTION_INIT_VAL;
|
||||
context->opt_timerlat_align = OSNOISE_OPTION_INIT_VAL;
|
||||
|
||||
context->orig_timerlat_align_us = OSNOISE_OPTION_INIT_VAL;
|
||||
context->timerlat_align_us = OSNOISE_OPTION_INIT_VAL;
|
||||
|
||||
osnoise_get_context(context);
|
||||
|
||||
return context;
|
||||
|
|
@ -986,6 +1135,8 @@ void osnoise_put_context(struct osnoise_context *context)
|
|||
osnoise_put_tracing_thresh(context);
|
||||
osnoise_put_irq_disable(context);
|
||||
osnoise_put_workload(context);
|
||||
osnoise_put_timerlat_align(context);
|
||||
osnoise_put_timerlat_align_us(context);
|
||||
|
||||
free(context);
|
||||
}
|
||||
|
|
@ -1171,7 +1322,7 @@ int osnoise_enable(struct osnoise_tool *tool)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void osnoise_usage(int err)
|
||||
__noreturn static void osnoise_usage(int err)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
|
@ -1209,7 +1360,7 @@ int osnoise_main(int argc, char *argv[])
|
|||
}
|
||||
|
||||
if ((strcmp(argv[1], "-h") == 0) || (strcmp(argv[1], "--help") == 0)) {
|
||||
osnoise_usage(0);
|
||||
osnoise_usage(129);
|
||||
} else if (str_has_prefix(argv[1], "-")) {
|
||||
/* the user skipped the tool, call the default one */
|
||||
run_tool(&osnoise_top_ops, argc, argv);
|
||||
|
|
@ -1223,8 +1374,7 @@ int osnoise_main(int argc, char *argv[])
|
|||
}
|
||||
|
||||
usage:
|
||||
osnoise_usage(1);
|
||||
exit(1);
|
||||
osnoise_usage(129);
|
||||
}
|
||||
|
||||
int hwnoise_main(int argc, char *argv[])
|
||||
|
|
|
|||
|
|
@ -49,6 +49,12 @@ void osnoise_restore_print_stack(struct osnoise_context *context);
|
|||
int osnoise_set_print_stack(struct osnoise_context *context,
|
||||
long long print_stack);
|
||||
|
||||
int osnoise_set_timerlat_align_us(struct osnoise_context *context,
|
||||
long long timerlat_align_us);
|
||||
void osnoise_restore_timerlat_align_us(struct osnoise_context *context);
|
||||
|
||||
int osnoise_set_timerlat_align(struct osnoise_context *context, bool onoff);
|
||||
|
||||
int osnoise_set_irq_disable(struct osnoise_context *context, bool onoff);
|
||||
void osnoise_report_missed_events(struct osnoise_tool *tool);
|
||||
int osnoise_apply_config(struct osnoise_tool *tool, struct osnoise_params *params);
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <getopt.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
|
|
@ -13,6 +12,7 @@
|
|||
#include <time.h>
|
||||
|
||||
#include "osnoise.h"
|
||||
#include "cli.h"
|
||||
|
||||
struct osnoise_hist_cpu {
|
||||
int *samples;
|
||||
|
|
@ -400,226 +400,6 @@ osnoise_print_stats(struct osnoise_tool *tool)
|
|||
osnoise_report_missed_events(tool);
|
||||
}
|
||||
|
||||
/*
|
||||
* osnoise_hist_usage - prints osnoise hist usage message
|
||||
*/
|
||||
static void osnoise_hist_usage(void)
|
||||
{
|
||||
static const char * const msg_start[] = {
|
||||
"[-D] [-d s] [-a us] [-p us] [-r us] [-s us] [-S us] \\",
|
||||
" [-T us] [-t [file]] [-e sys[:event]] [--filter <filter>] [--trigger <trigger>] \\",
|
||||
" [-c cpu-list] [-H cpu-list] [-P priority] [-b N] [-E N] [--no-header] [--no-summary] \\",
|
||||
" [--no-index] [--with-zeros] [-C [cgroup_name]] [--warm-up]",
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const char * const msg_opts[] = {
|
||||
" -a/--auto: set automatic trace mode, stopping the session if argument in us sample is hit",
|
||||
" -p/--period us: osnoise period in us",
|
||||
" -r/--runtime us: osnoise runtime in us",
|
||||
" -s/--stop us: stop trace if a single sample is higher than the argument in us",
|
||||
" -S/--stop-total us: stop trace if the total sample is higher than the argument in us",
|
||||
" -T/--threshold us: the minimum delta to be considered a noise",
|
||||
" -c/--cpus cpu-list: list of cpus to run osnoise threads",
|
||||
" -H/--house-keeping cpus: run rtla control threads only on the given cpus",
|
||||
" -C/--cgroup [cgroup_name]: set cgroup, if no cgroup_name is passed, the rtla's cgroup will be inherited",
|
||||
" -d/--duration time[s|m|h|d]: duration of the session",
|
||||
" -D/--debug: print debug info",
|
||||
" -t/--trace [file]: save the stopped trace to [file|osnoise_trace.txt]",
|
||||
" -e/--event <sys:event>: enable the <sys:event> in the trace instance, multiple -e are allowed",
|
||||
" --filter <filter>: enable a trace event filter to the previous -e event",
|
||||
" --trigger <trigger>: enable a trace event trigger to the previous -e event",
|
||||
" -b/--bucket-size N: set the histogram bucket size (default 1)",
|
||||
" -E/--entries N: set the number of entries of the histogram (default 256)",
|
||||
" --no-header: do not print header",
|
||||
" --no-summary: do not print summary",
|
||||
" --no-index: do not print index",
|
||||
" --with-zeros: print zero only entries",
|
||||
" -P/--priority o:prio|r:prio|f:prio|d:runtime:period: set scheduling parameters",
|
||||
" o:prio - use SCHED_OTHER with prio",
|
||||
" r:prio - use SCHED_RR with prio",
|
||||
" f:prio - use SCHED_FIFO with prio",
|
||||
" d:runtime[us|ms|s]:period[us|ms|s] - use SCHED_DEADLINE with runtime and period",
|
||||
" in nanoseconds",
|
||||
" --warm-up: let the workload run for s seconds before collecting data",
|
||||
" --trace-buffer-size kB: set the per-cpu trace buffer size in kB",
|
||||
" --on-threshold <action>: define action to be executed at stop-total threshold, multiple are allowed",
|
||||
" --on-end <action>: define action to be executed at measurement end, multiple are allowed",
|
||||
NULL,
|
||||
};
|
||||
|
||||
common_usage("osnoise", "hist", "a per-cpu histogram of the OS noise",
|
||||
msg_start, msg_opts);
|
||||
}
|
||||
|
||||
/*
|
||||
* osnoise_hist_parse_args - allocs, parse and fill the cmd line parameters
|
||||
*/
|
||||
static struct common_params
|
||||
*osnoise_hist_parse_args(int argc, char *argv[])
|
||||
{
|
||||
struct osnoise_params *params;
|
||||
int retval;
|
||||
int c;
|
||||
char *trace_output = NULL;
|
||||
|
||||
params = calloc_fatal(1, sizeof(*params));
|
||||
|
||||
actions_init(¶ms->common.threshold_actions);
|
||||
actions_init(¶ms->common.end_actions);
|
||||
|
||||
/* display data in microseconds */
|
||||
params->common.output_divisor = 1000;
|
||||
params->common.hist.bucket_size = 1;
|
||||
params->common.hist.entries = 256;
|
||||
|
||||
while (1) {
|
||||
static struct option long_options[] = {
|
||||
COMMON_OPTIONS,
|
||||
{"auto", required_argument, 0, 'a'},
|
||||
{"bucket-size", required_argument, 0, 'b'},
|
||||
{"entries", required_argument, 0, 'E'},
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{"period", required_argument, 0, 'p'},
|
||||
{"runtime", required_argument, 0, 'r'},
|
||||
{"stop", required_argument, 0, 's'},
|
||||
{"stop-total", required_argument, 0, 'S'},
|
||||
{"trace", optional_argument, 0, 't'},
|
||||
{"threshold", required_argument, 0, 'T'},
|
||||
{"no-header", no_argument, 0, '0'},
|
||||
{"no-summary", no_argument, 0, '1'},
|
||||
{"no-index", no_argument, 0, '2'},
|
||||
{"with-zeros", no_argument, 0, '3'},
|
||||
{"trigger", required_argument, 0, '4'},
|
||||
{"filter", required_argument, 0, '5'},
|
||||
{"warm-up", required_argument, 0, '6'},
|
||||
{"trace-buffer-size", required_argument, 0, '7'},
|
||||
{"on-threshold", required_argument, 0, '8'},
|
||||
{"on-end", required_argument, 0, '9'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
c = getopt_auto(argc, argv, long_options);
|
||||
|
||||
/* detect the end of the options. */
|
||||
if (c == -1)
|
||||
break;
|
||||
|
||||
if (set_common_option(c, argc, argv, ¶ms->common))
|
||||
continue;
|
||||
|
||||
switch (c) {
|
||||
case 'a':
|
||||
/* set sample stop to auto_thresh */
|
||||
params->common.stop_us = get_llong_from_str(optarg);
|
||||
|
||||
/* set sample threshold to 1 */
|
||||
params->threshold = 1;
|
||||
|
||||
/* set trace */
|
||||
if (!trace_output)
|
||||
trace_output = "osnoise_trace.txt";
|
||||
|
||||
break;
|
||||
case 'b':
|
||||
params->common.hist.bucket_size = get_llong_from_str(optarg);
|
||||
if (params->common.hist.bucket_size == 0 ||
|
||||
params->common.hist.bucket_size >= 1000000)
|
||||
fatal("Bucket size needs to be > 0 and <= 1000000");
|
||||
break;
|
||||
case 'E':
|
||||
params->common.hist.entries = get_llong_from_str(optarg);
|
||||
if (params->common.hist.entries < 10 ||
|
||||
params->common.hist.entries > 9999999)
|
||||
fatal("Entries must be > 10 and < 9999999");
|
||||
break;
|
||||
case 'h':
|
||||
case '?':
|
||||
osnoise_hist_usage();
|
||||
break;
|
||||
case 'p':
|
||||
params->period = get_llong_from_str(optarg);
|
||||
if (params->period > 10000000)
|
||||
fatal("Period longer than 10 s");
|
||||
break;
|
||||
case 'r':
|
||||
params->runtime = get_llong_from_str(optarg);
|
||||
if (params->runtime < 100)
|
||||
fatal("Runtime shorter than 100 us");
|
||||
break;
|
||||
case 's':
|
||||
params->common.stop_us = get_llong_from_str(optarg);
|
||||
break;
|
||||
case 'S':
|
||||
params->common.stop_total_us = get_llong_from_str(optarg);
|
||||
break;
|
||||
case 'T':
|
||||
params->threshold = get_llong_from_str(optarg);
|
||||
break;
|
||||
case 't':
|
||||
trace_output = parse_optional_arg(argc, argv);
|
||||
if (!trace_output)
|
||||
trace_output = "osnoise_trace.txt";
|
||||
break;
|
||||
case '0': /* no header */
|
||||
params->common.hist.no_header = 1;
|
||||
break;
|
||||
case '1': /* no summary */
|
||||
params->common.hist.no_summary = 1;
|
||||
break;
|
||||
case '2': /* no index */
|
||||
params->common.hist.no_index = 1;
|
||||
break;
|
||||
case '3': /* with zeros */
|
||||
params->common.hist.with_zeros = 1;
|
||||
break;
|
||||
case '4': /* trigger */
|
||||
if (params->common.events)
|
||||
trace_event_add_trigger(params->common.events, optarg);
|
||||
else
|
||||
fatal("--trigger requires a previous -e");
|
||||
break;
|
||||
case '5': /* filter */
|
||||
if (params->common.events)
|
||||
trace_event_add_filter(params->common.events, optarg);
|
||||
else
|
||||
fatal("--filter requires a previous -e");
|
||||
break;
|
||||
case '6':
|
||||
params->common.warmup = get_llong_from_str(optarg);
|
||||
break;
|
||||
case '7':
|
||||
params->common.buffer_size = get_llong_from_str(optarg);
|
||||
break;
|
||||
case '8':
|
||||
retval = actions_parse(¶ms->common.threshold_actions, optarg,
|
||||
"osnoise_trace.txt");
|
||||
if (retval)
|
||||
fatal("Invalid action %s", optarg);
|
||||
break;
|
||||
case '9':
|
||||
retval = actions_parse(¶ms->common.end_actions, optarg,
|
||||
"osnoise_trace.txt");
|
||||
if (retval)
|
||||
fatal("Invalid action %s", optarg);
|
||||
break;
|
||||
default:
|
||||
fatal("Invalid option");
|
||||
}
|
||||
}
|
||||
|
||||
if (trace_output)
|
||||
actions_add_trace_output(¶ms->common.threshold_actions, trace_output);
|
||||
|
||||
if (geteuid())
|
||||
fatal("rtla needs root permission");
|
||||
|
||||
if (params->common.hist.no_index && !params->common.hist.with_zeros)
|
||||
fatal("no-index set and with-zeros not set - it does not make sense");
|
||||
|
||||
return ¶ms->common;
|
||||
}
|
||||
|
||||
/*
|
||||
* osnoise_hist_apply_config - apply the hist configs to the initialized tool
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <getopt.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
|
|
@ -13,6 +12,7 @@
|
|||
#include <time.h>
|
||||
|
||||
#include "osnoise.h"
|
||||
#include "cli.h"
|
||||
|
||||
struct osnoise_top_cpu {
|
||||
unsigned long long sum_runtime;
|
||||
|
|
@ -245,205 +245,6 @@ osnoise_print_stats(struct osnoise_tool *top)
|
|||
osnoise_report_missed_events(top);
|
||||
}
|
||||
|
||||
/*
|
||||
* osnoise_top_usage - prints osnoise top usage message
|
||||
*/
|
||||
static void osnoise_top_usage(struct osnoise_params *params)
|
||||
{
|
||||
const char *tool, *mode, *desc;
|
||||
|
||||
static const char * const msg_start[] = {
|
||||
"[-q] [-D] [-d s] [-a us] [-p us] [-r us] [-s us] [-S us] \\",
|
||||
" [-T us] [-t [file]] [-e sys[:event]] [--filter <filter>] [--trigger <trigger>] \\",
|
||||
" [-c cpu-list] [-H cpu-list] [-P priority] [-C [cgroup_name]] [--warm-up s]",
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const char * const msg_opts[] = {
|
||||
" -a/--auto: set automatic trace mode, stopping the session if argument in us sample is hit",
|
||||
" -p/--period us: osnoise period in us",
|
||||
" -r/--runtime us: osnoise runtime in us",
|
||||
" -s/--stop us: stop trace if a single sample is higher than the argument in us",
|
||||
" -S/--stop-total us: stop trace if the total sample is higher than the argument in us",
|
||||
" -T/--threshold us: the minimum delta to be considered a noise",
|
||||
" -c/--cpus cpu-list: list of cpus to run osnoise threads",
|
||||
" -H/--house-keeping cpus: run rtla control threads only on the given cpus",
|
||||
" -C/--cgroup [cgroup_name]: set cgroup, if no cgroup_name is passed, the rtla's cgroup will be inherited",
|
||||
" -d/--duration time[s|m|h|d]: duration of the session",
|
||||
" -D/--debug: print debug info",
|
||||
" -t/--trace [file]: save the stopped trace to [file|osnoise_trace.txt]",
|
||||
" -e/--event <sys:event>: enable the <sys:event> in the trace instance, multiple -e are allowed",
|
||||
" --filter <filter>: enable a trace event filter to the previous -e event",
|
||||
" --trigger <trigger>: enable a trace event trigger to the previous -e event",
|
||||
" -q/--quiet print only a summary at the end",
|
||||
" -P/--priority o:prio|r:prio|f:prio|d:runtime:period : set scheduling parameters",
|
||||
" o:prio - use SCHED_OTHER with prio",
|
||||
" r:prio - use SCHED_RR with prio",
|
||||
" f:prio - use SCHED_FIFO with prio",
|
||||
" d:runtime[us|ms|s]:period[us|ms|s] - use SCHED_DEADLINE with runtime and period",
|
||||
" in nanoseconds",
|
||||
" --warm-up s: let the workload run for s seconds before collecting data",
|
||||
" --trace-buffer-size kB: set the per-cpu trace buffer size in kB",
|
||||
" --on-threshold <action>: define action to be executed at stop-total threshold, multiple are allowed",
|
||||
" --on-end: define action to be executed at measurement end, multiple are allowed",
|
||||
NULL,
|
||||
};
|
||||
|
||||
if (params->mode == MODE_OSNOISE) {
|
||||
tool = "osnoise";
|
||||
mode = "top";
|
||||
desc = "a per-cpu summary of the OS noise";
|
||||
} else {
|
||||
tool = "hwnoise";
|
||||
mode = "";
|
||||
desc = "a summary of hardware-related noise";
|
||||
}
|
||||
|
||||
common_usage(tool, mode, desc, msg_start, msg_opts);
|
||||
}
|
||||
|
||||
/*
|
||||
* osnoise_top_parse_args - allocs, parse and fill the cmd line parameters
|
||||
*/
|
||||
struct common_params *osnoise_top_parse_args(int argc, char **argv)
|
||||
{
|
||||
struct osnoise_params *params;
|
||||
int retval;
|
||||
int c;
|
||||
char *trace_output = NULL;
|
||||
|
||||
params = calloc_fatal(1, sizeof(*params));
|
||||
|
||||
actions_init(¶ms->common.threshold_actions);
|
||||
actions_init(¶ms->common.end_actions);
|
||||
|
||||
if (strcmp(argv[0], "hwnoise") == 0) {
|
||||
params->mode = MODE_HWNOISE;
|
||||
/*
|
||||
* Reduce CPU usage for 75% to avoid killing the system.
|
||||
*/
|
||||
params->runtime = 750000;
|
||||
params->period = 1000000;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
static struct option long_options[] = {
|
||||
COMMON_OPTIONS,
|
||||
{"auto", required_argument, 0, 'a'},
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{"period", required_argument, 0, 'p'},
|
||||
{"quiet", no_argument, 0, 'q'},
|
||||
{"runtime", required_argument, 0, 'r'},
|
||||
{"stop", required_argument, 0, 's'},
|
||||
{"stop-total", required_argument, 0, 'S'},
|
||||
{"threshold", required_argument, 0, 'T'},
|
||||
{"trace", optional_argument, 0, 't'},
|
||||
{"trigger", required_argument, 0, '0'},
|
||||
{"filter", required_argument, 0, '1'},
|
||||
{"warm-up", required_argument, 0, '2'},
|
||||
{"trace-buffer-size", required_argument, 0, '3'},
|
||||
{"on-threshold", required_argument, 0, '4'},
|
||||
{"on-end", required_argument, 0, '5'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
c = getopt_auto(argc, argv, long_options);
|
||||
|
||||
/* Detect the end of the options. */
|
||||
if (c == -1)
|
||||
break;
|
||||
|
||||
if (set_common_option(c, argc, argv, ¶ms->common))
|
||||
continue;
|
||||
|
||||
switch (c) {
|
||||
case 'a':
|
||||
/* set sample stop to auto_thresh */
|
||||
params->common.stop_us = get_llong_from_str(optarg);
|
||||
|
||||
/* set sample threshold to 1 */
|
||||
params->threshold = 1;
|
||||
|
||||
/* set trace */
|
||||
if (!trace_output)
|
||||
trace_output = "osnoise_trace.txt";
|
||||
|
||||
break;
|
||||
case 'h':
|
||||
case '?':
|
||||
osnoise_top_usage(params);
|
||||
break;
|
||||
case 'p':
|
||||
params->period = get_llong_from_str(optarg);
|
||||
if (params->period > 10000000)
|
||||
fatal("Period longer than 10 s");
|
||||
break;
|
||||
case 'q':
|
||||
params->common.quiet = 1;
|
||||
break;
|
||||
case 'r':
|
||||
params->runtime = get_llong_from_str(optarg);
|
||||
if (params->runtime < 100)
|
||||
fatal("Runtime shorter than 100 us");
|
||||
break;
|
||||
case 's':
|
||||
params->common.stop_us = get_llong_from_str(optarg);
|
||||
break;
|
||||
case 'S':
|
||||
params->common.stop_total_us = get_llong_from_str(optarg);
|
||||
break;
|
||||
case 't':
|
||||
trace_output = parse_optional_arg(argc, argv);
|
||||
if (!trace_output)
|
||||
trace_output = "osnoise_trace.txt";
|
||||
break;
|
||||
case 'T':
|
||||
params->threshold = get_llong_from_str(optarg);
|
||||
break;
|
||||
case '0': /* trigger */
|
||||
if (params->common.events)
|
||||
trace_event_add_trigger(params->common.events, optarg);
|
||||
else
|
||||
fatal("--trigger requires a previous -e");
|
||||
break;
|
||||
case '1': /* filter */
|
||||
if (params->common.events)
|
||||
trace_event_add_filter(params->common.events, optarg);
|
||||
else
|
||||
fatal("--filter requires a previous -e");
|
||||
break;
|
||||
case '2':
|
||||
params->common.warmup = get_llong_from_str(optarg);
|
||||
break;
|
||||
case '3':
|
||||
params->common.buffer_size = get_llong_from_str(optarg);
|
||||
break;
|
||||
case '4':
|
||||
retval = actions_parse(¶ms->common.threshold_actions, optarg,
|
||||
"osnoise_trace.txt");
|
||||
if (retval)
|
||||
fatal("Invalid action %s", optarg);
|
||||
break;
|
||||
case '5':
|
||||
retval = actions_parse(¶ms->common.end_actions, optarg,
|
||||
"osnoise_trace.txt");
|
||||
if (retval)
|
||||
fatal("Invalid action %s", optarg);
|
||||
break;
|
||||
default:
|
||||
fatal("Invalid option");
|
||||
}
|
||||
}
|
||||
|
||||
if (trace_output)
|
||||
actions_add_trace_output(¶ms->common.threshold_actions, trace_output);
|
||||
|
||||
if (geteuid())
|
||||
fatal("osnoise needs root permission");
|
||||
|
||||
return ¶ms->common;
|
||||
}
|
||||
|
||||
/*
|
||||
* osnoise_top_apply_config - apply the top configs to the initialized tool
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,89 +0,0 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2021 Red Hat Inc, Daniel Bristot de Oliveira <bristot@kernel.org>
|
||||
*/
|
||||
|
||||
#include <getopt.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "osnoise.h"
|
||||
#include "timerlat.h"
|
||||
|
||||
/*
|
||||
* rtla_usage - print rtla usage
|
||||
*/
|
||||
static void rtla_usage(int err)
|
||||
{
|
||||
int i;
|
||||
|
||||
static const char *msg[] = {
|
||||
"",
|
||||
"rtla version " VERSION,
|
||||
"",
|
||||
" usage: rtla COMMAND ...",
|
||||
"",
|
||||
" commands:",
|
||||
" osnoise - gives information about the operating system noise (osnoise)",
|
||||
" hwnoise - gives information about hardware-related noise",
|
||||
" timerlat - measures the timer irq and thread latency",
|
||||
"",
|
||||
NULL,
|
||||
};
|
||||
|
||||
for (i = 0; msg[i]; i++)
|
||||
fprintf(stderr, "%s\n", msg[i]);
|
||||
exit(err);
|
||||
}
|
||||
|
||||
/*
|
||||
* run_command - try to run a rtla tool command
|
||||
*
|
||||
* It returns 0 if it fails. The tool's main will generally not
|
||||
* return as they should call exit().
|
||||
*/
|
||||
int run_command(int argc, char **argv, int start_position)
|
||||
{
|
||||
if (strcmp(argv[start_position], "osnoise") == 0) {
|
||||
osnoise_main(argc-start_position, &argv[start_position]);
|
||||
goto ran;
|
||||
} else if (strcmp(argv[start_position], "hwnoise") == 0) {
|
||||
hwnoise_main(argc-start_position, &argv[start_position]);
|
||||
goto ran;
|
||||
} else if (strcmp(argv[start_position], "timerlat") == 0) {
|
||||
timerlat_main(argc-start_position, &argv[start_position]);
|
||||
goto ran;
|
||||
}
|
||||
|
||||
return 0;
|
||||
ran:
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int retval;
|
||||
|
||||
/* is it an alias? */
|
||||
retval = run_command(argc, argv, 0);
|
||||
if (retval)
|
||||
exit(0);
|
||||
|
||||
if (argc < 2)
|
||||
goto usage;
|
||||
|
||||
if (strcmp(argv[1], "-h") == 0) {
|
||||
rtla_usage(0);
|
||||
} else if (strcmp(argv[1], "--help") == 0) {
|
||||
rtla_usage(0);
|
||||
}
|
||||
|
||||
retval = run_command(argc, argv, 1);
|
||||
if (retval)
|
||||
exit(0);
|
||||
|
||||
usage:
|
||||
rtla_usage(1);
|
||||
exit(1);
|
||||
}
|
||||
|
|
@ -13,6 +13,8 @@
|
|||
#include <stdio.h>
|
||||
#include <sched.h>
|
||||
|
||||
#include <linux/compiler.h>
|
||||
|
||||
#include "timerlat.h"
|
||||
#include "timerlat_aa.h"
|
||||
#include "timerlat_bpf.h"
|
||||
|
|
@ -75,6 +77,24 @@ timerlat_apply_config(struct osnoise_tool *tool, struct timerlat_params *params)
|
|||
goto out_err;
|
||||
}
|
||||
|
||||
retval = osnoise_set_timerlat_align(tool->context, params->timerlat_align);
|
||||
if (retval && params->timerlat_align) {
|
||||
/*
|
||||
* We might be running on a kernel that does not support timerlat align.
|
||||
* Unless user requested it explicitly, ignore the error.
|
||||
*/
|
||||
err_msg("Failed to enable timerlat align\n");
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
if (params->timerlat_align) {
|
||||
retval = osnoise_set_timerlat_align_us(tool->context, params->timerlat_align_us);
|
||||
if (retval) {
|
||||
err_msg("Failed to set timerlat align us\n");
|
||||
goto out_err;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If the user did not specify a type of thread, try user-threads first.
|
||||
* Fall back to kernel threads otherwise.
|
||||
|
|
@ -202,7 +222,7 @@ void timerlat_analyze(struct osnoise_tool *tool, bool stopped)
|
|||
* If the trace did not stop with --aa-only, at least print
|
||||
* the max known latency.
|
||||
*/
|
||||
max_lat = tracefs_instance_file_read(trace_inst->inst, "tracing_max_latency", NULL);
|
||||
max_lat = tracefs_instance_file_read(tool->trace.inst, "tracing_max_latency", NULL);
|
||||
if (max_lat) {
|
||||
printf(" Max latency was %s\n", max_lat);
|
||||
free(max_lat);
|
||||
|
|
@ -231,7 +251,7 @@ void timerlat_free(struct osnoise_tool *tool)
|
|||
free_cpu_idle_disable_states();
|
||||
}
|
||||
|
||||
static void timerlat_usage(int err)
|
||||
__noreturn static void timerlat_usage(int err)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
|
@ -269,7 +289,7 @@ int timerlat_main(int argc, char *argv[])
|
|||
}
|
||||
|
||||
if ((strcmp(argv[1], "-h") == 0) || (strcmp(argv[1], "--help") == 0)) {
|
||||
timerlat_usage(0);
|
||||
timerlat_usage(129);
|
||||
} else if (str_has_prefix(argv[1], "-")) {
|
||||
/* the user skipped the tool, call the default one */
|
||||
run_tool(&timerlat_top_ops, argc, argv);
|
||||
|
|
@ -283,6 +303,5 @@ int timerlat_main(int argc, char *argv[])
|
|||
}
|
||||
|
||||
usage:
|
||||
timerlat_usage(1);
|
||||
exit(1);
|
||||
timerlat_usage(129);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
#pragma once
|
||||
|
||||
#include "osnoise.h"
|
||||
|
||||
/*
|
||||
|
|
@ -23,12 +25,14 @@ struct timerlat_params {
|
|||
long long timerlat_period_us;
|
||||
long long print_stack;
|
||||
int dma_latency;
|
||||
int no_aa;
|
||||
int dump_tasks;
|
||||
bool no_aa;
|
||||
bool dump_tasks;
|
||||
int deepest_idle_state;
|
||||
enum timerlat_tracing_mode mode;
|
||||
const char *bpf_action_program;
|
||||
enum stack_format stack_format;
|
||||
bool timerlat_align;
|
||||
unsigned long long timerlat_align_us;
|
||||
};
|
||||
|
||||
#define to_timerlat_params(ptr) container_of(ptr, struct timerlat_params, common)
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <getopt.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
|
|
@ -17,6 +16,7 @@
|
|||
#include "timerlat.h"
|
||||
#include "timerlat_aa.h"
|
||||
#include "timerlat_bpf.h"
|
||||
#include "cli.h"
|
||||
#include "common.h"
|
||||
|
||||
struct timerlat_hist_cpu {
|
||||
|
|
@ -685,322 +685,6 @@ timerlat_print_stats(struct osnoise_tool *tool)
|
|||
osnoise_report_missed_events(tool);
|
||||
}
|
||||
|
||||
/*
|
||||
* timerlat_hist_usage - prints timerlat top usage message
|
||||
*/
|
||||
static void timerlat_hist_usage(void)
|
||||
{
|
||||
static const char * const msg_start[] = {
|
||||
"[-d s] [-D] [-n] [-a us] [-p us] [-i us] [-T us] [-s us] \\",
|
||||
" [-t [file]] [-e sys[:event]] [--filter <filter>] [--trigger <trigger>] [-c cpu-list] [-H cpu-list]\\",
|
||||
" [-P priority] [-E N] [-b N] [--no-irq] [--no-thread] [--no-header] [--no-summary] \\",
|
||||
" [--no-index] [--with-zeros] [--dma-latency us] [-C [cgroup_name]] [--no-aa] [--dump-task] [-u|-k]",
|
||||
" [--warm-up s] [--deepest-idle-state n]",
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const char * const msg_opts[] = {
|
||||
" -a/--auto: set automatic trace mode, stopping the session if argument in us latency is hit",
|
||||
" -p/--period us: timerlat period in us",
|
||||
" -i/--irq us: stop trace if the irq latency is higher than the argument in us",
|
||||
" -T/--thread us: stop trace if the thread latency is higher than the argument in us",
|
||||
" -s/--stack us: save the stack trace at the IRQ if a thread latency is higher than the argument in us",
|
||||
" -c/--cpus cpus: run the tracer only on the given cpus",
|
||||
" -H/--house-keeping cpus: run rtla control threads only on the given cpus",
|
||||
" -C/--cgroup [cgroup_name]: set cgroup, if no cgroup_name is passed, the rtla's cgroup will be inherited",
|
||||
" -d/--duration time[m|h|d]: duration of the session in seconds",
|
||||
" --dump-tasks: prints the task running on all CPUs if stop conditions are met (depends on !--no-aa)",
|
||||
" -D/--debug: print debug info",
|
||||
" -t/--trace [file]: save the stopped trace to [file|timerlat_trace.txt]",
|
||||
" -e/--event <sys:event>: enable the <sys:event> in the trace instance, multiple -e are allowed",
|
||||
" --filter <filter>: enable a trace event filter to the previous -e event",
|
||||
" --trigger <trigger>: enable a trace event trigger to the previous -e event",
|
||||
" -n/--nano: display data in nanoseconds",
|
||||
" --no-aa: disable auto-analysis, reducing rtla timerlat cpu usage",
|
||||
" -b/--bucket-size N: set the histogram bucket size (default 1)",
|
||||
" -E/--entries N: set the number of entries of the histogram (default 256)",
|
||||
" --no-irq: ignore IRQ latencies",
|
||||
" --no-thread: ignore thread latencies",
|
||||
" --no-header: do not print header",
|
||||
" --no-summary: do not print summary",
|
||||
" --no-index: do not print index",
|
||||
" --with-zeros: print zero only entries",
|
||||
" --dma-latency us: set /dev/cpu_dma_latency latency <us> to reduce exit from idle latency",
|
||||
" -P/--priority o:prio|r:prio|f:prio|d:runtime:period : set scheduling parameters",
|
||||
" o:prio - use SCHED_OTHER with prio",
|
||||
" r:prio - use SCHED_RR with prio",
|
||||
" f:prio - use SCHED_FIFO with prio",
|
||||
" d:runtime[us|ms|s]:period[us|ms|s] - use SCHED_DEADLINE with runtime and period",
|
||||
" in nanoseconds",
|
||||
" -u/--user-threads: use rtla user-space threads instead of kernel-space timerlat threads",
|
||||
" -k/--kernel-threads: use timerlat kernel-space threads instead of rtla user-space threads",
|
||||
" -U/--user-load: enable timerlat for user-defined user-space workload",
|
||||
" --warm-up s: let the workload run for s seconds before collecting data",
|
||||
" --trace-buffer-size kB: set the per-cpu trace buffer size in kB",
|
||||
" --deepest-idle-state n: only go down to idle state n on cpus used by timerlat to reduce exit from idle latency",
|
||||
" --on-threshold <action>: define action to be executed at latency threshold, multiple are allowed",
|
||||
" --on-end <action>: define action to be executed at measurement end, multiple are allowed",
|
||||
" --bpf-action <program>: load and execute BPF program when latency threshold is exceeded",
|
||||
" --stack-format <format>: set the stack format (truncate, skip, full)",
|
||||
NULL,
|
||||
};
|
||||
|
||||
common_usage("timerlat", "hist", "a per-cpu histogram of the timer latency",
|
||||
msg_start, msg_opts);
|
||||
}
|
||||
|
||||
/*
|
||||
* timerlat_hist_parse_args - allocs, parse and fill the cmd line parameters
|
||||
*/
|
||||
static struct common_params
|
||||
*timerlat_hist_parse_args(int argc, char *argv[])
|
||||
{
|
||||
struct timerlat_params *params;
|
||||
int auto_thresh;
|
||||
int retval;
|
||||
int c;
|
||||
char *trace_output = NULL;
|
||||
|
||||
params = calloc_fatal(1, sizeof(*params));
|
||||
|
||||
actions_init(¶ms->common.threshold_actions);
|
||||
actions_init(¶ms->common.end_actions);
|
||||
|
||||
/* disabled by default */
|
||||
params->dma_latency = -1;
|
||||
|
||||
/* disabled by default */
|
||||
params->deepest_idle_state = -2;
|
||||
|
||||
/* display data in microseconds */
|
||||
params->common.output_divisor = 1000;
|
||||
params->common.hist.bucket_size = 1;
|
||||
params->common.hist.entries = 256;
|
||||
|
||||
/* default to BPF mode */
|
||||
params->mode = TRACING_MODE_BPF;
|
||||
|
||||
/* default to truncate stack format */
|
||||
params->stack_format = STACK_FORMAT_TRUNCATE;
|
||||
|
||||
while (1) {
|
||||
static struct option long_options[] = {
|
||||
COMMON_OPTIONS,
|
||||
{"auto", required_argument, 0, 'a'},
|
||||
{"bucket-size", required_argument, 0, 'b'},
|
||||
{"entries", required_argument, 0, 'E'},
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{"irq", required_argument, 0, 'i'},
|
||||
{"nano", no_argument, 0, 'n'},
|
||||
{"period", required_argument, 0, 'p'},
|
||||
{"stack", required_argument, 0, 's'},
|
||||
{"thread", required_argument, 0, 'T'},
|
||||
{"trace", optional_argument, 0, 't'},
|
||||
{"user-threads", no_argument, 0, 'u'},
|
||||
{"kernel-threads", no_argument, 0, 'k'},
|
||||
{"user-load", no_argument, 0, 'U'},
|
||||
{"no-irq", no_argument, 0, '0'},
|
||||
{"no-thread", no_argument, 0, '1'},
|
||||
{"no-header", no_argument, 0, '2'},
|
||||
{"no-summary", no_argument, 0, '3'},
|
||||
{"no-index", no_argument, 0, '4'},
|
||||
{"with-zeros", no_argument, 0, '5'},
|
||||
{"trigger", required_argument, 0, '6'},
|
||||
{"filter", required_argument, 0, '7'},
|
||||
{"dma-latency", required_argument, 0, '8'},
|
||||
{"no-aa", no_argument, 0, '9'},
|
||||
{"dump-task", no_argument, 0, '\1'},
|
||||
{"warm-up", required_argument, 0, '\2'},
|
||||
{"trace-buffer-size", required_argument, 0, '\3'},
|
||||
{"deepest-idle-state", required_argument, 0, '\4'},
|
||||
{"on-threshold", required_argument, 0, '\5'},
|
||||
{"on-end", required_argument, 0, '\6'},
|
||||
{"bpf-action", required_argument, 0, '\7'},
|
||||
{"stack-format", required_argument, 0, '\10'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
c = getopt_auto(argc, argv, long_options);
|
||||
|
||||
if (set_common_option(c, argc, argv, ¶ms->common))
|
||||
continue;
|
||||
|
||||
/* detect the end of the options. */
|
||||
if (c == -1)
|
||||
break;
|
||||
|
||||
switch (c) {
|
||||
case 'a':
|
||||
auto_thresh = get_llong_from_str(optarg);
|
||||
|
||||
/* set thread stop to auto_thresh */
|
||||
params->common.stop_total_us = auto_thresh;
|
||||
params->common.stop_us = auto_thresh;
|
||||
|
||||
/* get stack trace */
|
||||
params->print_stack = auto_thresh;
|
||||
|
||||
/* set trace */
|
||||
if (!trace_output)
|
||||
trace_output = "timerlat_trace.txt";
|
||||
|
||||
break;
|
||||
case 'b':
|
||||
params->common.hist.bucket_size = get_llong_from_str(optarg);
|
||||
if (params->common.hist.bucket_size == 0 ||
|
||||
params->common.hist.bucket_size >= 1000000)
|
||||
fatal("Bucket size needs to be > 0 and <= 1000000");
|
||||
break;
|
||||
case 'E':
|
||||
params->common.hist.entries = get_llong_from_str(optarg);
|
||||
if (params->common.hist.entries < 10 ||
|
||||
params->common.hist.entries > 9999999)
|
||||
fatal("Entries must be > 10 and < 9999999");
|
||||
break;
|
||||
case 'h':
|
||||
case '?':
|
||||
timerlat_hist_usage();
|
||||
break;
|
||||
case 'i':
|
||||
params->common.stop_us = get_llong_from_str(optarg);
|
||||
break;
|
||||
case 'k':
|
||||
params->common.kernel_workload = 1;
|
||||
break;
|
||||
case 'n':
|
||||
params->common.output_divisor = 1;
|
||||
break;
|
||||
case 'p':
|
||||
params->timerlat_period_us = get_llong_from_str(optarg);
|
||||
if (params->timerlat_period_us > 1000000)
|
||||
fatal("Period longer than 1 s");
|
||||
break;
|
||||
case 's':
|
||||
params->print_stack = get_llong_from_str(optarg);
|
||||
break;
|
||||
case 'T':
|
||||
params->common.stop_total_us = get_llong_from_str(optarg);
|
||||
break;
|
||||
case 't':
|
||||
trace_output = parse_optional_arg(argc, argv);
|
||||
if (!trace_output)
|
||||
trace_output = "timerlat_trace.txt";
|
||||
break;
|
||||
case 'u':
|
||||
params->common.user_workload = 1;
|
||||
/* fallback: -u implies in -U */
|
||||
case 'U':
|
||||
params->common.user_data = 1;
|
||||
break;
|
||||
case '0': /* no irq */
|
||||
params->common.hist.no_irq = 1;
|
||||
break;
|
||||
case '1': /* no thread */
|
||||
params->common.hist.no_thread = 1;
|
||||
break;
|
||||
case '2': /* no header */
|
||||
params->common.hist.no_header = 1;
|
||||
break;
|
||||
case '3': /* no summary */
|
||||
params->common.hist.no_summary = 1;
|
||||
break;
|
||||
case '4': /* no index */
|
||||
params->common.hist.no_index = 1;
|
||||
break;
|
||||
case '5': /* with zeros */
|
||||
params->common.hist.with_zeros = 1;
|
||||
break;
|
||||
case '6': /* trigger */
|
||||
if (params->common.events)
|
||||
trace_event_add_trigger(params->common.events, optarg);
|
||||
else
|
||||
fatal("--trigger requires a previous -e");
|
||||
break;
|
||||
case '7': /* filter */
|
||||
if (params->common.events)
|
||||
trace_event_add_filter(params->common.events, optarg);
|
||||
else
|
||||
fatal("--filter requires a previous -e");
|
||||
break;
|
||||
case '8':
|
||||
params->dma_latency = get_llong_from_str(optarg);
|
||||
if (params->dma_latency < 0 || params->dma_latency > 10000)
|
||||
fatal("--dma-latency needs to be >= 0 and < 10000");
|
||||
break;
|
||||
case '9':
|
||||
params->no_aa = 1;
|
||||
break;
|
||||
case '\1':
|
||||
params->dump_tasks = 1;
|
||||
break;
|
||||
case '\2':
|
||||
params->common.warmup = get_llong_from_str(optarg);
|
||||
break;
|
||||
case '\3':
|
||||
params->common.buffer_size = get_llong_from_str(optarg);
|
||||
break;
|
||||
case '\4':
|
||||
params->deepest_idle_state = get_llong_from_str(optarg);
|
||||
break;
|
||||
case '\5':
|
||||
retval = actions_parse(¶ms->common.threshold_actions, optarg,
|
||||
"timerlat_trace.txt");
|
||||
if (retval)
|
||||
fatal("Invalid action %s", optarg);
|
||||
break;
|
||||
case '\6':
|
||||
retval = actions_parse(¶ms->common.end_actions, optarg,
|
||||
"timerlat_trace.txt");
|
||||
if (retval)
|
||||
fatal("Invalid action %s", optarg);
|
||||
break;
|
||||
case '\7':
|
||||
params->bpf_action_program = optarg;
|
||||
break;
|
||||
case '\10':
|
||||
params->stack_format = parse_stack_format(optarg);
|
||||
if (params->stack_format == -1)
|
||||
fatal("Invalid --stack-format option");
|
||||
break;
|
||||
default:
|
||||
fatal("Invalid option");
|
||||
}
|
||||
}
|
||||
|
||||
if (trace_output)
|
||||
actions_add_trace_output(¶ms->common.threshold_actions, trace_output);
|
||||
|
||||
if (geteuid())
|
||||
fatal("rtla needs root permission");
|
||||
|
||||
if (params->common.hist.no_irq && params->common.hist.no_thread)
|
||||
fatal("no-irq and no-thread set, there is nothing to do here");
|
||||
|
||||
if (params->common.hist.no_index && !params->common.hist.with_zeros)
|
||||
fatal("no-index set with with-zeros is not set - it does not make sense");
|
||||
|
||||
/*
|
||||
* Auto analysis only happens if stop tracing, thus:
|
||||
*/
|
||||
if (!params->common.stop_us && !params->common.stop_total_us)
|
||||
params->no_aa = 1;
|
||||
|
||||
if (params->common.kernel_workload && params->common.user_workload)
|
||||
fatal("--kernel-threads and --user-threads are mutually exclusive!");
|
||||
|
||||
/*
|
||||
* If auto-analysis or trace output is enabled, switch from BPF mode to
|
||||
* mixed mode
|
||||
*/
|
||||
if (params->mode == TRACING_MODE_BPF &&
|
||||
(params->common.threshold_actions.present[ACTION_TRACE_OUTPUT] ||
|
||||
params->common.end_actions.present[ACTION_TRACE_OUTPUT] ||
|
||||
!params->no_aa))
|
||||
params->mode = TRACING_MODE_MIXED;
|
||||
|
||||
return ¶ms->common;
|
||||
}
|
||||
|
||||
/*
|
||||
* timerlat_hist_apply_config - apply the hist configs to the initialized tool
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <getopt.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
|
|
@ -17,6 +16,7 @@
|
|||
#include "timerlat.h"
|
||||
#include "timerlat_aa.h"
|
||||
#include "timerlat_bpf.h"
|
||||
#include "cli.h"
|
||||
#include "common.h"
|
||||
|
||||
struct timerlat_top_cpu {
|
||||
|
|
@ -459,290 +459,6 @@ timerlat_print_stats(struct osnoise_tool *top)
|
|||
osnoise_report_missed_events(top);
|
||||
}
|
||||
|
||||
/*
|
||||
* timerlat_top_usage - prints timerlat top usage message
|
||||
*/
|
||||
static void timerlat_top_usage(void)
|
||||
{
|
||||
static const char *const msg_start[] = {
|
||||
"[-q] [-a us] [-d s] [-D] [-n] [-p us] [-i us] [-T us] [-s us] \\",
|
||||
" [[-t [file]] [-e sys[:event]] [--filter <filter>] [--trigger <trigger>] [-c cpu-list] [-H cpu-list]\\",
|
||||
" [-P priority] [--dma-latency us] [--aa-only us] [-C [cgroup_name]] [-u|-k] [--warm-up s] [--deepest-idle-state n]",
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const char *const msg_opts[] = {
|
||||
" -a/--auto: set automatic trace mode, stopping the session if argument in us latency is hit",
|
||||
" --aa-only us: stop if <us> latency is hit, only printing the auto analysis (reduces CPU usage)",
|
||||
" -p/--period us: timerlat period in us",
|
||||
" -i/--irq us: stop trace if the irq latency is higher than the argument in us",
|
||||
" -T/--thread us: stop trace if the thread latency is higher than the argument in us",
|
||||
" -s/--stack us: save the stack trace at the IRQ if a thread latency is higher than the argument in us",
|
||||
" -c/--cpus cpus: run the tracer only on the given cpus",
|
||||
" -H/--house-keeping cpus: run rtla control threads only on the given cpus",
|
||||
" -C/--cgroup [cgroup_name]: set cgroup, if no cgroup_name is passed, the rtla's cgroup will be inherited",
|
||||
" -d/--duration time[s|m|h|d]: duration of the session",
|
||||
" -D/--debug: print debug info",
|
||||
" --dump-tasks: prints the task running on all CPUs if stop conditions are met (depends on !--no-aa)",
|
||||
" -t/--trace [file]: save the stopped trace to [file|timerlat_trace.txt]",
|
||||
" -e/--event <sys:event>: enable the <sys:event> in the trace instance, multiple -e are allowed",
|
||||
" --filter <command>: enable a trace event filter to the previous -e event",
|
||||
" --trigger <command>: enable a trace event trigger to the previous -e event",
|
||||
" -n/--nano: display data in nanoseconds",
|
||||
" --no-aa: disable auto-analysis, reducing rtla timerlat cpu usage",
|
||||
" -q/--quiet print only a summary at the end",
|
||||
" --dma-latency us: set /dev/cpu_dma_latency latency <us> to reduce exit from idle latency",
|
||||
" -P/--priority o:prio|r:prio|f:prio|d:runtime:period : set scheduling parameters",
|
||||
" o:prio - use SCHED_OTHER with prio",
|
||||
" r:prio - use SCHED_RR with prio",
|
||||
" f:prio - use SCHED_FIFO with prio",
|
||||
" d:runtime[us|ms|s]:period[us|ms|s] - use SCHED_DEADLINE with runtime and period",
|
||||
" in nanoseconds",
|
||||
" -u/--user-threads: use rtla user-space threads instead of kernel-space timerlat threads",
|
||||
" -k/--kernel-threads: use timerlat kernel-space threads instead of rtla user-space threads",
|
||||
" -U/--user-load: enable timerlat for user-defined user-space workload",
|
||||
" --warm-up s: let the workload run for s seconds before collecting data",
|
||||
" --trace-buffer-size kB: set the per-cpu trace buffer size in kB",
|
||||
" --deepest-idle-state n: only go down to idle state n on cpus used by timerlat to reduce exit from idle latency",
|
||||
" --on-threshold <action>: define action to be executed at latency threshold, multiple are allowed",
|
||||
" --on-end: define action to be executed at measurement end, multiple are allowed",
|
||||
" --bpf-action <program>: load and execute BPF program when latency threshold is exceeded",
|
||||
" --stack-format <format>: set the stack format (truncate, skip, full)",
|
||||
NULL,
|
||||
};
|
||||
|
||||
common_usage("timerlat", "top", "a per-cpu summary of the timer latency",
|
||||
msg_start, msg_opts);
|
||||
}
|
||||
|
||||
/*
|
||||
* timerlat_top_parse_args - allocs, parse and fill the cmd line parameters
|
||||
*/
|
||||
static struct common_params
|
||||
*timerlat_top_parse_args(int argc, char **argv)
|
||||
{
|
||||
struct timerlat_params *params;
|
||||
long long auto_thresh;
|
||||
int retval;
|
||||
int c;
|
||||
char *trace_output = NULL;
|
||||
|
||||
params = calloc_fatal(1, sizeof(*params));
|
||||
|
||||
actions_init(¶ms->common.threshold_actions);
|
||||
actions_init(¶ms->common.end_actions);
|
||||
|
||||
/* disabled by default */
|
||||
params->dma_latency = -1;
|
||||
|
||||
/* disabled by default */
|
||||
params->deepest_idle_state = -2;
|
||||
|
||||
/* display data in microseconds */
|
||||
params->common.output_divisor = 1000;
|
||||
|
||||
/* default to BPF mode */
|
||||
params->mode = TRACING_MODE_BPF;
|
||||
|
||||
/* default to truncate stack format */
|
||||
params->stack_format = STACK_FORMAT_TRUNCATE;
|
||||
|
||||
while (1) {
|
||||
static struct option long_options[] = {
|
||||
COMMON_OPTIONS,
|
||||
{"auto", required_argument, 0, 'a'},
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{"irq", required_argument, 0, 'i'},
|
||||
{"nano", no_argument, 0, 'n'},
|
||||
{"period", required_argument, 0, 'p'},
|
||||
{"quiet", no_argument, 0, 'q'},
|
||||
{"stack", required_argument, 0, 's'},
|
||||
{"thread", required_argument, 0, 'T'},
|
||||
{"trace", optional_argument, 0, 't'},
|
||||
{"user-threads", no_argument, 0, 'u'},
|
||||
{"kernel-threads", no_argument, 0, 'k'},
|
||||
{"user-load", no_argument, 0, 'U'},
|
||||
{"trigger", required_argument, 0, '0'},
|
||||
{"filter", required_argument, 0, '1'},
|
||||
{"dma-latency", required_argument, 0, '2'},
|
||||
{"no-aa", no_argument, 0, '3'},
|
||||
{"dump-tasks", no_argument, 0, '4'},
|
||||
{"aa-only", required_argument, 0, '5'},
|
||||
{"warm-up", required_argument, 0, '6'},
|
||||
{"trace-buffer-size", required_argument, 0, '7'},
|
||||
{"deepest-idle-state", required_argument, 0, '8'},
|
||||
{"on-threshold", required_argument, 0, '9'},
|
||||
{"on-end", required_argument, 0, '\1'},
|
||||
{"bpf-action", required_argument, 0, '\2'},
|
||||
{"stack-format", required_argument, 0, '\3'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
c = getopt_auto(argc, argv, long_options);
|
||||
|
||||
if (set_common_option(c, argc, argv, ¶ms->common))
|
||||
continue;
|
||||
|
||||
/* detect the end of the options. */
|
||||
if (c == -1)
|
||||
break;
|
||||
|
||||
switch (c) {
|
||||
case 'a':
|
||||
auto_thresh = get_llong_from_str(optarg);
|
||||
|
||||
/* set thread stop to auto_thresh */
|
||||
params->common.stop_total_us = auto_thresh;
|
||||
params->common.stop_us = auto_thresh;
|
||||
|
||||
/* get stack trace */
|
||||
params->print_stack = auto_thresh;
|
||||
|
||||
/* set trace */
|
||||
if (!trace_output)
|
||||
trace_output = "timerlat_trace.txt";
|
||||
|
||||
break;
|
||||
case '5':
|
||||
/* it is here because it is similar to -a */
|
||||
auto_thresh = get_llong_from_str(optarg);
|
||||
|
||||
/* set thread stop to auto_thresh */
|
||||
params->common.stop_total_us = auto_thresh;
|
||||
params->common.stop_us = auto_thresh;
|
||||
|
||||
/* get stack trace */
|
||||
params->print_stack = auto_thresh;
|
||||
|
||||
/* set aa_only to avoid parsing the trace */
|
||||
params->common.aa_only = 1;
|
||||
break;
|
||||
case 'h':
|
||||
case '?':
|
||||
timerlat_top_usage();
|
||||
break;
|
||||
case 'i':
|
||||
params->common.stop_us = get_llong_from_str(optarg);
|
||||
break;
|
||||
case 'k':
|
||||
params->common.kernel_workload = true;
|
||||
break;
|
||||
case 'n':
|
||||
params->common.output_divisor = 1;
|
||||
break;
|
||||
case 'p':
|
||||
params->timerlat_period_us = get_llong_from_str(optarg);
|
||||
if (params->timerlat_period_us > 1000000)
|
||||
fatal("Period longer than 1 s");
|
||||
break;
|
||||
case 'q':
|
||||
params->common.quiet = 1;
|
||||
break;
|
||||
case 's':
|
||||
params->print_stack = get_llong_from_str(optarg);
|
||||
break;
|
||||
case 'T':
|
||||
params->common.stop_total_us = get_llong_from_str(optarg);
|
||||
break;
|
||||
case 't':
|
||||
trace_output = parse_optional_arg(argc, argv);
|
||||
if (!trace_output)
|
||||
trace_output = "timerlat_trace.txt";
|
||||
break;
|
||||
case 'u':
|
||||
params->common.user_workload = true;
|
||||
/* fallback: -u implies -U */
|
||||
case 'U':
|
||||
params->common.user_data = true;
|
||||
break;
|
||||
case '0': /* trigger */
|
||||
if (params->common.events)
|
||||
trace_event_add_trigger(params->common.events, optarg);
|
||||
else
|
||||
fatal("--trigger requires a previous -e");
|
||||
break;
|
||||
case '1': /* filter */
|
||||
if (params->common.events)
|
||||
trace_event_add_filter(params->common.events, optarg);
|
||||
else
|
||||
fatal("--filter requires a previous -e");
|
||||
break;
|
||||
case '2': /* dma-latency */
|
||||
params->dma_latency = get_llong_from_str(optarg);
|
||||
if (params->dma_latency < 0 || params->dma_latency > 10000)
|
||||
fatal("--dma-latency needs to be >= 0 and < 10000");
|
||||
break;
|
||||
case '3': /* no-aa */
|
||||
params->no_aa = 1;
|
||||
break;
|
||||
case '4':
|
||||
params->dump_tasks = 1;
|
||||
break;
|
||||
case '6':
|
||||
params->common.warmup = get_llong_from_str(optarg);
|
||||
break;
|
||||
case '7':
|
||||
params->common.buffer_size = get_llong_from_str(optarg);
|
||||
break;
|
||||
case '8':
|
||||
params->deepest_idle_state = get_llong_from_str(optarg);
|
||||
break;
|
||||
case '9':
|
||||
retval = actions_parse(¶ms->common.threshold_actions, optarg,
|
||||
"timerlat_trace.txt");
|
||||
if (retval)
|
||||
fatal("Invalid action %s", optarg);
|
||||
break;
|
||||
case '\1':
|
||||
retval = actions_parse(¶ms->common.end_actions, optarg,
|
||||
"timerlat_trace.txt");
|
||||
if (retval)
|
||||
fatal("Invalid action %s", optarg);
|
||||
break;
|
||||
case '\2':
|
||||
params->bpf_action_program = optarg;
|
||||
break;
|
||||
case '\3':
|
||||
params->stack_format = parse_stack_format(optarg);
|
||||
if (params->stack_format == -1)
|
||||
fatal("Invalid --stack-format option");
|
||||
break;
|
||||
default:
|
||||
fatal("Invalid option");
|
||||
}
|
||||
}
|
||||
|
||||
if (trace_output)
|
||||
actions_add_trace_output(¶ms->common.threshold_actions, trace_output);
|
||||
|
||||
if (geteuid())
|
||||
fatal("rtla needs root permission");
|
||||
|
||||
/*
|
||||
* Auto analysis only happens if stop tracing, thus:
|
||||
*/
|
||||
if (!params->common.stop_us && !params->common.stop_total_us)
|
||||
params->no_aa = 1;
|
||||
|
||||
if (params->no_aa && params->common.aa_only)
|
||||
fatal("--no-aa and --aa-only are mutually exclusive!");
|
||||
|
||||
if (params->common.kernel_workload && params->common.user_workload)
|
||||
fatal("--kernel-threads and --user-threads are mutually exclusive!");
|
||||
|
||||
/*
|
||||
* If auto-analysis or trace output is enabled, switch from BPF mode to
|
||||
* mixed mode
|
||||
*/
|
||||
if (params->mode == TRACING_MODE_BPF &&
|
||||
(params->common.threshold_actions.present[ACTION_TRACE_OUTPUT] ||
|
||||
params->common.end_actions.present[ACTION_TRACE_OUTPUT] ||
|
||||
!params->no_aa))
|
||||
params->mode = TRACING_MODE_MIXED;
|
||||
|
||||
return ¶ms->common;
|
||||
}
|
||||
|
||||
/*
|
||||
* timerlat_top_apply_config - apply the top configs to the initialized tool
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
#include "common.h"
|
||||
|
||||
#define MAX_MSG_LENGTH 1024
|
||||
int config_debug;
|
||||
bool config_debug;
|
||||
|
||||
/*
|
||||
* err_msg - print an error message to the stderr
|
||||
|
|
@ -1011,32 +1011,6 @@ int auto_house_keeping(cpu_set_t *monitored_cpus)
|
|||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* parse_optional_arg - Parse optional argument value
|
||||
*
|
||||
* Parse optional argument value, which can be in the form of:
|
||||
* -sarg, -s/--long=arg, -s/--long arg
|
||||
*
|
||||
* Returns arg value if found, NULL otherwise.
|
||||
*/
|
||||
char *parse_optional_arg(int argc, char **argv)
|
||||
{
|
||||
if (optarg) {
|
||||
if (optarg[0] == '=') {
|
||||
/* skip the = */
|
||||
return &optarg[1];
|
||||
} else {
|
||||
return optarg;
|
||||
}
|
||||
/* parse argument of form -s [arg] and --long [arg]*/
|
||||
} else if (optind < argc && argv[optind][0] != '-') {
|
||||
/* consume optind */
|
||||
return argv[optind++];
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* strtoi - convert string to integer with error checking
|
||||
*
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@
|
|||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <linux/container_of.h>
|
||||
|
||||
/*
|
||||
* '18446744073709551615\0'
|
||||
*/
|
||||
|
|
@ -37,11 +39,7 @@ static inline bool str_has_prefix(const char *str, const char *prefix)
|
|||
return strncmp(str, prefix, strlen(prefix)) == 0;
|
||||
}
|
||||
|
||||
#define container_of(ptr, type, member)({ \
|
||||
const typeof(((type *)0)->member) *__mptr = (ptr); \
|
||||
(type *)((char *)__mptr - offsetof(type, member)) ; })
|
||||
|
||||
extern int config_debug;
|
||||
extern bool config_debug;
|
||||
void debug_msg(const char *fmt, ...);
|
||||
void err_msg(const char *fmt, ...);
|
||||
void fatal(const char *fmt, ...);
|
||||
|
|
@ -49,7 +47,6 @@ void fatal(const char *fmt, ...);
|
|||
long parse_seconds_duration(char *val);
|
||||
void get_duration(time_t start_time, char *output, int output_size);
|
||||
|
||||
char *parse_optional_arg(int argc, char **argv);
|
||||
long long get_llong_from_str(char *start);
|
||||
|
||||
static inline void
|
||||
|
|
|
|||
|
|
@ -4,6 +4,9 @@ test_begin() {
|
|||
# Count tests to allow the test harness to double-check if all were
|
||||
# included correctly.
|
||||
ctr=0
|
||||
# Set test directory to the directory of the script
|
||||
scriptfile=$(realpath "$0")
|
||||
testdir=$(dirname "$scriptfile")
|
||||
[ -z "$RTLA" ] && RTLA="./rtla"
|
||||
[ -n "$TEST_COUNT" ] && echo "1..$TEST_COUNT"
|
||||
}
|
||||
|
|
@ -51,6 +54,11 @@ check() {
|
|||
then
|
||||
# Reset osnoise options before running test.
|
||||
[ "$NO_RESET_OSNOISE" == 1 ] || reset_osnoise
|
||||
|
||||
# Create a temporary directory to contain rtla output
|
||||
tmpdir=$(mktemp -d)
|
||||
pushd $tmpdir >/dev/null
|
||||
|
||||
# Run rtla; in case of failure, include its output as comment
|
||||
# in the test results.
|
||||
result=$(eval stdbuf -oL $TIMEOUT "$RTLA" $2 2>&1); exitcode=$?
|
||||
|
|
@ -82,6 +90,10 @@ check() {
|
|||
echo "$result" | col -b | while read line; do echo "# $line"; done
|
||||
printf "#\n# exit code %s\n" $exitcode
|
||||
fi
|
||||
|
||||
# Remove temporary directory
|
||||
popd >/dev/null
|
||||
rm -r $tmpdir
|
||||
fi
|
||||
}
|
||||
|
||||
|
|
@ -112,6 +124,21 @@ check_with_osnoise_options() {
|
|||
NO_RESET_OSNOISE=1 check "$arg1" "$arg2" "$arg3"
|
||||
}
|
||||
|
||||
check_top_hist() {
|
||||
# Test one command with both "top" and "hist" tools, replacing "TOOL" in
|
||||
# command with either "top" or "hist" respectively, and prefixing the test
|
||||
# names with "top " and "hist ".
|
||||
check "top $1" "$(echo "$2" | sed 's/TOOL/top/g')" "${@:3}"
|
||||
check "hist $1" "$(echo "$2" | sed 's/TOOL/hist/g')" "${@:3}"
|
||||
}
|
||||
|
||||
check_top_q_hist() {
|
||||
# Same as above, but pass "-q" to top so that strings printed in main
|
||||
# loop are on their own line for top too, not only for hist.
|
||||
check "top $1" "$(echo "$2" | sed 's/TOOL/top -q/g')" "${@:3}"
|
||||
check "hist $1" "$(echo "$2" | sed 's/TOOL/hist/g')" "${@:3}"
|
||||
}
|
||||
|
||||
set_timeout() {
|
||||
TIMEOUT="timeout -v -k 15s $1"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ test_begin
|
|||
set_timeout 2m
|
||||
|
||||
check "verify help page" \
|
||||
"hwnoise --help" 0 "summary of hardware-related noise"
|
||||
"hwnoise --help" 129 "Usage: rtla hwnoise"
|
||||
check "detect noise higher than one microsecond" \
|
||||
"hwnoise -c 0 -T 1 -d 5s -q" 0
|
||||
check "set the automatic trace mode" \
|
||||
|
|
|
|||
|
|
@ -6,16 +6,41 @@ test_begin
|
|||
set_timeout 2m
|
||||
|
||||
check "verify help page" \
|
||||
"osnoise --help" 0 "osnoise version"
|
||||
check "verify the --priority/-P param" \
|
||||
"osnoise top -P F:1 -c 0 -r 900000 -d 10s -q -S 1 --on-threshold shell,command=\"tests/scripts/check-priority.sh osnoise/ SCHED_FIFO 1\"" \
|
||||
"osnoise --help" 129 "osnoise version"
|
||||
check_top_hist "verify help page" \
|
||||
"osnoise TOOL --help" 129 "rtla osnoise"
|
||||
check_top_q_hist "verify the --stop/-s param" \
|
||||
"osnoise TOOL -s 30 -T 1" 2 "osnoise hit stop tracing"
|
||||
check_top_q_hist "verify the --trace param" \
|
||||
"osnoise TOOL -s 30 -T 1 -t" 2 "Saving trace to osnoise_trace.txt"
|
||||
|
||||
# Thread tests
|
||||
check_top_q_hist "verify the --priority/-P param" \
|
||||
"osnoise TOOL -P F:1 -c 0 -r 900000 -d 10s -S 1 --on-threshold shell,command=\"$testdir/scripts/check-priority.sh SCHED_FIFO 1\"" \
|
||||
2 "Priorities are set correctly"
|
||||
check "verify the --stop/-s param" \
|
||||
"osnoise top -s 30 -T 1" 2 "osnoise hit stop tracing"
|
||||
check "verify the --trace param" \
|
||||
"osnoise hist -s 30 -T 1 -t" 2 "Saving trace to osnoise_trace.txt"
|
||||
check "verify the --entries/-E param" \
|
||||
"osnoise hist -P F:1 -c 0 -r 900000 -d 10s -b 10 -E 25"
|
||||
check_top_q_hist "verify the -C/--cgroup param" \
|
||||
"osnoise TOOL -C -c 0 -r 900000 -d 10s -S 1 --on-threshold shell,command=\"$testdir/scripts/check-cgroup-match.sh\"" \
|
||||
2 "cgroup matches for all workload PIDs"
|
||||
check_top_q_hist "verify the -c/--cpus param" \
|
||||
"osnoise TOOL -P F:1 -c 0 -r 900000 -d 10s -S 1 --on-threshold shell,command=$testdir/scripts/check-cpus.sh" 2 "^Affinity of threads: 0$"
|
||||
check_top_q_hist "verify the -H/--house-keeping param" \
|
||||
"osnoise TOOL -P F:1 -H 0 -r 900000 -d 10s -S 1 --on-threshold shell,command=$testdir/scripts/check-housekeeping-cpus.sh" 2 "^Affinity of threads: 0$"
|
||||
|
||||
# Histogram tests
|
||||
check "hist with -b/--bucket-size" \
|
||||
"osnoise hist -b 1 -d 1s"
|
||||
check "hist with -E/--entries" \
|
||||
"osnoise hist -E 10 -d 1s"
|
||||
check "hist with -E/--entries out of range" \
|
||||
"osnoise hist -E 1 -d 1s" 1 "^Entries must be > 10 and < 10000000$"
|
||||
check "hist with --no-header" \
|
||||
"osnoise hist --no-header -d 1s" 0 "" "RTLA osnoise histogram"
|
||||
check "hist with --with-zeros" \
|
||||
"osnoise hist --with-zeros -b 100000 -E 21 -d 1s" 0 '^2000000\s+0\s+'
|
||||
check "hist with --no-index" \
|
||||
"osnoise hist --no-index --with-zeros -d 1s" 0 "" "^count:"
|
||||
check "hist with --no-summary" \
|
||||
"osnoise hist --no-summary -d 1s" 0 "" "^count:"
|
||||
|
||||
# Test setting default period by putting an absurdly high period
|
||||
# and stopping on threshold.
|
||||
|
|
@ -24,27 +49,25 @@ check_with_osnoise_options "apply default period" \
|
|||
"osnoise hist -s 1" 2 period_us=600000000
|
||||
|
||||
# Actions tests
|
||||
check "trace output through -t with custom filename" \
|
||||
"osnoise hist -S 2 -t custom_filename.txt" 2 "^ Saving trace to custom_filename.txt$"
|
||||
check "trace output through --on-threshold trace" \
|
||||
"osnoise hist -S 2 --on-threshold trace" 2 "^ Saving trace to osnoise_trace.txt$"
|
||||
check "trace output through --on-threshold trace with custom filename" \
|
||||
"osnoise hist -S 2 --on-threshold trace,file=custom_filename.txt" 2 "^ Saving trace to custom_filename.txt$"
|
||||
check "exec command" \
|
||||
"osnoise hist -S 2 --on-threshold shell,command='echo TestOutput'" 2 "^TestOutput$"
|
||||
check "multiple actions" \
|
||||
"osnoise hist -S 2 --on-threshold shell,command='echo -n 1' --on-threshold shell,command='echo 2'" 2 "^12$"
|
||||
check_top_q_hist "trace output through -t with custom filename" \
|
||||
"osnoise TOOL -S 2 -t custom_filename.txt" 2 "^ Saving trace to custom_filename.txt$"
|
||||
check_top_q_hist "trace output through --on-threshold trace" \
|
||||
"osnoise TOOL -S 2 --on-threshold trace" 2 "^ Saving trace to osnoise_trace.txt$"
|
||||
check_top_q_hist "trace output through --on-threshold trace with custom filename" \
|
||||
"osnoise TOOL -S 2 --on-threshold trace,file=custom_filename.txt" 2 "^ Saving trace to custom_filename.txt$"
|
||||
check_top_q_hist "exec command" \
|
||||
"osnoise TOOL -S 2 --on-threshold shell,command='echo TestOutput'" 2 "^TestOutput$"
|
||||
check_top_q_hist "multiple actions" \
|
||||
"osnoise TOOL -S 2 --on-threshold shell,command='echo -n 1' --on-threshold shell,command='echo 2'" 2 "^12$"
|
||||
check "hist stop at failed action" \
|
||||
"osnoise hist -S 2 --on-threshold shell,command='echo -n 1; false' --on-threshold shell,command='echo -n 2'" 2 "^1# RTLA osnoise histogram$"
|
||||
check "top stop at failed action" \
|
||||
"osnoise top -S 2 --on-threshold shell,command='echo -n abc; false' --on-threshold shell,command='echo -n defgh'" 2 "^abc" "defgh"
|
||||
check "hist with continue" \
|
||||
"osnoise hist -S 2 -d 5s --on-threshold shell,command='echo TestOutput' --on-threshold continue" 0 "^TestOutput$"
|
||||
check "top with continue" \
|
||||
"osnoise top -q -S 2 -d 5s --on-threshold shell,command='echo TestOutput' --on-threshold continue" 0 "^TestOutput$"
|
||||
check "hist with trace output at end" \
|
||||
"osnoise hist -d 1s --on-end trace" 0 "^ Saving trace to osnoise_trace.txt$"
|
||||
check "top with trace output at end" \
|
||||
"osnoise top -d 1s --on-end trace" 0 "^ Saving trace to osnoise_trace.txt$"
|
||||
check_top_q_hist "with continue" \
|
||||
"osnoise TOOL -S 2 -d 5s --on-threshold shell,command='echo TestOutput' --on-threshold continue" 0 "^TestOutput$"
|
||||
check_top_q_hist "with conditional continue" \
|
||||
"osnoise TOOL -S 2 --on-threshold shell,command='if [ -f a ]; then echo 2; exit 1; else echo -n 1; touch a; fi' --on-threshold continue" 2 "^12$" "^2$"
|
||||
check_top_hist "with trace output at end" \
|
||||
"osnoise TOOL -d 1s --on-end trace" 0 "^ Saving trace to osnoise_trace.txt$"
|
||||
|
||||
test_end
|
||||
|
|
|
|||
17
tools/tracing/rtla/tests/scripts/check-cgroup-match.sh
Executable file
17
tools/tracing/rtla/tests/scripts/check-cgroup-match.sh
Executable file
|
|
@ -0,0 +1,17 @@
|
|||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
. "$(dirname $0)/lib/get_workload_pids.sh"
|
||||
rtla_pid=$(echo $(ps -o ppid= $$))
|
||||
rtla_cgroup=$(</proc/$rtla_pid/cgroup)
|
||||
echo "RTLA cgroup: $rtla_cgroup"
|
||||
for pid in $(get_workload_pids)
|
||||
do
|
||||
pid_cgroup=$(</proc/$pid/cgroup)
|
||||
echo "PID $pid cgroup: $pid_cgroup"
|
||||
if ! [ "$pid_cgroup" = "$rtla_cgroup" ]
|
||||
then
|
||||
echo "Mismatch!"
|
||||
exit 0
|
||||
fi
|
||||
done
|
||||
echo "cgroup matches for all workload PIDs"
|
||||
9
tools/tracing/rtla/tests/scripts/check-cpus.sh
Executable file
9
tools/tracing/rtla/tests/scripts/check-cpus.sh
Executable file
|
|
@ -0,0 +1,9 @@
|
|||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
. "$(dirname $0)/lib/get_workload_pids.sh"
|
||||
echo -n "Affinity of threads: "
|
||||
for pid in $(get_workload_pids)
|
||||
do
|
||||
echo -n $(taskset -c -p $pid | cut -d ':' -f 2)
|
||||
done
|
||||
echo
|
||||
4
tools/tracing/rtla/tests/scripts/check-housekeeping-cpus.sh
Executable file
4
tools/tracing/rtla/tests/scripts/check-housekeeping-cpus.sh
Executable file
|
|
@ -0,0 +1,4 @@
|
|||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
pid=$(ps -o ppid= $$)
|
||||
echo "Affinity of threads:$(taskset -c -p $pid | cut -d ':' -f 2)"
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
pids="$(pgrep ^$1)" || exit 1
|
||||
for pid in $pids
|
||||
. "$(dirname $0)/lib/get_workload_pids.sh"
|
||||
for pid in $(get_workload_pids)
|
||||
do
|
||||
chrt -p $pid | cut -d ':' -f 2 | head -n1 | grep "^ $2\$" >/dev/null
|
||||
chrt -p $pid | cut -d ':' -f 2 | tail -n1 | grep "^ $3\$" >/dev/null
|
||||
chrt -p $pid | cut -d ':' -f 2 | head -n1 | grep "^ $1\$" >/dev/null
|
||||
chrt -p $pid | cut -d ':' -f 2 | tail -n1 | grep "^ $2\$" >/dev/null
|
||||
done && echo "Priorities are set correctly"
|
||||
|
|
|
|||
16
tools/tracing/rtla/tests/scripts/check-user-kernel-threads.sh
Executable file
16
tools/tracing/rtla/tests/scripts/check-user-kernel-threads.sh
Executable file
|
|
@ -0,0 +1,16 @@
|
|||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
. "$(dirname $0)/lib/get_workload_pids.sh"
|
||||
kthreadd_pid=$(pgrep ^kthreadd$)
|
||||
cnt_kernel=0
|
||||
cnt_user=0
|
||||
for pid in $(get_workload_pids)
|
||||
do
|
||||
if [ "$(echo $(ps -o ppid= $pid))" = "$kthreadd_pid" ]
|
||||
then
|
||||
((++cnt_kernel))
|
||||
else
|
||||
((++cnt_user))
|
||||
fi
|
||||
done
|
||||
echo "$cnt_kernel kernel threads, $cnt_user user threads"
|
||||
11
tools/tracing/rtla/tests/scripts/lib/get_workload_pids.sh
Normal file
11
tools/tracing/rtla/tests/scripts/lib/get_workload_pids.sh
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
get_workload_pids() {
|
||||
local shell_pid=$$
|
||||
local rtla_pid=$(ps -o ppid= $shell_pid)
|
||||
|
||||
# kernel threads
|
||||
pgrep -P $(pgrep ^kthreadd$) -f '^(osnoise|timerlat)/[0-9]+$'
|
||||
# user threads
|
||||
pgrep -P $rtla_pid | grep -v "^$shell_pid$"
|
||||
}
|
||||
|
|
@ -21,65 +21,96 @@ export RTLA_NO_BPF=$option
|
|||
|
||||
# Basic tests
|
||||
check "verify help page" \
|
||||
"timerlat --help" 0 "timerlat version"
|
||||
check "verify -s/--stack" \
|
||||
"timerlat top -s 3 -T 10 -t" 2 "Blocking thread stack trace"
|
||||
check "verify -P/--priority" \
|
||||
"timerlat top -P F:1 -c 0 -d 10s -q -T 1 --on-threshold shell,command=\"tests/scripts/check-priority.sh timerlatu/ SCHED_FIFO 1\"" \
|
||||
"timerlat --help" 129 "timerlat version"
|
||||
check_top_hist "verify help page" \
|
||||
"timerlat TOOL --help" 129 "rtla timerlat"
|
||||
check_top_hist "verify -s/--stack" \
|
||||
"timerlat TOOL -s 3 -T 10 -t" 2 "Blocking thread stack trace"
|
||||
check_top_hist "test in nanoseconds" \
|
||||
"timerlat TOOL -i 2 -c 0 -n -d 10s" 2 "ns"
|
||||
check_top_hist "set the automatic trace mode" \
|
||||
"timerlat TOOL -a 5" 2 "analyzing it"
|
||||
check_top_hist "dump tasks" \
|
||||
"timerlat TOOL -a 5 --dump-tasks" 2 "Printing CPU tasks"
|
||||
check "verify --aa-only stop on threshold" \
|
||||
"timerlat top --aa-only 5" 2 "analyzing it" "Timer Latency"
|
||||
check "verify --aa-only max latency" \
|
||||
"timerlat top --aa-only 2000000 -d 1s" 0 "^ Max latency was" "Timer Latency"
|
||||
check_top_hist "disable auto-analysis" \
|
||||
"timerlat TOOL -s 3 -T 10 -t --no-aa" 2 "" "analyzing it"
|
||||
|
||||
# Thread tests
|
||||
check_top_hist "verify -P/--priority" \
|
||||
"timerlat TOOL -P F:1 -c 0 -d 10s -T 1 --on-threshold shell,command=\"$testdir/scripts/check-priority.sh SCHED_FIFO 1\"" \
|
||||
2 "Priorities are set correctly"
|
||||
check "test in nanoseconds" \
|
||||
"timerlat top -i 2 -c 0 -n -d 10s" 2 "ns"
|
||||
check "set the automatic trace mode" \
|
||||
"timerlat top -a 5" 2 "analyzing it"
|
||||
check "dump tasks" \
|
||||
"timerlat top -a 5 --dump-tasks" 2 "Printing CPU tasks"
|
||||
check "print the auto-analysis if hits the stop tracing condition" \
|
||||
"timerlat top --aa-only 5" 2
|
||||
check "disable auto-analysis" \
|
||||
"timerlat top -s 3 -T 10 -t --no-aa" 2
|
||||
check "verify -c/--cpus" \
|
||||
"timerlat hist -c 0 -d 10s"
|
||||
check "hist test in nanoseconds" \
|
||||
"timerlat hist -i 2 -c 0 -n -d 10s" 2 "ns"
|
||||
check_top_hist "verify -C/--cgroup" \
|
||||
"timerlat TOOL -k -C -c 0 -d 10s -T 1 --on-threshold shell,command=\"$testdir/scripts/check-cgroup-match.sh\"" \
|
||||
2 "cgroup matches for all workload PIDs"
|
||||
check_top_q_hist "verify -c/--cpus" \
|
||||
"timerlat TOOL -c 0 -d 10s -T 1 --on-threshold shell,command=$testdir/scripts/check-cpus.sh" 2 "^Affinity of threads: 0$"
|
||||
check_top_q_hist "verify -H/--house-keeping" \
|
||||
"timerlat TOOL -H 0 -d 10s -T 1 --on-threshold shell,command=$testdir/scripts/check-housekeeping-cpus.sh" 2 "^Affinity of threads: 0$"
|
||||
check_top_q_hist "verify -k/--kernel-threads" \
|
||||
"timerlat TOOL -k -c 0 -d 10s -T 1 --on-threshold shell,command=$testdir/scripts/check-user-kernel-threads.sh" 2 "1 kernel threads, 0 user threads"
|
||||
check_top_q_hist "verify -u/--user-threads" \
|
||||
"timerlat TOOL -u -c 0 -d 10s -T 1 --on-threshold shell,command=$testdir/scripts/check-user-kernel-threads.sh" 2 "0 kernel threads, 1 user threads"
|
||||
|
||||
# Histogram tests
|
||||
check "hist with -b/--bucket-size" \
|
||||
"timerlat hist -b 1 -d 1s"
|
||||
check "hist with -E/--entries" \
|
||||
"timerlat hist -E 10 -d 1s"
|
||||
check "hist with -E/--entries out of range" \
|
||||
"timerlat hist -E 1 -d 1s" 1 "^Entries must be > 10 and < 10000000$"
|
||||
check "hist with --no-header" \
|
||||
"timerlat hist --no-header -d 1s" 0 "" "RTLA timerlat histogram"
|
||||
check "hist with --with-zeros" \
|
||||
"timerlat hist --with-zeros -b 100000 -E 21 -d 1s" 0 '^2000000\s+0\s+'
|
||||
check "hist with --no-index" \
|
||||
"timerlat hist --no-index --with-zeros -d 1s" 0 "" "^count:"
|
||||
check "hist with --no-summary" \
|
||||
"timerlat hist --no-summary -d 1s" 0 "" "^ALL:"
|
||||
check "hist with --no-irq" \
|
||||
"timerlat hist --no-irq -d 1s" 0 "" "IRQ-"
|
||||
check "hist with --no-thread" \
|
||||
"timerlat hist --no-thread -d 1s" 0 "" "Thr-"
|
||||
|
||||
# Actions tests
|
||||
check "trace output through -t" \
|
||||
"timerlat hist -T 2 -t" 2 "^ Saving trace to timerlat_trace.txt$"
|
||||
check "trace output through -t with custom filename" \
|
||||
"timerlat hist -T 2 -t custom_filename.txt" 2 "^ Saving trace to custom_filename.txt$"
|
||||
check "trace output through --on-threshold trace" \
|
||||
"timerlat hist -T 2 --on-threshold trace" 2 "^ Saving trace to timerlat_trace.txt$"
|
||||
check "trace output through --on-threshold trace with custom filename" \
|
||||
"timerlat hist -T 2 --on-threshold trace,file=custom_filename.txt" 2 "^ Saving trace to custom_filename.txt$"
|
||||
check "exec command" \
|
||||
"timerlat hist -T 2 --on-threshold shell,command='echo TestOutput'" 2 "^TestOutput$"
|
||||
check "multiple actions" \
|
||||
"timerlat hist -T 2 --on-threshold shell,command='echo -n 1' --on-threshold shell,command='echo 2'" 2 "^12$"
|
||||
check_top_q_hist "trace output through -t" \
|
||||
"timerlat TOOL -T 2 -t" 2 "^ Saving trace to timerlat_trace.txt$"
|
||||
check_top_q_hist "trace output through -t with custom filename" \
|
||||
"timerlat TOOL -T 2 -t custom_filename.txt" 2 "^ Saving trace to custom_filename.txt$"
|
||||
check_top_q_hist "trace output through --on-threshold trace" \
|
||||
"timerlat TOOL -T 2 --on-threshold trace" 2 "^ Saving trace to timerlat_trace.txt$"
|
||||
check_top_q_hist "trace output through --on-threshold trace with custom filename" \
|
||||
"timerlat TOOL -T 2 --on-threshold trace,file=custom_filename.txt" 2 "^ Saving trace to custom_filename.txt$"
|
||||
check_top_q_hist "exec command" \
|
||||
"timerlat TOOL -T 2 --on-threshold shell,command='echo TestOutput'" 2 "^TestOutput$"
|
||||
check_top_q_hist "multiple actions" \
|
||||
"timerlat TOOL -T 2 --on-threshold shell,command='echo -n 1' --on-threshold shell,command='echo 2'" 2 "^12$"
|
||||
check "hist stop at failed action" \
|
||||
"timerlat hist -T 2 --on-threshold shell,command='echo -n 1; false' --on-threshold shell,command='echo -n 2'" 2 "^1# RTLA timerlat histogram$"
|
||||
check "top stop at failed action" \
|
||||
"timerlat top -T 2 --on-threshold shell,command='echo -n abc; false' --on-threshold shell,command='echo -n defgh'" 2 "^abc" "defgh"
|
||||
check "hist with continue" \
|
||||
"timerlat hist -T 2 -d 5s --on-threshold shell,command='echo TestOutput' --on-threshold continue" 0 "^TestOutput$"
|
||||
check "top with continue" \
|
||||
"timerlat top -q -T 2 -d 5s --on-threshold shell,command='echo TestOutput' --on-threshold continue" 0 "^TestOutput$"
|
||||
check "hist with trace output at end" \
|
||||
"timerlat hist -d 1s --on-end trace" 0 "^ Saving trace to timerlat_trace.txt$"
|
||||
check "top with trace output at end" \
|
||||
"timerlat top -d 1s --on-end trace" 0 "^ Saving trace to timerlat_trace.txt$"
|
||||
check_top_q_hist "with continue" \
|
||||
"timerlat TOOL -T 2 -d 5s --on-threshold shell,command='echo TestOutput' --on-threshold continue" 0 "^TestOutput$"
|
||||
check_top_q_hist "with conditional continue" \
|
||||
"timerlat TOOL -T 2 --on-threshold shell,command='if [ -f a ]; then echo 2; exit 1; else echo -n 1; touch a; fi' --on-threshold continue" 2 "^12$" "^2$"
|
||||
check_top_hist "with trace output at end" \
|
||||
"timerlat TOOL -d 1s --on-end trace" 0 "^ Saving trace to timerlat_trace.txt$"
|
||||
|
||||
# BPF action program tests
|
||||
if [ "$option" -eq 0 ]
|
||||
then
|
||||
# Test BPF action program properly in BPF mode
|
||||
[ -z "$BPFTOOL" ] && BPFTOOL=bpftool
|
||||
check "hist with BPF action program (BPF mode)" \
|
||||
"timerlat hist -T 2 --bpf-action tests/bpf/bpf_action_map.o --on-threshold shell,command='$BPFTOOL map dump name rtla_test_map'" \
|
||||
check_top_q_hist "with BPF action program (BPF mode)" \
|
||||
"timerlat TOOL -T 2 --bpf-action $testdir/bpf/bpf_action_map.o --on-threshold shell,command='$BPFTOOL map dump name rtla_test_map'" \
|
||||
2 '"value": 42'
|
||||
else
|
||||
# Test BPF action program failure in non-BPF mode
|
||||
check "hist with BPF action program (non-BPF mode)" \
|
||||
"timerlat hist -T 2 --bpf-action tests/bpf/bpf_action_map.o" \
|
||||
check_top_q_hist "with BPF action program (non-BPF mode)" \
|
||||
"timerlat TOOL -T 2 --bpf-action $testdir/bpf/bpf_action_map.o" \
|
||||
1 "BPF actions are not supported in tracefs-only mode"
|
||||
fi
|
||||
done
|
||||
|
|
|
|||
|
|
@ -1,2 +1,8 @@
|
|||
unit_tests-y += utils.o
|
||||
unit_tests-y += actions.o
|
||||
unit_tests-y += unit_tests.o
|
||||
unit_tests-y +=../../src/utils.o
|
||||
unit_tests-y += osnoise_top_cli.o
|
||||
unit_tests-y += osnoise_hist_cli.o
|
||||
unit_tests-y += timerlat_top_cli.o
|
||||
unit_tests-y += timerlat_hist_cli.o
|
||||
unit_tests-y += cli_opt_callback.o
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@
|
|||
UNIT_TESTS := $(OUTPUT)unit_tests
|
||||
UNIT_TESTS_IN := $(UNIT_TESTS)-in.o
|
||||
|
||||
$(UNIT_TESTS): $(UNIT_TESTS_IN)
|
||||
$(QUIET_LINK)$(CC) $(LDFLAGS) -o $@ $^ -lcheck
|
||||
$(UNIT_TESTS): $(UNIT_TESTS_IN) $(RTLA_IN) $(LIBSUBCMD) $(LIB_STRING) $(LIB_STR_ERROR_R)
|
||||
$(QUIET_LINK)$(CC) $(LDFLAGS) -o $@ $^ $(EXTLIBS) -lcheck
|
||||
|
||||
$(UNIT_TESTS_IN):
|
||||
$(UNIT_TESTS_IN): fixdep $(LIBSUBCMD_INCLUDES)
|
||||
make $(build)=unit_tests
|
||||
|
||||
unit-tests: FORCE
|
||||
|
|
|
|||
393
tools/tracing/rtla/tests/unit/actions.c
Normal file
393
tools/tracing/rtla/tests/unit/actions.c
Normal file
|
|
@ -0,0 +1,393 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <check.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "../../src/actions.h"
|
||||
|
||||
static struct actions actions_fixture;
|
||||
|
||||
static void actions_fixture_setup(void)
|
||||
{
|
||||
actions_init(&actions_fixture);
|
||||
}
|
||||
|
||||
static void actions_fixture_teardown(void)
|
||||
{
|
||||
actions_destroy(&actions_fixture);
|
||||
}
|
||||
|
||||
START_TEST(test_actions_init)
|
||||
{
|
||||
struct actions actions;
|
||||
|
||||
actions_init(&actions);
|
||||
|
||||
ck_assert_int_eq(actions.len, 0);
|
||||
ck_assert_int_eq(actions.size, action_default_size);
|
||||
ck_assert(!actions.continue_flag);
|
||||
ck_assert_ptr_eq(actions.trace_output_inst, NULL);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_actions_destroy)
|
||||
{
|
||||
struct actions actions;
|
||||
|
||||
actions_init(&actions);
|
||||
actions_destroy(&actions);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_actions_reallocate)
|
||||
{
|
||||
struct actions actions;
|
||||
int i;
|
||||
|
||||
actions_init(&actions);
|
||||
|
||||
ck_assert_int_eq(actions.len, 0);
|
||||
ck_assert_int_eq(actions.size, action_default_size);
|
||||
|
||||
/* Fill size of actions array */
|
||||
for (i = 0; i < action_default_size; i++)
|
||||
actions_add_continue(&actions);
|
||||
|
||||
ck_assert_int_eq(actions.len, action_default_size);
|
||||
ck_assert_int_eq(actions.size, action_default_size);
|
||||
|
||||
/* Add one more action to trigger reallocation */
|
||||
actions_add_continue(&actions);
|
||||
|
||||
ck_assert_int_eq(actions.len, action_default_size + 1);
|
||||
ck_assert_int_eq(actions.size, action_default_size * 2);
|
||||
|
||||
actions_destroy(&actions);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_actions_add_trace_output)
|
||||
{
|
||||
actions_add_trace_output(&actions_fixture, "trace_output.txt");
|
||||
|
||||
ck_assert_int_eq(actions_fixture.len, 1);
|
||||
ck_assert_int_eq(actions_fixture.list[0].type, ACTION_TRACE_OUTPUT);
|
||||
ck_assert_str_eq(actions_fixture.list[0].trace_output, "trace_output.txt");
|
||||
ck_assert(actions_fixture.present[ACTION_TRACE_OUTPUT]);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_actions_add_signal)
|
||||
{
|
||||
actions_add_signal(&actions_fixture, SIGINT, 1234);
|
||||
|
||||
ck_assert_int_eq(actions_fixture.len, 1);
|
||||
ck_assert_int_eq(actions_fixture.list[0].type, ACTION_SIGNAL);
|
||||
ck_assert_int_eq(actions_fixture.list[0].signal, SIGINT);
|
||||
ck_assert_int_eq(actions_fixture.list[0].pid, 1234);
|
||||
ck_assert(actions_fixture.present[ACTION_SIGNAL]);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_actions_add_shell)
|
||||
{
|
||||
actions_add_shell(&actions_fixture, "echo Hello");
|
||||
|
||||
ck_assert_int_eq(actions_fixture.len, 1);
|
||||
ck_assert_int_eq(actions_fixture.list[0].type, ACTION_SHELL);
|
||||
ck_assert_str_eq(actions_fixture.list[0].command, "echo Hello");
|
||||
ck_assert(actions_fixture.present[ACTION_SHELL]);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_actions_add_continue)
|
||||
{
|
||||
actions_add_continue(&actions_fixture);
|
||||
|
||||
ck_assert_int_eq(actions_fixture.len, 1);
|
||||
ck_assert_int_eq(actions_fixture.list[0].type, ACTION_CONTINUE);
|
||||
ck_assert(actions_fixture.present[ACTION_CONTINUE]);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_actions_add_multiple_same_action)
|
||||
{
|
||||
actions_add_trace_output(&actions_fixture, "trace1.txt");
|
||||
actions_add_trace_output(&actions_fixture, "trace2.txt");
|
||||
|
||||
ck_assert_int_eq(actions_fixture.len, 2);
|
||||
ck_assert_int_eq(actions_fixture.list[0].type, ACTION_TRACE_OUTPUT);
|
||||
ck_assert_str_eq(actions_fixture.list[0].trace_output, "trace1.txt");
|
||||
ck_assert_int_eq(actions_fixture.list[1].type, ACTION_TRACE_OUTPUT);
|
||||
ck_assert_str_eq(actions_fixture.list[1].trace_output, "trace2.txt");
|
||||
ck_assert(actions_fixture.present[ACTION_TRACE_OUTPUT]);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_actions_add_multiple_different_action)
|
||||
{
|
||||
actions_add_trace_output(&actions_fixture, "trace_output.txt");
|
||||
actions_add_signal(&actions_fixture, SIGINT, 1234);
|
||||
|
||||
ck_assert_int_eq(actions_fixture.len, 2);
|
||||
ck_assert_int_eq(actions_fixture.list[0].type, ACTION_TRACE_OUTPUT);
|
||||
ck_assert_str_eq(actions_fixture.list[0].trace_output, "trace_output.txt");
|
||||
ck_assert(actions_fixture.present[ACTION_TRACE_OUTPUT]);
|
||||
ck_assert_int_eq(actions_fixture.list[1].type, ACTION_SIGNAL);
|
||||
ck_assert_int_eq(actions_fixture.list[1].signal, SIGINT);
|
||||
ck_assert_int_eq(actions_fixture.list[1].pid, 1234);
|
||||
ck_assert(actions_fixture.present[ACTION_SIGNAL]);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_actions_parse_trace_output)
|
||||
{
|
||||
ck_assert_int_eq(actions_parse(&actions_fixture, "trace", "trace.txt"), 0);
|
||||
|
||||
ck_assert_int_eq(actions_fixture.len, 1);
|
||||
ck_assert_int_eq(actions_fixture.list[0].type, ACTION_TRACE_OUTPUT);
|
||||
ck_assert_str_eq(actions_fixture.list[0].trace_output, "trace.txt");
|
||||
ck_assert(actions_fixture.present[ACTION_TRACE_OUTPUT]);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_actions_parse_trace_output_arg)
|
||||
{
|
||||
ck_assert_int_eq(actions_parse(&actions_fixture, "trace,file=trace2.txt", "trace1.txt"), 0);
|
||||
|
||||
ck_assert_int_eq(actions_fixture.len, 1);
|
||||
ck_assert_int_eq(actions_fixture.list[0].type, ACTION_TRACE_OUTPUT);
|
||||
ck_assert_str_eq(actions_fixture.list[0].trace_output, "trace2.txt");
|
||||
ck_assert(actions_fixture.present[ACTION_TRACE_OUTPUT]);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_actions_parse_trace_output_arg_bad)
|
||||
{
|
||||
ck_assert_int_eq(actions_parse(&actions_fixture, "trace,foo=bar", "trace_output.txt"), -1);
|
||||
|
||||
ck_assert_int_eq(actions_fixture.len, 0);
|
||||
ck_assert(!actions_fixture.present[ACTION_TRACE_OUTPUT]);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_actions_parse_signal)
|
||||
{
|
||||
ck_assert_int_eq(actions_parse(&actions_fixture, "signal,num=1,pid=1234", NULL), 0);
|
||||
|
||||
ck_assert_int_eq(actions_fixture.len, 1);
|
||||
ck_assert_int_eq(actions_fixture.list[0].type, ACTION_SIGNAL);
|
||||
ck_assert_int_eq(actions_fixture.list[0].signal, 1);
|
||||
ck_assert_int_eq(actions_fixture.list[0].pid, 1234);
|
||||
ck_assert(actions_fixture.present[ACTION_SIGNAL]);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_actions_parse_signal_swapped)
|
||||
{
|
||||
ck_assert_int_eq(actions_parse(&actions_fixture, "signal,pid=1234,num=1", NULL), 0);
|
||||
|
||||
ck_assert_int_eq(actions_fixture.len, 1);
|
||||
ck_assert_int_eq(actions_fixture.list[0].type, ACTION_SIGNAL);
|
||||
ck_assert_int_eq(actions_fixture.list[0].signal, 1);
|
||||
ck_assert_int_eq(actions_fixture.list[0].pid, 1234);
|
||||
ck_assert(actions_fixture.present[ACTION_SIGNAL]);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_actions_parse_signal_parent)
|
||||
{
|
||||
ck_assert_int_eq(actions_parse(&actions_fixture, "signal,pid=parent,num=1", NULL), 0);
|
||||
|
||||
ck_assert_int_eq(actions_fixture.len, 1);
|
||||
ck_assert_int_eq(actions_fixture.list[0].type, ACTION_SIGNAL);
|
||||
ck_assert_int_eq(actions_fixture.list[0].signal, 1);
|
||||
ck_assert_int_eq(actions_fixture.list[0].pid, -1);
|
||||
ck_assert(actions_fixture.present[ACTION_SIGNAL]);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_actions_parse_signal_no_arg)
|
||||
{
|
||||
ck_assert_int_eq(actions_parse(&actions_fixture, "signal", NULL), -1);
|
||||
|
||||
ck_assert_int_eq(actions_fixture.len, 0);
|
||||
ck_assert(!actions_fixture.present[ACTION_SIGNAL]);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_actions_parse_signal_no_pid)
|
||||
{
|
||||
ck_assert_int_eq(actions_parse(&actions_fixture, "signal,num=1", NULL), -1);
|
||||
|
||||
ck_assert_int_eq(actions_fixture.len, 0);
|
||||
ck_assert(!actions_fixture.present[ACTION_SIGNAL]);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_actions_parse_signal_no_num)
|
||||
{
|
||||
ck_assert_int_eq(actions_parse(&actions_fixture, "signal,pid=1234", NULL), -1);
|
||||
|
||||
ck_assert_int_eq(actions_fixture.len, 0);
|
||||
ck_assert(!actions_fixture.present[ACTION_SIGNAL]);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_actions_parse_signal_arg_bad)
|
||||
{
|
||||
ck_assert_int_eq(actions_parse(&actions_fixture, "signal,foo=bar", NULL), -1);
|
||||
|
||||
ck_assert_int_eq(actions_fixture.len, 0);
|
||||
ck_assert(!actions_fixture.present[ACTION_SIGNAL]);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_actions_parse_shell)
|
||||
{
|
||||
ck_assert_int_eq(actions_parse(&actions_fixture, "shell,command=echo Hello", NULL), 0);
|
||||
|
||||
ck_assert_int_eq(actions_fixture.len, 1);
|
||||
ck_assert_int_eq(actions_fixture.list[0].type, ACTION_SHELL);
|
||||
ck_assert_str_eq(actions_fixture.list[0].command, "echo Hello");
|
||||
ck_assert(actions_fixture.present[ACTION_SHELL]);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_actions_parse_shell_no_arg)
|
||||
{
|
||||
ck_assert_int_eq(actions_parse(&actions_fixture, "shell", NULL), -1);
|
||||
|
||||
ck_assert_int_eq(actions_fixture.len, 0);
|
||||
ck_assert(!actions_fixture.present[ACTION_SHELL]);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_actions_parse_shell_arg_bad)
|
||||
{
|
||||
ck_assert_int_eq(actions_parse(&actions_fixture, "shell,foo=bar", NULL), -1);
|
||||
ck_assert_int_eq(actions_fixture.len, 0);
|
||||
ck_assert(!actions_fixture.present[ACTION_SHELL]);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_actions_parse_continue)
|
||||
{
|
||||
ck_assert_int_eq(actions_parse(&actions_fixture, "continue", NULL), 0);
|
||||
|
||||
ck_assert_int_eq(actions_fixture.len, 1);
|
||||
ck_assert_int_eq(actions_fixture.list[0].type, ACTION_CONTINUE);
|
||||
ck_assert(actions_fixture.present[ACTION_CONTINUE]);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_actions_parse_continue_arg_bad)
|
||||
{
|
||||
ck_assert_int_eq(actions_parse(&actions_fixture, "continue,foo=bar", NULL), -1);
|
||||
|
||||
ck_assert_int_eq(actions_fixture.len, 0);
|
||||
ck_assert(!actions_fixture.present[ACTION_CONTINUE]);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_actions_parse_invalid)
|
||||
{
|
||||
ck_assert_int_eq(actions_parse(&actions_fixture, "foobar", NULL), -1);
|
||||
|
||||
ck_assert_int_eq(actions_fixture.len, 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_actions_perform_continue)
|
||||
{
|
||||
actions_add_continue(&actions_fixture);
|
||||
ck_assert_int_eq(actions_perform(&actions_fixture), 0);
|
||||
|
||||
ck_assert(actions_fixture.continue_flag);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_actions_perform_continue_after_successful_shell_command)
|
||||
{
|
||||
actions_add_shell(&actions_fixture, "exit 0");
|
||||
actions_add_continue(&actions_fixture);
|
||||
ck_assert_int_eq(actions_perform(&actions_fixture), 0 << 8);
|
||||
|
||||
ck_assert(actions_fixture.continue_flag);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_actions_perform_continue_after_failed_shell_command)
|
||||
{
|
||||
actions_add_shell(&actions_fixture, "exit 1");
|
||||
actions_add_continue(&actions_fixture);
|
||||
ck_assert_int_eq(actions_perform(&actions_fixture), 1 << 8);
|
||||
|
||||
ck_assert(!actions_fixture.continue_flag);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_actions_perform_continue_unset_flag)
|
||||
{
|
||||
actions_fixture.continue_flag = true;
|
||||
|
||||
actions_add_shell(&actions_fixture, "exit 1");
|
||||
actions_add_continue(&actions_fixture);
|
||||
ck_assert_int_eq(actions_perform(&actions_fixture), 1 << 8);
|
||||
|
||||
ck_assert(!actions_fixture.continue_flag);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
Suite *actions_suite(void)
|
||||
{
|
||||
Suite *s = suite_create("actions");
|
||||
TCase *tc;
|
||||
|
||||
tc = tcase_create("alloc");
|
||||
tcase_add_test(tc, test_actions_init);
|
||||
tcase_add_test(tc, test_actions_destroy);
|
||||
tcase_add_test(tc, test_actions_reallocate);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
tc = tcase_create("add");
|
||||
tcase_add_checked_fixture(tc, actions_fixture_setup, actions_fixture_teardown);
|
||||
tcase_add_test(tc, test_actions_add_trace_output);
|
||||
tcase_add_test(tc, test_actions_add_signal);
|
||||
tcase_add_test(tc, test_actions_add_shell);
|
||||
tcase_add_test(tc, test_actions_add_continue);
|
||||
tcase_add_test(tc, test_actions_add_multiple_same_action);
|
||||
tcase_add_test(tc, test_actions_add_multiple_different_action);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
tc = tcase_create("parse");
|
||||
tcase_add_checked_fixture(tc, actions_fixture_setup, actions_fixture_teardown);
|
||||
tcase_add_test(tc, test_actions_parse_trace_output);
|
||||
tcase_add_test(tc, test_actions_parse_trace_output_arg);
|
||||
tcase_add_test(tc, test_actions_parse_trace_output_arg_bad);
|
||||
tcase_add_test(tc, test_actions_parse_signal);
|
||||
tcase_add_test(tc, test_actions_parse_signal_swapped);
|
||||
tcase_add_test(tc, test_actions_parse_signal_parent);
|
||||
tcase_add_test(tc, test_actions_parse_signal_no_arg);
|
||||
tcase_add_test(tc, test_actions_parse_signal_no_pid);
|
||||
tcase_add_test(tc, test_actions_parse_signal_no_num);
|
||||
tcase_add_test(tc, test_actions_parse_signal_arg_bad);
|
||||
tcase_add_test(tc, test_actions_parse_shell);
|
||||
tcase_add_test(tc, test_actions_parse_shell_no_arg);
|
||||
tcase_add_test(tc, test_actions_parse_shell_arg_bad);
|
||||
tcase_add_test(tc, test_actions_parse_continue);
|
||||
tcase_add_test(tc, test_actions_parse_continue_arg_bad);
|
||||
tcase_add_test(tc, test_actions_parse_invalid);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
tc = tcase_create("perform");
|
||||
tcase_add_checked_fixture(tc, actions_fixture_setup, actions_fixture_teardown);
|
||||
tcase_add_test(tc, test_actions_perform_continue);
|
||||
tcase_add_test(tc, test_actions_perform_continue_after_successful_shell_command);
|
||||
tcase_add_test(tc, test_actions_perform_continue_after_failed_shell_command);
|
||||
tcase_add_test(tc, test_actions_perform_continue_unset_flag);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
return s;
|
||||
}
|
||||
716
tools/tracing/rtla/tests/unit/cli_opt_callback.c
Normal file
716
tools/tracing/rtla/tests/unit/cli_opt_callback.c
Normal file
|
|
@ -0,0 +1,716 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <check.h>
|
||||
|
||||
#define RTLA_ALLOW_CLI_P_H
|
||||
#include "../../src/cli_p.h"
|
||||
#include "cli_params_assert.h"
|
||||
|
||||
#define TEST_CALLBACK(value, cb) OPT_CALLBACK('t', "test", value, "test value", "test help", cb)
|
||||
|
||||
START_TEST(test_opt_llong_callback_simple)
|
||||
{
|
||||
long long test_value = 0;
|
||||
const struct option opt = TEST_CALLBACK(&test_value, opt_llong_callback);
|
||||
|
||||
ck_assert_int_eq(opt_llong_callback(&opt, "1234567890", 0), 0);
|
||||
ck_assert_int_eq(test_value, 1234567890);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_opt_llong_callback_max)
|
||||
{
|
||||
long long test_value = 0;
|
||||
const struct option opt = TEST_CALLBACK(&test_value, opt_llong_callback);
|
||||
|
||||
ck_assert_int_eq(opt_llong_callback(&opt, "9223372036854775807", 0), 0);
|
||||
ck_assert_int_eq(test_value, 9223372036854775807LL);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_opt_llong_callback_min)
|
||||
{
|
||||
long long test_value = 0;
|
||||
const struct option opt = TEST_CALLBACK(&test_value, opt_llong_callback);
|
||||
|
||||
ck_assert_int_eq(opt_llong_callback(&opt, "-9223372036854775808", 0), 0);
|
||||
ck_assert_int_eq(test_value, ~9223372036854775807LL);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_opt_int_callback_simple)
|
||||
{
|
||||
int test_value = 0;
|
||||
const struct option opt = TEST_CALLBACK(&test_value, opt_int_callback);
|
||||
|
||||
ck_assert_int_eq(opt_int_callback(&opt, "1234567890", 0), 0);
|
||||
ck_assert_int_eq(test_value, 1234567890);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_opt_int_callback_max)
|
||||
{
|
||||
int test_value = 0;
|
||||
const struct option opt = TEST_CALLBACK(&test_value, opt_int_callback);
|
||||
|
||||
ck_assert_int_eq(opt_int_callback(&opt, "2147483647", 0), 0);
|
||||
ck_assert_int_eq(test_value, 2147483647);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_opt_int_callback_min)
|
||||
{
|
||||
int test_value = 0;
|
||||
const struct option opt = TEST_CALLBACK(&test_value, opt_int_callback);
|
||||
|
||||
ck_assert_int_eq(opt_int_callback(&opt, "-2147483648", 0), 0);
|
||||
ck_assert_int_eq(test_value, -2147483648);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_opt_int_callback_non_numeric)
|
||||
{
|
||||
int test_value = 0;
|
||||
const struct option opt = TEST_CALLBACK(&test_value, opt_int_callback);
|
||||
|
||||
ck_assert_int_eq(opt_int_callback(&opt, "abc", 0), -1);
|
||||
ck_assert_int_eq(test_value, 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_opt_int_callback_non_numeric_suffix)
|
||||
{
|
||||
int test_value = 0;
|
||||
const struct option opt = TEST_CALLBACK(&test_value, opt_int_callback);
|
||||
|
||||
ck_assert_int_eq(opt_int_callback(&opt, "1234567890abc", 0), -1);
|
||||
ck_assert_int_eq(test_value, 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_opt_cpus_cb)
|
||||
{
|
||||
struct common_params params = {0};
|
||||
const struct option opt = TEST_CALLBACK(¶ms, opt_cpus_cb);
|
||||
|
||||
nr_cpus = 4;
|
||||
ck_assert_int_eq(opt_cpus_cb(&opt, "0-3", 0), 0);
|
||||
ck_assert_str_eq(params.cpus, "0-3");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_opt_cpus_cb_invalid)
|
||||
{
|
||||
struct common_params params = {0};
|
||||
const struct option opt = TEST_CALLBACK(¶ms, opt_cpus_cb);
|
||||
|
||||
nr_cpus = 4;
|
||||
assert(freopen("/dev/null", "w", stderr));
|
||||
opt_cpus_cb(&opt, "0-3,5", 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_opt_cgroup_cb)
|
||||
{
|
||||
struct common_params params = {0};
|
||||
const struct option opt = TEST_CALLBACK(¶ms, opt_cgroup_cb);
|
||||
|
||||
ck_assert_int_eq(opt_cgroup_cb(&opt, "cgroup", 0), 0);
|
||||
ck_assert_int_eq(params.cgroup, 1);
|
||||
ck_assert_str_eq(params.cgroup_name, "cgroup");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_opt_cgroup_cb_equals)
|
||||
{
|
||||
struct common_params params = {0};
|
||||
const struct option opt = TEST_CALLBACK(¶ms, opt_cgroup_cb);
|
||||
|
||||
ck_assert_int_eq(opt_cgroup_cb(&opt, "=cgroup", 0), 0);
|
||||
ck_assert_int_eq(params.cgroup, 1);
|
||||
ck_assert_str_eq(params.cgroup_name, "cgroup");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_opt_duration_cb)
|
||||
{
|
||||
struct common_params params = {0};
|
||||
const struct option opt = TEST_CALLBACK(¶ms, opt_duration_cb);
|
||||
|
||||
ck_assert_int_eq(opt_duration_cb(&opt, "1m", 0), 0);
|
||||
ck_assert_int_eq(params.duration, 60);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_opt_duration_cb_invalid)
|
||||
{
|
||||
struct common_params params = {0};
|
||||
const struct option opt = TEST_CALLBACK(¶ms, opt_duration_cb);
|
||||
|
||||
assert(freopen("/dev/null", "w", stderr));
|
||||
opt_duration_cb(&opt, "abc", 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_opt_event_cb)
|
||||
{
|
||||
struct trace_events *events = NULL;
|
||||
const struct option opt = TEST_CALLBACK(&events, opt_event_cb);
|
||||
|
||||
ck_assert_int_eq(opt_event_cb(&opt, "sched:sched_switch", 0), 0);
|
||||
ck_assert_str_eq(events->system, "sched");
|
||||
ck_assert_str_eq(events->event, "sched_switch");
|
||||
ck_assert_ptr_eq(events->next, NULL);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_opt_event_cb_multiple)
|
||||
{
|
||||
struct trace_events *events = NULL;
|
||||
const struct option opt = TEST_CALLBACK(&events, opt_event_cb);
|
||||
|
||||
ck_assert_int_eq(opt_event_cb(&opt, "sched:sched_switch", 0), 0);
|
||||
ck_assert_int_eq(opt_event_cb(&opt, "sched:sched_wakeup", 0), 0);
|
||||
ck_assert_str_eq(events->system, "sched");
|
||||
ck_assert_str_eq(events->event, "sched_wakeup");
|
||||
ck_assert_str_eq(events->next->system, "sched");
|
||||
ck_assert_str_eq(events->next->event, "sched_switch");
|
||||
ck_assert_ptr_eq(events->next->next, NULL);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_opt_housekeeping_cb)
|
||||
{
|
||||
struct common_params __params = {0};
|
||||
struct common_params *params = &__params;
|
||||
const struct option opt = TEST_CALLBACK(params, opt_housekeeping_cb);
|
||||
|
||||
nr_cpus = 4;
|
||||
ck_assert_int_eq(opt_housekeeping_cb(&opt, "0-3", 0), 0);
|
||||
ck_assert_int_eq(params->hk_cpus, 1);
|
||||
CLI_ASSERT_CPUSET(hk_cpu_set, 0, 1, 2, 3);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_opt_housekeeping_cb_invalid)
|
||||
{
|
||||
struct common_params params = {0};
|
||||
const struct option opt = TEST_CALLBACK(¶ms, opt_housekeeping_cb);
|
||||
|
||||
nr_cpus = 4;
|
||||
assert(freopen("/dev/null", "w", stderr));
|
||||
opt_housekeeping_cb(&opt, "0-3,5", 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_opt_priority_cb)
|
||||
{
|
||||
struct common_params params = {0};
|
||||
const struct option opt = TEST_CALLBACK(¶ms, opt_priority_cb);
|
||||
|
||||
ck_assert_int_eq(opt_priority_cb(&opt, "f:95", 0), 0);
|
||||
ck_assert_int_eq(params.sched_param.sched_policy, SCHED_FIFO);
|
||||
ck_assert_int_eq(params.sched_param.sched_priority, 95);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_opt_priority_cb_invalid)
|
||||
{
|
||||
struct common_params params = {0};
|
||||
const struct option opt = TEST_CALLBACK(¶ms, opt_priority_cb);
|
||||
|
||||
assert(freopen("/dev/null", "w", stderr));
|
||||
opt_priority_cb(&opt, "abc", 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_opt_trigger_cb)
|
||||
{
|
||||
struct trace_events *events = trace_event_alloc("sched:sched_switch");
|
||||
const struct option opt = TEST_CALLBACK(&events, opt_trigger_cb);
|
||||
|
||||
ck_assert_int_eq(opt_trigger_cb(&opt, "stacktrace", 0), 0);
|
||||
ck_assert_str_eq(events->trigger, "stacktrace");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_opt_trigger_cb_no_event)
|
||||
{
|
||||
struct trace_events *events = NULL;
|
||||
const struct option opt = TEST_CALLBACK(&events, opt_trigger_cb);
|
||||
|
||||
assert(freopen("/dev/null", "w", stderr));
|
||||
opt_trigger_cb(&opt, "stacktrace", 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_opt_filter_cb)
|
||||
{
|
||||
struct trace_events *events = trace_event_alloc("sched:sched_switch");
|
||||
const struct option opt = TEST_CALLBACK(&events, opt_filter_cb);
|
||||
|
||||
ck_assert_int_eq(opt_filter_cb(&opt, "comm ~ \"rtla\"", 0), 0);
|
||||
ck_assert_str_eq(events->filter, "comm ~ \"rtla\"");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_opt_filter_cb_no_event)
|
||||
{
|
||||
struct trace_events *events = NULL;
|
||||
const struct option opt = TEST_CALLBACK(&events, opt_filter_cb);
|
||||
|
||||
assert(freopen("/dev/null", "w", stderr));
|
||||
opt_filter_cb(&opt, "comm ~ \"rtla\"", 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_opt_osnoise_auto_cb)
|
||||
{
|
||||
struct osnoise_params params = {0};
|
||||
struct osnoise_cb_data cb_data = {¶ms};
|
||||
const struct option opt = TEST_CALLBACK(&cb_data, opt_osnoise_auto_cb);
|
||||
|
||||
ck_assert_int_eq(opt_osnoise_auto_cb(&opt, "10", 0), 0);
|
||||
ck_assert_int_eq(params.common.stop_us, 10);
|
||||
ck_assert_int_eq(params.threshold, 1);
|
||||
ck_assert_str_eq(cb_data.trace_output, "osnoise_trace.txt");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_opt_osnoise_period_cb)
|
||||
{
|
||||
unsigned long long period = 0;
|
||||
const struct option opt = TEST_CALLBACK(&period, opt_osnoise_period_cb);
|
||||
|
||||
ck_assert_int_eq(opt_osnoise_period_cb(&opt, "1000000", 0), 0);
|
||||
ck_assert_int_eq(period, 1000000);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_opt_osnoise_period_cb_invalid)
|
||||
{
|
||||
unsigned long long period = 0;
|
||||
const struct option opt = TEST_CALLBACK(&period, opt_osnoise_period_cb);
|
||||
|
||||
assert(freopen("/dev/null", "w", stderr));
|
||||
opt_osnoise_period_cb(&opt, "10000001", 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_opt_osnoise_runtime_cb)
|
||||
{
|
||||
unsigned long long runtime = 0;
|
||||
const struct option opt = TEST_CALLBACK(&runtime, opt_osnoise_runtime_cb);
|
||||
|
||||
ck_assert_int_eq(opt_osnoise_runtime_cb(&opt, "900000", 0), 0);
|
||||
ck_assert_int_eq(runtime, 900000);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_opt_osnoise_runtime_cb_invalid)
|
||||
{
|
||||
unsigned long long runtime = 0;
|
||||
const struct option opt = TEST_CALLBACK(&runtime, opt_osnoise_runtime_cb);
|
||||
|
||||
assert(freopen("/dev/null", "w", stderr));
|
||||
opt_osnoise_runtime_cb(&opt, "99", 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_opt_osnoise_trace_output_cb)
|
||||
{
|
||||
const char *trace_output = NULL;
|
||||
const struct option opt = TEST_CALLBACK(&trace_output, opt_osnoise_trace_output_cb);
|
||||
|
||||
ck_assert_int_eq(opt_osnoise_trace_output_cb(&opt, "trace.txt", 0), 0);
|
||||
ck_assert_str_eq(trace_output, "trace.txt");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_opt_osnoise_trace_output_cb_noarg)
|
||||
{
|
||||
const char *trace_output = NULL;
|
||||
const struct option opt = TEST_CALLBACK(&trace_output, opt_osnoise_trace_output_cb);
|
||||
|
||||
ck_assert_int_eq(opt_osnoise_trace_output_cb(&opt, NULL, 0), 0);
|
||||
ck_assert_str_eq(trace_output, "osnoise_trace.txt");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_opt_osnoise_on_threshold_cb)
|
||||
{
|
||||
struct actions actions = {0};
|
||||
const struct option opt = TEST_CALLBACK(&actions, opt_osnoise_on_threshold_cb);
|
||||
|
||||
ck_assert_int_eq(opt_osnoise_on_threshold_cb(&opt, "trace", 0), 0);
|
||||
ck_assert_int_eq(actions.len, 1);
|
||||
ck_assert_int_eq(actions.list[0].type, ACTION_TRACE_OUTPUT);
|
||||
ck_assert_str_eq(actions.list[0].trace_output, "osnoise_trace.txt");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_opt_osnoise_on_threshold_cb_invalid)
|
||||
{
|
||||
struct actions actions = {0};
|
||||
const struct option opt = TEST_CALLBACK(&actions, opt_osnoise_on_threshold_cb);
|
||||
|
||||
assert(freopen("/dev/null", "w", stderr));
|
||||
opt_osnoise_on_threshold_cb(&opt, "abc", 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_opt_osnoise_on_end_cb)
|
||||
{
|
||||
struct actions actions = {0};
|
||||
const struct option opt = TEST_CALLBACK(&actions, opt_osnoise_on_end_cb);
|
||||
|
||||
ck_assert_int_eq(opt_osnoise_on_end_cb(&opt, "trace", 0), 0);
|
||||
ck_assert_int_eq(actions.len, 1);
|
||||
ck_assert_int_eq(actions.list[0].type, ACTION_TRACE_OUTPUT);
|
||||
ck_assert_str_eq(actions.list[0].trace_output, "osnoise_trace.txt");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_opt_osnoise_on_end_cb_invalid)
|
||||
{
|
||||
struct actions actions = {0};
|
||||
const struct option opt = TEST_CALLBACK(&actions, opt_osnoise_on_end_cb);
|
||||
|
||||
assert(freopen("/dev/null", "w", stderr));
|
||||
opt_osnoise_on_end_cb(&opt, "abc", 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_opt_timerlat_period_cb)
|
||||
{
|
||||
long long period = 0;
|
||||
const struct option opt = TEST_CALLBACK(&period, opt_timerlat_period_cb);
|
||||
|
||||
ck_assert_int_eq(opt_timerlat_period_cb(&opt, "1000", 0), 0);
|
||||
ck_assert_int_eq(period, 1000);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_opt_timerlat_period_cb_invalid)
|
||||
{
|
||||
long long period = 0;
|
||||
const struct option opt = TEST_CALLBACK(&period, opt_timerlat_period_cb);
|
||||
|
||||
assert(freopen("/dev/null", "w", stderr));
|
||||
opt_timerlat_period_cb(&opt, "1000001", 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_opt_timerlat_auto_cb)
|
||||
{
|
||||
struct timerlat_params params = {0};
|
||||
struct timerlat_cb_data cb_data = {¶ms};
|
||||
const struct option opt = TEST_CALLBACK(&cb_data, opt_timerlat_auto_cb);
|
||||
|
||||
ck_assert_int_eq(opt_timerlat_auto_cb(&opt, "10", 0), 0);
|
||||
ck_assert_int_eq(params.common.stop_us, 10);
|
||||
ck_assert_int_eq(params.common.stop_total_us, 10);
|
||||
ck_assert_int_eq(params.print_stack, 10);
|
||||
ck_assert_str_eq(cb_data.trace_output, "timerlat_trace.txt");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_opt_dma_latency_cb)
|
||||
{
|
||||
int dma_latency = 0;
|
||||
const struct option opt = TEST_CALLBACK(&dma_latency, opt_dma_latency_cb);
|
||||
|
||||
ck_assert_int_eq(opt_dma_latency_cb(&opt, "1000", 0), 0);
|
||||
ck_assert_int_eq(dma_latency, 1000);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_opt_dma_latency_cb_min)
|
||||
{
|
||||
int dma_latency = 0;
|
||||
const struct option opt = TEST_CALLBACK(&dma_latency, opt_dma_latency_cb);
|
||||
|
||||
assert(freopen("/dev/null", "w", stderr));
|
||||
opt_dma_latency_cb(&opt, "-1", 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_opt_dma_latency_cb_max)
|
||||
{
|
||||
int dma_latency = 0;
|
||||
const struct option opt = TEST_CALLBACK(&dma_latency, opt_dma_latency_cb);
|
||||
|
||||
assert(freopen("/dev/null", "w", stderr));
|
||||
opt_dma_latency_cb(&opt, "10001", 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_opt_aa_only_cb)
|
||||
{
|
||||
struct timerlat_params params = {0};
|
||||
const struct option opt = TEST_CALLBACK(¶ms, opt_aa_only_cb);
|
||||
|
||||
ck_assert_int_eq(opt_aa_only_cb(&opt, "10", 0), 0);
|
||||
ck_assert_int_eq(params.common.stop_us, 10);
|
||||
ck_assert_int_eq(params.common.stop_total_us, 10);
|
||||
ck_assert_int_eq(params.print_stack, 10);
|
||||
ck_assert_int_eq(params.common.aa_only, 1);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_opt_timerlat_trace_output_cb)
|
||||
{
|
||||
const char *trace_output = NULL;
|
||||
const struct option opt = TEST_CALLBACK(&trace_output, opt_timerlat_trace_output_cb);
|
||||
|
||||
ck_assert_int_eq(opt_timerlat_trace_output_cb(&opt, "trace.txt", 0), 0);
|
||||
ck_assert_str_eq(trace_output, "trace.txt");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_opt_timerlat_trace_output_cb_noarg)
|
||||
{
|
||||
const char *trace_output = NULL;
|
||||
const struct option opt = TEST_CALLBACK(&trace_output, opt_timerlat_trace_output_cb);
|
||||
|
||||
ck_assert_int_eq(opt_timerlat_trace_output_cb(&opt, NULL, 0), 0);
|
||||
ck_assert_str_eq(trace_output, "timerlat_trace.txt");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_opt_timerlat_on_threshold_cb)
|
||||
{
|
||||
struct actions actions = {0};
|
||||
const struct option opt = TEST_CALLBACK(&actions, opt_timerlat_on_threshold_cb);
|
||||
|
||||
ck_assert_int_eq(opt_timerlat_on_threshold_cb(&opt, "trace", 0), 0);
|
||||
ck_assert_int_eq(actions.len, 1);
|
||||
ck_assert_int_eq(actions.list[0].type, ACTION_TRACE_OUTPUT);
|
||||
ck_assert_str_eq(actions.list[0].trace_output, "timerlat_trace.txt");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_opt_timerlat_on_threshold_cb_invalid)
|
||||
{
|
||||
struct actions actions = {0};
|
||||
const struct option opt = TEST_CALLBACK(&actions, opt_timerlat_on_threshold_cb);
|
||||
|
||||
assert(freopen("/dev/null", "w", stderr));
|
||||
opt_timerlat_on_threshold_cb(&opt, "abc", 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_opt_timerlat_on_end_cb)
|
||||
{
|
||||
struct actions actions = {0};
|
||||
const struct option opt = TEST_CALLBACK(&actions, opt_timerlat_on_end_cb);
|
||||
|
||||
ck_assert_int_eq(opt_timerlat_on_end_cb(&opt, "trace", 0), 0);
|
||||
ck_assert_int_eq(actions.len, 1);
|
||||
ck_assert_int_eq(actions.list[0].type, ACTION_TRACE_OUTPUT);
|
||||
ck_assert_str_eq(actions.list[0].trace_output, "timerlat_trace.txt");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_opt_timerlat_on_end_cb_invalid)
|
||||
{
|
||||
struct actions actions = {0};
|
||||
const struct option opt = TEST_CALLBACK(&actions, opt_timerlat_on_end_cb);
|
||||
|
||||
assert(freopen("/dev/null", "w", stderr));
|
||||
opt_timerlat_on_end_cb(&opt, "abc", 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_opt_user_threads_cb)
|
||||
{
|
||||
struct timerlat_params params = {0};
|
||||
const struct option opt = TEST_CALLBACK(¶ms, opt_user_threads_cb);
|
||||
|
||||
ck_assert_int_eq(opt_user_threads_cb(&opt, NULL, 0), 0);
|
||||
ck_assert_int_eq(params.common.user_workload, 1);
|
||||
ck_assert_int_eq(params.common.user_data, 1);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_opt_nano_cb)
|
||||
{
|
||||
struct timerlat_params params = {0};
|
||||
const struct option opt = TEST_CALLBACK(¶ms, opt_nano_cb);
|
||||
|
||||
ck_assert_int_eq(opt_nano_cb(&opt, NULL, 0), 0);
|
||||
ck_assert_int_eq(params.common.output_divisor, 1);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_opt_timerlat_align_cb)
|
||||
{
|
||||
struct timerlat_params params = {0};
|
||||
const struct option opt = TEST_CALLBACK(¶ms, opt_timerlat_align_cb);
|
||||
|
||||
ck_assert_int_eq(opt_timerlat_align_cb(&opt, "500", 0), 0);
|
||||
ck_assert(params.timerlat_align);
|
||||
ck_assert_int_eq(params.timerlat_align_us, 500);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_opt_stack_format_cb)
|
||||
{
|
||||
int stack_format = 0;
|
||||
const struct option opt = TEST_CALLBACK(&stack_format, opt_stack_format_cb);
|
||||
|
||||
ck_assert_int_eq(opt_stack_format_cb(&opt, "full", 0), 0);
|
||||
ck_assert_int_eq(stack_format, STACK_FORMAT_FULL);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_opt_stack_format_cb_invalid)
|
||||
{
|
||||
int stack_format = 0;
|
||||
const struct option opt = TEST_CALLBACK(&stack_format, opt_stack_format_cb);
|
||||
|
||||
assert(freopen("/dev/null", "w", stderr));
|
||||
opt_stack_format_cb(&opt, "abc", 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_opt_bucket_size_cb)
|
||||
{
|
||||
int bucket_size = 0;
|
||||
const struct option opt = TEST_CALLBACK(&bucket_size, opt_bucket_size_cb);
|
||||
|
||||
ck_assert_int_eq(opt_bucket_size_cb(&opt, "100", 0), 0);
|
||||
ck_assert_int_eq(bucket_size, 100);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_opt_bucket_size_min)
|
||||
{
|
||||
int bucket_size = 0;
|
||||
const struct option opt = TEST_CALLBACK(&bucket_size, opt_bucket_size_cb);
|
||||
|
||||
assert(freopen("/dev/null", "w", stderr));
|
||||
opt_bucket_size_cb(&opt, "0", 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_opt_bucket_size_max)
|
||||
{
|
||||
int bucket_size = 0;
|
||||
const struct option opt = TEST_CALLBACK(&bucket_size, opt_bucket_size_cb);
|
||||
|
||||
assert(freopen("/dev/null", "w", stderr));
|
||||
opt_bucket_size_cb(&opt, "1000001", 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_opt_entries_cb)
|
||||
{
|
||||
int entries = 0;
|
||||
const struct option opt = TEST_CALLBACK(&entries, opt_entries_cb);
|
||||
|
||||
ck_assert_int_eq(opt_entries_cb(&opt, "100", 0), 0);
|
||||
ck_assert_int_eq(entries, 100);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_opt_entries_min)
|
||||
{
|
||||
int entries = 0;
|
||||
const struct option opt = TEST_CALLBACK(&entries, opt_entries_cb);
|
||||
|
||||
assert(freopen("/dev/null", "w", stderr));
|
||||
opt_entries_cb(&opt, "9", 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_opt_entries_max)
|
||||
{
|
||||
int entries = 0;
|
||||
const struct option opt = TEST_CALLBACK(&entries, opt_entries_cb);
|
||||
|
||||
assert(freopen("/dev/null", "w", stderr));
|
||||
opt_entries_cb(&opt, "10000000", 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
Suite *cli_opt_callback_suite(void)
|
||||
{
|
||||
Suite *s = suite_create("cli_opt_callback");
|
||||
TCase *tc;
|
||||
|
||||
tc = tcase_create("common");
|
||||
tcase_add_test(tc, test_opt_llong_callback_simple);
|
||||
tcase_add_test(tc, test_opt_llong_callback_max);
|
||||
tcase_add_test(tc, test_opt_llong_callback_min);
|
||||
tcase_add_test(tc, test_opt_int_callback_simple);
|
||||
tcase_add_test(tc, test_opt_int_callback_max);
|
||||
tcase_add_test(tc, test_opt_int_callback_min);
|
||||
tcase_add_test(tc, test_opt_int_callback_non_numeric);
|
||||
tcase_add_test(tc, test_opt_int_callback_non_numeric_suffix);
|
||||
tcase_add_test(tc, test_opt_cpus_cb);
|
||||
tcase_add_exit_test(tc, test_opt_cpus_cb_invalid, EXIT_FAILURE);
|
||||
tcase_add_test(tc, test_opt_cgroup_cb);
|
||||
tcase_add_test(tc, test_opt_cgroup_cb_equals);
|
||||
tcase_add_test(tc, test_opt_duration_cb);
|
||||
tcase_add_exit_test(tc, test_opt_duration_cb_invalid, EXIT_FAILURE);
|
||||
tcase_add_test(tc, test_opt_event_cb);
|
||||
tcase_add_test(tc, test_opt_event_cb_multiple);
|
||||
tcase_add_test(tc, test_opt_housekeeping_cb);
|
||||
tcase_add_exit_test(tc, test_opt_housekeeping_cb_invalid, EXIT_FAILURE);
|
||||
tcase_add_test(tc, test_opt_priority_cb);
|
||||
tcase_add_exit_test(tc, test_opt_priority_cb_invalid, EXIT_FAILURE);
|
||||
tcase_add_test(tc, test_opt_trigger_cb);
|
||||
tcase_add_exit_test(tc, test_opt_trigger_cb_no_event, EXIT_FAILURE);
|
||||
tcase_add_test(tc, test_opt_filter_cb);
|
||||
tcase_add_exit_test(tc, test_opt_filter_cb_no_event, EXIT_FAILURE);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
tc = tcase_create("osnoise");
|
||||
tcase_add_test(tc, test_opt_osnoise_auto_cb);
|
||||
tcase_add_test(tc, test_opt_osnoise_period_cb);
|
||||
tcase_add_exit_test(tc, test_opt_osnoise_period_cb_invalid, EXIT_FAILURE);
|
||||
tcase_add_test(tc, test_opt_osnoise_runtime_cb);
|
||||
tcase_add_exit_test(tc, test_opt_osnoise_runtime_cb_invalid, EXIT_FAILURE);
|
||||
tcase_add_test(tc, test_opt_osnoise_trace_output_cb);
|
||||
tcase_add_test(tc, test_opt_osnoise_trace_output_cb_noarg);
|
||||
tcase_add_test(tc, test_opt_osnoise_on_threshold_cb);
|
||||
tcase_add_exit_test(tc, test_opt_osnoise_on_threshold_cb_invalid, EXIT_FAILURE);
|
||||
tcase_add_test(tc, test_opt_osnoise_on_end_cb);
|
||||
tcase_add_exit_test(tc, test_opt_osnoise_on_end_cb_invalid, EXIT_FAILURE);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
tc = tcase_create("timerlat");
|
||||
tcase_add_test(tc, test_opt_timerlat_period_cb);
|
||||
tcase_add_exit_test(tc, test_opt_timerlat_period_cb_invalid, EXIT_FAILURE);
|
||||
tcase_add_test(tc, test_opt_timerlat_auto_cb);
|
||||
tcase_add_test(tc, test_opt_dma_latency_cb);
|
||||
tcase_add_exit_test(tc, test_opt_dma_latency_cb_min, EXIT_FAILURE);
|
||||
tcase_add_exit_test(tc, test_opt_dma_latency_cb_max, EXIT_FAILURE);
|
||||
tcase_add_test(tc, test_opt_aa_only_cb);
|
||||
tcase_add_test(tc, test_opt_timerlat_trace_output_cb);
|
||||
tcase_add_test(tc, test_opt_timerlat_trace_output_cb_noarg);
|
||||
tcase_add_test(tc, test_opt_timerlat_on_threshold_cb);
|
||||
tcase_add_exit_test(tc, test_opt_timerlat_on_threshold_cb_invalid, EXIT_FAILURE);
|
||||
tcase_add_test(tc, test_opt_timerlat_on_end_cb);
|
||||
tcase_add_exit_test(tc, test_opt_timerlat_on_end_cb_invalid, EXIT_FAILURE);
|
||||
tcase_add_test(tc, test_opt_user_threads_cb);
|
||||
tcase_add_test(tc, test_opt_nano_cb);
|
||||
tcase_add_test(tc, test_opt_stack_format_cb);
|
||||
tcase_add_exit_test(tc, test_opt_stack_format_cb_invalid, EXIT_FAILURE);
|
||||
tcase_add_test(tc, test_opt_timerlat_align_cb);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
tc = tcase_create("histogram");
|
||||
tcase_add_test(tc, test_opt_bucket_size_cb);
|
||||
tcase_add_exit_test(tc, test_opt_bucket_size_min, EXIT_FAILURE);
|
||||
tcase_add_exit_test(tc, test_opt_bucket_size_max, EXIT_FAILURE);
|
||||
tcase_add_test(tc, test_opt_entries_cb);
|
||||
tcase_add_exit_test(tc, test_opt_entries_min, EXIT_FAILURE);
|
||||
tcase_add_exit_test(tc, test_opt_entries_max, EXIT_FAILURE);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
return s;
|
||||
}
|
||||
68
tools/tracing/rtla/tests/unit/cli_params_assert.h
Normal file
68
tools/tracing/rtla/tests/unit/cli_params_assert.h
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#pragma once
|
||||
|
||||
#include "../../src/timerlat.h"
|
||||
|
||||
/* Tracing Options */
|
||||
|
||||
#define CLI_ASSERT_SINGLE_EVENT(_system, _event) do {\
|
||||
ck_assert_ptr_nonnull(params->events);\
|
||||
ck_assert_str_eq(params->events->system, _system);\
|
||||
ck_assert_str_eq(params->events->event, _event);\
|
||||
ck_assert_ptr_null(params->events->next);\
|
||||
} while (0)
|
||||
|
||||
#define CLI_ASSERT_SINGLE_FILTER(_filter) do {\
|
||||
ck_assert_ptr_nonnull(params->events);\
|
||||
ck_assert_str_eq(params->events->filter, _filter);\
|
||||
ck_assert_ptr_null(params->events->next);\
|
||||
} while (0)
|
||||
|
||||
#define CLI_ASSERT_SINGLE_TRIGGER(_trigger) do {\
|
||||
ck_assert_ptr_nonnull(params->events);\
|
||||
ck_assert_str_eq(params->events->trigger, _trigger);\
|
||||
ck_assert_ptr_null(params->events->next);\
|
||||
} while (0)
|
||||
|
||||
/* CPU Configuration */
|
||||
|
||||
#define CLI_ASSERT_CPUSET(_field, ...) do {\
|
||||
int n;\
|
||||
int cpus[] = { __VA_ARGS__ };\
|
||||
for (n = 0; n < sizeof(cpus) / sizeof(int); n++)\
|
||||
ck_assert(CPU_ISSET(cpus[n], ¶ms->_field));\
|
||||
ck_assert_int_eq(CPU_COUNT(¶ms->_field), n);\
|
||||
} while (0)
|
||||
|
||||
/* Auto Analysis and Actions */
|
||||
|
||||
#define CLI_OSNOISE_ASSERT_AUTO(_stop) do {\
|
||||
ck_assert_int_eq(params->stop_us, _stop);\
|
||||
ck_assert_int_eq(osn_params->threshold, 1);\
|
||||
ck_assert_int_eq(params->threshold_actions.len, 1);\
|
||||
ck_assert_int_eq(params->threshold_actions.list[0].type, ACTION_TRACE_OUTPUT);\
|
||||
ck_assert_str_eq(params->threshold_actions.list[0].trace_output, "osnoise_trace.txt");\
|
||||
} while (0)
|
||||
|
||||
#define CLI_TIMERLAT_ASSERT_AUTO(_threshold) do {\
|
||||
ck_assert_int_eq(params->stop_us, _threshold);\
|
||||
ck_assert_int_eq(params->stop_total_us, _threshold);\
|
||||
ck_assert_int_eq(tlat_params->print_stack, _threshold);\
|
||||
ck_assert_int_eq(params->threshold_actions.len, 1);\
|
||||
ck_assert_int_eq(params->threshold_actions.list[0].type, ACTION_TRACE_OUTPUT);\
|
||||
ck_assert_str_eq(params->threshold_actions.list[0].trace_output, "timerlat_trace.txt");\
|
||||
} while (0)
|
||||
|
||||
#define CLI_TIMERLAT_ASSERT_AA_ONLY(_threshold) do {\
|
||||
ck_assert_int_eq(params->stop_us, _threshold);\
|
||||
ck_assert_int_eq(params->stop_total_us, _threshold);\
|
||||
ck_assert_int_eq(tlat_params->print_stack, _threshold);\
|
||||
ck_assert_int_eq(params->threshold_actions.len, 0);\
|
||||
ck_assert(params->aa_only);\
|
||||
} while (0)
|
||||
|
||||
#define CLI_ASSERT_SINGLE_ACTION(_actions, _type, _arg, _valtype, _value) do {\
|
||||
ck_assert_int_eq(params->_actions.len, 1);\
|
||||
ck_assert_int_eq(params->_actions.list[0].type, _type);\
|
||||
ck_assert_##_valtype##_eq(params->_actions.list[0]._arg, _value);\
|
||||
} while (0)
|
||||
557
tools/tracing/rtla/tests/unit/osnoise_hist_cli.c
Normal file
557
tools/tracing/rtla/tests/unit/osnoise_hist_cli.c
Normal file
|
|
@ -0,0 +1,557 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <check.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sched.h>
|
||||
#include <limits.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/sysinfo.h>
|
||||
|
||||
#include "cli_params_assert.h"
|
||||
#include "../../src/cli.h"
|
||||
|
||||
#define PARSE_ARGS(...) char *argv[] = { __VA_ARGS__, NULL };\
|
||||
int argc = sizeof(argv) / sizeof(char *) - 1;\
|
||||
struct common_params *params =\
|
||||
osnoise_hist_parse_args(argc, argv);\
|
||||
struct osnoise_params *osn_params __maybe_unused =\
|
||||
to_osnoise_params(params)
|
||||
|
||||
/* Tracing Options */
|
||||
|
||||
START_TEST(test_period_short)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "hist", "-p", "100000");
|
||||
|
||||
ck_assert_int_eq(osn_params->period, 100000);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_period_long)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "hist", "--period", "100000");
|
||||
|
||||
ck_assert_int_eq(osn_params->period, 100000);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_runtime_short)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "hist", "-r", "95000");
|
||||
|
||||
ck_assert_int_eq(osn_params->runtime, 95000);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_runtime_long)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "hist", "--runtime", "95000");
|
||||
|
||||
ck_assert_int_eq(osn_params->runtime, 95000);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_stop_short)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "hist", "-s", "20");
|
||||
|
||||
ck_assert_int_eq(params->stop_us, 20);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_stop_long)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "hist", "--stop", "20");
|
||||
|
||||
ck_assert_int_eq(params->stop_us, 20);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_stop_total_short)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "hist", "-S", "20");
|
||||
|
||||
ck_assert_int_eq(params->stop_total_us, 20);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_stop_total_long)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "hist", "--stop-total", "20");
|
||||
|
||||
ck_assert_int_eq(params->stop_total_us, 20);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_threshold_short)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "hist", "-T", "5");
|
||||
|
||||
ck_assert_int_eq(osn_params->threshold, 5);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_threshold_long)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "hist", "--threshold", "5");
|
||||
|
||||
ck_assert_int_eq(osn_params->threshold, 5);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_trace_short_noarg)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "hist", "-t");
|
||||
|
||||
CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str,
|
||||
"osnoise_trace.txt");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_trace_short_followarg)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "hist", "-t", "-d", "20");
|
||||
|
||||
CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str,
|
||||
"osnoise_trace.txt");
|
||||
ck_assert_int_eq(params->duration, 20); /* check if next argument is read correctly */
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_trace_short_space)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "hist", "-t", "tracefile");
|
||||
|
||||
CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str,
|
||||
"tracefile");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_trace_short_equals)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "hist", "-t=tracefile");
|
||||
|
||||
CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str,
|
||||
"tracefile");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_trace_long_noarg)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "hist", "--trace");
|
||||
|
||||
CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str,
|
||||
"osnoise_trace.txt");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_trace_long_followarg)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "hist", "--trace", "-d", "20");
|
||||
|
||||
CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str,
|
||||
"osnoise_trace.txt");
|
||||
ck_assert_int_eq(params->duration, 20); /* check if next argument is read correctly */
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_trace_long_space)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "hist", "--trace", "tracefile");
|
||||
|
||||
CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str,
|
||||
"tracefile");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_trace_long_equals)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "hist", "--trace=tracefile");
|
||||
|
||||
CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str,
|
||||
"tracefile");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/* Event Configuration */
|
||||
|
||||
START_TEST(test_event_short)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "hist", "-e", "system:event");
|
||||
|
||||
CLI_ASSERT_SINGLE_EVENT("system", "event");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_event_long)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "hist", "--event", "system:event");
|
||||
|
||||
CLI_ASSERT_SINGLE_EVENT("system", "event");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_filter)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "hist", "-e", "system:event", "--filter", "filter");
|
||||
|
||||
CLI_ASSERT_SINGLE_FILTER("filter");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_trigger)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "hist", "-e", "system:event", "--trigger", "trigger");
|
||||
|
||||
CLI_ASSERT_SINGLE_TRIGGER("trigger");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/* CPU Configuration */
|
||||
|
||||
START_TEST(test_cpus_short)
|
||||
{
|
||||
nr_cpus = 4;
|
||||
|
||||
PARSE_ARGS("osnoise", "hist", "-c", "0-1,3");
|
||||
|
||||
ck_assert_str_eq(params->cpus, "0-1,3");
|
||||
CLI_ASSERT_CPUSET(monitored_cpus, 0, 1, 3);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_cpus_long)
|
||||
{
|
||||
nr_cpus = 4;
|
||||
|
||||
PARSE_ARGS("osnoise", "hist", "--cpus", "0-1,3");
|
||||
|
||||
ck_assert_str_eq(params->cpus, "0-1,3");
|
||||
CLI_ASSERT_CPUSET(monitored_cpus, 0, 1, 3);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_housekeeping_short)
|
||||
{
|
||||
nr_cpus = 4;
|
||||
|
||||
PARSE_ARGS("osnoise", "hist", "-H", "0-1,3");
|
||||
|
||||
CLI_ASSERT_CPUSET(hk_cpu_set, 0, 1, 3);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_housekeeping_long)
|
||||
{
|
||||
nr_cpus = 4;
|
||||
|
||||
PARSE_ARGS("osnoise", "hist", "--house-keeping", "0-1,3");
|
||||
|
||||
CLI_ASSERT_CPUSET(hk_cpu_set, 0, 1, 3);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/* Thread Configuration */
|
||||
|
||||
START_TEST(test_cgroup_short_noarg)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "hist", "-C");
|
||||
|
||||
ck_assert(params->cgroup);
|
||||
ck_assert_ptr_null(params->cgroup_name);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_cgroup_short_space)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "hist", "-C", "cgroup");
|
||||
|
||||
ck_assert(params->cgroup);
|
||||
ck_assert_str_eq(params->cgroup_name, "cgroup");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_cgroup_short_equals)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "hist", "-C=cgroup");
|
||||
|
||||
ck_assert(params->cgroup);
|
||||
ck_assert_str_eq(params->cgroup_name, "cgroup");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_cgroup_long_noarg)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "hist", "--cgroup");
|
||||
|
||||
ck_assert(params->cgroup);
|
||||
ck_assert_ptr_null(params->cgroup_name);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_cgroup_long_space)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "hist", "--cgroup", "cgroup");
|
||||
|
||||
ck_assert(params->cgroup);
|
||||
ck_assert_str_eq(params->cgroup_name, "cgroup");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_cgroup_long_equals)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "hist", "--cgroup=cgroup");
|
||||
|
||||
ck_assert(params->cgroup);
|
||||
ck_assert_str_eq(params->cgroup_name, "cgroup");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_priority_short)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "hist", "-P", "f:95");
|
||||
|
||||
ck_assert_int_eq(params->sched_param.sched_policy, SCHED_FIFO);
|
||||
ck_assert_int_eq(params->sched_param.sched_priority, 95);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_priority_long)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "hist", "--priority", "f:95");
|
||||
|
||||
ck_assert_int_eq(params->sched_param.sched_policy, SCHED_FIFO);
|
||||
ck_assert_int_eq(params->sched_param.sched_priority, 95);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/* Histogram Options */
|
||||
|
||||
START_TEST(test_bucket_size_short)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "hist", "-b", "2");
|
||||
|
||||
ck_assert_int_eq(params->hist.bucket_size, 2);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_bucket_size_long)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "hist", "--bucket-size", "2");
|
||||
|
||||
ck_assert_int_eq(params->hist.bucket_size, 2);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_entries_short)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "hist", "-E", "512");
|
||||
|
||||
ck_assert_int_eq(params->hist.entries, 512);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_entries_long)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "hist", "--entries", "512");
|
||||
|
||||
ck_assert_int_eq(params->hist.entries, 512);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_no_header)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "hist", "--no-header");
|
||||
|
||||
ck_assert(params->hist.no_header);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_no_index)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "hist", "--with-zeros", "--no-index");
|
||||
|
||||
ck_assert(params->hist.no_index);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_no_summary)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "hist", "--no-summary");
|
||||
|
||||
ck_assert(params->hist.no_summary);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_with_zeros)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "hist", "--with-zeros");
|
||||
|
||||
ck_assert(params->hist.with_zeros);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/* System Tuning */
|
||||
|
||||
START_TEST(test_trace_buffer_size)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "hist", "--trace-buffer-size", "200");
|
||||
|
||||
ck_assert_int_eq(params->buffer_size, 200);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_warm_up)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "hist", "--warm-up", "5");
|
||||
|
||||
ck_assert_int_eq(params->warmup, 5);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/* Auto Analysis and Actions */
|
||||
|
||||
START_TEST(test_auto)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "hist", "-a", "20");
|
||||
|
||||
CLI_OSNOISE_ASSERT_AUTO(20);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_on_end)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "hist", "--on-end", "trace");
|
||||
|
||||
CLI_ASSERT_SINGLE_ACTION(end_actions, ACTION_TRACE_OUTPUT, trace_output, str,
|
||||
"osnoise_trace.txt");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_on_threshold)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "hist", "--on-threshold", "trace");
|
||||
|
||||
CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str,
|
||||
"osnoise_trace.txt");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/* General */
|
||||
|
||||
START_TEST(test_debug_short)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "hist", "-D");
|
||||
|
||||
ck_assert(config_debug);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_debug_long)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "hist", "--debug");
|
||||
|
||||
ck_assert(config_debug);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_duration_short)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "hist", "-d", "1m");
|
||||
|
||||
ck_assert_int_eq(params->duration, 60);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_duration_long)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "hist", "--duration", "1m");
|
||||
|
||||
ck_assert_int_eq(params->duration, 60);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
Suite *osnoise_hist_cli_suite(void)
|
||||
{
|
||||
Suite *s = suite_create("osnoise_hist_cli");
|
||||
TCase *tc;
|
||||
|
||||
tc = tcase_create("tracing_options");
|
||||
tcase_add_test(tc, test_period_short);
|
||||
tcase_add_test(tc, test_period_long);
|
||||
tcase_add_test(tc, test_runtime_short);
|
||||
tcase_add_test(tc, test_runtime_long);
|
||||
tcase_add_test(tc, test_stop_short);
|
||||
tcase_add_test(tc, test_stop_long);
|
||||
tcase_add_test(tc, test_stop_total_short);
|
||||
tcase_add_test(tc, test_stop_total_long);
|
||||
tcase_add_test(tc, test_threshold_short);
|
||||
tcase_add_test(tc, test_threshold_long);
|
||||
tcase_add_test(tc, test_trace_short_noarg);
|
||||
tcase_add_test(tc, test_trace_short_followarg);
|
||||
tcase_add_test(tc, test_trace_short_space);
|
||||
tcase_add_test(tc, test_trace_short_equals);
|
||||
tcase_add_test(tc, test_trace_long_noarg);
|
||||
tcase_add_test(tc, test_trace_long_followarg);
|
||||
tcase_add_test(tc, test_trace_long_space);
|
||||
tcase_add_test(tc, test_trace_long_equals);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
tc = tcase_create("event_configuration");
|
||||
tcase_add_test(tc, test_event_short);
|
||||
tcase_add_test(tc, test_event_long);
|
||||
tcase_add_test(tc, test_filter);
|
||||
tcase_add_test(tc, test_trigger);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
tc = tcase_create("cpu_configuration");
|
||||
tcase_add_test(tc, test_cpus_short);
|
||||
tcase_add_test(tc, test_cpus_long);
|
||||
tcase_add_test(tc, test_housekeeping_short);
|
||||
tcase_add_test(tc, test_housekeeping_long);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
tc = tcase_create("thread_configuration");
|
||||
tcase_add_test(tc, test_cgroup_short_noarg);
|
||||
tcase_add_test(tc, test_cgroup_short_space);
|
||||
tcase_add_test(tc, test_cgroup_short_equals);
|
||||
tcase_add_test(tc, test_cgroup_long_noarg);
|
||||
tcase_add_test(tc, test_cgroup_long_space);
|
||||
tcase_add_test(tc, test_cgroup_long_equals);
|
||||
tcase_add_test(tc, test_priority_short);
|
||||
tcase_add_test(tc, test_priority_long);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
tc = tcase_create("histogram_options");
|
||||
tcase_add_test(tc, test_bucket_size_short);
|
||||
tcase_add_test(tc, test_bucket_size_long);
|
||||
tcase_add_test(tc, test_entries_short);
|
||||
tcase_add_test(tc, test_entries_long);
|
||||
tcase_add_test(tc, test_no_header);
|
||||
tcase_add_test(tc, test_no_index);
|
||||
tcase_add_test(tc, test_no_summary);
|
||||
tcase_add_test(tc, test_with_zeros);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
tc = tcase_create("system_tuning");
|
||||
tcase_add_test(tc, test_trace_buffer_size);
|
||||
tcase_add_test(tc, test_warm_up);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
tc = tcase_create("aa_actions");
|
||||
tcase_add_test(tc, test_auto);
|
||||
tcase_add_test(tc, test_on_end);
|
||||
tcase_add_test(tc, test_on_threshold);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
tc = tcase_create("general");
|
||||
tcase_add_test(tc, test_debug_short);
|
||||
tcase_add_test(tc, test_debug_long);
|
||||
tcase_add_test(tc, test_duration_short);
|
||||
tcase_add_test(tc, test_duration_long);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
return s;
|
||||
}
|
||||
503
tools/tracing/rtla/tests/unit/osnoise_top_cli.c
Normal file
503
tools/tracing/rtla/tests/unit/osnoise_top_cli.c
Normal file
|
|
@ -0,0 +1,503 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <check.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sched.h>
|
||||
#include <limits.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/sysinfo.h>
|
||||
|
||||
#include "cli_params_assert.h"
|
||||
#include "../../src/cli.h"
|
||||
|
||||
#define PARSE_ARGS(...) char *argv[] = { __VA_ARGS__, NULL };\
|
||||
int argc = sizeof(argv) / sizeof(char *) - 1;\
|
||||
struct common_params *params =\
|
||||
osnoise_top_parse_args(argc, argv);\
|
||||
struct osnoise_params *osn_params __maybe_unused =\
|
||||
to_osnoise_params(params)
|
||||
|
||||
/* Tracing Options */
|
||||
|
||||
START_TEST(test_period_short)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "top", "-p", "100000");
|
||||
|
||||
ck_assert_int_eq(osn_params->period, 100000);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_period_long)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "top", "--period", "100000");
|
||||
|
||||
ck_assert_int_eq(osn_params->period, 100000);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_runtime_short)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "top", "-r", "95000");
|
||||
|
||||
ck_assert_int_eq(osn_params->runtime, 95000);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_runtime_long)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "top", "--runtime", "95000");
|
||||
|
||||
ck_assert_int_eq(osn_params->runtime, 95000);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_stop_short)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "top", "-s", "20");
|
||||
|
||||
ck_assert_int_eq(params->stop_us, 20);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_stop_long)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "top", "--stop", "20");
|
||||
|
||||
ck_assert_int_eq(params->stop_us, 20);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_stop_total_short)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "top", "-S", "20");
|
||||
|
||||
ck_assert_int_eq(params->stop_total_us, 20);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_stop_total_long)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "top", "--stop-total", "20");
|
||||
|
||||
ck_assert_int_eq(params->stop_total_us, 20);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_threshold_short)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "top", "-T", "5");
|
||||
|
||||
ck_assert_int_eq(osn_params->threshold, 5);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_threshold_long)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "top", "--threshold", "5");
|
||||
|
||||
ck_assert_int_eq(osn_params->threshold, 5);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_trace_short_noarg)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "top", "-t");
|
||||
|
||||
CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str,
|
||||
"osnoise_trace.txt");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_trace_short_followarg)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "top", "-t", "-d", "20");
|
||||
|
||||
CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str,
|
||||
"osnoise_trace.txt");
|
||||
ck_assert_int_eq(params->duration, 20); /* check if next argument is read correctly */
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_trace_short_space)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "top", "-t", "tracefile");
|
||||
|
||||
CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str,
|
||||
"tracefile");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_trace_short_equals)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "top", "-t=tracefile");
|
||||
|
||||
CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str,
|
||||
"tracefile");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_trace_long_noarg)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "top", "--trace");
|
||||
|
||||
CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str,
|
||||
"osnoise_trace.txt");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_trace_long_followarg)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "top", "--trace", "-d", "20");
|
||||
|
||||
CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str,
|
||||
"osnoise_trace.txt");
|
||||
ck_assert_int_eq(params->duration, 20); /* check if next argument is read correctly */
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_trace_long_space)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "top", "--trace", "tracefile");
|
||||
|
||||
CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str,
|
||||
"tracefile");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_trace_long_equals)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "top", "--trace=tracefile");
|
||||
|
||||
CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str,
|
||||
"tracefile");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/* Event Configuration */
|
||||
|
||||
START_TEST(test_event_short)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "top", "-e", "system:event");
|
||||
|
||||
CLI_ASSERT_SINGLE_EVENT("system", "event");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_event_long)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "top", "--event", "system:event");
|
||||
|
||||
CLI_ASSERT_SINGLE_EVENT("system", "event");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_filter)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "top", "-e", "system:event", "--filter", "filter");
|
||||
|
||||
CLI_ASSERT_SINGLE_FILTER("filter");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_trigger)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "top", "-e", "system:event", "--trigger", "trigger");
|
||||
|
||||
CLI_ASSERT_SINGLE_TRIGGER("trigger");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/* CPU Configuration */
|
||||
|
||||
START_TEST(test_cpus_short)
|
||||
{
|
||||
nr_cpus = 4;
|
||||
|
||||
PARSE_ARGS("osnoise", "top", "-c", "0-1,3");
|
||||
|
||||
ck_assert_str_eq(params->cpus, "0-1,3");
|
||||
CLI_ASSERT_CPUSET(monitored_cpus, 0, 1, 3);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_cpus_long)
|
||||
{
|
||||
nr_cpus = 4;
|
||||
|
||||
PARSE_ARGS("osnoise", "top", "--cpus", "0-1,3");
|
||||
|
||||
ck_assert_str_eq(params->cpus, "0-1,3");
|
||||
CLI_ASSERT_CPUSET(monitored_cpus, 0, 1, 3);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_housekeeping_short)
|
||||
{
|
||||
nr_cpus = 4;
|
||||
|
||||
PARSE_ARGS("osnoise", "top", "-H", "0-1,3");
|
||||
|
||||
CLI_ASSERT_CPUSET(hk_cpu_set, 0, 1, 3);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_housekeeping_long)
|
||||
{
|
||||
nr_cpus = 4;
|
||||
|
||||
PARSE_ARGS("osnoise", "top", "--house-keeping", "0-1,3");
|
||||
|
||||
CLI_ASSERT_CPUSET(hk_cpu_set, 0, 1, 3);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/* Thread Configuration */
|
||||
|
||||
START_TEST(test_cgroup_short_noarg)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "top", "-C");
|
||||
|
||||
ck_assert(params->cgroup);
|
||||
ck_assert_ptr_null(params->cgroup_name);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_cgroup_short_space)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "top", "-C", "cgroup");
|
||||
|
||||
ck_assert(params->cgroup);
|
||||
ck_assert_str_eq(params->cgroup_name, "cgroup");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_cgroup_short_equals)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "top", "-C=cgroup");
|
||||
|
||||
ck_assert(params->cgroup);
|
||||
ck_assert_str_eq(params->cgroup_name, "cgroup");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_cgroup_long_noarg)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "top", "--cgroup");
|
||||
|
||||
ck_assert(params->cgroup);
|
||||
ck_assert_ptr_null(params->cgroup_name);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_cgroup_long_space)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "top", "--cgroup", "cgroup");
|
||||
|
||||
ck_assert(params->cgroup);
|
||||
ck_assert_str_eq(params->cgroup_name, "cgroup");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_cgroup_long_equals)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "top", "--cgroup=cgroup");
|
||||
|
||||
ck_assert(params->cgroup);
|
||||
ck_assert_str_eq(params->cgroup_name, "cgroup");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_priority_short)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "top", "-P", "f:95");
|
||||
|
||||
ck_assert_int_eq(params->sched_param.sched_policy, SCHED_FIFO);
|
||||
ck_assert_int_eq(params->sched_param.sched_priority, 95);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_priority_long)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "top", "--priority", "f:95");
|
||||
|
||||
ck_assert_int_eq(params->sched_param.sched_policy, SCHED_FIFO);
|
||||
ck_assert_int_eq(params->sched_param.sched_priority, 95);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/* Output */
|
||||
|
||||
START_TEST(test_quiet_short)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "top", "-q");
|
||||
|
||||
ck_assert(params->quiet);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_quiet_long)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "top", "--quiet");
|
||||
|
||||
ck_assert(params->quiet);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/* Auto Analysis and Actions */
|
||||
|
||||
START_TEST(test_auto)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "top", "-a", "20");
|
||||
|
||||
CLI_OSNOISE_ASSERT_AUTO(20);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_on_end)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "top", "--on-end", "trace");
|
||||
|
||||
CLI_ASSERT_SINGLE_ACTION(end_actions, ACTION_TRACE_OUTPUT, trace_output, str,
|
||||
"osnoise_trace.txt");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_on_threshold)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "top", "--on-threshold", "trace");
|
||||
|
||||
CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str,
|
||||
"osnoise_trace.txt");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/* System Tuning */
|
||||
|
||||
START_TEST(test_trace_buffer_size)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "top", "--trace-buffer-size", "200");
|
||||
|
||||
ck_assert_int_eq(params->buffer_size, 200);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_warm_up)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "top", "--warm-up", "5");
|
||||
|
||||
ck_assert_int_eq(params->warmup, 5);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/* General */
|
||||
|
||||
START_TEST(test_debug_short)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "top", "-D");
|
||||
|
||||
ck_assert(config_debug);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_debug_long)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "top", "--debug");
|
||||
|
||||
ck_assert(config_debug);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_duration_short)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "top", "-d", "1m");
|
||||
|
||||
ck_assert_int_eq(params->duration, 60);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_duration_long)
|
||||
{
|
||||
PARSE_ARGS("osnoise", "top", "--duration", "1m");
|
||||
|
||||
ck_assert_int_eq(params->duration, 60);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
Suite *osnoise_top_cli_suite(void)
|
||||
{
|
||||
Suite *s = suite_create("osnoise_top_cli");
|
||||
TCase *tc;
|
||||
|
||||
tc = tcase_create("tracing_options");
|
||||
tcase_add_test(tc, test_period_short);
|
||||
tcase_add_test(tc, test_period_long);
|
||||
tcase_add_test(tc, test_runtime_short);
|
||||
tcase_add_test(tc, test_runtime_long);
|
||||
tcase_add_test(tc, test_stop_short);
|
||||
tcase_add_test(tc, test_stop_long);
|
||||
tcase_add_test(tc, test_stop_total_short);
|
||||
tcase_add_test(tc, test_stop_total_long);
|
||||
tcase_add_test(tc, test_threshold_short);
|
||||
tcase_add_test(tc, test_threshold_long);
|
||||
tcase_add_test(tc, test_trace_short_noarg);
|
||||
tcase_add_test(tc, test_trace_short_followarg);
|
||||
tcase_add_test(tc, test_trace_short_space);
|
||||
tcase_add_test(tc, test_trace_short_equals);
|
||||
tcase_add_test(tc, test_trace_long_noarg);
|
||||
tcase_add_test(tc, test_trace_long_followarg);
|
||||
tcase_add_test(tc, test_trace_long_space);
|
||||
tcase_add_test(tc, test_trace_long_equals);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
tc = tcase_create("event_configuration");
|
||||
tcase_add_test(tc, test_event_short);
|
||||
tcase_add_test(tc, test_event_long);
|
||||
tcase_add_test(tc, test_filter);
|
||||
tcase_add_test(tc, test_trigger);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
tc = tcase_create("cpu_configuration");
|
||||
tcase_add_test(tc, test_cpus_short);
|
||||
tcase_add_test(tc, test_cpus_long);
|
||||
tcase_add_test(tc, test_housekeeping_short);
|
||||
tcase_add_test(tc, test_housekeeping_long);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
tc = tcase_create("thread_configuration");
|
||||
tcase_add_test(tc, test_cgroup_short_noarg);
|
||||
tcase_add_test(tc, test_cgroup_short_space);
|
||||
tcase_add_test(tc, test_cgroup_short_equals);
|
||||
tcase_add_test(tc, test_cgroup_long_noarg);
|
||||
tcase_add_test(tc, test_cgroup_long_space);
|
||||
tcase_add_test(tc, test_cgroup_long_equals);
|
||||
tcase_add_test(tc, test_priority_short);
|
||||
tcase_add_test(tc, test_priority_long);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
tc = tcase_create("output");
|
||||
tcase_add_test(tc, test_quiet_short);
|
||||
tcase_add_test(tc, test_quiet_long);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
tc = tcase_create("system_tuning");
|
||||
tcase_add_test(tc, test_trace_buffer_size);
|
||||
tcase_add_test(tc, test_warm_up);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
tc = tcase_create("aa_actions");
|
||||
tcase_add_test(tc, test_auto);
|
||||
tcase_add_test(tc, test_on_end);
|
||||
tcase_add_test(tc, test_on_threshold);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
tc = tcase_create("general");
|
||||
tcase_add_test(tc, test_debug_short);
|
||||
tcase_add_test(tc, test_debug_long);
|
||||
tcase_add_test(tc, test_duration_short);
|
||||
tcase_add_test(tc, test_duration_long);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
return s;
|
||||
}
|
||||
722
tools/tracing/rtla/tests/unit/timerlat_hist_cli.c
Normal file
722
tools/tracing/rtla/tests/unit/timerlat_hist_cli.c
Normal file
|
|
@ -0,0 +1,722 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <check.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sched.h>
|
||||
#include <limits.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/sysinfo.h>
|
||||
|
||||
#include <linux/container_of.h>
|
||||
|
||||
#include "cli_params_assert.h"
|
||||
#include "../../src/cli.h"
|
||||
|
||||
#define PARSE_ARGS(...) char *argv[] = { __VA_ARGS__, NULL };\
|
||||
int argc = sizeof(argv) / sizeof(char *) - 1;\
|
||||
struct common_params *params =\
|
||||
timerlat_hist_parse_args(argc, argv);\
|
||||
struct timerlat_params *tlat_params __maybe_unused =\
|
||||
to_timerlat_params(params)
|
||||
|
||||
/* Tracing Options */
|
||||
|
||||
START_TEST(test_irq_short)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "hist", "-i", "20");
|
||||
|
||||
ck_assert_int_eq(params->stop_us, 20);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_irq_long)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "hist", "--irq", "20");
|
||||
|
||||
ck_assert_int_eq(params->stop_us, 20);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_period_short)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "hist", "-p", "200");
|
||||
|
||||
ck_assert_int_eq(tlat_params->timerlat_period_us, 200);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_period_long)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "hist", "--period", "200");
|
||||
|
||||
ck_assert_int_eq(tlat_params->timerlat_period_us, 200);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_stack_short)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "hist", "-s", "20");
|
||||
|
||||
ck_assert_int_eq(tlat_params->print_stack, 20);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_stack_long)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "hist", "--stack", "20");
|
||||
|
||||
ck_assert_int_eq(tlat_params->print_stack, 20);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_thread_short)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "hist", "-T", "20");
|
||||
|
||||
ck_assert_int_eq(params->stop_total_us, 20);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_thread_long)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "hist", "--thread", "20");
|
||||
|
||||
ck_assert_int_eq(params->stop_total_us, 20);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_trace_short_noarg)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "hist", "-t");
|
||||
|
||||
CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str,
|
||||
"timerlat_trace.txt");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_trace_short_followarg)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "hist", "-t", "-d", "20");
|
||||
|
||||
CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str,
|
||||
"timerlat_trace.txt");
|
||||
ck_assert_int_eq(params->duration, 20); /* check if next argument is read correctly */
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_trace_short_space)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "hist", "-t", "tracefile");
|
||||
|
||||
CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str,
|
||||
"tracefile");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_trace_short_equals)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "hist", "-t=tracefile");
|
||||
|
||||
CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str,
|
||||
"tracefile");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_trace_long_noarg)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "hist", "--trace");
|
||||
|
||||
CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str,
|
||||
"timerlat_trace.txt");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_trace_long_followarg)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "hist", "--trace", "-d", "20");
|
||||
|
||||
CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str,
|
||||
"timerlat_trace.txt");
|
||||
ck_assert_int_eq(params->duration, 20); /* check if next argument is read correctly */
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_trace_long_space)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "hist", "--trace", "tracefile");
|
||||
|
||||
CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str,
|
||||
"tracefile");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_trace_long_equals)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "hist", "--trace=tracefile");
|
||||
|
||||
CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str,
|
||||
"tracefile");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/* Event Configuration */
|
||||
|
||||
START_TEST(test_event_short)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "hist", "-e", "system:event");
|
||||
|
||||
CLI_ASSERT_SINGLE_EVENT("system", "event");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_event_long)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "hist", "--event", "system:event");
|
||||
|
||||
CLI_ASSERT_SINGLE_EVENT("system", "event");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_filter)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "hist", "-e", "system:event", "--filter", "filter");
|
||||
|
||||
CLI_ASSERT_SINGLE_FILTER("filter");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_trigger)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "hist", "-e", "system:event", "--trigger", "trigger");
|
||||
|
||||
CLI_ASSERT_SINGLE_TRIGGER("trigger");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/* CPU Configuration */
|
||||
|
||||
START_TEST(test_cpus_short)
|
||||
{
|
||||
nr_cpus = 4;
|
||||
|
||||
PARSE_ARGS("timerlat", "hist", "-c", "0-1,3");
|
||||
|
||||
ck_assert_str_eq(params->cpus, "0-1,3");
|
||||
CLI_ASSERT_CPUSET(monitored_cpus, 0, 1, 3);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_cpus_long)
|
||||
{
|
||||
nr_cpus = 4;
|
||||
|
||||
PARSE_ARGS("timerlat", "hist", "--cpus", "0-1,3");
|
||||
|
||||
ck_assert_str_eq(params->cpus, "0-1,3");
|
||||
CLI_ASSERT_CPUSET(monitored_cpus, 0, 1, 3);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_housekeeping_short)
|
||||
{
|
||||
nr_cpus = 4;
|
||||
|
||||
PARSE_ARGS("timerlat", "hist", "-H", "0-1,3");
|
||||
|
||||
CLI_ASSERT_CPUSET(hk_cpu_set, 0, 1, 3);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_housekeeping_long)
|
||||
{
|
||||
nr_cpus = 4;
|
||||
|
||||
PARSE_ARGS("timerlat", "hist", "--house-keeping", "0-1,3");
|
||||
|
||||
CLI_ASSERT_CPUSET(hk_cpu_set, 0, 1, 3);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/* Thread Configuration */
|
||||
|
||||
START_TEST(test_cgroup_short_noarg)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "hist", "-C");
|
||||
|
||||
ck_assert(params->cgroup);
|
||||
ck_assert_ptr_null(params->cgroup_name);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_cgroup_short_space)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "hist", "-C", "cgroup");
|
||||
|
||||
ck_assert(params->cgroup);
|
||||
ck_assert_str_eq(params->cgroup_name, "cgroup");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_cgroup_short_equals)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "hist", "-C=cgroup");
|
||||
|
||||
ck_assert(params->cgroup);
|
||||
ck_assert_str_eq(params->cgroup_name, "cgroup");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_cgroup_long_noarg)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "hist", "--cgroup");
|
||||
|
||||
ck_assert(params->cgroup);
|
||||
ck_assert_ptr_null(params->cgroup_name);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_cgroup_long_space)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "hist", "--cgroup", "cgroup");
|
||||
|
||||
ck_assert(params->cgroup);
|
||||
ck_assert_str_eq(params->cgroup_name, "cgroup");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_cgroup_long_equals)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "hist", "--cgroup=cgroup");
|
||||
|
||||
ck_assert(params->cgroup);
|
||||
ck_assert_str_eq(params->cgroup_name, "cgroup");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_kernel_threads_short)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "hist", "-k");
|
||||
|
||||
ck_assert(params->kernel_workload);
|
||||
ck_assert(!params->user_workload);
|
||||
ck_assert(!params->user_data);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_kernel_threads_long)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "hist", "--kernel-threads");
|
||||
|
||||
ck_assert(params->kernel_workload);
|
||||
ck_assert(!params->user_workload);
|
||||
ck_assert(!params->user_data);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_priority_short)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "hist", "-P", "f:95");
|
||||
|
||||
ck_assert_int_eq(params->sched_param.sched_policy, SCHED_FIFO);
|
||||
ck_assert_int_eq(params->sched_param.sched_priority, 95);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_priority_long)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "hist", "--priority", "f:95");
|
||||
|
||||
ck_assert_int_eq(params->sched_param.sched_policy, SCHED_FIFO);
|
||||
ck_assert_int_eq(params->sched_param.sched_priority, 95);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_user_load_short)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "hist", "-U");
|
||||
|
||||
ck_assert(!params->kernel_workload);
|
||||
ck_assert(!params->user_workload);
|
||||
ck_assert(params->user_data);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_user_load_long)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "hist", "--user-load");
|
||||
|
||||
ck_assert(!params->kernel_workload);
|
||||
ck_assert(!params->user_workload);
|
||||
ck_assert(params->user_data);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_user_threads_short)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "hist", "-u");
|
||||
|
||||
ck_assert(!params->kernel_workload);
|
||||
ck_assert(params->user_workload);
|
||||
ck_assert(params->user_data);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_user_threads_long)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "hist", "--user-threads");
|
||||
|
||||
ck_assert(!params->kernel_workload);
|
||||
ck_assert(params->user_workload);
|
||||
ck_assert(params->user_data);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_aligned_short)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "hist", "-A", "500");
|
||||
|
||||
ck_assert(tlat_params->timerlat_align);
|
||||
ck_assert_int_eq(tlat_params->timerlat_align_us, 500);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_aligned_long)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "hist", "--aligned", "500");
|
||||
|
||||
ck_assert(tlat_params->timerlat_align);
|
||||
ck_assert_int_eq(tlat_params->timerlat_align_us, 500);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/* Histogram Options */
|
||||
|
||||
START_TEST(test_bucket_size_short)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "hist", "-b", "2");
|
||||
|
||||
ck_assert_int_eq(params->hist.bucket_size, 2);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_bucket_size_long)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "hist", "--bucket-size", "2");
|
||||
|
||||
ck_assert_int_eq(params->hist.bucket_size, 2);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_entries_short)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "hist", "-E", "512");
|
||||
|
||||
ck_assert_int_eq(params->hist.entries, 512);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_entries_long)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "hist", "--entries", "512");
|
||||
|
||||
ck_assert_int_eq(params->hist.entries, 512);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_no_header)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "hist", "--no-header");
|
||||
|
||||
ck_assert(params->hist.no_header);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_no_index)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "hist", "--with-zeros", "--no-index");
|
||||
|
||||
ck_assert(params->hist.no_index);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_no_irq)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "hist", "--no-irq");
|
||||
|
||||
ck_assert(params->hist.no_irq);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_no_summary)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "hist", "--no-summary");
|
||||
|
||||
ck_assert(params->hist.no_summary);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_no_thread)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "hist", "--no-thread");
|
||||
|
||||
ck_assert(params->hist.no_thread);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_with_zeros)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "hist", "--with-zeros");
|
||||
|
||||
ck_assert(params->hist.with_zeros);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/* Output */
|
||||
|
||||
START_TEST(test_nano_short)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "hist", "-n");
|
||||
|
||||
ck_assert_int_eq(params->output_divisor, 1);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_nano_long)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "hist", "--nano");
|
||||
|
||||
ck_assert_int_eq(params->output_divisor, 1);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/* System Tuning */
|
||||
|
||||
START_TEST(test_deepest_idle_state)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "hist", "--deepest-idle-state", "1");
|
||||
|
||||
ck_assert_int_eq(tlat_params->deepest_idle_state, 1);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_dma_latency)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "hist", "--dma-latency", "10");
|
||||
|
||||
ck_assert_int_eq(tlat_params->dma_latency, 10);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_trace_buffer_size)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "hist", "--trace-buffer-size", "200");
|
||||
|
||||
ck_assert_int_eq(params->buffer_size, 200);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_warm_up)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "hist", "--warm-up", "5");
|
||||
|
||||
ck_assert_int_eq(params->warmup, 5);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/* Auto Analysis and Actions */
|
||||
|
||||
START_TEST(test_auto)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "hist", "-a", "20");
|
||||
|
||||
CLI_TIMERLAT_ASSERT_AUTO(20);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_bpf_action)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "hist", "--bpf-action", "program");
|
||||
|
||||
ck_assert_str_eq(tlat_params->bpf_action_program, "program");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_dump_tasks)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "hist", "--dump-tasks");
|
||||
|
||||
ck_assert(tlat_params->dump_tasks);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_no_aa)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "hist", "--no-aa");
|
||||
|
||||
ck_assert(tlat_params->no_aa);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_on_end)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "hist", "--on-end", "trace");
|
||||
|
||||
CLI_ASSERT_SINGLE_ACTION(end_actions, ACTION_TRACE_OUTPUT, trace_output, str,
|
||||
"timerlat_trace.txt");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_on_threshold)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "hist", "--on-threshold", "trace");
|
||||
|
||||
CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str,
|
||||
"timerlat_trace.txt");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_stack_format)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "hist", "--stack-format", "truncate");
|
||||
|
||||
ck_assert_int_eq(tlat_params->stack_format, STACK_FORMAT_TRUNCATE);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/* General */
|
||||
|
||||
START_TEST(test_debug_short)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "hist", "-D");
|
||||
|
||||
ck_assert(config_debug);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_debug_long)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "hist", "--debug");
|
||||
|
||||
ck_assert(config_debug);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_duration_short)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "hist", "-d", "1m");
|
||||
|
||||
ck_assert_int_eq(params->duration, 60);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_duration_long)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "hist", "--duration", "1m");
|
||||
|
||||
ck_assert_int_eq(params->duration, 60);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
Suite *timerlat_hist_cli_suite(void)
|
||||
{
|
||||
Suite *s = suite_create("timerlat_hist_cli");
|
||||
TCase *tc;
|
||||
|
||||
tc = tcase_create("tracing_options");
|
||||
tcase_add_test(tc, test_irq_short);
|
||||
tcase_add_test(tc, test_irq_long);
|
||||
tcase_add_test(tc, test_period_short);
|
||||
tcase_add_test(tc, test_period_long);
|
||||
tcase_add_test(tc, test_stack_short);
|
||||
tcase_add_test(tc, test_stack_long);
|
||||
tcase_add_test(tc, test_thread_short);
|
||||
tcase_add_test(tc, test_thread_long);
|
||||
tcase_add_test(tc, test_trace_short_noarg);
|
||||
tcase_add_test(tc, test_trace_short_followarg);
|
||||
tcase_add_test(tc, test_trace_short_space);
|
||||
tcase_add_test(tc, test_trace_short_equals);
|
||||
tcase_add_test(tc, test_trace_long_noarg);
|
||||
tcase_add_test(tc, test_trace_long_followarg);
|
||||
tcase_add_test(tc, test_trace_long_space);
|
||||
tcase_add_test(tc, test_trace_long_equals);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
tc = tcase_create("event_configuration");
|
||||
tcase_add_test(tc, test_event_short);
|
||||
tcase_add_test(tc, test_event_long);
|
||||
tcase_add_test(tc, test_filter);
|
||||
tcase_add_test(tc, test_trigger);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
tc = tcase_create("cpu_configuration");
|
||||
tcase_add_test(tc, test_cpus_short);
|
||||
tcase_add_test(tc, test_cpus_long);
|
||||
tcase_add_test(tc, test_housekeeping_short);
|
||||
tcase_add_test(tc, test_housekeeping_long);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
tc = tcase_create("thread_configuration");
|
||||
tcase_add_test(tc, test_cgroup_short_noarg);
|
||||
tcase_add_test(tc, test_cgroup_short_space);
|
||||
tcase_add_test(tc, test_cgroup_short_equals);
|
||||
tcase_add_test(tc, test_cgroup_long_noarg);
|
||||
tcase_add_test(tc, test_cgroup_long_space);
|
||||
tcase_add_test(tc, test_cgroup_long_equals);
|
||||
tcase_add_test(tc, test_kernel_threads_short);
|
||||
tcase_add_test(tc, test_kernel_threads_long);
|
||||
tcase_add_test(tc, test_priority_short);
|
||||
tcase_add_test(tc, test_priority_long);
|
||||
tcase_add_test(tc, test_user_load_short);
|
||||
tcase_add_test(tc, test_user_load_long);
|
||||
tcase_add_test(tc, test_user_threads_short);
|
||||
tcase_add_test(tc, test_user_threads_long);
|
||||
tcase_add_test(tc, test_aligned_short);
|
||||
tcase_add_test(tc, test_aligned_long);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
tc = tcase_create("histogram_options");
|
||||
tcase_add_test(tc, test_bucket_size_short);
|
||||
tcase_add_test(tc, test_bucket_size_long);
|
||||
tcase_add_test(tc, test_entries_short);
|
||||
tcase_add_test(tc, test_entries_long);
|
||||
tcase_add_test(tc, test_no_header);
|
||||
tcase_add_test(tc, test_no_index);
|
||||
tcase_add_test(tc, test_no_irq);
|
||||
tcase_add_test(tc, test_no_summary);
|
||||
tcase_add_test(tc, test_no_thread);
|
||||
tcase_add_test(tc, test_with_zeros);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
tc = tcase_create("output");
|
||||
tcase_add_test(tc, test_nano_short);
|
||||
tcase_add_test(tc, test_nano_long);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
tc = tcase_create("system_tuning");
|
||||
tcase_add_test(tc, test_deepest_idle_state);
|
||||
tcase_add_test(tc, test_dma_latency);
|
||||
tcase_add_test(tc, test_trace_buffer_size);
|
||||
tcase_add_test(tc, test_warm_up);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
tc = tcase_create("aa_actions");
|
||||
tcase_add_test(tc, test_auto);
|
||||
tcase_add_test(tc, test_bpf_action);
|
||||
tcase_add_test(tc, test_dump_tasks);
|
||||
tcase_add_test(tc, test_no_aa);
|
||||
tcase_add_test(tc, test_on_end);
|
||||
tcase_add_test(tc, test_on_threshold);
|
||||
tcase_add_test(tc, test_stack_format);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
tc = tcase_create("general");
|
||||
tcase_add_test(tc, test_debug_short);
|
||||
tcase_add_test(tc, test_debug_long);
|
||||
tcase_add_test(tc, test_duration_short);
|
||||
tcase_add_test(tc, test_duration_long);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
return s;
|
||||
}
|
||||
654
tools/tracing/rtla/tests/unit/timerlat_top_cli.c
Normal file
654
tools/tracing/rtla/tests/unit/timerlat_top_cli.c
Normal file
|
|
@ -0,0 +1,654 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <check.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sched.h>
|
||||
#include <limits.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/sysinfo.h>
|
||||
|
||||
#include <linux/container_of.h>
|
||||
|
||||
#include "cli_params_assert.h"
|
||||
#include "../../src/cli.h"
|
||||
|
||||
#define PARSE_ARGS(...) char *argv[] = { __VA_ARGS__, NULL };\
|
||||
int argc = sizeof(argv) / sizeof(char *) - 1;\
|
||||
struct common_params *params =\
|
||||
timerlat_top_parse_args(argc, argv);\
|
||||
struct timerlat_params *tlat_params __maybe_unused =\
|
||||
to_timerlat_params(params)
|
||||
|
||||
/* Tracing Options */
|
||||
|
||||
START_TEST(test_irq_short)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "top", "-i", "20");
|
||||
|
||||
ck_assert_int_eq(params->stop_us, 20);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_irq_long)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "top", "--irq", "20");
|
||||
|
||||
ck_assert_int_eq(params->stop_us, 20);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_period_short)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "top", "-p", "200");
|
||||
|
||||
ck_assert_int_eq(tlat_params->timerlat_period_us, 200);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_period_long)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "top", "--period", "200");
|
||||
|
||||
ck_assert_int_eq(tlat_params->timerlat_period_us, 200);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_stack_short)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "top", "-s", "20");
|
||||
|
||||
ck_assert_int_eq(tlat_params->print_stack, 20);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_stack_long)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "top", "--stack", "20");
|
||||
|
||||
ck_assert_int_eq(tlat_params->print_stack, 20);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_thread_short)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "top", "-T", "20");
|
||||
|
||||
ck_assert_int_eq(params->stop_total_us, 20);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_thread_long)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "top", "--thread", "20");
|
||||
|
||||
ck_assert_int_eq(params->stop_total_us, 20);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/* Event Configuration */
|
||||
|
||||
START_TEST(test_event_short)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "top", "-e", "system:event");
|
||||
|
||||
CLI_ASSERT_SINGLE_EVENT("system", "event");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_event_long)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "top", "--event", "system:event");
|
||||
|
||||
CLI_ASSERT_SINGLE_EVENT("system", "event");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_filter)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "top", "-e", "system:event", "--filter", "filter");
|
||||
|
||||
CLI_ASSERT_SINGLE_FILTER("filter");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_trigger)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "top", "-e", "system:event", "--trigger", "trigger");
|
||||
|
||||
CLI_ASSERT_SINGLE_TRIGGER("trigger");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_trace_short_noarg)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "top", "-t");
|
||||
|
||||
CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str,
|
||||
"timerlat_trace.txt");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_trace_short_followarg)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "top", "-t", "-d", "20");
|
||||
|
||||
CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str,
|
||||
"timerlat_trace.txt");
|
||||
ck_assert_int_eq(params->duration, 20); /* check if next argument is read correctly */
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_trace_short_space)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "top", "-t", "tracefile");
|
||||
|
||||
CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str,
|
||||
"tracefile");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_trace_short_equals)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "top", "-t=tracefile");
|
||||
|
||||
CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str,
|
||||
"tracefile");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_trace_long_noarg)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "top", "--trace");
|
||||
|
||||
CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str,
|
||||
"timerlat_trace.txt");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_trace_long_followarg)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "top", "--trace", "-d", "20");
|
||||
|
||||
CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str,
|
||||
"timerlat_trace.txt");
|
||||
ck_assert_int_eq(params->duration, 20); /* check if next argument is read correctly */
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_trace_long_space)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "top", "--trace", "tracefile");
|
||||
|
||||
CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str,
|
||||
"tracefile");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_trace_long_equals)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "top", "--trace=tracefile");
|
||||
|
||||
CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str,
|
||||
"tracefile");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/* CPU Configuration */
|
||||
|
||||
START_TEST(test_cpus_short)
|
||||
{
|
||||
nr_cpus = 4;
|
||||
|
||||
PARSE_ARGS("timerlat", "top", "-c", "0-1,3");
|
||||
|
||||
ck_assert_str_eq(params->cpus, "0-1,3");
|
||||
CLI_ASSERT_CPUSET(monitored_cpus, 0, 1, 3);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_cpus_long)
|
||||
{
|
||||
nr_cpus = 4;
|
||||
|
||||
PARSE_ARGS("timerlat", "top", "--cpus", "0-1,3");
|
||||
|
||||
ck_assert_str_eq(params->cpus, "0-1,3");
|
||||
CLI_ASSERT_CPUSET(monitored_cpus, 0, 1, 3);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_housekeeping_short)
|
||||
{
|
||||
nr_cpus = 4;
|
||||
|
||||
PARSE_ARGS("timerlat", "top", "-H", "0-1,3");
|
||||
|
||||
CLI_ASSERT_CPUSET(hk_cpu_set, 0, 1, 3);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_housekeeping_long)
|
||||
{
|
||||
nr_cpus = 4;
|
||||
|
||||
PARSE_ARGS("timerlat", "top", "--house-keeping", "0-1,3");
|
||||
|
||||
CLI_ASSERT_CPUSET(hk_cpu_set, 0, 1, 3);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/* Thread Configuration */
|
||||
|
||||
START_TEST(test_cgroup_short_noarg)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "top", "-C");
|
||||
|
||||
ck_assert(params->cgroup);
|
||||
ck_assert_ptr_null(params->cgroup_name);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_cgroup_short_space)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "top", "-C", "cgroup");
|
||||
|
||||
ck_assert(params->cgroup);
|
||||
ck_assert_str_eq(params->cgroup_name, "cgroup");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_cgroup_short_equals)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "top", "-C=cgroup");
|
||||
|
||||
ck_assert(params->cgroup);
|
||||
ck_assert_str_eq(params->cgroup_name, "cgroup");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_cgroup_long_noarg)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "top", "--cgroup");
|
||||
|
||||
ck_assert(params->cgroup);
|
||||
ck_assert_ptr_null(params->cgroup_name);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_cgroup_long_space)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "top", "--cgroup", "cgroup");
|
||||
|
||||
ck_assert(params->cgroup);
|
||||
ck_assert_str_eq(params->cgroup_name, "cgroup");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_cgroup_long_equals)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "top", "--cgroup=cgroup");
|
||||
|
||||
ck_assert(params->cgroup);
|
||||
ck_assert_str_eq(params->cgroup_name, "cgroup");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_kernel_threads_short)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "top", "-k");
|
||||
|
||||
ck_assert(params->kernel_workload);
|
||||
ck_assert(!params->user_workload);
|
||||
ck_assert(!params->user_data);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_kernel_threads_long)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "top", "--kernel-threads");
|
||||
|
||||
ck_assert(params->kernel_workload);
|
||||
ck_assert(!params->user_workload);
|
||||
ck_assert(!params->user_data);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_priority_short)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "top", "-P", "f:95");
|
||||
|
||||
ck_assert_int_eq(params->sched_param.sched_policy, SCHED_FIFO);
|
||||
ck_assert_int_eq(params->sched_param.sched_priority, 95);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_priority_long)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "top", "--priority", "f:95");
|
||||
|
||||
ck_assert_int_eq(params->sched_param.sched_policy, SCHED_FIFO);
|
||||
ck_assert_int_eq(params->sched_param.sched_priority, 95);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_user_load_short)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "top", "-U");
|
||||
|
||||
ck_assert(!params->kernel_workload);
|
||||
ck_assert(!params->user_workload);
|
||||
ck_assert(params->user_data);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_user_load_long)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "top", "--user-load");
|
||||
|
||||
ck_assert(!params->kernel_workload);
|
||||
ck_assert(!params->user_workload);
|
||||
ck_assert(params->user_data);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_user_threads_short)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "top", "-u");
|
||||
|
||||
ck_assert(!params->kernel_workload);
|
||||
ck_assert(params->user_workload);
|
||||
ck_assert(params->user_data);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_user_threads_long)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "top", "--user-threads");
|
||||
|
||||
ck_assert(!params->kernel_workload);
|
||||
ck_assert(params->user_workload);
|
||||
ck_assert(params->user_data);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_aligned_short)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "top", "-A", "500");
|
||||
|
||||
ck_assert(tlat_params->timerlat_align);
|
||||
ck_assert_int_eq(tlat_params->timerlat_align_us, 500);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_aligned_long)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "top", "--aligned", "500");
|
||||
|
||||
ck_assert(tlat_params->timerlat_align);
|
||||
ck_assert_int_eq(tlat_params->timerlat_align_us, 500);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/* Output */
|
||||
|
||||
START_TEST(test_nano_short)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "top", "-n");
|
||||
|
||||
ck_assert_int_eq(params->output_divisor, 1);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_nano_long)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "top", "--nano");
|
||||
|
||||
ck_assert_int_eq(params->output_divisor, 1);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_quiet_short)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "top", "-q");
|
||||
|
||||
ck_assert(params->quiet);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_quiet_long)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "top", "--quiet");
|
||||
|
||||
ck_assert(params->quiet);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/* System Tuning */
|
||||
|
||||
START_TEST(test_deepest_idle_state)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "top", "--deepest-idle-state", "1");
|
||||
|
||||
ck_assert_int_eq(tlat_params->deepest_idle_state, 1);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_dma_latency)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "top", "--dma-latency", "10");
|
||||
|
||||
ck_assert_int_eq(tlat_params->dma_latency, 10);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_trace_buffer_size)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "top", "--trace-buffer-size", "200");
|
||||
|
||||
ck_assert_int_eq(params->buffer_size, 200);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_warm_up)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "top", "--warm-up", "5");
|
||||
|
||||
ck_assert_int_eq(params->warmup, 5);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/* Auto Analysis and Actions */
|
||||
|
||||
START_TEST(test_auto)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "top", "-a", "20");
|
||||
|
||||
CLI_TIMERLAT_ASSERT_AUTO(20);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_aa_only)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "top", "--aa-only", "20");
|
||||
|
||||
CLI_TIMERLAT_ASSERT_AA_ONLY(20);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_bpf_action)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "top", "--bpf-action", "program");
|
||||
|
||||
ck_assert_str_eq(tlat_params->bpf_action_program, "program");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_dump_tasks)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "top", "--dump-tasks");
|
||||
|
||||
ck_assert(tlat_params->dump_tasks);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_no_aa)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "top", "--no-aa");
|
||||
|
||||
ck_assert(tlat_params->no_aa);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_on_end)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "top", "--on-end", "trace");
|
||||
|
||||
CLI_ASSERT_SINGLE_ACTION(end_actions, ACTION_TRACE_OUTPUT, trace_output, str,
|
||||
"timerlat_trace.txt");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_on_threshold)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "top", "--on-threshold", "trace");
|
||||
|
||||
CLI_ASSERT_SINGLE_ACTION(threshold_actions, ACTION_TRACE_OUTPUT, trace_output, str,
|
||||
"timerlat_trace.txt");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_stack_format)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "top", "--stack-format", "truncate");
|
||||
|
||||
ck_assert_int_eq(tlat_params->stack_format, STACK_FORMAT_TRUNCATE);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/* General */
|
||||
|
||||
START_TEST(test_debug_short)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "top", "-D");
|
||||
|
||||
ck_assert(config_debug);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_debug_long)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "top", "--debug");
|
||||
|
||||
ck_assert(config_debug);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_duration_short)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "top", "-d", "1m");
|
||||
|
||||
ck_assert_int_eq(params->duration, 60);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_duration_long)
|
||||
{
|
||||
PARSE_ARGS("timerlat", "top", "--duration", "1m");
|
||||
|
||||
ck_assert_int_eq(params->duration, 60);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
Suite *timerlat_top_cli_suite(void)
|
||||
{
|
||||
Suite *s = suite_create("timerlat_top_cli");
|
||||
TCase *tc;
|
||||
|
||||
tc = tcase_create("tracing_options");
|
||||
tcase_add_test(tc, test_irq_short);
|
||||
tcase_add_test(tc, test_irq_long);
|
||||
tcase_add_test(tc, test_period_short);
|
||||
tcase_add_test(tc, test_period_long);
|
||||
tcase_add_test(tc, test_stack_short);
|
||||
tcase_add_test(tc, test_stack_long);
|
||||
tcase_add_test(tc, test_thread_short);
|
||||
tcase_add_test(tc, test_thread_long);
|
||||
tcase_add_test(tc, test_trace_short_noarg);
|
||||
tcase_add_test(tc, test_trace_short_followarg);
|
||||
tcase_add_test(tc, test_trace_short_space);
|
||||
tcase_add_test(tc, test_trace_short_equals);
|
||||
tcase_add_test(tc, test_trace_long_noarg);
|
||||
tcase_add_test(tc, test_trace_long_followarg);
|
||||
tcase_add_test(tc, test_trace_long_space);
|
||||
tcase_add_test(tc, test_trace_long_equals);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
tc = tcase_create("event_configuration");
|
||||
tcase_add_test(tc, test_event_short);
|
||||
tcase_add_test(tc, test_event_long);
|
||||
tcase_add_test(tc, test_filter);
|
||||
tcase_add_test(tc, test_trigger);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
tc = tcase_create("cpu_configuration");
|
||||
tcase_add_test(tc, test_cpus_short);
|
||||
tcase_add_test(tc, test_cpus_long);
|
||||
tcase_add_test(tc, test_housekeeping_short);
|
||||
tcase_add_test(tc, test_housekeeping_long);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
tc = tcase_create("thread_configuration");
|
||||
tcase_add_test(tc, test_cgroup_short_noarg);
|
||||
tcase_add_test(tc, test_cgroup_short_space);
|
||||
tcase_add_test(tc, test_cgroup_short_equals);
|
||||
tcase_add_test(tc, test_cgroup_long_noarg);
|
||||
tcase_add_test(tc, test_cgroup_long_space);
|
||||
tcase_add_test(tc, test_cgroup_long_equals);
|
||||
tcase_add_test(tc, test_kernel_threads_short);
|
||||
tcase_add_test(tc, test_kernel_threads_long);
|
||||
tcase_add_test(tc, test_priority_short);
|
||||
tcase_add_test(tc, test_priority_long);
|
||||
tcase_add_test(tc, test_user_load_short);
|
||||
tcase_add_test(tc, test_user_load_long);
|
||||
tcase_add_test(tc, test_user_threads_short);
|
||||
tcase_add_test(tc, test_user_threads_long);
|
||||
tcase_add_test(tc, test_aligned_short);
|
||||
tcase_add_test(tc, test_aligned_long);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
tc = tcase_create("output");
|
||||
tcase_add_test(tc, test_nano_short);
|
||||
tcase_add_test(tc, test_nano_long);
|
||||
tcase_add_test(tc, test_quiet_short);
|
||||
tcase_add_test(tc, test_quiet_long);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
tc = tcase_create("system_tuning");
|
||||
tcase_add_test(tc, test_deepest_idle_state);
|
||||
tcase_add_test(tc, test_dma_latency);
|
||||
tcase_add_test(tc, test_trace_buffer_size);
|
||||
tcase_add_test(tc, test_warm_up);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
tc = tcase_create("aa_actions");
|
||||
tcase_add_test(tc, test_auto);
|
||||
tcase_add_test(tc, test_aa_only);
|
||||
tcase_add_test(tc, test_bpf_action);
|
||||
tcase_add_test(tc, test_dump_tasks);
|
||||
tcase_add_test(tc, test_no_aa);
|
||||
tcase_add_test(tc, test_on_end);
|
||||
tcase_add_test(tc, test_on_threshold);
|
||||
tcase_add_test(tc, test_stack_format);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
tc = tcase_create("general");
|
||||
tcase_add_test(tc, test_debug_short);
|
||||
tcase_add_test(tc, test_debug_long);
|
||||
tcase_add_test(tc, test_duration_short);
|
||||
tcase_add_test(tc, test_duration_long);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
|
@ -2,115 +2,35 @@
|
|||
|
||||
#define _GNU_SOURCE
|
||||
#include <check.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sched.h>
|
||||
#include <limits.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/sysinfo.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "../../src/utils.h"
|
||||
int nr_cpus;
|
||||
#include "../../src/cli.h"
|
||||
|
||||
START_TEST(test_strtoi)
|
||||
{
|
||||
int result;
|
||||
char buf[64];
|
||||
Suite *utils_suite(void);
|
||||
Suite *actions_suite(void);
|
||||
Suite *osnoise_top_cli_suite(void);
|
||||
Suite *osnoise_hist_cli_suite(void);
|
||||
Suite *timerlat_top_cli_suite(void);
|
||||
Suite *timerlat_hist_cli_suite(void);
|
||||
Suite *cli_opt_callback_suite(void);
|
||||
|
||||
ck_assert_int_eq(strtoi("123", &result), 0);
|
||||
ck_assert_int_eq(result, 123);
|
||||
ck_assert_int_eq(strtoi(" -456", &result), 0);
|
||||
ck_assert_int_eq(result, -456);
|
||||
|
||||
snprintf(buf, sizeof(buf), "%d", INT_MAX);
|
||||
ck_assert_int_eq(strtoi(buf, &result), 0);
|
||||
snprintf(buf, sizeof(buf), "%ld", (long)INT_MAX + 1);
|
||||
ck_assert_int_eq(strtoi(buf, &result), -1);
|
||||
|
||||
ck_assert_int_eq(strtoi("", &result), -1);
|
||||
ck_assert_int_eq(strtoi("123abc", &result), -1);
|
||||
ck_assert_int_eq(strtoi("123 ", &result), -1);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_parse_cpu_set)
|
||||
{
|
||||
cpu_set_t set;
|
||||
|
||||
nr_cpus = 8;
|
||||
ck_assert_int_eq(parse_cpu_set("0", &set), 0);
|
||||
ck_assert(CPU_ISSET(0, &set));
|
||||
ck_assert(!CPU_ISSET(1, &set));
|
||||
|
||||
ck_assert_int_eq(parse_cpu_set("0,2", &set), 0);
|
||||
ck_assert(CPU_ISSET(0, &set));
|
||||
ck_assert(CPU_ISSET(2, &set));
|
||||
|
||||
ck_assert_int_eq(parse_cpu_set("0-3", &set), 0);
|
||||
ck_assert(CPU_ISSET(0, &set));
|
||||
ck_assert(CPU_ISSET(1, &set));
|
||||
ck_assert(CPU_ISSET(2, &set));
|
||||
ck_assert(CPU_ISSET(3, &set));
|
||||
|
||||
ck_assert_int_eq(parse_cpu_set("1-3,5", &set), 0);
|
||||
ck_assert(!CPU_ISSET(0, &set));
|
||||
ck_assert(CPU_ISSET(1, &set));
|
||||
ck_assert(CPU_ISSET(2, &set));
|
||||
ck_assert(CPU_ISSET(3, &set));
|
||||
ck_assert(!CPU_ISSET(4, &set));
|
||||
ck_assert(CPU_ISSET(5, &set));
|
||||
|
||||
ck_assert_int_eq(parse_cpu_set("-1", &set), 1);
|
||||
ck_assert_int_eq(parse_cpu_set("abc", &set), 1);
|
||||
ck_assert_int_eq(parse_cpu_set("9999", &set), 1);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_parse_prio)
|
||||
{
|
||||
struct sched_attr attr;
|
||||
|
||||
ck_assert_int_eq(parse_prio("f:50", &attr), 0);
|
||||
ck_assert_uint_eq(attr.sched_policy, SCHED_FIFO);
|
||||
ck_assert_uint_eq(attr.sched_priority, 50U);
|
||||
|
||||
ck_assert_int_eq(parse_prio("r:30", &attr), 0);
|
||||
ck_assert_uint_eq(attr.sched_policy, SCHED_RR);
|
||||
|
||||
ck_assert_int_eq(parse_prio("o:0", &attr), 0);
|
||||
ck_assert_uint_eq(attr.sched_policy, SCHED_OTHER);
|
||||
ck_assert_int_eq(attr.sched_nice, 0);
|
||||
|
||||
ck_assert_int_eq(parse_prio("d:10ms:100ms", &attr), 0);
|
||||
ck_assert_uint_eq(attr.sched_policy, 6U);
|
||||
|
||||
ck_assert_int_eq(parse_prio("f:999", &attr), -1);
|
||||
ck_assert_int_eq(parse_prio("o:-20", &attr), -1);
|
||||
ck_assert_int_eq(parse_prio("d:100ms:10ms", &attr), -1);
|
||||
ck_assert_int_eq(parse_prio("x:50", &attr), -1);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
Suite *utils_suite(void)
|
||||
{
|
||||
Suite *s = suite_create("utils");
|
||||
TCase *tc = tcase_create("core");
|
||||
|
||||
tcase_add_test(tc, test_strtoi);
|
||||
tcase_add_test(tc, test_parse_cpu_set);
|
||||
tcase_add_test(tc, test_parse_prio);
|
||||
|
||||
suite_add_tcase(s, tc);
|
||||
return s;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int num_failed;
|
||||
SRunner *sr;
|
||||
|
||||
in_unit_test = true;
|
||||
|
||||
sr = srunner_create(utils_suite());
|
||||
srunner_run_all(sr, CK_NORMAL);
|
||||
srunner_add_suite(sr, cli_opt_callback_suite());
|
||||
srunner_add_suite(sr, actions_suite());
|
||||
srunner_add_suite(sr, osnoise_top_cli_suite());
|
||||
srunner_add_suite(sr, osnoise_hist_cli_suite());
|
||||
srunner_add_suite(sr, timerlat_top_cli_suite());
|
||||
srunner_add_suite(sr, timerlat_hist_cli_suite());
|
||||
|
||||
srunner_run_all(sr, CK_VERBOSE);
|
||||
num_failed = srunner_ntests_failed(sr);
|
||||
|
||||
srunner_free(sr);
|
||||
|
|
|
|||
106
tools/tracing/rtla/tests/unit/utils.c
Normal file
106
tools/tracing/rtla/tests/unit/utils.c
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <check.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sched.h>
|
||||
#include <limits.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/sysinfo.h>
|
||||
|
||||
#include "../../src/utils.h"
|
||||
|
||||
extern int nr_cpus;
|
||||
|
||||
START_TEST(test_strtoi)
|
||||
{
|
||||
int result;
|
||||
char buf[64];
|
||||
|
||||
ck_assert_int_eq(strtoi("123", &result), 0);
|
||||
ck_assert_int_eq(result, 123);
|
||||
ck_assert_int_eq(strtoi(" -456", &result), 0);
|
||||
ck_assert_int_eq(result, -456);
|
||||
|
||||
snprintf(buf, sizeof(buf), "%d", INT_MAX);
|
||||
ck_assert_int_eq(strtoi(buf, &result), 0);
|
||||
snprintf(buf, sizeof(buf), "%ld", (long)INT_MAX + 1);
|
||||
ck_assert_int_eq(strtoi(buf, &result), -1);
|
||||
|
||||
ck_assert_int_eq(strtoi("", &result), -1);
|
||||
ck_assert_int_eq(strtoi("123abc", &result), -1);
|
||||
ck_assert_int_eq(strtoi("123 ", &result), -1);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_parse_cpu_set)
|
||||
{
|
||||
cpu_set_t set;
|
||||
|
||||
nr_cpus = 8;
|
||||
ck_assert_int_eq(parse_cpu_set("0", &set), 0);
|
||||
ck_assert(CPU_ISSET(0, &set));
|
||||
ck_assert(!CPU_ISSET(1, &set));
|
||||
|
||||
ck_assert_int_eq(parse_cpu_set("0,2", &set), 0);
|
||||
ck_assert(CPU_ISSET(0, &set));
|
||||
ck_assert(CPU_ISSET(2, &set));
|
||||
|
||||
ck_assert_int_eq(parse_cpu_set("0-3", &set), 0);
|
||||
ck_assert(CPU_ISSET(0, &set));
|
||||
ck_assert(CPU_ISSET(1, &set));
|
||||
ck_assert(CPU_ISSET(2, &set));
|
||||
ck_assert(CPU_ISSET(3, &set));
|
||||
|
||||
ck_assert_int_eq(parse_cpu_set("1-3,5", &set), 0);
|
||||
ck_assert(!CPU_ISSET(0, &set));
|
||||
ck_assert(CPU_ISSET(1, &set));
|
||||
ck_assert(CPU_ISSET(2, &set));
|
||||
ck_assert(CPU_ISSET(3, &set));
|
||||
ck_assert(!CPU_ISSET(4, &set));
|
||||
ck_assert(CPU_ISSET(5, &set));
|
||||
|
||||
ck_assert_int_eq(parse_cpu_set("-1", &set), 1);
|
||||
ck_assert_int_eq(parse_cpu_set("abc", &set), 1);
|
||||
ck_assert_int_eq(parse_cpu_set("9999", &set), 1);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_parse_prio)
|
||||
{
|
||||
struct sched_attr attr;
|
||||
|
||||
ck_assert_int_eq(parse_prio("f:50", &attr), 0);
|
||||
ck_assert_uint_eq(attr.sched_policy, SCHED_FIFO);
|
||||
ck_assert_uint_eq(attr.sched_priority, 50U);
|
||||
|
||||
ck_assert_int_eq(parse_prio("r:30", &attr), 0);
|
||||
ck_assert_uint_eq(attr.sched_policy, SCHED_RR);
|
||||
|
||||
ck_assert_int_eq(parse_prio("o:0", &attr), 0);
|
||||
ck_assert_uint_eq(attr.sched_policy, SCHED_OTHER);
|
||||
ck_assert_int_eq(attr.sched_nice, 0);
|
||||
|
||||
ck_assert_int_eq(parse_prio("d:10ms:100ms", &attr), 0);
|
||||
ck_assert_uint_eq(attr.sched_policy, 6U);
|
||||
|
||||
ck_assert_int_eq(parse_prio("f:999", &attr), -1);
|
||||
ck_assert_int_eq(parse_prio("o:-20", &attr), -1);
|
||||
ck_assert_int_eq(parse_prio("d:100ms:10ms", &attr), -1);
|
||||
ck_assert_int_eq(parse_prio("x:50", &attr), -1);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
Suite *utils_suite(void)
|
||||
{
|
||||
Suite *s = suite_create("utils");
|
||||
TCase *tc = tcase_create("core");
|
||||
|
||||
tcase_add_test(tc, test_strtoi);
|
||||
tcase_add_test(tc, test_parse_cpu_set);
|
||||
tcase_add_test(tc, test_parse_prio);
|
||||
|
||||
suite_add_tcase(s, tc);
|
||||
return s;
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user