lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20200807071620.11907-4-leo.yan@linaro.org>
Date:   Fri,  7 Aug 2020 15:16:19 +0800
From:   Leo Yan <leo.yan@...aro.org>
To:     Arnaldo Carvalho de Melo <acme@...nel.org>,
        Ian Rogers <irogers@...gle.com>, Will Deacon <will@...nel.org>,
        Mark Rutland <mark.rutland@....com>,
        Peter Zijlstra <peterz@...radead.org>,
        Ingo Molnar <mingo@...hat.com>,
        Alexander Shishkin <alexander.shishkin@...ux.intel.com>,
        Jiri Olsa <jolsa@...hat.com>,
        Namhyung Kim <namhyung@...nel.org>,
        Kemeng Shi <shikemeng@...wei.com>,
        "Naveen N. Rao" <naveen.n.rao@...ux.vnet.ibm.com>,
        Adrian Hunter <adrian.hunter@...el.com>,
        Mathieu Poirier <mathieu.poirier@...aro.org>,
        Igor Lubashev <ilubashe@...mai.com>,
        Andi Kleen <ak@...ux.intel.com>,
        Jin Yao <yao.jin@...ux.intel.com>,
        Stephane Eranian <eranian@...gle.com>,
        James Clark <james.clark@....com>, linux-kernel@...r.kernel.org
Cc:     Leo Yan <leo.yan@...aro.org>
Subject: [PATCH v2 3/4] perf arm_arch_timer: Test conversion between counter and timestamp

x86 arch has provides the testing for conversion between tsc and perf
time, this patch studies it and writes a similar testing for conversion
between arch timer's counter and sample's time.

The testing approach firstly creates three time points:

  Time point 1: 1st process's sample with perf time 'comm1_time';
  Time point 2: read out arch timer counter 'test_arch_timer_cnt';
  Time point 3: 2nd process's sample with perf time 'comm2_time';

The testing converts perf time to and from arch timer counter for these
three values and the testing can pass only if the counter values and
time values are in the order.

The test steps are as below:

  # perf test list
    [...]
    67: Convert perf time to arch timer counter

  # perf test 67 -v
    67: Convert perf time to arch timer counter
    --- start ---
    test child forked, pid 5463
    mmap size 528384B
    1st event perf time 2231755083020 arch timer cnt 113097053477
    test time           2231755087460 arch timer cnt 113097053699
    2nd event perf time 2231755090680 arch timer cnt 113097053860
    test child finished with 0
    ---- end ----

Signed-off-by: Leo Yan <leo.yan@...aro.org>
---
 tools/perf/arch/arm64/include/arch-tests.h    |   6 +
 tools/perf/arch/arm64/tests/Build             |   1 +
 tools/perf/arch/arm64/tests/arch-tests.c      |   4 +
 .../tests/perf-time-to-arch-timer-counter.c   | 189 ++++++++++++++++++
 4 files changed, 200 insertions(+)
 create mode 100644 tools/perf/arch/arm64/tests/perf-time-to-arch-timer-counter.c

diff --git a/tools/perf/arch/arm64/include/arch-tests.h b/tools/perf/arch/arm64/include/arch-tests.h
index 90ec4c8cb880..12ad7592c9aa 100644
--- a/tools/perf/arch/arm64/include/arch-tests.h
+++ b/tools/perf/arch/arm64/include/arch-tests.h
@@ -2,6 +2,12 @@
 #ifndef ARCH_TESTS_H
 #define ARCH_TESTS_H
 
+#include <linux/compiler.h>
+
+/* Tests */
+int test__perf_time_to_arch_timer_cnt(struct test *test __maybe_unused,
+				      int subtest __maybe_unused);
+
 #ifdef HAVE_DWARF_UNWIND_SUPPORT
 struct thread;
 struct perf_sample;
diff --git a/tools/perf/arch/arm64/tests/Build b/tools/perf/arch/arm64/tests/Build
index a61c06bdb757..1fd819e4f80f 100644
--- a/tools/perf/arch/arm64/tests/Build
+++ b/tools/perf/arch/arm64/tests/Build
@@ -2,3 +2,4 @@ perf-y += regs_load.o
 perf-$(CONFIG_DWARF_UNWIND) += dwarf-unwind.o
 
 perf-y += arch-tests.o
