Re: [kvm-unit-tests PATCH RFC] s390x: factor out running of tests into common code

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 12/09/2017 16:16, David Hildenbrand wrote:
> I want to use this in another file, so instead of replicating, factoring
> it out feels like the right thing to do.
> 
> Let's directly provide it for all architectures, they just have
> to implement get_time_ms() in asm/time.h to use it.
> 
> Signed-off-by: David Hildenbrand <david@xxxxxxxxxx>
> ---
> 
> The next step would be allowing to add custom parameters to a test.
> (defining them similar to the test cases).
> 
> Any other requests/nice to have? Does this make sense?

It does, but we have at least this, vmx.c (v1 and v2) and vmexit.c, with
not exactly overlapping usecases and command-line syntax.  Would it make
sense to have an API that is not home-grown, e.g. a subset of GTest?
The command-line arguments could be globs (like GTest's "-p").

Paolo

>  lib/s390x/asm/time.h |  24 ++++++++++++
>  lib/testrun.c        |  89 ++++++++++++++++++++++++++++++++++++++++++
>  lib/testrun.h        |  41 ++++++++++++++++++++
>  s390x/Makefile       |   1 +
>  s390x/intercept.c    | 106 ++++++++-------------------------------------------
>  5 files changed, 170 insertions(+), 91 deletions(-)
>  create mode 100644 lib/s390x/asm/time.h
>  create mode 100644 lib/testrun.c
>  create mode 100644 lib/testrun.h
> 
> diff --git a/lib/s390x/asm/time.h b/lib/s390x/asm/time.h
> new file mode 100644
> index 0000000..856facd
> --- /dev/null
> +++ b/lib/s390x/asm/time.h
> @@ -0,0 +1,24 @@
> +/*
> + * Copyright (c) 2017 Red Hat Inc
> + *
> + * Authors:
> + *  Thomas Huth <thuth@xxxxxxxxxx>
> + *  David Hildenbrand <david@xxxxxxxxxx>
> + *
> + * This code is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU Library General Public License version 2.
> + */
> +#ifndef __ASMS390X_TIME_H
> +#define __ASMS390X_TIME_H
> +
> +static inline uint64_t get_clock_ms(void)
> +{
> +	uint64_t clk;
> +
> +	asm volatile(" stck %0 " : : "Q"(clk) : "memory");
> +
> +	/* Bit 51 is incrememented each microsecond */
> +	return (clk >> (63 - 51)) / 1000;
> +}
> +
> +#endif
> diff --git a/lib/testrun.c b/lib/testrun.c
> new file mode 100644
> index 0000000..6034767
> --- /dev/null
> +++ b/lib/testrun.c
> @@ -0,0 +1,89 @@
> +/*
> + * Utility functions for running/configuring a set of tests
> + *
> + * Copyright (c) 2017 Red Hat Inc
> + *
> + * Authors:
> + *  Thomas Huth <thuth@xxxxxxxxxx>
> + *  David Hildenbrand <david@xxxxxxxxxx>
> + *
> + * This code is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU Library General Public License version 2.
> + */
> +
> +#include <testrun.h>
> +#include <asm/time.h>
> +
> +void parse_test_args(const int argc, const char **argv, struct test *test)
> +{
> +	bool run_all = true;
> +	int i, ti;
> +
> +	test->iterations = 0;
> +	test->time_to_run = 0;
> +
> +	for (i = 1; i < argc; i++) {
> +		if (!strcmp("-i", argv[i])) {
> +			i++;
> +			if (i >= argc)
> +				report_abort("-i needs a parameter");
> +			test->iterations = atol(argv[i]);
> +		} else if (!strcmp("-t", argv[i])) {
> +			i++;
> +			if (i >= argc)
> +				report_abort("-t needs a parameter");
> +			test->time_to_run = atol(argv[i]);
> +		} else for (ti = 0; test->test_cases[ti].name != NULL; ti++) {
> +			if (!strcmp(test->test_cases[ti].name, argv[i])) {
> +				run_all = false;
> +				test->test_cases[ti].run_it = true;
> +				break;
> +			} else if (test->test_cases[ti + 1].name == NULL) {
> +				report_abort("Unsupported parameter '%s'",
> +					     argv[i]);
> +			}
> +		}
> +	}
> +
> +	if (test->iterations == 0 && test->time_to_run == 0)
> +		test->iterations = 1;
> +
> +	if ((test->iterations > 1 || test->time_to_run) &&
> +	    !test->multirun_supported)
> +		report_abort("Test does not support multiruns.");
> +
> +	if (run_all) {
> +		for (ti = 0; test->test_cases[ti].name != NULL; ti++)
> +			test->test_cases[ti].run_it = true;
> +	}
> +}
> +
> +int run_test(struct test *test)
> +{
> +	unsigned long iterations = test->iterations;
> +	unsigned long time_to_run = test->time_to_run;
> +	uint64_t startclk;
> +	int ti;
> +
> +	report_prefix_push(test->name);
> +	startclk = get_clock_ms();
> +	for (;;) {
> +		for (ti = 0; test->test_cases[ti].name != NULL; ti++) {
> +			report_prefix_push(test->test_cases[ti].name);
> +			if (test->test_cases[ti].run_it)
> +				test->test_cases[ti].func();
> +			report_prefix_pop();
> +		}
> +		if (iterations) {
> +			iterations -= 1;
> +			if (iterations == 0)
> +				break;
> +		}
> +		if (time_to_run) {
> +			if (get_clock_ms() - startclk > time_to_run)
> +				break;
> +		}
> +	}
> +	report_prefix_pop();
> +	return report_summary();
> +}
> diff --git a/lib/testrun.h b/lib/testrun.h
> new file mode 100644
> index 0000000..8f9a2d7
> --- /dev/null
> +++ b/lib/testrun.h
> @@ -0,0 +1,41 @@
> +/*
> + * Utility functions for running/configuring a set of test cases
> + *
> + * Copyright (c) 2017 Red Hat Inc
> + *
> + * Authors:
> + *  Thomas Huth <thuth@xxxxxxxxxx>
> + *  David Hildenbrand <david@xxxxxxxxxx>
> + *
> + * This code is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU Library General Public License version 2.
> + */
> +#ifndef __TESTRUN_H
> +#define __TESTRUN_H
> +
> +#include <libcflat.h>
> +
> +struct test_case {
> +	const char *name;
> +	void (*func)(void);
> +	/* initialized by parse_test_args() */
> +	bool run_it;
> +};
> +
> +#define DEFINE_TEST_CASE(_name, _func) { _name, _func, false }
> +#define DEFINE_TEST_CASE_END_OF_LIST() { }
> +
> +struct test {
> +	/* to be initialized by the test */
> +	const char *name;
> +	bool multirun_supported;
> +	struct test_case *test_cases;
> +	/* initialized by parse_test_args() */
> +	unsigned long iterations;
> +	unsigned long time_to_run;
> +};
> +
> +void parse_test_args(int argc, const char **argv, struct test *test);
> +int run_test(struct test *test);
> +
> +#endif /* __TESTRUN_H */
> diff --git a/s390x/Makefile b/s390x/Makefile
> index bc099da..e174895 100644
> --- a/s390x/Makefile
> +++ b/s390x/Makefile
> @@ -21,6 +21,7 @@ include $(SRCDIR)/scripts/asm-offsets.mak
>  
>  cflatobjs += lib/util.o
>  cflatobjs += lib/alloc.o
> +cflatobjs += lib/testrun.o
>  cflatobjs += lib/s390x/io.o
>  cflatobjs += lib/s390x/stack.o
>  cflatobjs += lib/s390x/sclp-ascii.o
> diff --git a/s390x/intercept.c b/s390x/intercept.c
> index 59e5fca..15e50f6 100644
> --- a/s390x/intercept.c
> +++ b/s390x/intercept.c
> @@ -10,15 +10,13 @@
>   * under the terms of the GNU Library General Public License version 2.
>   */
>  #include <libcflat.h>
> +#include <testrun.h>
>  #include <asm/asm-offsets.h>
>  #include <asm/interrupt.h>
>  #include <asm/page.h>
>  
>  static uint8_t pagebuf[PAGE_SIZE * 2] __attribute__((aligned(PAGE_SIZE * 2)));
>  
> -static unsigned long nr_iterations;
> -static unsigned long time_to_run;
> -
>  /* Test the STORE PREFIX instruction */
>  static void test_stpx(void)
>  {
> @@ -159,95 +157,21 @@ static void test_testblock(void)
>  	check_pgm_int_code(PGM_INT_CODE_ADDRESSING);
>  }
>  
> -static uint64_t get_clock_ms(void)
> -{
> -	uint64_t clk;
> -
> -	asm volatile(" stck %0 " : : "Q"(clk) : "memory");
> -
> -	/* Bit 51 is incrememented each microsecond */
> -	return (clk >> (63 - 51)) / 1000;
> -}
> -
> -struct {
> -	const char *name;
> -	void (*func)(void);
> -	bool run_it;
> -} tests[] = {
> -	{ "stpx", test_stpx, false },
> -	{ "spx", test_spx, false },
> -	{ "stap", test_stap, false },
> -	{ "stidp", test_stidp, false },
> -	{ "testblock", test_testblock, false },
> -	{ NULL, NULL, false }
> -};
> -
> -static void parse_intercept_test_args(int argc, char **argv)
> -{
> -	int i, ti;
> -	bool run_all = true;
> -
> -	for (i = 1; i < argc; i++) {
> -		if (!strcmp("-i", argv[i])) {
> -			i++;
> -			if (i >= argc)
> -				report_abort("-i needs a parameter");
> -			nr_iterations = atol(argv[i]);
> -		} else if (!strcmp("-t", argv[i])) {
> -			i++;
> -			if (i >= argc)
> -				report_abort("-t needs a parameter");
> -			time_to_run = atol(argv[i]);
> -		} else for (ti = 0; tests[ti].name != NULL; ti++) {
> -			if (!strcmp(tests[ti].name, argv[i])) {
> -				run_all = false;
> -				tests[ti].run_it = true;
> -				break;
> -			} else if (tests[ti + 1].name == NULL) {
> -				report_abort("Unsupported parameter '%s'",
> -					     argv[i]);
> -			}
> -		}
> -	}
> -
> -	if (run_all) {
> -		for (ti = 0; tests[ti].name != NULL; ti++)
> -			tests[ti].run_it = true;
> +static struct test test = {
> +	.name = "intercept",
> +	.multirun_supported = true,
> +	.test_cases = (struct test_case[]) {
> +		DEFINE_TEST_CASE("stpx", test_stpx),
> +		DEFINE_TEST_CASE("spx", test_spx),
> +		DEFINE_TEST_CASE("stap", test_stap),
> +		DEFINE_TEST_CASE("stidp", test_stidp),
> +		DEFINE_TEST_CASE("testblock", test_testblock),
> +		DEFINE_TEST_CASE_END_OF_LIST()
>  	}
> -}
> +};
>  
> -int main(int argc, char **argv)
> +int main(int argc, const char **argv)
>  {
> -	uint64_t startclk;
> -	int ti;
> -
> -	parse_intercept_test_args(argc, argv);
> -
> -	if (nr_iterations == 0 && time_to_run == 0)
> -		nr_iterations = 1;
> -
> -	report_prefix_push("intercept");
> -
> -	startclk = get_clock_ms();
> -	for (;;) {
> -		for (ti = 0; tests[ti].name != NULL; ti++) {
> -			report_prefix_push(tests[ti].name);
> -			if (tests[ti].run_it)
> -				tests[ti].func();
> -			report_prefix_pop();
> -		}
> -		if (nr_iterations) {
> -			nr_iterations -= 1;
> -			if (nr_iterations == 0)
> -				break;
> -		}
> -		if (time_to_run) {
> -			if (get_clock_ms() - startclk > time_to_run)
> -				break;
> -		}
> -	}
> -
> -	report_prefix_pop();
> -
> -	return report_summary();
> +	parse_test_args(argc, argv, &test);
> +	return run_test(&test);
>  }
> 




[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux