[PATCH 2/2] tests for absolute timestamp

From: Korben Rusek
Date: Thu Jun 18 2020 - 18:16:42 EST


Tested:
kselftest output:

Found regular timestamps when force-abs-timestamp flag is off - [PASS]
Found absolute timestamps when force-abs-timestamp flag is on - [PASS]

Reviewed-by: Peter Shier <pshier@xxxxxxxxxx>
Signed-off-by: Korben Rusek <korben@xxxxxxxxxx>
---
tools/testing/selftests/Makefile | 1 +
tools/testing/selftests/timestamp/Makefile | 25 +++
tools/testing/selftests/timestamp/abs-test.sh | 156 ++++++++++++++
.../selftests/timestamp/abs-timestamp.c | 198 ++++++++++++++++++
4 files changed, 380 insertions(+)
create mode 100644 tools/testing/selftests/timestamp/Makefile
create mode 100644 tools/testing/selftests/timestamp/abs-test.sh
create mode 100644 tools/testing/selftests/timestamp/abs-timestamp.c

diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
index 1195bd85af38..bda1cd0a608f 100644
--- a/tools/testing/selftests/Makefile
+++ b/tools/testing/selftests/Makefile
@@ -58,6 +58,7 @@ TARGETS += timens
ifneq (1, $(quicktest))
TARGETS += timers
endif
+TARGETS += timestamp
TARGETS += tmpfs
TARGETS += tpm2
TARGETS += user
diff --git a/tools/testing/selftests/timestamp/Makefile b/tools/testing/selftests/timestamp/Makefile
new file mode 100644
index 000000000000..a8aa3b7278cf
--- /dev/null
+++ b/tools/testing/selftests/timestamp/Makefile
@@ -0,0 +1,25 @@
+TEST_PROGS := abs-test.sh
+
+.PHONY: all clean
+
+include ../lib.mk
+
+override define RUN_TESTS
+ @cd $(OUTPUT); ./abs-test.sh
+endef
+
+override define INSTALL_RULE
+ mkdir -p $(INSTALL_PATH)
+ $(CC) -o $(INSTALL_PATH)/abs-timestamp abs-timestamp.c -static
+ echo $(INSTALL_PATH)
+ cp abs-test.sh $(INSTALL_PATH)/abs-test.sh
+ chmod u+x $(INSTALL_PATH)/abs-test.sh
+endef
+
+override define CLEAN
+ rm -f abs-timestamp
+endef
+
+override define EMIT_TESTS
+ echo "./abs-test.sh"
+endef
diff --git a/tools/testing/selftests/timestamp/abs-test.sh b/tools/testing/selftests/timestamp/abs-test.sh
new file mode 100644
index 000000000000..067a09c2e77d
--- /dev/null
+++ b/tools/testing/selftests/timestamp/abs-test.sh
@@ -0,0 +1,156 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+# description: event tracing - enable/disable abs_timestamp option
+
+TMPDIR=`mktemp -d /tmp/ftracetest-dir.XXXXXX`
+# Parameters
+DEBUGFS_DIR=`grep debugfs /proc/mounts | cut -f2 -d' ' | head -1`
+if [ -z "$DEBUGFS_DIR" ]; then
+ TRACING_DIR=`grep tracefs /proc/mounts | cut -f2 -d' ' | head -1`
+else
+ TRACING_DIR=$DEBUGFS_DIR/tracing
+fi
+
+clear_trace() {
+ echo > $TRACING_DIR/trace
+}
+
+disable_tracing() {
+ echo 0 > $TRACING_DIR/tracing_on
+}
+
+enable_tracing() {
+ echo 1 > $TRACING_DIR/tracing_on
+}
+
+reset_tracer() {
+ echo nop > $TRACING_DIR/current_tracer
+}
+
+do_reset() {
+ clear_trace
+ echo > $TRACING_DIR/set_event
+}
+
+exit_fail() {
+ exit 1
+}
+
+if [ -z `grep "force-abs-timestamp" $TRACING_DIR/trace_options` ]; then
+ echo "force-abs-timestamp is unsupported - [FAIL]"
+ exit 2
+fi
+
+# select all supported event types
+available=$( cat $TRACING_DIR/available_events | tr "\n" " " )
+events=($available)
+
+BUFSIZEK=1024
+
+emit_events() {
+ # give the system several opportunities to emit trace events
+ ping localhost -c 1 || sleep .001 || usleep 1 || sleep 1
+}
+
+check_absolute_timestamps() {
+ pids=()
+ PAGE_SIZE=`tail -n 1 $TRACING_DIR/events/header_page | awk -F";" '{print $3}' | awk -F":" '{print $2}'`
+ CORRECT=0
+ ERROR=0
+ FAILURE=""
+ for cf in $TRACING_DIR/per_cpu/cpu*
+ do
+ cpuname="${cf##*/}"
+ touch "${TMPDIR}/${cpuname}"
+ cat "${cf}/trace_pipe_raw" > "${TMPDIR}/${cpuname}" &
+ pids+=($!)
+ disown
+
+ RET=`./abs-timestamp "${TMPDIR}/${cpuname}" "$PAGE_SIZE" $1`
+ if [ $RET != $1 ]; then
+ if [ $RET != "empty" ]; then
+ ERROR=1
+ FAILURE=$cpuname
+ fi
+ fi
+ if [ "$RET" == "$1" ]; then
+ CORRECT=1
+ fi
+ done
+
+ if [ $ERROR == "1" ]; then
+ echo $FAILURE
+ elif [ $CORRECT == "1" ]; then
+ rm $TMPDIR/$cpuname
+ echo "SUCCESS"
+ else
+ echo "EMPTY"
+ fi
+}
+
+clean() {
+ do_reset
+ rm -rf $TMPDIR
+}
+
+fail() {
+ clean
+ echo $1
+ exit_fail
+}
+
+disable_tracing
+
+reset_tracer
+
+# Set buffer size
+echo ${BUFSIZEK} > $TRACING_DIR/buffer_size_kb
+# Remove newest events when the buffer overflows instead of oldest.
+echo "overwrite" > $TRACING_DIR/trace_options
+# Turn off absolute timestamp option
+echo "noforce-abs-timestamp" > $TRACING_DIR/trace_options
+# Enable events
+echo > $TRACING_DIR/set_event
+for event in "${events[@]}"
+do
+ echo "${event}" >> $TRACING_DIR/set_event
+done
+
+clear_trace
+enable_tracing
+emit_events
+disable_tracing
+RET=`check_absolute_timestamps "noabs-timestamp"`
+if [ $RET == "EMPTY" ]; then
+ echo "No traces found when force-abs-timestamp flag is off - [UNRESOLVED]"
+elif [ "$RET" != "SUCCESS" ]; then
+ fail "found unexpected absolute timestamps with noforce-abs-timestamp - [FAIL]"
+else
+ echo "Found regular timestamps when force-abs-timestamp flag is off - [PASS]"
+fi
+
+rm -rf $TMPDIR/*
+
+# Turn on absolute timestamp option
+echo "force-abs-timestamp" > $TRACING_DIR/trace_options
+for event in "${events[@]}"
+do
+ echo "${event}" >> $TRACING_DIR/set_event
+done
+
+clear_trace
+enable_tracing
+emit_events
+disable_tracing
+
+RET=`check_absolute_timestamps "abs-timestamp"`
+if [ $RET == "EMPTY" ]; then
+ echo "No traces found when force-abs-timestamp flag is on - [UNRESOLVED]"
+elif [ $RET != "SUCCESS" ]; then
+ echo $RET
+ fail "did not find absolute timestamps - [FAIL]"
+else
+ echo "Found absolute timestamps when force-abs-timestamp flag is on - [PASS]"
+fi
+
+clean
diff --git a/tools/testing/selftests/timestamp/abs-timestamp.c b/tools/testing/selftests/timestamp/abs-timestamp.c
new file mode 100644
index 000000000000..134268464a5a
--- /dev/null
+++ b/tools/testing/selftests/timestamp/abs-timestamp.c
@@ -0,0 +1,200 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ftrace absolute timestamp test helper.
+ *
+ * ./abs-timestamp [FILE] [PAGE_SIZE] [METHOD]
+ *
+ * - FILE: path to a raw cpu trace
+ * - PAGE_SIZE: expected page size for the trace
+ * - METHOD: should be either abs-timestamp or noabs-timestamp
+ *
+ * This program reads the trace data in [FILE]. It checks whether
+ * every data element contains an absolute timestamp element
+ * before it. If this is the case for every event it prints
+ * "abs-timestamp" otherwise it prints "noabs-timestamp".
+ * If no data is found then "no-data" is printed.
+ *
+ * It returns 0 if METHOD matches what is found or if no
+ * data is found.
+ */
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define INT32_SIZE 4
+
+#define EVENT_TYPE_VARIABLE_SIZE 0
+#define EVENT_TYPE_LEN_MAX 28
+#define EVENT_TYPE_PADDING 29
+#define EVENT_TYPE_EXTEND 30
+#define EVENT_TYPE_ABSTIME 31
+
+#define EVENT_TYPE_MASK 0b11111
+
+#define MINIMUM_EVENT_SIZE 16
+
+#define PAGE_HEADER_SIZE 16
+
+#define RET_PASS 0
+#define RET_FAIL -2
+
+int page_size = 4080 + PAGE_HEADER_SIZE;
+
+int skip_bytes(int bytes, FILE *file)
+{
+ return fseek(file, bytes, SEEK_CUR) == 0;
+}
+
+unsigned long read_int64(FILE *file)
+{
+ unsigned long data;
+
+ if (!fread(&data, 8, 1, file))
+ return 0;
+ return data;
+}
+
+unsigned int read_int32(FILE *file)
+{
+ unsigned int data;
+
+ fread(&data, 4, 1, file);
+ return data;
+}
+
+char peek_byte(FILE *file)
+{
+ char byte;
+
+ fread(&byte, 1, 1, file);
+ skip_bytes(-1, file);
+ return byte;
+}
+
+int peek_event_type(FILE *file)
+{
+ if (feof(file))
+ return -1;
+ return peek_byte(file) & EVENT_TYPE_MASK;
+}
+
+// Extract the length of the page data from the page header. This length does
+// not include the size of the header (16 bytes).
+unsigned long page_data_length(FILE *file)
+{
+ unsigned long position = ftell(file);
+
+ if (position) {
+ int remaining =
+ (page_size - (position % page_size)) % page_size;
+
+ if (!skip_bytes(remaining, file))
+ return -1;
+ }
+ if (feof(file))
+ return 0;
+ if (!skip_bytes(8, file))
+ return 0;
+ return read_int64(file) & 0xFFFFF;
+}
+
+// Move to the next page if it exists. If successful the ending position of the
+// page is returned. It returns zero if there are no more pages.
+int move_next_page(FILE *file)
+{
+ unsigned long length = page_data_length(file);
+
+ if (length == 0)
+ return 0;
+ return ftell(file) + length;
+}
+
+void skip_event(int type, FILE *file)
+{
+ switch (type) {
+ // Time extend and absolute timestamp events are fixed length.
+ case EVENT_TYPE_EXTEND:
+ case EVENT_TYPE_ABSTIME:
+ skip_bytes(8, file);
+ return;
+ // Padding events and event type 0 are both variable length events where
+ // the next 32 bits indicate the length of the event. We also skip the
+ // next 4 bytes which indicate timestamp delta.
+ case EVENT_TYPE_PADDING:
+ case EVENT_TYPE_VARIABLE_SIZE: {
+ skip_bytes(4, file);
+ unsigned int length = read_int32(file);
+
+ skip_bytes(length - INT32_SIZE, file);
+ return;
+ }
+ // Other events (type 1...32) have a length of 4*type. We also skip the
+ // next 4 bytes which indicate timestamp delta.
+ default: {
+ skip_bytes(4, file);
+ unsigned int length = type << 2;
+
+ skip_bytes(length, file);
+ return;
+ }
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ char absolute[] = "abs-timestamp";
+ FILE *file = fopen(argv[1], "r");
+ unsigned long page_end = page_data_length(file) + PAGE_HEADER_SIZE;
+ bool checking_abs = (argc > 3) && (strcmp(absolute, argv[3]) == 0);
+ bool satisfies_abs = true;
+ bool unaccounted_abs = false;
+ bool data_seen = false;
+
+ if (argc > 2) {
+ int base_page_size = strtol(argv[2], NULL, 10);
+
+ if (!base_page_size) {
+ printf("invalid format - header size missing");
+ return RET_FAIL;
+ }
+ page_size = base_page_size + PAGE_HEADER_SIZE;
+ }
+
+ while (!feof(file)) {
+ int type;
+
+ type = peek_event_type(file);
+ if (type == EVENT_TYPE_ABSTIME) {
+ unaccounted_abs = true;
+ } else if (type <= EVENT_TYPE_LEN_MAX) {
+ data_seen = true;
+ satisfies_abs = unaccounted_abs;
+ unaccounted_abs = false;
+ }
+ if (!satisfies_abs)
+ break;
+
+ skip_event(type, file);
+
+ if (ftell(file) + MINIMUM_EVENT_SIZE > page_end) {
+ page_end = move_next_page(file);
+ if (!page_end)
+ break;
+ }
+ }
+
+ if (!data_seen) {
+ printf("empty");
+ return RET_PASS;
+ }
+ if (satisfies_abs)
+ printf("abs-timestamp");
+ else
+ printf("noabs-timestamp");
+
+ if (satisfies_abs == checking_abs)
+ return RET_PASS;
+ return RET_FAIL;
+}
+
--
2.27.0.290.gba653c62da-goog