xref: /aosp_15_r20/external/trace-cmd/utest/tracefs-utest.c (revision 58e6ee5f017f6a8912852c892d18457e4bafb554)
1 // SPDX-License-Identifier: LGPL-2.1
2 /*
3  * Copyright (C) 2020, VMware, Tzvetomir Stoyanov <[email protected]>
4  *
5  */
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <sys/stat.h>
9 #include <fcntl.h>
10 #include <unistd.h>
11 #include <time.h>
12 #include <dirent.h>
13 
14 #include <CUnit/CUnit.h>
15 #include <CUnit/Basic.h>
16 
17 #include "tracefs.h"
18 
19 #define TRACEFS_SUITE		"trasefs library"
20 #define TEST_INSTANCE_NAME	"cunit_test_iter"
21 #define TEST_ARRAY_SIZE		500
22 
23 static struct tracefs_instance *test_instance;
24 static struct tep_handle *test_tep;
25 struct test_sample {
26 	int cpu;
27 	int value;
28 };
29 static struct test_sample test_array[TEST_ARRAY_SIZE];
30 static int test_found;
31 
test_callback(struct tep_event * event,struct tep_record * record,int cpu,void * context)32 static int test_callback(struct tep_event *event, struct tep_record *record,
33 			  int cpu, void *context)
34 {
35 	struct tep_format_field *field;
36 	struct test_sample *sample;
37 	int *cpu_test = (int *)context;
38 	int i;
39 
40 	if (cpu_test && *cpu_test >= 0 && *cpu_test != cpu)
41 		return 0;
42 	field = tep_find_field(event, "buf");
43 	if (field) {
44 		sample = ((struct test_sample *)(record->data + field->offset));
45 		for (i = 0; i < TEST_ARRAY_SIZE; i++) {
46 			if (test_array[i].value == sample->value &&
47 			    test_array[i].cpu == cpu) {
48 				test_array[i].value = 0;
49 				test_found++;
50 				break;
51 			}
52 		}
53 	}
54 
55 	return 0;
56 }
57 
test_iter_write(void)58 static void test_iter_write(void)
59 {
60 	int cpus = sysconf(_SC_NPROCESSORS_CONF);
61 	cpu_set_t *cpuset, *cpusave;
62 	int cpu_size;
63 	char *path;
64 	int i, fd;
65 	int ret;
66 	cpuset = CPU_ALLOC(cpus);
67 	cpusave = CPU_ALLOC(cpus);
68 	cpu_size = CPU_ALLOC_SIZE(cpus);
69 	CPU_ZERO_S(cpu_size, cpuset);
70 
71 	sched_getaffinity(0, cpu_size, cpusave);
72 
73 	path = tracefs_instance_get_file(test_instance, "trace_marker");
74 	CU_TEST(path != NULL);
75 	fd = open(path, O_WRONLY);
76 	tracefs_put_tracing_file(path);
77 	CU_TEST(fd >= 0);
78 
79 	for (i = 0; i < TEST_ARRAY_SIZE; i++) {
80 		test_array[i].cpu = rand() % cpus;
81 		test_array[i].value = random();
82 		if (!test_array[i].value)
83 			test_array[i].value++;
84 		CU_TEST(test_array[i].cpu < cpus);
85 		CPU_ZERO_S(cpu_size, cpuset);
86 		CPU_SET(test_array[i].cpu, cpuset);
87 		sched_setaffinity(0, cpu_size, cpuset);
88 		ret = write(fd, test_array + i, sizeof(struct test_sample));
89 		CU_TEST(ret == sizeof(struct test_sample));
90 	}
91 
92 	sched_setaffinity(0, cpu_size, cpusave);
93 	close(fd);
94 }
95 
96 
iter_raw_events_on_cpu(int cpu)97 static void iter_raw_events_on_cpu(int cpu)
98 {
99 	int check = 0;
100 	int ret;
101 	int i;
102 
103 	test_found = 0;
104 	test_iter_write();
105 	ret = tracefs_iterate_raw_events(test_tep, test_instance, NULL, 0,
106 					 test_callback, &cpu);
107 	CU_TEST(ret == 0);
108 	if (cpu < 0) {
109 		CU_TEST(test_found == TEST_ARRAY_SIZE);
110 	} else {
111 		for (i = 0; i < TEST_ARRAY_SIZE; i++) {
112 			if (test_array[i].cpu == cpu) {
113 				check++;
114 				CU_TEST(test_array[i].value == 0)
115 			} else {
116 				CU_TEST(test_array[i].value != 0)
117 			}
118 		}
119 		CU_TEST(test_found == check);
120 	}
121 }
122 
test_iter_raw_events(void)123 static void test_iter_raw_events(void)
124 {
125 	int cpus = sysconf(_SC_NPROCESSORS_CONF);
126 	int ret;
127 	int i;
128 
129 	ret = tracefs_iterate_raw_events(NULL, test_instance, NULL, 0, test_callback, NULL);
130 	CU_TEST(ret < 0);
131 	ret = tracefs_iterate_raw_events(test_tep, NULL, NULL, 0, test_callback, NULL);
132 	CU_TEST(ret == 0);
133 	ret = tracefs_iterate_raw_events(test_tep, test_instance, NULL, 0, NULL, NULL);
134 	CU_TEST(ret < 0);
135 
136 	iter_raw_events_on_cpu(-1);
137 	for (i = 0; i < cpus; i++)
138 		iter_raw_events_on_cpu(i);
139 }
140 
141 #define RAND_STR_SIZE 20
142 #define RAND_ASCII "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
get_rand_str()143 static const char *get_rand_str()
144 {
145 	static char str[RAND_STR_SIZE];
146 	static char sym[] = RAND_ASCII;
147 	struct timespec clk;
148 	int i;
149 
150 	clock_gettime(CLOCK_REALTIME, &clk);
151 	srand(clk.tv_nsec);
152 	for (i = 0; i < RAND_STR_SIZE; i++)
153 		str[i] = sym[rand() % (sizeof(sym) - 1)];
154 
155 	str[RAND_STR_SIZE - 1] = 0;
156 	return str;
157 }
158 
test_trace_file(void)159 static void test_trace_file(void)
160 {
161 	const char *tmp = get_rand_str();
162 	const char *tdir;
163 	struct stat st;
164 	char *file;
165 
166 	tdir  = tracefs_tracing_dir();
167 	CU_TEST(tdir != NULL);
168 	CU_TEST(stat(tdir, &st) == 0);
169 	CU_TEST(S_ISDIR(st.st_mode));
170 
171 	file = tracefs_get_tracing_file(NULL);
172 	CU_TEST(file == NULL);
173 	file = tracefs_get_tracing_file(tmp);
174 	CU_TEST(file != NULL);
175 	CU_TEST(stat(file, &st) != 0);
176 	tracefs_put_tracing_file(file);
177 
178 	file = tracefs_get_tracing_file("trace");
179 	CU_TEST(file != NULL);
180 	CU_TEST(stat(file, &st) == 0);
181 	tracefs_put_tracing_file(file);
182 }
183 
test_instance_file_read(struct tracefs_instance * inst,char * fname)184 static void test_instance_file_read(struct tracefs_instance *inst, char *fname)
185 {
186 	const char *tdir  = tracefs_tracing_dir();
187 	char buf[BUFSIZ];
188 	char *fpath;
189 	char *file;
190 	size_t fsize = 0;
191 	int size = 0;
192 	int fd;
193 
194 	if (inst) {
195 		CU_TEST(asprintf(&fpath, "%s/instances/%s/%s",
196 			tdir, tracefs_instance_get_name(inst), fname) > 0);
197 	} else {
198 		CU_TEST(asprintf(&fpath, "%s/%s", tdir, fname) > 0);
199 	}
200 
201 	memset(buf, 0, BUFSIZ);
202 	fd = open(fpath, O_RDONLY);
203 	CU_TEST(fd >= 0);
204 	fsize = read(fd, buf, BUFSIZ);
205 	CU_TEST(fsize >= 0);
206 	close(fd);
207 	buf[BUFSIZ - 1] = 0;
208 
209 	file = tracefs_instance_file_read(inst, fname, &size);
210 	CU_TEST(file != NULL);
211 	CU_TEST(size == fsize);
212 	CU_TEST(strcmp(file, buf) == 0);
213 
214 	free(fpath);
215 	free(file);
216 }
217 
218 #define ALL_TRACERS	"available_tracers"
219 #define CUR_TRACER	"current_tracer"
220 #define PER_CPU		"per_cpu"
test_instance_file(void)221 static void test_instance_file(void)
222 {
223 	struct tracefs_instance *instance = NULL;
224 	struct tracefs_instance *second = NULL;
225 	const char *name = get_rand_str();
226 	const char *inst_name = NULL;
227 	const char *tdir;
228 	char *inst_file;
229 	char *inst_dir;
230 	struct stat st;
231 	char *fname;
232 	char *file1;
233 	char *file2;
234 	char *tracer;
235 	int size;
236 	int ret;
237 
238 	tdir  = tracefs_tracing_dir();
239 	CU_TEST(tdir != NULL);
240 	CU_TEST(asprintf(&inst_dir, "%s/instances/%s", tdir, name) > 0);
241 	CU_TEST(stat(inst_dir, &st) != 0);
242 
243 	CU_TEST(tracefs_instance_exists(name) == false);
244 	instance = tracefs_instance_create(name);
245 	CU_TEST(instance != NULL);
246 	CU_TEST(tracefs_instance_is_new(instance));
247 	second = tracefs_instance_create(name);
248 	CU_TEST(second != NULL);
249 	CU_TEST(!tracefs_instance_is_new(second));
250 	tracefs_instance_free(second);
251 	CU_TEST(tracefs_instance_exists(name) == true);
252 	CU_TEST(stat(inst_dir, &st) == 0);
253 	CU_TEST(S_ISDIR(st.st_mode));
254 	inst_name = tracefs_instance_get_name(instance);
255 	CU_TEST(inst_name != NULL);
256 	CU_TEST(strcmp(inst_name, name) == 0);
257 
258 	fname = tracefs_instance_get_dir(NULL);
259 	CU_TEST(fname != NULL);
260 	CU_TEST(strcmp(fname, tdir) == 0);
261 	free(fname);
262 
263 	fname = tracefs_instance_get_dir(instance);
264 	CU_TEST(fname != NULL);
265 	CU_TEST(strcmp(fname, inst_dir) == 0);
266 	free(fname);
267 
268 	CU_TEST(asprintf(&fname, "%s/"ALL_TRACERS, tdir) > 0);
269 	CU_TEST(fname != NULL);
270 	inst_file = tracefs_instance_get_file(NULL, ALL_TRACERS);
271 	CU_TEST(inst_file != NULL);
272 	CU_TEST(strcmp(fname, inst_file) == 0);
273 	tracefs_put_tracing_file(inst_file);
274 	free(fname);
275 
276 	CU_TEST(asprintf(&fname, "%s/instances/%s/"ALL_TRACERS, tdir, name) > 0);
277 	CU_TEST(fname != NULL);
278 	CU_TEST(stat(fname, &st) == 0);
279 	inst_file = tracefs_instance_get_file(instance, ALL_TRACERS);
280 	CU_TEST(inst_file != NULL);
281 	CU_TEST(strcmp(fname, inst_file) == 0);
282 
283 	test_instance_file_read(NULL, ALL_TRACERS);
284 	test_instance_file_read(instance, ALL_TRACERS);
285 
286 	file1 = tracefs_instance_file_read(instance, ALL_TRACERS, NULL);
287 	CU_TEST(file1 != NULL);
288 	tracer = strtok(file1, " ");
289 	CU_TEST(tracer != NULL);
290 	ret = tracefs_instance_file_write(instance, CUR_TRACER, tracer);
291 	CU_TEST(ret == strlen(tracer));
292 	file2 = tracefs_instance_file_read(instance, CUR_TRACER, &size);
293 	CU_TEST(file2 != NULL);
294 	CU_TEST(size >= strlen(tracer));
295 	CU_TEST(strncmp(file2, tracer, strlen(tracer)) == 0);
296 	free(file1);
297 	free(file2);
298 
299 	tracefs_put_tracing_file(inst_file);
300 	free(fname);
301 
302 	CU_TEST(tracefs_file_exists(NULL, (char *)name) == false);
303 	CU_TEST(tracefs_dir_exists(NULL, (char *)name) == false);
304 	CU_TEST(tracefs_file_exists(instance, (char *)name) == false);
305 	CU_TEST(tracefs_dir_exists(instance, (char *)name) == false);
306 
307 	CU_TEST(tracefs_file_exists(NULL, CUR_TRACER) == true);
308 	CU_TEST(tracefs_dir_exists(NULL, CUR_TRACER) == false);
309 	CU_TEST(tracefs_file_exists(instance, CUR_TRACER) == true);
310 	CU_TEST(tracefs_dir_exists(instance, CUR_TRACER) == false);
311 
312 	CU_TEST(tracefs_file_exists(NULL, PER_CPU) == false);
313 	CU_TEST(tracefs_dir_exists(NULL, PER_CPU) == true);
314 	CU_TEST(tracefs_file_exists(instance, PER_CPU) == false);
315 	CU_TEST(tracefs_dir_exists(instance, PER_CPU) == true);
316 
317 	CU_TEST(tracefs_instance_destroy(NULL) != 0);
318 	CU_TEST(tracefs_instance_destroy(instance) == 0);
319 	CU_TEST(tracefs_instance_destroy(instance) != 0);
320 	tracefs_instance_free(instance);
321 	CU_TEST(stat(inst_dir, &st) != 0);
322 	free(inst_dir);
323 }
324 
exclude_string(char ** strings,char * name)325 static void exclude_string(char **strings, char *name)
326 {
327 	int i;
328 
329 	for (i = 0; strings[i]; i++) {
330 		if (strcmp(strings[i], name) == 0) {
331 			free(strings[i]);
332 			strings[i] = strdup("/");
333 			return;
334 		}
335 	}
336 }
337 
test_check_files(const char * fdir,char ** files)338 static void test_check_files(const char *fdir, char **files)
339 {
340 	struct dirent *dent;
341 	DIR *dir;
342 	int i;
343 
344 	dir = opendir(fdir);
345 	CU_TEST(dir != NULL);
346 
347 	while ((dent = readdir(dir)))
348 		exclude_string(files, dent->d_name);
349 
350 	closedir(dir);
351 
352 	for (i = 0; files[i]; i++)
353 		CU_TEST(files[i][0] == '/');
354 }
355 
test_system_event(void)356 static void test_system_event(void)
357 {
358 	const char *tdir;
359 	char **systems;
360 	char **events;
361 	char *sdir = NULL;
362 
363 	tdir  = tracefs_tracing_dir();
364 	CU_TEST(tdir != NULL);
365 
366 	systems = tracefs_event_systems(tdir);
367 	CU_TEST(systems != NULL);
368 
369 	events = tracefs_system_events(tdir, systems[0]);
370 	CU_TEST(events != NULL);
371 
372 	asprintf(&sdir, "%s/events/%s", tdir, systems[0]);
373 	CU_TEST(sdir != NULL);
374 	test_check_files(sdir, events);
375 	free(sdir);
376 	sdir = NULL;
377 
378 	asprintf(&sdir, "%s/events", tdir);
379 	CU_TEST(sdir != NULL);
380 	test_check_files(sdir, systems);
381 
382 	tracefs_list_free(systems);
383 	tracefs_list_free(events);
384 
385 	free(sdir);
386 }
387 
test_tracers(void)388 static void test_tracers(void)
389 {
390 	const char *tdir;
391 	char **tracers;
392 	char *tfile;
393 	char *tracer;
394 	int i;
395 
396 	tdir  = tracefs_tracing_dir();
397 	CU_TEST(tdir != NULL);
398 
399 	tracers = tracefs_tracers(tdir);
400 	CU_TEST(tracers != NULL);
401 
402 	tfile = tracefs_instance_file_read(NULL, ALL_TRACERS, NULL);
403 
404 	tracer = strtok(tfile, " ");
405 	while (tracer) {
406 		exclude_string(tracers, tracer);
407 		tracer = strtok(NULL, " ");
408 	}
409 
410 	for (i = 0; tracers[i]; i++)
411 		CU_TEST(tracers[i][0] == '/');
412 
413 	tracefs_list_free(tracers);
414 	free(tfile);
415 }
416 
test_check_events(struct tep_handle * tep,char * system,bool exist)417 static void test_check_events(struct tep_handle *tep, char *system, bool exist)
418 {
419 	struct dirent *dent;
420 	char file[PATH_MAX];
421 	char buf[1024];
422 	char *edir = NULL;
423 	const char *tdir;
424 	DIR *dir;
425 	int fd;
426 
427 	tdir  = tracefs_tracing_dir();
428 	CU_TEST(tdir != NULL);
429 
430 	asprintf(&edir, "%s/events/%s", tdir, system);
431 	dir = opendir(edir);
432 	CU_TEST(dir != NULL);
433 
434 	while ((dent = readdir(dir))) {
435 		if (dent->d_name[0] == '.')
436 			continue;
437 		sprintf(file, "%s/%s/id", edir, dent->d_name);
438 		fd = open(file, O_RDONLY);
439 		if (fd < 0)
440 			continue;
441 		CU_TEST(read(fd, buf, 1024) > 0);
442 		if (exist) {
443 			CU_TEST(tep_find_event(tep, atoi(buf)) != NULL);
444 		} else {
445 			CU_TEST(tep_find_event(tep, atoi(buf)) == NULL);
446 		}
447 
448 		close(fd);
449 	}
450 
451 	closedir(dir);
452 	free(edir);
453 
454 }
455 
test_local_events(void)456 static void test_local_events(void)
457 {
458 	struct tep_handle *tep;
459 	const char *tdir;
460 	char **systems;
461 	char *lsystems[3];
462 	int i;
463 
464 	tdir  = tracefs_tracing_dir();
465 	CU_TEST(tdir != NULL);
466 
467 	tep = tracefs_local_events(tdir);
468 	CU_TEST(tep != NULL);
469 
470 	systems = tracefs_event_systems(tdir);
471 	CU_TEST(systems != NULL);
472 
473 	for (i = 0; systems[i]; i++)
474 		test_check_events(tep, systems[i], true);
475 	tep_free(tep);
476 
477 	memset(lsystems, 0, sizeof(lsystems));
478 	for (i = 0; systems[i]; i++) {
479 		if (!lsystems[0])
480 			lsystems[0] = systems[i];
481 		else if (!lsystems[2])
482 			lsystems[2] = systems[i];
483 		else
484 			break;
485 	}
486 
487 	if (lsystems[0] && lsystems[2]) {
488 		tep = tracefs_local_events_system(tdir,
489 						  (const char * const *)lsystems);
490 		CU_TEST(tep != NULL);
491 		test_check_events(tep, lsystems[0], true);
492 		test_check_events(tep, lsystems[2], false);
493 	}
494 	tep_free(tep);
495 
496 	tep = tep_alloc();
497 	CU_TEST(tep != NULL);
498 	CU_TEST(tracefs_fill_local_events(tdir, tep, NULL) == 0);
499 	for (i = 0; systems[i]; i++)
500 		test_check_events(tep, systems[i], true);
501 
502 	tep_free(tep);
503 
504 	tracefs_list_free(systems);
505 }
506 
507 struct test_walk_instance {
508 	struct tracefs_instance *instance;
509 	bool found;
510 };
511 #define WALK_COUNT 10
test_instances_walk_cb(const char * name,void * data)512 int test_instances_walk_cb(const char *name, void *data)
513 {
514 	struct test_walk_instance *instances  = (struct test_walk_instance *)data;
515 	int i;
516 
517 	CU_TEST(instances != NULL);
518 	CU_TEST(name != NULL);
519 
520 	for (i = 0; i < WALK_COUNT; i++) {
521 		if (!strcmp(name,
522 			    tracefs_instance_get_name(instances[i].instance))) {
523 			instances[i].found = true;
524 			break;
525 		}
526 	}
527 
528 	return 0;
529 }
530 
test_instances_walk(void)531 static void test_instances_walk(void)
532 {
533 	struct test_walk_instance instances[WALK_COUNT];
534 	int i;
535 
536 	memset(instances, 0, WALK_COUNT * sizeof(struct test_walk_instance));
537 	for (i = 0; i < WALK_COUNT; i++) {
538 		instances[i].instance = tracefs_instance_create(get_rand_str());
539 		CU_TEST(instances[i].instance != NULL);
540 	}
541 
542 	CU_TEST(tracefs_instances_walk(test_instances_walk_cb, instances) == 0);
543 	for (i = 0; i < WALK_COUNT; i++) {
544 		CU_TEST(instances[i].found);
545 		tracefs_instance_destroy(instances[i].instance);
546 		instances[i].found = false;
547 	}
548 
549 	CU_TEST(tracefs_instances_walk(test_instances_walk_cb, instances) == 0);
550 	for (i = 0; i < WALK_COUNT; i++) {
551 		CU_TEST(!instances[i].found);
552 		tracefs_instance_free(instances[i].instance);
553 	}
554 }
555 
current_clock_check(const char * clock)556 static void current_clock_check(const char *clock)
557 {
558 	int size = 0;
559 	char *clocks;
560 	char *str;
561 
562 	clocks = tracefs_instance_file_read(test_instance, "trace_clock", &size);
563 	CU_TEST(clocks != NULL);
564 	CU_TEST(size > strlen(clock));
565 	str = strstr(clocks, clock);
566 	CU_TEST(str != NULL);
567 	CU_TEST(str != clocks);
568 	CU_TEST(*(str - 1) == '[');
569 	CU_TEST(*(str + strlen(clock)) == ']');
570 	free(clocks);
571 }
572 
test_get_clock(void)573 static void test_get_clock(void)
574 {
575 	const char *clock;
576 
577 	clock = tracefs_get_clock(test_instance);
578 	CU_TEST(clock != NULL);
579 	current_clock_check(clock);
580 	free((char *)clock);
581 }
582 
test_suite_destroy(void)583 static int test_suite_destroy(void)
584 {
585 	tracefs_instance_destroy(test_instance);
586 	tracefs_instance_free(test_instance);
587 	tep_free(test_tep);
588 	return 0;
589 }
590 
test_suite_init(void)591 static int test_suite_init(void)
592 {
593 	const char *systems[] = {"ftrace", NULL};
594 
595 	test_tep = tracefs_local_events_system(NULL, systems);
596 	if (test_tep == NULL)
597 		return 1;
598 	test_instance = tracefs_instance_create(TEST_INSTANCE_NAME);
599 	if (!test_instance)
600 		return 1;
601 
602 	return 0;
603 }
604 
test_tracefs_lib(void)605 void test_tracefs_lib(void)
606 {
607 	CU_pSuite suite = NULL;
608 
609 	suite = CU_add_suite(TRACEFS_SUITE, test_suite_init, test_suite_destroy);
610 	if (suite == NULL) {
611 		fprintf(stderr, "Suite \"%s\" cannot be ceated\n", TRACEFS_SUITE);
612 		return;
613 	}
614 	CU_add_test(suite, "tracing file / directory APIs",
615 		    test_trace_file);
616 	CU_add_test(suite, "instance file / directory APIs",
617 		    test_instance_file);
618 	CU_add_test(suite, "systems and events APIs",
619 		    test_system_event);
620 	CU_add_test(suite, "tracefs_iterate_raw_events API",
621 		    test_iter_raw_events);
622 	CU_add_test(suite, "tracefs_tracers API",
623 		    test_tracers);
624 	CU_add_test(suite, "tracefs_local events API",
625 		    test_local_events);
626 	CU_add_test(suite, "tracefs_instances_walk API",
627 		    test_instances_walk);
628 	CU_add_test(suite, "tracefs_get_clock API",
629 		    test_get_clock);
630 }
631