+perf-y += perf-time-to-arch-timer-counter.o
diff --git a/tools/perf/arch/arm64/tests/arch-tests.c b/tools/perf/arch/arm64/tests/arch-tests.c
index 5b1543c98022..99d8ab865668 100644
--- a/tools/perf/arch/arm64/tests/arch-tests.c
+++ b/tools/perf/arch/arm64/tests/arch-tests.c
@@ -4,6 +4,10 @@
 #include "arch-tests.h"
 
 struct test arch_tests[] = {
+	{
+		.desc = "Convert perf time to arch timer counter",
+		.func = test__perf_time_to_arch_timer_cnt,
+	},
 #ifdef HAVE_DWARF_UNWIND_SUPPORT
 	{
 		.desc = "DWARF unwind",
diff --git a/tools/perf/arch/arm64/tests/perf-time-to-arch-timer-counter.c b/tools/perf/arch/arm64/tests/perf-time-to-arch-timer-counter.c
new file mode 100644
index 000000000000..09b9f43b48a4
--- /dev/null
+++ b/tools/perf/arch/arm64/tests/perf-time-to-arch-timer-counter.c
@@ -0,0 +1,189 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <errno.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <linux/types.h>
+#include <sys/prctl.h>
+#include <perf/cpumap.h>
+#include <perf/evlist.h>
+#include <perf/mmap.h>
+
+#include "arm_arch_timer.h"
+#include "debug.h"
+#include "parse-events.h"
+#include "evlist.h"
+#include "evsel.h"
+#include "thread_map.h"
+#include "record.h"
+#include "util/mmap.h"
+#include "tests/tests.h"
+
+#include "arch-tests.h"
+
+#define CHECK_NOT_LESS_ZERO(x) {		\
+	while ((x) < 0) {			\
+		pr_debug(#x " failed!\n");	\
+		goto out_err;			\
+	}					\
+}
+
+#define CHECK_NOT_NULL(x) {			\
+	while ((x) == NULL) {			\
+		pr_debug(#x " failed!\n");	\
+		goto out_err;			\
+	}					\
+}
+
+/*
+ * The arch timer's offset is set to zero, the virtual counter and physical
+ * counter should have the same value; so the user space program can read out
+ * counter with system register cntvct_el0 and it can be used to compare with
+ * kernel's counter.
+ */
+#define read_cntvct_el0(r) ({					\
+	u64 __val;						\
+	asm volatile("mrs %0, cntvct_el0" : "=r" (__val));	\
+	__val;							\
+})
+
+/**
+ * test__perf_time_to_arch_timer_cnt - test converting perf time to Arm arch
+ * timer counter.
+ *
+ * This function implements a test that checks that the conversion of perf time
+ * to and from Arm arch timer counter is consistent with the order of events.
+ * Returns 0 if the test passes, otherwise returns -1.  If TSC conversion is not
+ * supported then then the test passes but " (not supported)" is printed.
+ */
+int test__perf_time_to_arch_timer_cnt(struct test *test __maybe_unused,
+				      int subtest __maybe_unused)
+{
+	struct record_opts opts = {
+		.mmap_pages	     = UINT_MAX,
+		.user_freq	     = UINT_MAX,
+		.user_interval	     = ULLONG_MAX,
+		.target		     = {
+			.uses_mmap   = true,
+		},
+		.sample_time	     = true,
+	};
+	struct perf_thread_map *threads = NULL;
+	struct perf_cpu_map *cpus = NULL;
+	struct evlist *evlist = NULL;
+	struct evsel *evsel = NULL;
+	int err = -1, ret, i;
+	const char *comm1, *comm2;
+	struct perf_arch_timer_conversion tc;
+	struct perf_event_mmap_page *pc;
+	union perf_event *event;
+	u64 test_arch_timer_cnt;
+	u64 comm1_arch_timer_cnt;
+	u64 comm2_arch_timer_cnt;
+	u64 test_time, comm1_time = 0, comm2_time = 0;
+	struct mmap *md;
+
+	threads = thread_map__new(-1, getpid(), UINT_MAX);
+	CHECK_NOT_NULL(threads);
+
+	cpus = perf_cpu_map__new(NULL);
+	CHECK_NOT_NULL(cpus);
+
+	evlist = evlist__new();
+	CHECK_NOT_NULL(evlist);
+
+	perf_evlist__set_maps(&evlist->core, cpus, threads);
+
+	CHECK_NOT_LESS_ZERO(parse_events(evlist, "cycles:u", NULL));
+
+	perf_evlist__config(evlist, &opts, NULL);
+
+	evsel = evlist__first(evlist);
+
+	evsel->core.attr.comm = 1;
+	evsel->core.attr.disabled = 1;
+	evsel->core.attr.enable_on_exec = 0;
+
+	CHECK_NOT_LESS_ZERO(evlist__open(evlist));
+
+	CHECK_NOT_LESS_ZERO(evlist__mmap(evlist, UINT_MAX));
+
+	pc = evlist->mmap[0].core.base;
+	ret = perf_read_arch_timer_conversion(pc, &tc);
+	if (ret) {
+		if (ret == -EOPNOTSUPP) {
+			fprintf(stderr, " (not supported)");
+			return 0;
+		}
+		goto out_err;
+	}
+
+	evlist__enable(evlist);
+
+	comm1 = "Test COMM 1";
+	CHECK_NOT_LESS_ZERO(prctl(PR_SET_NAME, (unsigned long)comm1, 0, 0, 0));
+
+	test_arch_timer_cnt = read_cntvct_el0();
+
+	comm2 = "Test COMM 2";
+	CHECK_NOT_LESS_ZERO(prctl(PR_SET_NAME, (unsigned long)comm2, 0, 0, 0));
+
+	evlist__disable(evlist);
+
+	for (i = 0; i < evlist->core.nr_mmaps; i++) {
+		md = &evlist->mmap[i];
+		if (perf_mmap__read_init(&md->core) < 0)
+			continue;
+
+		while ((event = perf_mmap__read_event(&md->core)) != NULL) {
+			struct perf_sample sample;
+
+			if (event->header.type != PERF_RECORD_COMM ||
+			    (pid_t)event->comm.pid != getpid() ||
+			    (pid_t)event->comm.tid != getpid())
+				goto next_event;
+
+			if (strcmp(event->comm.comm, comm1) == 0) {
+				CHECK_NOT_LESS_ZERO(evsel__parse_sample(evsel, event, &sample));
+				comm1_time = sample.time;
+			}
+			if (strcmp(event->comm.comm, comm2) == 0) {
+				CHECK_NOT_LESS_ZERO(evsel__parse_sample(evsel, event, &sample));
+				comm2_time = sample.time;
+			}
+next_event:
+			perf_mmap__consume(&md->core);
+		}
+		perf_mmap__read_done(&md->core);
+	}
+
+	if (!comm1_time || !comm2_time)
+		goto out_err;
+
+	test_time = arch_timer_cyc_to_perf_time(test_arch_timer_cnt, &tc);
+	comm1_arch_timer_cnt = perf_time_to_arch_timer_cyc(comm1_time, &tc);
+	comm2_arch_timer_cnt = perf_time_to_arch_timer_cyc(comm2_time, &tc);
+
+	pr_debug("1st event perf time %"PRIu64" arch timer cnt %"PRIu64"\n",
+		 comm1_time, comm1_arch_timer_cnt);
+	pr_debug("test time           %"PRIu64" arch timer cnt %"PRIu64"\n",
+		 test_time, test_arch_timer_cnt);
+	pr_debug("2nd event perf time %"PRIu64" arch timer cnt %"PRIu64"\n",
+		 comm2_time, comm2_arch_timer_cnt);
+
+	if (test_time <= comm1_time ||
+	    test_time >= comm2_time)
+		goto out_err;
+
+	if (test_arch_timer_cnt <= comm1_arch_timer_cnt ||
+	    test_arch_timer_cnt >= comm2_arch_timer_cnt)
+		goto out_err;
+
+	err = 0;
+
+out_err:
+	evlist__delete(evlist);
+	return err;
+}
-- 
2.17.1

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