aboutsummaryrefslogtreecommitdiff
path: root/utest/tracefs-utest.c
diff options
context:
space:
mode:
Diffstat (limited to 'utest/tracefs-utest.c')
-rw-r--r--utest/tracefs-utest.c630
1 files changed, 630 insertions, 0 deletions
diff --git a/utest/tracefs-utest.c b/utest/tracefs-utest.c
new file mode 100644
index 00000000..9c9eee06
--- /dev/null
+++ b/utest/tracefs-utest.c
@@ -0,0 +1,630 @@
+// SPDX-License-Identifier: LGPL-2.1
+/*
+ * Copyright (C) 2020, VMware, Tzvetomir Stoyanov <tz.stoyanov@gmail.com>
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <time.h>
+#include <dirent.h>
+
+#include <CUnit/CUnit.h>
+#include <CUnit/Basic.h>
+
+#include "tracefs.h"
+
+#define TRACEFS_SUITE "trasefs library"
+#define TEST_INSTANCE_NAME "cunit_test_iter"
+#define TEST_ARRAY_SIZE 500
+
+static struct tracefs_instance *test_instance;
+static struct tep_handle *test_tep;
+struct test_sample {
+ int cpu;
+ int value;
+};
+static struct test_sample test_array[TEST_ARRAY_SIZE];
+static int test_found;
+
+static int test_callback(struct tep_event *event, struct tep_record *record,
+ int cpu, void *context)
+{
+ struct tep_format_field *field;
+ struct test_sample *sample;
+ int *cpu_test = (int *)context;
+ int i;
+
+ if (cpu_test && *cpu_test >= 0 && *cpu_test != cpu)
+ return 0;
+ field = tep_find_field(event, "buf");
+ if (field) {
+ sample = ((struct test_sample *)(record->data + field->offset));
+ for (i = 0; i < TEST_ARRAY_SIZE; i++) {
+ if (test_array[i].value == sample->value &&
+ test_array[i].cpu == cpu) {
+ test_array[i].value = 0;
+ test_found++;
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static void test_iter_write(void)
+{
+ int cpus = sysconf(_SC_NPROCESSORS_CONF);
+ cpu_set_t *cpuset, *cpusave;
+ int cpu_size;
+ char *path;
+ int i, fd;
+ int ret;
+ cpuset = CPU_ALLOC(cpus);
+ cpusave = CPU_ALLOC(cpus);
+ cpu_size = CPU_ALLOC_SIZE(cpus);
+ CPU_ZERO_S(cpu_size, cpuset);
+
+ sched_getaffinity(0, cpu_size, cpusave);
+
+ path = tracefs_instance_get_file(test_instance, "trace_marker");
+ CU_TEST(path != NULL);
+ fd = open(path, O_WRONLY);
+ tracefs_put_tracing_file(path);
+ CU_TEST(fd >= 0);
+
+ for (i = 0; i < TEST_ARRAY_SIZE; i++) {
+ test_array[i].cpu = rand() % cpus;
+ test_array[i].value = random();
+ if (!test_array[i].value)
+ test_array[i].value++;
+ CU_TEST(test_array[i].cpu < cpus);
+ CPU_ZERO_S(cpu_size, cpuset);
+ CPU_SET(test_array[i].cpu, cpuset);
+ sched_setaffinity(0, cpu_size, cpuset);
+ ret = write(fd, test_array + i, sizeof(struct test_sample));
+ CU_TEST(ret == sizeof(struct test_sample));
+ }
+
+ sched_setaffinity(0, cpu_size, cpusave);
+ close(fd);
+}
+
+
+static void iter_raw_events_on_cpu(int cpu)
+{
+ int check = 0;
+ int ret;
+ int i;
+
+ test_found = 0;
+ test_iter_write();
+ ret = tracefs_iterate_raw_events(test_tep, test_instance, NULL, 0,
+ test_callback, &cpu);
+ CU_TEST(ret == 0);
+ if (cpu < 0) {
+ CU_TEST(test_found == TEST_ARRAY_SIZE);
+ } else {
+ for (i = 0; i < TEST_ARRAY_SIZE; i++) {
+ if (test_array[i].cpu == cpu) {
+ check++;
+ CU_TEST(test_array[i].value == 0)
+ } else {
+ CU_TEST(test_array[i].value != 0)
+ }
+ }
+ CU_TEST(test_found == check);
+ }
+}
+
+static void test_iter_raw_events(void)
+{
+ int cpus = sysconf(_SC_NPROCESSORS_CONF);
+ int ret;
+ int i;
+
+ ret = tracefs_iterate_raw_events(NULL, test_instance, NULL, 0, test_callback, NULL);
+ CU_TEST(ret < 0);
+ ret = tracefs_iterate_raw_events(test_tep, NULL, NULL, 0, test_callback, NULL);
+ CU_TEST(ret == 0);
+ ret = tracefs_iterate_raw_events(test_tep, test_instance, NULL, 0, NULL, NULL);
+ CU_TEST(ret < 0);
+
+ iter_raw_events_on_cpu(-1);
+ for (i = 0; i < cpus; i++)
+ iter_raw_events_on_cpu(i);
+}
+
+#define RAND_STR_SIZE 20
+#define RAND_ASCII "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+static const char *get_rand_str()
+{
+ static char str[RAND_STR_SIZE];
+ static char sym[] = RAND_ASCII;
+ struct timespec clk;
+ int i;
+
+ clock_gettime(CLOCK_REALTIME, &clk);
+ srand(clk.tv_nsec);
+ for (i = 0; i < RAND_STR_SIZE; i++)
+ str[i] = sym[rand() % (sizeof(sym) - 1)];
+
+ str[RAND_STR_SIZE - 1] = 0;
+ return str;
+}
+
+static void test_trace_file(void)
+{
+ const char *tmp = get_rand_str();
+ const char *tdir;
+ struct stat st;
+ char *file;
+
+ tdir = tracefs_tracing_dir();
+ CU_TEST(tdir != NULL);
+ CU_TEST(stat(tdir, &st) == 0);
+ CU_TEST(S_ISDIR(st.st_mode));
+
+ file = tracefs_get_tracing_file(NULL);
+ CU_TEST(file == NULL);
+ file = tracefs_get_tracing_file(tmp);
+ CU_TEST(file != NULL);
+ CU_TEST(stat(file, &st) != 0);
+ tracefs_put_tracing_file(file);
+
+ file = tracefs_get_tracing_file("trace");
+ CU_TEST(file != NULL);
+ CU_TEST(stat(file, &st) == 0);
+ tracefs_put_tracing_file(file);
+}
+
+static void test_instance_file_read(struct tracefs_instance *inst, char *fname)
+{
+ const char *tdir = tracefs_tracing_dir();
+ char buf[BUFSIZ];
+ char *fpath;
+ char *file;
+ size_t fsize = 0;
+ int size = 0;
+ int fd;
+
+ if (inst) {
+ CU_TEST(asprintf(&fpath, "%s/instances/%s/%s",
+ tdir, tracefs_instance_get_name(inst), fname) > 0);
+ } else {
+ CU_TEST(asprintf(&fpath, "%s/%s", tdir, fname) > 0);
+ }
+
+ memset(buf, 0, BUFSIZ);
+ fd = open(fpath, O_RDONLY);
+ CU_TEST(fd >= 0);
+ fsize = read(fd, buf, BUFSIZ);
+ CU_TEST(fsize >= 0);
+ close(fd);
+ buf[BUFSIZ - 1] = 0;
+
+ file = tracefs_instance_file_read(inst, fname, &size);
+ CU_TEST(file != NULL);
+ CU_TEST(size == fsize);
+ CU_TEST(strcmp(file, buf) == 0);
+
+ free(fpath);
+ free(file);
+}
+
+#define ALL_TRACERS "available_tracers"
+#define CUR_TRACER "current_tracer"
+#define PER_CPU "per_cpu"
+static void test_instance_file(void)
+{
+ struct tracefs_instance *instance = NULL;
+ struct tracefs_instance *second = NULL;
+ const char *name = get_rand_str();
+ const char *inst_name = NULL;
+ const char *tdir;
+ char *inst_file;
+ char *inst_dir;
+ struct stat st;
+ char *fname;
+ char *file1;
+ char *file2;
+ char *tracer;
+ int size;
+ int ret;
+
+ tdir = tracefs_tracing_dir();
+ CU_TEST(tdir != NULL);
+ CU_TEST(asprintf(&inst_dir, "%s/instances/%s", tdir, name) > 0);
+ CU_TEST(stat(inst_dir, &st) != 0);
+
+ CU_TEST(tracefs_instance_exists(name) == false);
+ instance = tracefs_instance_create(name);
+ CU_TEST(instance != NULL);
+ CU_TEST(tracefs_instance_is_new(instance));
+ second = tracefs_instance_create(name);
+ CU_TEST(second != NULL);
+ CU_TEST(!tracefs_instance_is_new(second));
+ tracefs_instance_free(second);
+ CU_TEST(tracefs_instance_exists(name) == true);
+ CU_TEST(stat(inst_dir, &st) == 0);
+ CU_TEST(S_ISDIR(st.st_mode));
+ inst_name = tracefs_instance_get_name(instance);
+ CU_TEST(inst_name != NULL);
+ CU_TEST(strcmp(inst_name, name) == 0);
+
+ fname = tracefs_instance_get_dir(NULL);
+ CU_TEST(fname != NULL);
+ CU_TEST(strcmp(fname, tdir) == 0);
+ free(fname);
+
+ fname = tracefs_instance_get_dir(instance);
+ CU_TEST(fname != NULL);
+ CU_TEST(strcmp(fname, inst_dir) == 0);
+ free(fname);
+
+ CU_TEST(asprintf(&fname, "%s/"ALL_TRACERS, tdir) > 0);
+ CU_TEST(fname != NULL);
+ inst_file = tracefs_instance_get_file(NULL, ALL_TRACERS);
+ CU_TEST(inst_file != NULL);
+ CU_TEST(strcmp(fname, inst_file) == 0);
+ tracefs_put_tracing_file(inst_file);
+ free(fname);
+
+ CU_TEST(asprintf(&fname, "%s/instances/%s/"ALL_TRACERS, tdir, name) > 0);
+ CU_TEST(fname != NULL);
+ CU_TEST(stat(fname, &st) == 0);
+ inst_file = tracefs_instance_get_file(instance, ALL_TRACERS);
+ CU_TEST(inst_file != NULL);
+ CU_TEST(strcmp(fname, inst_file) == 0);
+
+ test_instance_file_read(NULL, ALL_TRACERS);
+ test_instance_file_read(instance, ALL_TRACERS);
+
+ file1 = tracefs_instance_file_read(instance, ALL_TRACERS, NULL);
+ CU_TEST(file1 != NULL);
+ tracer = strtok(file1, " ");
+ CU_TEST(tracer != NULL);
+ ret = tracefs_instance_file_write(instance, CUR_TRACER, tracer);
+ CU_TEST(ret == strlen(tracer));
+ file2 = tracefs_instance_file_read(instance, CUR_TRACER, &size);
+ CU_TEST(file2 != NULL);
+ CU_TEST(size >= strlen(tracer));
+ CU_TEST(strncmp(file2, tracer, strlen(tracer)) == 0);
+ free(file1);
+ free(file2);
+
+ tracefs_put_tracing_file(inst_file);
+ free(fname);
+
+ CU_TEST(tracefs_file_exists(NULL, (char *)name) == false);
+ CU_TEST(tracefs_dir_exists(NULL, (char *)name) == false);
+ CU_TEST(tracefs_file_exists(instance, (char *)name) == false);
+ CU_TEST(tracefs_dir_exists(instance, (char *)name) == false);
+
+ CU_TEST(tracefs_file_exists(NULL, CUR_TRACER) == true);
+ CU_TEST(tracefs_dir_exists(NULL, CUR_TRACER) == false);
+ CU_TEST(tracefs_file_exists(instance, CUR_TRACER) == true);
+ CU_TEST(tracefs_dir_exists(instance, CUR_TRACER) == false);
+
+ CU_TEST(tracefs_file_exists(NULL, PER_CPU) == false);
+ CU_TEST(tracefs_dir_exists(NULL, PER_CPU) == true);
+ CU_TEST(tracefs_file_exists(instance, PER_CPU) == false);
+ CU_TEST(tracefs_dir_exists(instance, PER_CPU) == true);
+
+ CU_TEST(tracefs_instance_destroy(NULL) != 0);
+ CU_TEST(tracefs_instance_destroy(instance) == 0);
+ CU_TEST(tracefs_instance_destroy(instance) != 0);
+ tracefs_instance_free(instance);
+ CU_TEST(stat(inst_dir, &st) != 0);
+ free(inst_dir);
+}
+
+static void exclude_string(char **strings, char *name)
+{
+ int i;
+
+ for (i = 0; strings[i]; i++) {
+ if (strcmp(strings[i], name) == 0) {
+ free(strings[i]);
+ strings[i] = strdup("/");
+ return;
+ }
+ }
+}
+
+static void test_check_files(const char *fdir, char **files)
+{
+ struct dirent *dent;
+ DIR *dir;
+ int i;
+
+ dir = opendir(fdir);
+ CU_TEST(dir != NULL);
+
+ while ((dent = readdir(dir)))
+ exclude_string(files, dent->d_name);
+
+ closedir(dir);
+
+ for (i = 0; files[i]; i++)
+ CU_TEST(files[i][0] == '/');
+}
+
+static void test_system_event(void)
+{
+ const char *tdir;
+ char **systems;
+ char **events;
+ char *sdir = NULL;
+
+ tdir = tracefs_tracing_dir();
+ CU_TEST(tdir != NULL);
+
+ systems = tracefs_event_systems(tdir);
+ CU_TEST(systems != NULL);
+
+ events = tracefs_system_events(tdir, systems[0]);
+ CU_TEST(events != NULL);
+
+ asprintf(&sdir, "%s/events/%s", tdir, systems[0]);
+ CU_TEST(sdir != NULL);
+ test_check_files(sdir, events);
+ free(sdir);
+ sdir = NULL;
+
+ asprintf(&sdir, "%s/events", tdir);
+ CU_TEST(sdir != NULL);
+ test_check_files(sdir, systems);
+
+ tracefs_list_free(systems);
+ tracefs_list_free(events);
+
+ free(sdir);
+}
+
+static void test_tracers(void)
+{
+ const char *tdir;
+ char **tracers;
+ char *tfile;
+ char *tracer;
+ int i;
+
+ tdir = tracefs_tracing_dir();
+ CU_TEST(tdir != NULL);
+
+ tracers = tracefs_tracers(tdir);
+ CU_TEST(tracers != NULL);
+
+ tfile = tracefs_instance_file_read(NULL, ALL_TRACERS, NULL);
+
+ tracer = strtok(tfile, " ");
+ while (tracer) {
+ exclude_string(tracers, tracer);
+ tracer = strtok(NULL, " ");
+ }
+
+ for (i = 0; tracers[i]; i++)
+ CU_TEST(tracers[i][0] == '/');
+
+ tracefs_list_free(tracers);
+ free(tfile);
+}
+
+static void test_check_events(struct tep_handle *tep, char *system, bool exist)
+{
+ struct dirent *dent;
+ char file[PATH_MAX];
+ char buf[1024];
+ char *edir = NULL;
+ const char *tdir;
+ DIR *dir;
+ int fd;
+
+ tdir = tracefs_tracing_dir();
+ CU_TEST(tdir != NULL);
+
+ asprintf(&edir, "%s/events/%s", tdir, system);
+ dir = opendir(edir);
+ CU_TEST(dir != NULL);
+
+ while ((dent = readdir(dir))) {
+ if (dent->d_name[0] == '.')
+ continue;
+ sprintf(file, "%s/%s/id", edir, dent->d_name);
+ fd = open(file, O_RDONLY);
+ if (fd < 0)
+ continue;
+ CU_TEST(read(fd, buf, 1024) > 0);
+ if (exist) {
+ CU_TEST(tep_find_event(tep, atoi(buf)) != NULL);
+ } else {
+ CU_TEST(tep_find_event(tep, atoi(buf)) == NULL);
+ }
+
+ close(fd);
+ }
+
+ closedir(dir);
+ free(edir);
+
+}
+
+static void test_local_events(void)
+{
+ struct tep_handle *tep;
+ const char *tdir;
+ char **systems;
+ char *lsystems[3];
+ int i;
+
+ tdir = tracefs_tracing_dir();
+ CU_TEST(tdir != NULL);
+
+ tep = tracefs_local_events(tdir);
+ CU_TEST(tep != NULL);
+
+ systems = tracefs_event_systems(tdir);
+ CU_TEST(systems != NULL);
+
+ for (i = 0; systems[i]; i++)
+ test_check_events(tep, systems[i], true);
+ tep_free(tep);
+
+ memset(lsystems, 0, sizeof(lsystems));
+ for (i = 0; systems[i]; i++) {
+ if (!lsystems[0])
+ lsystems[0] = systems[i];
+ else if (!lsystems[2])
+ lsystems[2] = systems[i];
+ else
+ break;
+ }
+
+ if (lsystems[0] && lsystems[2]) {
+ tep = tracefs_local_events_system(tdir,
+ (const char * const *)lsystems);
+ CU_TEST(tep != NULL);
+ test_check_events(tep, lsystems[0], true);
+ test_check_events(tep, lsystems[2], false);
+ }
+ tep_free(tep);
+
+ tep = tep_alloc();
+ CU_TEST(tep != NULL);
+ CU_TEST(tracefs_fill_local_events(tdir, tep, NULL) == 0);
+ for (i = 0; systems[i]; i++)
+ test_check_events(tep, systems[i], true);
+
+ tep_free(tep);
+
+ tracefs_list_free(systems);
+}
+
+struct test_walk_instance {
+ struct tracefs_instance *instance;
+ bool found;
+};
+#define WALK_COUNT 10
+int test_instances_walk_cb(const char *name, void *data)
+{
+ struct test_walk_instance *instances = (struct test_walk_instance *)data;
+ int i;
+
+ CU_TEST(instances != NULL);
+ CU_TEST(name != NULL);
+
+ for (i = 0; i < WALK_COUNT; i++) {
+ if (!strcmp(name,
+ tracefs_instance_get_name(instances[i].instance))) {
+ instances[i].found = true;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static void test_instances_walk(void)
+{
+ struct test_walk_instance instances[WALK_COUNT];
+ int i;
+
+ memset(instances, 0, WALK_COUNT * sizeof(struct test_walk_instance));
+ for (i = 0; i < WALK_COUNT; i++) {
+ instances[i].instance = tracefs_instance_create(get_rand_str());
+ CU_TEST(instances[i].instance != NULL);
+ }
+
+ CU_TEST(tracefs_instances_walk(test_instances_walk_cb, instances) == 0);
+ for (i = 0; i < WALK_COUNT; i++) {
+ CU_TEST(instances[i].found);
+ tracefs_instance_destroy(instances[i].instance);
+ instances[i].found = false;
+ }
+
+ CU_TEST(tracefs_instances_walk(test_instances_walk_cb, instances) == 0);
+ for (i = 0; i < WALK_COUNT; i++) {
+ CU_TEST(!instances[i].found);
+ tracefs_instance_free(instances[i].instance);
+ }
+}
+
+static void current_clock_check(const char *clock)
+{
+ int size = 0;
+ char *clocks;
+ char *str;
+
+ clocks = tracefs_instance_file_read(test_instance, "trace_clock", &size);
+ CU_TEST(clocks != NULL);
+ CU_TEST(size > strlen(clock));
+ str = strstr(clocks, clock);
+ CU_TEST(str != NULL);
+ CU_TEST(str != clocks);
+ CU_TEST(*(str - 1) == '[');
+ CU_TEST(*(str + strlen(clock)) == ']');
+ free(clocks);
+}
+
+static void test_get_clock(void)
+{
+ const char *clock;
+
+ clock = tracefs_get_clock(test_instance);
+ CU_TEST(clock != NULL);
+ current_clock_check(clock);
+ free((char *)clock);
+}
+
+static int test_suite_destroy(void)
+{
+ tracefs_instance_destroy(test_instance);
+ tracefs_instance_free(test_instance);
+ tep_free(test_tep);
+ return 0;
+}
+
+static int test_suite_init(void)
+{
+ const char *systems[] = {"ftrace", NULL};
+
+ test_tep = tracefs_local_events_system(NULL, systems);
+ if (test_tep == NULL)
+ return 1;
+ test_instance = tracefs_instance_create(TEST_INSTANCE_NAME);
+ if (!test_instance)
+ return 1;
+
+ return 0;
+}
+
+void test_tracefs_lib(void)
+{
+ CU_pSuite suite = NULL;
+
+ suite = CU_add_suite(TRACEFS_SUITE, test_suite_init, test_suite_destroy);
+ if (suite == NULL) {
+ fprintf(stderr, "Suite \"%s\" cannot be ceated\n", TRACEFS_SUITE);
+ return;
+ }
+ CU_add_test(suite, "tracing file / directory APIs",
+ test_trace_file);
+ CU_add_test(suite, "instance file / directory APIs",
+ test_instance_file);
+ CU_add_test(suite, "systems and events APIs",
+ test_system_event);
+ CU_add_test(suite, "tracefs_iterate_raw_events API",
+ test_iter_raw_events);
+ CU_add_test(suite, "tracefs_tracers API",
+ test_tracers);
+ CU_add_test(suite, "tracefs_local events API",
+ test_local_events);
+ CU_add_test(suite, "tracefs_instances_walk API",
+ test_instances_walk);
+ CU_add_test(suite, "tracefs_get_clock API",
+ test_get_clock);
+}