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