linux/kernel/trace/synth_event_gen_test.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Test module for in-kernel sythetic event creation and generation.
   4 *
   5 * Copyright (C) 2019 Tom Zanussi <zanussi@kernel.org>
   6 */
   7
   8#include <linux/module.h>
   9#include <linux/trace_events.h>
  10
  11/*
  12 * This module is a simple test of basic functionality for in-kernel
  13 * synthetic event creation and generation, the first and second tests
  14 * using synth_event_gen_cmd_start() and synth_event_add_field(), the
  15 * third uses synth_event_create() to do it all at once with a static
  16 * field array.
  17 *
  18 * Following that are a few examples using the created events to test
  19 * various ways of tracing a synthetic event.
  20 *
  21 * To test, select CONFIG_SYNTH_EVENT_GEN_TEST and build the module.
  22 * Then:
  23 *
  24 * # insmod kernel/trace/synth_event_gen_test.ko
  25 * # cat /sys/kernel/debug/tracing/trace
  26 *
  27 * You should see several events in the trace buffer -
  28 * "create_synth_test", "empty_synth_test", and several instances of
  29 * "gen_synth_test".
  30 *
  31 * To remove the events, remove the module:
  32 *
  33 * # rmmod synth_event_gen_test
  34 *
  35 */
  36
  37static struct trace_event_file *create_synth_test;
  38static struct trace_event_file *empty_synth_test;
  39static struct trace_event_file *gen_synth_test;
  40
  41/*
  42 * Test to make sure we can create a synthetic event, then add more
  43 * fields.
  44 */
  45static int __init test_gen_synth_cmd(void)
  46{
  47        struct dynevent_cmd cmd;
  48        u64 vals[7];
  49        char *buf;
  50        int ret;
  51
  52        /* Create a buffer to hold the generated command */
  53        buf = kzalloc(MAX_DYNEVENT_CMD_LEN, GFP_KERNEL);
  54        if (!buf)
  55                return -ENOMEM;
  56
  57        /* Before generating the command, initialize the cmd object */
  58        synth_event_cmd_init(&cmd, buf, MAX_DYNEVENT_CMD_LEN);
  59
  60        /*
  61         * Create the empty gen_synth_test synthetic event with the
  62         * first 4 fields.
  63         */
  64        ret = synth_event_gen_cmd_start(&cmd, "gen_synth_test", THIS_MODULE,
  65                                        "pid_t", "next_pid_field",
  66                                        "char[16]", "next_comm_field",
  67                                        "u64", "ts_ns",
  68                                        "u64", "ts_ms");
  69        if (ret)
  70                goto free;
  71
  72        /* Use synth_event_add_field to add the rest of the fields */
  73
  74        ret = synth_event_add_field(&cmd, "unsigned int", "cpu");
  75        if (ret)
  76                goto free;
  77
  78        ret = synth_event_add_field(&cmd, "char[64]", "my_string_field");
  79        if (ret)
  80                goto free;
  81
  82        ret = synth_event_add_field(&cmd, "int", "my_int_field");
  83        if (ret)
  84                goto free;
  85
  86        ret = synth_event_gen_cmd_end(&cmd);
  87        if (ret)
  88                goto free;
  89
  90        /*
  91         * Now get the gen_synth_test event file.  We need to prevent
  92         * the instance and event from disappearing from underneath
  93         * us, which trace_get_event_file() does (though in this case
  94         * we're using the top-level instance which never goes away).
  95         */
  96        gen_synth_test = trace_get_event_file(NULL, "synthetic",
  97                                              "gen_synth_test");
  98        if (IS_ERR(gen_synth_test)) {
  99                ret = PTR_ERR(gen_synth_test);
 100                goto delete;
 101        }
 102
 103        /* Enable the event or you won't see anything */
 104        ret = trace_array_set_clr_event(gen_synth_test->tr,
 105                                        "synthetic", "gen_synth_test", true);
 106        if (ret) {
 107                trace_put_event_file(gen_synth_test);
 108                goto delete;
 109        }
 110
 111        /* Create some bogus values just for testing */
 112
 113        vals[0] = 777;                  /* next_pid_field */
 114        vals[1] = (u64)(long)"hula hoops";      /* next_comm_field */
 115        vals[2] = 1000000;              /* ts_ns */
 116        vals[3] = 1000;                 /* ts_ms */
 117        vals[4] = raw_smp_processor_id(); /* cpu */
 118        vals[5] = (u64)(long)"thneed";  /* my_string_field */
 119        vals[6] = 598;                  /* my_int_field */
 120
 121        /* Now generate a gen_synth_test event */
 122        ret = synth_event_trace_array(gen_synth_test, vals, ARRAY_SIZE(vals));
 123 out:
 124        return ret;
 125 delete:
 126        /* We got an error after creating the event, delete it */
 127        synth_event_delete("gen_synth_test");
 128 free:
 129        kfree(buf);
 130
 131        goto out;
 132}
 133
 134/*
 135 * Test to make sure we can create an initially empty synthetic event,
 136 * then add all the fields.
 137 */
 138static int __init test_empty_synth_event(void)
 139{
 140        struct dynevent_cmd cmd;
 141        u64 vals[7];
 142        char *buf;
 143        int ret;
 144
 145        /* Create a buffer to hold the generated command */
 146        buf = kzalloc(MAX_DYNEVENT_CMD_LEN, GFP_KERNEL);
 147        if (!buf)
 148                return -ENOMEM;
 149
 150        /* Before generating the command, initialize the cmd object */
 151        synth_event_cmd_init(&cmd, buf, MAX_DYNEVENT_CMD_LEN);
 152
 153        /*
 154         * Create the empty_synth_test synthetic event with no fields.
 155         */
 156        ret = synth_event_gen_cmd_start(&cmd, "empty_synth_test", THIS_MODULE);
 157        if (ret)
 158                goto free;
 159
 160        /* Use synth_event_add_field to add all of the fields */
 161
 162        ret = synth_event_add_field(&cmd, "pid_t", "next_pid_field");
 163        if (ret)
 164                goto free;
 165
 166        ret = synth_event_add_field(&cmd, "char[16]", "next_comm_field");
 167        if (ret)
 168                goto free;
 169
 170        ret = synth_event_add_field(&cmd, "u64", "ts_ns");
 171        if (ret)
 172                goto free;
 173
 174        ret = synth_event_add_field(&cmd, "u64", "ts_ms");
 175        if (ret)
 176                goto free;
 177
 178        ret = synth_event_add_field(&cmd, "unsigned int", "cpu");
 179        if (ret)
 180                goto free;
 181
 182        ret = synth_event_add_field(&cmd, "char[64]", "my_string_field");
 183        if (ret)
 184                goto free;
 185
 186        ret = synth_event_add_field(&cmd, "int", "my_int_field");
 187        if (ret)
 188                goto free;
 189
 190        /* All fields have been added, close and register the synth event */
 191
 192        ret = synth_event_gen_cmd_end(&cmd);
 193        if (ret)
 194                goto free;
 195
 196        /*
 197         * Now get the empty_synth_test event file.  We need to
 198         * prevent the instance and event from disappearing from
 199         * underneath us, which trace_get_event_file() does (though in
 200         * this case we're using the top-level instance which never
 201         * goes away).
 202         */
 203        empty_synth_test = trace_get_event_file(NULL, "synthetic",
 204                                                "empty_synth_test");
 205        if (IS_ERR(empty_synth_test)) {
 206                ret = PTR_ERR(empty_synth_test);
 207                goto delete;
 208        }
 209
 210        /* Enable the event or you won't see anything */
 211        ret = trace_array_set_clr_event(empty_synth_test->tr,
 212                                        "synthetic", "empty_synth_test", true);
 213        if (ret) {
 214                trace_put_event_file(empty_synth_test);
 215                goto delete;
 216        }
 217
 218        /* Create some bogus values just for testing */
 219
 220        vals[0] = 777;                  /* next_pid_field */
 221        vals[1] = (u64)(long)"tiddlywinks";     /* next_comm_field */
 222        vals[2] = 1000000;              /* ts_ns */
 223        vals[3] = 1000;                 /* ts_ms */
 224        vals[4] = raw_smp_processor_id(); /* cpu */
 225        vals[5] = (u64)(long)"thneed_2.0";      /* my_string_field */
 226        vals[6] = 399;                  /* my_int_field */
 227
 228        /* Now trace an empty_synth_test event */
 229        ret = synth_event_trace_array(empty_synth_test, vals, ARRAY_SIZE(vals));
 230 out:
 231        return ret;
 232 delete:
 233        /* We got an error after creating the event, delete it */
 234        synth_event_delete("empty_synth_test");
 235 free:
 236        kfree(buf);
 237
 238        goto out;
 239}
 240
 241static struct synth_field_desc create_synth_test_fields[] = {
 242        { .type = "pid_t",              .name = "next_pid_field" },
 243        { .type = "char[16]",           .name = "next_comm_field" },
 244        { .type = "u64",                .name = "ts_ns" },
 245        { .type = "u64",                .name = "ts_ms" },
 246        { .type = "unsigned int",       .name = "cpu" },
 247        { .type = "char[64]",           .name = "my_string_field" },
 248        { .type = "int",                .name = "my_int_field" },
 249};
 250
 251/*
 252 * Test synthetic event creation all at once from array of field
 253 * descriptors.
 254 */
 255static int __init test_create_synth_event(void)
 256{
 257        u64 vals[7];
 258        int ret;
 259
 260        /* Create the create_synth_test event with the fields above */
 261        ret = synth_event_create("create_synth_test",
 262                                 create_synth_test_fields,
 263                                 ARRAY_SIZE(create_synth_test_fields),
 264                                 THIS_MODULE);
 265        if (ret)
 266                goto out;
 267
 268        /*
 269         * Now get the create_synth_test event file.  We need to
 270         * prevent the instance and event from disappearing from
 271         * underneath us, which trace_get_event_file() does (though in
 272         * this case we're using the top-level instance which never
 273         * goes away).
 274         */
 275        create_synth_test = trace_get_event_file(NULL, "synthetic",
 276                                                 "create_synth_test");
 277        if (IS_ERR(create_synth_test)) {
 278                ret = PTR_ERR(create_synth_test);
 279                goto delete;
 280        }
 281
 282        /* Enable the event or you won't see anything */
 283        ret = trace_array_set_clr_event(create_synth_test->tr,
 284                                        "synthetic", "create_synth_test", true);
 285        if (ret) {
 286                trace_put_event_file(create_synth_test);
 287                goto delete;
 288        }
 289
 290        /* Create some bogus values just for testing */
 291
 292        vals[0] = 777;                  /* next_pid_field */
 293        vals[1] = (u64)(long)"tiddlywinks";     /* next_comm_field */
 294        vals[2] = 1000000;              /* ts_ns */
 295        vals[3] = 1000;                 /* ts_ms */
 296        vals[4] = raw_smp_processor_id(); /* cpu */
 297        vals[5] = (u64)(long)"thneed";  /* my_string_field */
 298        vals[6] = 398;                  /* my_int_field */
 299
 300        /* Now generate a create_synth_test event */
 301        ret = synth_event_trace_array(create_synth_test, vals, ARRAY_SIZE(vals));
 302 out:
 303        return ret;
 304 delete:
 305        /* We got an error after creating the event, delete it */
 306        ret = synth_event_delete("create_synth_test");
 307
 308        goto out;
 309}
 310
 311/*
 312 * Test tracing a synthetic event by reserving trace buffer space,
 313 * then filling in fields one after another.
 314 */
 315static int __init test_add_next_synth_val(void)
 316{
 317        struct synth_event_trace_state trace_state;
 318        int ret;
 319
 320        /* Start by reserving space in the trace buffer */
 321        ret = synth_event_trace_start(gen_synth_test, &trace_state);
 322        if (ret)
 323                return ret;
 324
 325        /* Write some bogus values into the trace buffer, one after another */
 326
 327        /* next_pid_field */
 328        ret = synth_event_add_next_val(777, &trace_state);
 329        if (ret)
 330                goto out;
 331
 332        /* next_comm_field */
 333        ret = synth_event_add_next_val((u64)(long)"slinky", &trace_state);
 334        if (ret)
 335                goto out;
 336
 337        /* ts_ns */
 338        ret = synth_event_add_next_val(1000000, &trace_state);
 339        if (ret)
 340                goto out;
 341
 342        /* ts_ms */
 343        ret = synth_event_add_next_val(1000, &trace_state);
 344        if (ret)
 345                goto out;
 346
 347        /* cpu */
 348        ret = synth_event_add_next_val(raw_smp_processor_id(), &trace_state);
 349        if (ret)
 350                goto out;
 351
 352        /* my_string_field */
 353        ret = synth_event_add_next_val((u64)(long)"thneed_2.01", &trace_state);
 354        if (ret)
 355                goto out;
 356
 357        /* my_int_field */
 358        ret = synth_event_add_next_val(395, &trace_state);
 359 out:
 360        /* Finally, commit the event */
 361        ret = synth_event_trace_end(&trace_state);
 362
 363        return ret;
 364}
 365
 366/*
 367 * Test tracing a synthetic event by reserving trace buffer space,
 368 * then filling in fields using field names, which can be done in any
 369 * order.
 370 */
 371static int __init test_add_synth_val(void)
 372{
 373        struct synth_event_trace_state trace_state;
 374        int ret;
 375
 376        /* Start by reserving space in the trace buffer */
 377        ret = synth_event_trace_start(gen_synth_test, &trace_state);
 378        if (ret)
 379                return ret;
 380
 381        /* Write some bogus values into the trace buffer, using field names */
 382
 383        ret = synth_event_add_val("ts_ns", 1000000, &trace_state);
 384        if (ret)
 385                goto out;
 386
 387        ret = synth_event_add_val("ts_ms", 1000, &trace_state);
 388        if (ret)
 389                goto out;
 390
 391        ret = synth_event_add_val("cpu", raw_smp_processor_id(), &trace_state);
 392        if (ret)
 393                goto out;
 394
 395        ret = synth_event_add_val("next_pid_field", 777, &trace_state);
 396        if (ret)
 397                goto out;
 398
 399        ret = synth_event_add_val("next_comm_field", (u64)(long)"silly putty",
 400                                  &trace_state);
 401        if (ret)
 402                goto out;
 403
 404        ret = synth_event_add_val("my_string_field", (u64)(long)"thneed_9",
 405                                  &trace_state);
 406        if (ret)
 407                goto out;
 408
 409        ret = synth_event_add_val("my_int_field", 3999, &trace_state);
 410 out:
 411        /* Finally, commit the event */
 412        ret = synth_event_trace_end(&trace_state);
 413
 414        return ret;
 415}
 416
 417/*
 418 * Test tracing a synthetic event all at once from array of values.
 419 */
 420static int __init test_trace_synth_event(void)
 421{
 422        int ret;
 423
 424        /* Trace some bogus values just for testing */
 425        ret = synth_event_trace(create_synth_test, 7,   /* number of values */
 426                                (u64)444,               /* next_pid_field */
 427                                (u64)(long)"clackers",  /* next_comm_field */
 428                                (u64)1000000,           /* ts_ns */
 429                                (u64)1000,              /* ts_ms */
 430                                (u64)raw_smp_processor_id(), /* cpu */
 431                                (u64)(long)"Thneed",    /* my_string_field */
 432                                (u64)999);              /* my_int_field */
 433        return ret;
 434}
 435
 436static int __init synth_event_gen_test_init(void)
 437{
 438        int ret;
 439
 440        ret = test_gen_synth_cmd();
 441        if (ret)
 442                return ret;
 443
 444        ret = test_empty_synth_event();
 445        if (ret) {
 446                WARN_ON(trace_array_set_clr_event(gen_synth_test->tr,
 447                                                  "synthetic",
 448                                                  "gen_synth_test", false));
 449                trace_put_event_file(gen_synth_test);
 450                WARN_ON(synth_event_delete("gen_synth_test"));
 451                goto out;
 452        }
 453
 454        ret = test_create_synth_event();
 455        if (ret) {
 456                WARN_ON(trace_array_set_clr_event(gen_synth_test->tr,
 457                                                  "synthetic",
 458                                                  "gen_synth_test", false));
 459                trace_put_event_file(gen_synth_test);
 460                WARN_ON(synth_event_delete("gen_synth_test"));
 461
 462                WARN_ON(trace_array_set_clr_event(empty_synth_test->tr,
 463                                                  "synthetic",
 464                                                  "empty_synth_test", false));
 465                trace_put_event_file(empty_synth_test);
 466                WARN_ON(synth_event_delete("empty_synth_test"));
 467                goto out;
 468        }
 469
 470        ret = test_add_next_synth_val();
 471        WARN_ON(ret);
 472
 473        ret = test_add_synth_val();
 474        WARN_ON(ret);
 475
 476        ret = test_trace_synth_event();
 477        WARN_ON(ret);
 478 out:
 479        return ret;
 480}
 481
 482static void __exit synth_event_gen_test_exit(void)
 483{
 484        /* Disable the event or you can't remove it */
 485        WARN_ON(trace_array_set_clr_event(gen_synth_test->tr,
 486                                          "synthetic",
 487                                          "gen_synth_test", false));
 488
 489        /* Now give the file and instance back */
 490        trace_put_event_file(gen_synth_test);
 491
 492        /* Now unregister and free the synthetic event */
 493        WARN_ON(synth_event_delete("gen_synth_test"));
 494
 495        /* Disable the event or you can't remove it */
 496        WARN_ON(trace_array_set_clr_event(empty_synth_test->tr,
 497                                          "synthetic",
 498                                          "empty_synth_test", false));
 499
 500        /* Now give the file and instance back */
 501        trace_put_event_file(empty_synth_test);
 502
 503        /* Now unregister and free the synthetic event */
 504        WARN_ON(synth_event_delete("empty_synth_test"));
 505
 506        /* Disable the event or you can't remove it */
 507        WARN_ON(trace_array_set_clr_event(create_synth_test->tr,
 508                                          "synthetic",
 509                                          "create_synth_test", false));
 510
 511        /* Now give the file and instance back */
 512        trace_put_event_file(create_synth_test);
 513
 514        /* Now unregister and free the synthetic event */
 515        WARN_ON(synth_event_delete("create_synth_test"));
 516}
 517
 518module_init(synth_event_gen_test_init)
 519module_exit(synth_event_gen_test_exit)
 520
 521MODULE_AUTHOR("Tom Zanussi");
 522MODULE_DESCRIPTION("synthetic event generation test");
 523MODULE_LICENSE("GPL v2");
 524