1193323Sed// SPDX-License-Identifier: GPL-2.0
2193323Sed/*
3193323Sed * Test module for in-kernel synthetic event creation and generation.
4193323Sed *
5193323Sed * Copyright (C) 2019 Tom Zanussi <zanussi@kernel.org>
6193323Sed */
7193323Sed
8193323Sed#include <linux/module.h>
9193323Sed#include <linux/trace_events.h>
10193323Sed
11193323Sed/*
12193323Sed * This module is a simple test of basic functionality for in-kernel
13193323Sed * synthetic event creation and generation, the first and second tests
14193323Sed * using synth_event_gen_cmd_start() and synth_event_add_field(), the
15193323Sed * third uses synth_event_create() to do it all at once with a static
16193323Sed * field array.
17193323Sed *
18218893Sdim * Following that are a few examples using the created events to test
19193323Sed * various ways of tracing a synthetic event.
20193323Sed *
21193323Sed * To test, select CONFIG_SYNTH_EVENT_GEN_TEST and build the module.
22224145Sdim * Then:
23193323Sed *
24198090Srdivacky * # insmod kernel/trace/synth_event_gen_test.ko
25193323Sed * # cat /sys/kernel/tracing/trace
26193323Sed *
27193323Sed * You should see several events in the trace buffer -
28224145Sdim * "create_synth_test", "empty_synth_test", and several instances of
29224145Sdim * "gen_synth_test".
30224145Sdim *
31224145Sdim * To remove the events, remove the module:
32224145Sdim *
33224145Sdim * # rmmod synth_event_gen_test
34193323Sed *
35193323Sed */
36193323Sed
37193323Sedstatic struct trace_event_file *create_synth_test;
38193323Sedstatic struct trace_event_file *empty_synth_test;
39193323Sedstatic struct trace_event_file *gen_synth_test;
40224145Sdim
41224145Sdim/*
42224145Sdim * Test to make sure we can create a synthetic event, then add more
43193323Sed * fields.
44193323Sed */
45193323Sedstatic int __init test_gen_synth_cmd(void)
46193323Sed{
47218893Sdim	struct dynevent_cmd cmd;
48224145Sdim	u64 vals[7];
49218893Sdim	char *buf;
50218893Sdim	int ret;
51218893Sdim
52218893Sdim	/* Create a buffer to hold the generated command */
53193323Sed	buf = kzalloc(MAX_DYNEVENT_CMD_LEN, GFP_KERNEL);
54193323Sed	if (!buf)
55193323Sed		return -ENOMEM;
56193323Sed
57193323Sed	/* Before generating the command, initialize the cmd object */
58193323Sed	synth_event_cmd_init(&cmd, buf, MAX_DYNEVENT_CMD_LEN);
59202375Srdivacky
60193323Sed	/*
61193323Sed	 * Create the empty gen_synth_test synthetic event with the
62193323Sed	 * first 4 fields.
63193323Sed	 */
64193323Sed	ret = synth_event_gen_cmd_start(&cmd, "gen_synth_test", THIS_MODULE,
65193323Sed					"pid_t", "next_pid_field",
66193323Sed					"char[16]", "next_comm_field",
67193323Sed					"u64", "ts_ns",
68193323Sed					"u64", "ts_ms");
69193323Sed	if (ret)
70193323Sed		goto free;
71193323Sed
72193323Sed	/* Use synth_event_add_field to add the rest of the fields */
73193323Sed
74193323Sed	ret = synth_event_add_field(&cmd, "unsigned int", "cpu");
75193323Sed	if (ret)
76193323Sed		goto free;
77193323Sed
78198090Srdivacky	ret = synth_event_add_field(&cmd, "char[64]", "my_string_field");
79202375Srdivacky	if (ret)
80198090Srdivacky		goto free;
81202375Srdivacky
82198090Srdivacky	ret = synth_event_add_field(&cmd, "int", "my_int_field");
83193323Sed	if (ret)
84193323Sed		goto free;
85193323Sed
86193323Sed	ret = synth_event_gen_cmd_end(&cmd);
87193323Sed	if (ret)
88218893Sdim		goto free;
89193323Sed
90193323Sed	/*
91193323Sed	 * Now get the gen_synth_test event file.  We need to prevent
92193323Sed	 * the instance and event from disappearing from underneath
93218893Sdim	 * us, which trace_get_event_file() does (though in this case
94193323Sed	 * we're using the top-level instance which never goes away).
95193323Sed	 */
96193323Sed	gen_synth_test = trace_get_event_file(NULL, "synthetic",
97193323Sed					      "gen_synth_test");
98193323Sed	if (IS_ERR(gen_synth_test)) {
99193323Sed		ret = PTR_ERR(gen_synth_test);
100198090Srdivacky		goto delete;
101198090Srdivacky	}
102193323Sed
103193323Sed	/* Enable the event or you won't see anything */
104193323Sed	ret = trace_array_set_clr_event(gen_synth_test->tr,
105198090Srdivacky					"synthetic", "gen_synth_test", true);
106198090Srdivacky	if (ret) {
107193323Sed		trace_put_event_file(gen_synth_test);
108198090Srdivacky		goto delete;
109198090Srdivacky	}
110198090Srdivacky
111193323Sed	/* Create some bogus values just for testing */
112198090Srdivacky
113193323Sed	vals[0] = 777;			/* next_pid_field */
114193323Sed	vals[1] = (u64)(long)"hula hoops";	/* next_comm_field */
115193323Sed	vals[2] = 1000000;		/* ts_ns */
116193323Sed	vals[3] = 1000;			/* ts_ms */
117193323Sed	vals[4] = raw_smp_processor_id(); /* cpu */
118193323Sed	vals[5] = (u64)(long)"thneed";	/* my_string_field */
119218893Sdim	vals[6] = 598;			/* my_int_field */
120193323Sed
121193323Sed	/* Now generate a gen_synth_test event */
122193323Sed	ret = synth_event_trace_array(gen_synth_test, vals, ARRAY_SIZE(vals));
123193323Sed free:
124193323Sed	kfree(buf);
125193323Sed	return ret;
126193323Sed delete:
127193323Sed	/* We got an error after creating the event, delete it */
128193323Sed	synth_event_delete("gen_synth_test");
129193323Sed	goto free;
130193323Sed}
131193323Sed
132193323Sed/*
133193323Sed * Test to make sure we can create an initially empty synthetic event,
134193323Sed * then add all the fields.
135193323Sed */
136193323Sedstatic int __init test_empty_synth_event(void)
137193323Sed{
138193323Sed	struct dynevent_cmd cmd;
139193323Sed	u64 vals[7];
140193323Sed	char *buf;
141193323Sed	int ret;
142193323Sed
143193323Sed	/* Create a buffer to hold the generated command */
144193323Sed	buf = kzalloc(MAX_DYNEVENT_CMD_LEN, GFP_KERNEL);
145193323Sed	if (!buf)
146198090Srdivacky		return -ENOMEM;
147198090Srdivacky
148193323Sed	/* Before generating the command, initialize the cmd object */
149193323Sed	synth_event_cmd_init(&cmd, buf, MAX_DYNEVENT_CMD_LEN);
150193323Sed
151198090Srdivacky	/*
152198090Srdivacky	 * Create the empty_synth_test synthetic event with no fields.
153193323Sed	 */
154198090Srdivacky	ret = synth_event_gen_cmd_start(&cmd, "empty_synth_test", THIS_MODULE);
155198090Srdivacky	if (ret)
156198090Srdivacky		goto free;
157193323Sed
158198090Srdivacky	/* Use synth_event_add_field to add all of the fields */
159193323Sed
160193323Sed	ret = synth_event_add_field(&cmd, "pid_t", "next_pid_field");
161193323Sed	if (ret)
162193323Sed		goto free;
163193323Sed
164193323Sed	ret = synth_event_add_field(&cmd, "char[16]", "next_comm_field");
165193323Sed	if (ret)
166193323Sed		goto free;
167193323Sed
168193323Sed	ret = synth_event_add_field(&cmd, "u64", "ts_ns");
169193323Sed	if (ret)
170193323Sed		goto free;
171193323Sed
172193323Sed	ret = synth_event_add_field(&cmd, "u64", "ts_ms");
173193323Sed	if (ret)
174193323Sed		goto free;
175193323Sed
176193323Sed	ret = synth_event_add_field(&cmd, "unsigned int", "cpu");
177193323Sed	if (ret)
178193323Sed		goto free;
179193323Sed
180193323Sed	ret = synth_event_add_field(&cmd, "char[64]", "my_string_field");
181193323Sed	if (ret)
182193323Sed		goto free;
183193323Sed
184193323Sed	ret = synth_event_add_field(&cmd, "int", "my_int_field");
185193323Sed	if (ret)
186193323Sed		goto free;
187193323Sed
188193323Sed	/* All fields have been added, close and register the synth event */
189193323Sed
190193323Sed	ret = synth_event_gen_cmd_end(&cmd);
191193323Sed	if (ret)
192193323Sed		goto free;
193193323Sed
194193323Sed	/*
195193323Sed	 * Now get the empty_synth_test event file.  We need to
196193323Sed	 * prevent the instance and event from disappearing from
197193323Sed	 * underneath us, which trace_get_event_file() does (though in
198193323Sed	 * this case we're using the top-level instance which never
199193323Sed	 * goes away).
200193323Sed	 */
201193323Sed	empty_synth_test = trace_get_event_file(NULL, "synthetic",
202199989Srdivacky						"empty_synth_test");
203199989Srdivacky	if (IS_ERR(empty_synth_test)) {
204193323Sed		ret = PTR_ERR(empty_synth_test);
205193323Sed		goto delete;
206193323Sed	}
207193323Sed
208193323Sed	/* Enable the event or you won't see anything */
209193323Sed	ret = trace_array_set_clr_event(empty_synth_test->tr,
210193323Sed					"synthetic", "empty_synth_test", true);
211193323Sed	if (ret) {
212193323Sed		trace_put_event_file(empty_synth_test);
213199989Srdivacky		goto delete;
214199989Srdivacky	}
215193323Sed
216193323Sed	/* Create some bogus values just for testing */
217193323Sed
218193323Sed	vals[0] = 777;			/* next_pid_field */
219193323Sed	vals[1] = (u64)(long)"tiddlywinks";	/* next_comm_field */
220193323Sed	vals[2] = 1000000;		/* ts_ns */
221193323Sed	vals[3] = 1000;			/* ts_ms */
222193323Sed	vals[4] = raw_smp_processor_id(); /* cpu */
223199989Srdivacky	vals[5] = (u64)(long)"thneed_2.0";	/* my_string_field */
224193323Sed	vals[6] = 399;			/* my_int_field */
225193323Sed
226193323Sed	/* Now trace an empty_synth_test event */
227193323Sed	ret = synth_event_trace_array(empty_synth_test, vals, ARRAY_SIZE(vals));
228193323Sed free:
229193323Sed	kfree(buf);
230193323Sed	return ret;
231193323Sed delete:
232193323Sed	/* We got an error after creating the event, delete it */
233193323Sed	synth_event_delete("empty_synth_test");
234193323Sed	goto free;
235193323Sed}
236193323Sed
237193323Sedstatic struct synth_field_desc create_synth_test_fields[] = {
238193323Sed	{ .type = "pid_t",		.name = "next_pid_field" },
239193323Sed	{ .type = "char[16]",		.name = "next_comm_field" },
240193323Sed	{ .type = "u64",		.name = "ts_ns" },
241193323Sed	{ .type = "char[]",		.name = "dynstring_field_1" },
242193323Sed	{ .type = "u64",		.name = "ts_ms" },
243193323Sed	{ .type = "unsigned int",	.name = "cpu" },
244193323Sed	{ .type = "char[64]",		.name = "my_string_field" },
245193323Sed	{ .type = "char[]",		.name = "dynstring_field_2" },
246193323Sed	{ .type = "int",		.name = "my_int_field" },
247193323Sed};
248193323Sed
249193323Sed/*
250193323Sed * Test synthetic event creation all at once from array of field
251193323Sed * descriptors.
252193323Sed */
253193323Sedstatic int __init test_create_synth_event(void)
254193323Sed{
255193323Sed	u64 vals[9];
256199989Srdivacky	int ret;
257193323Sed
258193323Sed	/* Create the create_synth_test event with the fields above */
259193323Sed	ret = synth_event_create("create_synth_test",
260193323Sed				 create_synth_test_fields,
261193323Sed				 ARRAY_SIZE(create_synth_test_fields),
262193323Sed				 THIS_MODULE);
263193323Sed	if (ret)
264193323Sed		goto out;
265193323Sed
266193323Sed	/*
267193323Sed	 * Now get the create_synth_test event file.  We need to
268193323Sed	 * prevent the instance and event from disappearing from
269193323Sed	 * underneath us, which trace_get_event_file() does (though in
270193323Sed	 * this case we're using the top-level instance which never
271193323Sed	 * goes away).
272193323Sed	 */
273193323Sed	create_synth_test = trace_get_event_file(NULL, "synthetic",
274193323Sed						 "create_synth_test");
275193323Sed	if (IS_ERR(create_synth_test)) {
276193323Sed		ret = PTR_ERR(create_synth_test);
277193323Sed		goto delete;
278193323Sed	}
279193323Sed
280193323Sed	/* Enable the event or you won't see anything */
281193323Sed	ret = trace_array_set_clr_event(create_synth_test->tr,
282193323Sed					"synthetic", "create_synth_test", true);
283193323Sed	if (ret) {
284193323Sed		trace_put_event_file(create_synth_test);
285193323Sed		goto delete;
286193323Sed	}
287193323Sed
288193323Sed	/* Create some bogus values just for testing */
289193323Sed
290202375Srdivacky	vals[0] = 777;			/* next_pid_field */
291193323Sed	vals[1] = (u64)(long)"tiddlywinks";	/* next_comm_field */
292193323Sed	vals[2] = 1000000;		/* ts_ns */
293193323Sed	vals[3] = (u64)(long)"xrayspecs";	/* dynstring_field_1 */
294193323Sed	vals[4] = 1000;			/* ts_ms */
295193323Sed	vals[5] = raw_smp_processor_id(); /* cpu */
296193323Sed	vals[6] = (u64)(long)"thneed";	/* my_string_field */
297202375Srdivacky	vals[7] = (u64)(long)"kerplunk";	/* dynstring_field_2 */
298202375Srdivacky	vals[8] = 398;			/* my_int_field */
299218893Sdim
300202375Srdivacky	/* Now generate a create_synth_test event */
301202375Srdivacky	ret = synth_event_trace_array(create_synth_test, vals, ARRAY_SIZE(vals));
302202375Srdivacky out:
303193323Sed	return ret;
304193323Sed delete:
305202375Srdivacky	/* We got an error after creating the event, delete it */
306193323Sed	synth_event_delete("create_synth_test");
307193323Sed
308202375Srdivacky	goto out;
309193323Sed}
310202375Srdivacky
311202375Srdivacky/*
312202375Srdivacky * Test tracing a synthetic event by reserving trace buffer space,
313202375Srdivacky * then filling in fields one after another.
314193323Sed */
315202375Srdivackystatic int __init test_add_next_synth_val(void)
316202375Srdivacky{
317193323Sed	struct synth_event_trace_state trace_state;
318202375Srdivacky	int ret;
319202375Srdivacky
320224145Sdim	/* Start by reserving space in the trace buffer */
321224145Sdim	ret = synth_event_trace_start(gen_synth_test, &trace_state);
322202375Srdivacky	if (ret)
323193323Sed		return ret;
324193323Sed
325193323Sed	/* Write some bogus values into the trace buffer, one after another */
326202375Srdivacky
327193323Sed	/* next_pid_field */
328193323Sed	ret = synth_event_add_next_val(777, &trace_state);
329202375Srdivacky	if (ret)
330193323Sed		goto out;
331202375Srdivacky
332202375Srdivacky	/* next_comm_field */
333202375Srdivacky	ret = synth_event_add_next_val((u64)(long)"slinky", &trace_state);
334202375Srdivacky	if (ret)
335193323Sed		goto out;
336202375Srdivacky
337202375Srdivacky	/* ts_ns */
338193323Sed	ret = synth_event_add_next_val(1000000, &trace_state);
339202375Srdivacky	if (ret)
340202375Srdivacky		goto out;
341202375Srdivacky
342193323Sed	/* ts_ms */
343193323Sed	ret = synth_event_add_next_val(1000, &trace_state);
344202375Srdivacky	if (ret)
345193323Sed		goto out;
346193323Sed
347193323Sed	/* cpu */
348193323Sed	ret = synth_event_add_next_val(raw_smp_processor_id(), &trace_state);
349193323Sed	if (ret)
350193323Sed		goto out;
351193323Sed
352193323Sed	/* my_string_field */
353193323Sed	ret = synth_event_add_next_val((u64)(long)"thneed_2.01", &trace_state);
354193323Sed	if (ret)
355193323Sed		goto out;
356193323Sed
357193323Sed	/* my_int_field */
358193323Sed	ret = synth_event_add_next_val(395, &trace_state);
359193323Sed out:
360193323Sed	/* Finally, commit the event */
361193323Sed	ret = synth_event_trace_end(&trace_state);
362202375Srdivacky
363193323Sed	return ret;
364202375Srdivacky}
365193323Sed
366193323Sed/*
367193323Sed * Test tracing a synthetic event by reserving trace buffer space,
368198892Srdivacky * then filling in fields using field names, which can be done in any
369193323Sed * order.
370193323Sed */
371202375Srdivackystatic int __init test_add_synth_val(void)
372193323Sed{
373202375Srdivacky	struct synth_event_trace_state trace_state;
374193323Sed	int ret;
375193323Sed
376193323Sed	/* Start by reserving space in the trace buffer */
377193323Sed	ret = synth_event_trace_start(gen_synth_test, &trace_state);
378193323Sed	if (ret)
379193323Sed		return ret;
380202375Srdivacky
381193323Sed	/* Write some bogus values into the trace buffer, using field names */
382202375Srdivacky
383193323Sed	ret = synth_event_add_val("ts_ns", 1000000, &trace_state);
384193323Sed	if (ret)
385193323Sed		goto out;
386193323Sed
387193323Sed	ret = synth_event_add_val("ts_ms", 1000, &trace_state);
388202375Srdivacky	if (ret)
389193323Sed		goto out;
390202375Srdivacky
391193323Sed	ret = synth_event_add_val("cpu", raw_smp_processor_id(), &trace_state);
392193323Sed	if (ret)
393193323Sed		goto out;
394193323Sed
395193323Sed	ret = synth_event_add_val("next_pid_field", 777, &trace_state);
396193323Sed	if (ret)
397193323Sed		goto out;
398193323Sed
399193323Sed	ret = synth_event_add_val("next_comm_field", (u64)(long)"silly putty",
400193323Sed				  &trace_state);
401193323Sed	if (ret)
402193323Sed		goto out;
403193323Sed
404210299Sed	ret = synth_event_add_val("my_string_field", (u64)(long)"thneed_9",
405193323Sed				  &trace_state);
406193323Sed	if (ret)
407210299Sed		goto out;
408193323Sed
409193323Sed	ret = synth_event_add_val("my_int_field", 3999, &trace_state);
410210299Sed out:
411210299Sed	/* Finally, commit the event */
412193323Sed	ret = synth_event_trace_end(&trace_state);
413193323Sed
414210299Sed	return ret;
415193323Sed}
416193323Sed
417193323Sed/*
418193323Sed * Test tracing a synthetic event all at once from array of values.
419210299Sed */
420193323Sedstatic int __init test_trace_synth_event(void)
421193323Sed{
422193323Sed	int ret;
423210299Sed
424193323Sed	/* Trace some bogus values just for testing */
425193323Sed	ret = synth_event_trace(create_synth_test, 9,	/* number of values */
426193323Sed				(u64)444,		/* next_pid_field */
427193323Sed				(u64)(long)"clackers",	/* next_comm_field */
428193323Sed				(u64)1000000,		/* ts_ns */
429193323Sed				(u64)(long)"viewmaster",/* dynstring_field_1 */
430193323Sed				(u64)1000,		/* ts_ms */
431193323Sed				(u64)raw_smp_processor_id(), /* cpu */
432193323Sed				(u64)(long)"Thneed",	/* my_string_field */
433193323Sed				(u64)(long)"yoyos",	/* dynstring_field_2 */
434193323Sed				(u64)999);		/* my_int_field */
435193323Sed	return ret;
436193323Sed}
437193323Sed
438193323Sedstatic int __init synth_event_gen_test_init(void)
439193323Sed{
440193323Sed	int ret;
441193323Sed
442193323Sed	ret = test_gen_synth_cmd();
443193323Sed	if (ret)
444193323Sed		return ret;
445193323Sed
446193323Sed	ret = test_empty_synth_event();
447193323Sed	if (ret) {
448193323Sed		WARN_ON(trace_array_set_clr_event(gen_synth_test->tr,
449193323Sed						  "synthetic",
450193323Sed						  "gen_synth_test", false));
451193323Sed		trace_put_event_file(gen_synth_test);
452193323Sed		WARN_ON(synth_event_delete("gen_synth_test"));
453193323Sed		goto out;
454193323Sed	}
455210299Sed
456193323Sed	ret = test_create_synth_event();
457193323Sed	if (ret) {
458193323Sed		WARN_ON(trace_array_set_clr_event(gen_synth_test->tr,
459193323Sed						  "synthetic",
460193323Sed						  "gen_synth_test", false));
461193323Sed		trace_put_event_file(gen_synth_test);
462193323Sed		WARN_ON(synth_event_delete("gen_synth_test"));
463193323Sed
464193323Sed		WARN_ON(trace_array_set_clr_event(empty_synth_test->tr,
465193323Sed						  "synthetic",
466193323Sed						  "empty_synth_test", false));
467193323Sed		trace_put_event_file(empty_synth_test);
468193323Sed		WARN_ON(synth_event_delete("empty_synth_test"));
469193323Sed		goto out;
470193323Sed	}
471193323Sed
472193323Sed	ret = test_add_next_synth_val();
473193323Sed	WARN_ON(ret);
474193323Sed
475193323Sed	ret = test_add_synth_val();
476193323Sed	WARN_ON(ret);
477193323Sed
478193323Sed	ret = test_trace_synth_event();
479193323Sed	WARN_ON(ret);
480210299Sed
481193323Sed	/* Disable when done */
482193323Sed	trace_array_set_clr_event(gen_synth_test->tr,
483193323Sed				  "synthetic",
484193323Sed				  "gen_synth_test", false);
485193323Sed	trace_array_set_clr_event(empty_synth_test->tr,
486193323Sed				  "synthetic",
487221345Sdim				  "empty_synth_test", false);
488193323Sed	trace_array_set_clr_event(create_synth_test->tr,
489193323Sed				  "synthetic",
490193323Sed				  "create_synth_test", false);
491193323Sed out:
492193323Sed	return ret;
493193323Sed}
494193323Sed
495193323Sedstatic void __exit synth_event_gen_test_exit(void)
496193323Sed{
497193323Sed	/* Disable the event or you can't remove it */
498193323Sed	WARN_ON(trace_array_set_clr_event(gen_synth_test->tr,
499193323Sed					  "synthetic",
500193323Sed					  "gen_synth_test", false));
501193323Sed
502193323Sed	/* Now give the file and instance back */
503193323Sed	trace_put_event_file(gen_synth_test);
504193323Sed
505221345Sdim	/* Now unregister and free the synthetic event */
506193323Sed	WARN_ON(synth_event_delete("gen_synth_test"));
507193323Sed
508193323Sed	/* Disable the event or you can't remove it */
509193323Sed	WARN_ON(trace_array_set_clr_event(empty_synth_test->tr,
510193323Sed					  "synthetic",
511193323Sed					  "empty_synth_test", false));
512193323Sed
513193323Sed	/* Now give the file and instance back */
514193323Sed	trace_put_event_file(empty_synth_test);
515193323Sed
516218893Sdim	/* Now unregister and free the synthetic event */
517193323Sed	WARN_ON(synth_event_delete("empty_synth_test"));
518210299Sed
519193323Sed	/* Disable the event or you can't remove it */
520193323Sed	WARN_ON(trace_array_set_clr_event(create_synth_test->tr,
521193323Sed					  "synthetic",
522193323Sed					  "create_synth_test", false));
523193323Sed
524193323Sed	/* Now give the file and instance back */
525193323Sed	trace_put_event_file(create_synth_test);
526193323Sed
527193323Sed	/* Now unregister and free the synthetic event */
528210299Sed	WARN_ON(synth_event_delete("create_synth_test"));
529193323Sed}
530193323Sed
531193323Sedmodule_init(synth_event_gen_test_init)
532193323Sedmodule_exit(synth_event_gen_test_exit)
533193323Sed
534210299SedMODULE_AUTHOR("Tom Zanussi");
535210299SedMODULE_DESCRIPTION("synthetic event generation test");
536193323SedMODULE_LICENSE("GPL v2");
537193323Sed