Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Test module for in-kernel synthetic event creation and generation.
0004  *
0005  * Copyright (C) 2019 Tom Zanussi <zanussi@kernel.org>
0006  */
0007 
0008 #include <linux/module.h>
0009 #include <linux/trace_events.h>
0010 
0011 /*
0012  * This module is a simple test of basic functionality for in-kernel
0013  * synthetic event creation and generation, the first and second tests
0014  * using synth_event_gen_cmd_start() and synth_event_add_field(), the
0015  * third uses synth_event_create() to do it all at once with a static
0016  * field array.
0017  *
0018  * Following that are a few examples using the created events to test
0019  * various ways of tracing a synthetic event.
0020  *
0021  * To test, select CONFIG_SYNTH_EVENT_GEN_TEST and build the module.
0022  * Then:
0023  *
0024  * # insmod kernel/trace/synth_event_gen_test.ko
0025  * # cat /sys/kernel/debug/tracing/trace
0026  *
0027  * You should see several events in the trace buffer -
0028  * "create_synth_test", "empty_synth_test", and several instances of
0029  * "gen_synth_test".
0030  *
0031  * To remove the events, remove the module:
0032  *
0033  * # rmmod synth_event_gen_test
0034  *
0035  */
0036 
0037 static struct trace_event_file *create_synth_test;
0038 static struct trace_event_file *empty_synth_test;
0039 static struct trace_event_file *gen_synth_test;
0040 
0041 /*
0042  * Test to make sure we can create a synthetic event, then add more
0043  * fields.
0044  */
0045 static int __init test_gen_synth_cmd(void)
0046 {
0047     struct dynevent_cmd cmd;
0048     u64 vals[7];
0049     char *buf;
0050     int ret;
0051 
0052     /* Create a buffer to hold the generated command */
0053     buf = kzalloc(MAX_DYNEVENT_CMD_LEN, GFP_KERNEL);
0054     if (!buf)
0055         return -ENOMEM;
0056 
0057     /* Before generating the command, initialize the cmd object */
0058     synth_event_cmd_init(&cmd, buf, MAX_DYNEVENT_CMD_LEN);
0059 
0060     /*
0061      * Create the empty gen_synth_test synthetic event with the
0062      * first 4 fields.
0063      */
0064     ret = synth_event_gen_cmd_start(&cmd, "gen_synth_test", THIS_MODULE,
0065                     "pid_t", "next_pid_field",
0066                     "char[16]", "next_comm_field",
0067                     "u64", "ts_ns",
0068                     "u64", "ts_ms");
0069     if (ret)
0070         goto free;
0071 
0072     /* Use synth_event_add_field to add the rest of the fields */
0073 
0074     ret = synth_event_add_field(&cmd, "unsigned int", "cpu");
0075     if (ret)
0076         goto free;
0077 
0078     ret = synth_event_add_field(&cmd, "char[64]", "my_string_field");
0079     if (ret)
0080         goto free;
0081 
0082     ret = synth_event_add_field(&cmd, "int", "my_int_field");
0083     if (ret)
0084         goto free;
0085 
0086     ret = synth_event_gen_cmd_end(&cmd);
0087     if (ret)
0088         goto free;
0089 
0090     /*
0091      * Now get the gen_synth_test event file.  We need to prevent
0092      * the instance and event from disappearing from underneath
0093      * us, which trace_get_event_file() does (though in this case
0094      * we're using the top-level instance which never goes away).
0095      */
0096     gen_synth_test = trace_get_event_file(NULL, "synthetic",
0097                           "gen_synth_test");
0098     if (IS_ERR(gen_synth_test)) {
0099         ret = PTR_ERR(gen_synth_test);
0100         goto delete;
0101     }
0102 
0103     /* Enable the event or you won't see anything */
0104     ret = trace_array_set_clr_event(gen_synth_test->tr,
0105                     "synthetic", "gen_synth_test", true);
0106     if (ret) {
0107         trace_put_event_file(gen_synth_test);
0108         goto delete;
0109     }
0110 
0111     /* Create some bogus values just for testing */
0112 
0113     vals[0] = 777;          /* next_pid_field */
0114     vals[1] = (u64)(long)"hula hoops";  /* next_comm_field */
0115     vals[2] = 1000000;      /* ts_ns */
0116     vals[3] = 1000;         /* ts_ms */
0117     vals[4] = raw_smp_processor_id(); /* cpu */
0118     vals[5] = (u64)(long)"thneed";  /* my_string_field */
0119     vals[6] = 598;          /* my_int_field */
0120 
0121     /* Now generate a gen_synth_test event */
0122     ret = synth_event_trace_array(gen_synth_test, vals, ARRAY_SIZE(vals));
0123  out:
0124     return ret;
0125  delete:
0126     /* We got an error after creating the event, delete it */
0127     synth_event_delete("gen_synth_test");
0128  free:
0129     kfree(buf);
0130 
0131     goto out;
0132 }
0133 
0134 /*
0135  * Test to make sure we can create an initially empty synthetic event,
0136  * then add all the fields.
0137  */
0138 static int __init test_empty_synth_event(void)
0139 {
0140     struct dynevent_cmd cmd;
0141     u64 vals[7];
0142     char *buf;
0143     int ret;
0144 
0145     /* Create a buffer to hold the generated command */
0146     buf = kzalloc(MAX_DYNEVENT_CMD_LEN, GFP_KERNEL);
0147     if (!buf)
0148         return -ENOMEM;
0149 
0150     /* Before generating the command, initialize the cmd object */
0151     synth_event_cmd_init(&cmd, buf, MAX_DYNEVENT_CMD_LEN);
0152 
0153     /*
0154      * Create the empty_synth_test synthetic event with no fields.
0155      */
0156     ret = synth_event_gen_cmd_start(&cmd, "empty_synth_test", THIS_MODULE);
0157     if (ret)
0158         goto free;
0159 
0160     /* Use synth_event_add_field to add all of the fields */
0161 
0162     ret = synth_event_add_field(&cmd, "pid_t", "next_pid_field");
0163     if (ret)
0164         goto free;
0165 
0166     ret = synth_event_add_field(&cmd, "char[16]", "next_comm_field");
0167     if (ret)
0168         goto free;
0169 
0170     ret = synth_event_add_field(&cmd, "u64", "ts_ns");
0171     if (ret)
0172         goto free;
0173 
0174     ret = synth_event_add_field(&cmd, "u64", "ts_ms");
0175     if (ret)
0176         goto free;
0177 
0178     ret = synth_event_add_field(&cmd, "unsigned int", "cpu");
0179     if (ret)
0180         goto free;
0181 
0182     ret = synth_event_add_field(&cmd, "char[64]", "my_string_field");
0183     if (ret)
0184         goto free;
0185 
0186     ret = synth_event_add_field(&cmd, "int", "my_int_field");
0187     if (ret)
0188         goto free;
0189 
0190     /* All fields have been added, close and register the synth event */
0191 
0192     ret = synth_event_gen_cmd_end(&cmd);
0193     if (ret)
0194         goto free;
0195 
0196     /*
0197      * Now get the empty_synth_test event file.  We need to
0198      * prevent the instance and event from disappearing from
0199      * underneath us, which trace_get_event_file() does (though in
0200      * this case we're using the top-level instance which never
0201      * goes away).
0202      */
0203     empty_synth_test = trace_get_event_file(NULL, "synthetic",
0204                         "empty_synth_test");
0205     if (IS_ERR(empty_synth_test)) {
0206         ret = PTR_ERR(empty_synth_test);
0207         goto delete;
0208     }
0209 
0210     /* Enable the event or you won't see anything */
0211     ret = trace_array_set_clr_event(empty_synth_test->tr,
0212                     "synthetic", "empty_synth_test", true);
0213     if (ret) {
0214         trace_put_event_file(empty_synth_test);
0215         goto delete;
0216     }
0217 
0218     /* Create some bogus values just for testing */
0219 
0220     vals[0] = 777;          /* next_pid_field */
0221     vals[1] = (u64)(long)"tiddlywinks"; /* next_comm_field */
0222     vals[2] = 1000000;      /* ts_ns */
0223     vals[3] = 1000;         /* ts_ms */
0224     vals[4] = raw_smp_processor_id(); /* cpu */
0225     vals[5] = (u64)(long)"thneed_2.0";  /* my_string_field */
0226     vals[6] = 399;          /* my_int_field */
0227 
0228     /* Now trace an empty_synth_test event */
0229     ret = synth_event_trace_array(empty_synth_test, vals, ARRAY_SIZE(vals));
0230  out:
0231     return ret;
0232  delete:
0233     /* We got an error after creating the event, delete it */
0234     synth_event_delete("empty_synth_test");
0235  free:
0236     kfree(buf);
0237 
0238     goto out;
0239 }
0240 
0241 static struct synth_field_desc create_synth_test_fields[] = {
0242     { .type = "pid_t",      .name = "next_pid_field" },
0243     { .type = "char[16]",       .name = "next_comm_field" },
0244     { .type = "u64",        .name = "ts_ns" },
0245     { .type = "char[]",     .name = "dynstring_field_1" },
0246     { .type = "u64",        .name = "ts_ms" },
0247     { .type = "unsigned int",   .name = "cpu" },
0248     { .type = "char[64]",       .name = "my_string_field" },
0249     { .type = "char[]",     .name = "dynstring_field_2" },
0250     { .type = "int",        .name = "my_int_field" },
0251 };
0252 
0253 /*
0254  * Test synthetic event creation all at once from array of field
0255  * descriptors.
0256  */
0257 static int __init test_create_synth_event(void)
0258 {
0259     u64 vals[9];
0260     int ret;
0261 
0262     /* Create the create_synth_test event with the fields above */
0263     ret = synth_event_create("create_synth_test",
0264                  create_synth_test_fields,
0265                  ARRAY_SIZE(create_synth_test_fields),
0266                  THIS_MODULE);
0267     if (ret)
0268         goto out;
0269 
0270     /*
0271      * Now get the create_synth_test event file.  We need to
0272      * prevent the instance and event from disappearing from
0273      * underneath us, which trace_get_event_file() does (though in
0274      * this case we're using the top-level instance which never
0275      * goes away).
0276      */
0277     create_synth_test = trace_get_event_file(NULL, "synthetic",
0278                          "create_synth_test");
0279     if (IS_ERR(create_synth_test)) {
0280         ret = PTR_ERR(create_synth_test);
0281         goto delete;
0282     }
0283 
0284     /* Enable the event or you won't see anything */
0285     ret = trace_array_set_clr_event(create_synth_test->tr,
0286                     "synthetic", "create_synth_test", true);
0287     if (ret) {
0288         trace_put_event_file(create_synth_test);
0289         goto delete;
0290     }
0291 
0292     /* Create some bogus values just for testing */
0293 
0294     vals[0] = 777;          /* next_pid_field */
0295     vals[1] = (u64)(long)"tiddlywinks"; /* next_comm_field */
0296     vals[2] = 1000000;      /* ts_ns */
0297     vals[3] = (u64)(long)"xrayspecs";   /* dynstring_field_1 */
0298     vals[4] = 1000;         /* ts_ms */
0299     vals[5] = raw_smp_processor_id(); /* cpu */
0300     vals[6] = (u64)(long)"thneed";  /* my_string_field */
0301     vals[7] = (u64)(long)"kerplunk";    /* dynstring_field_2 */
0302     vals[8] = 398;          /* my_int_field */
0303 
0304     /* Now generate a create_synth_test event */
0305     ret = synth_event_trace_array(create_synth_test, vals, ARRAY_SIZE(vals));
0306  out:
0307     return ret;
0308  delete:
0309     /* We got an error after creating the event, delete it */
0310     synth_event_delete("create_synth_test");
0311 
0312     goto out;
0313 }
0314 
0315 /*
0316  * Test tracing a synthetic event by reserving trace buffer space,
0317  * then filling in fields one after another.
0318  */
0319 static int __init test_add_next_synth_val(void)
0320 {
0321     struct synth_event_trace_state trace_state;
0322     int ret;
0323 
0324     /* Start by reserving space in the trace buffer */
0325     ret = synth_event_trace_start(gen_synth_test, &trace_state);
0326     if (ret)
0327         return ret;
0328 
0329     /* Write some bogus values into the trace buffer, one after another */
0330 
0331     /* next_pid_field */
0332     ret = synth_event_add_next_val(777, &trace_state);
0333     if (ret)
0334         goto out;
0335 
0336     /* next_comm_field */
0337     ret = synth_event_add_next_val((u64)(long)"slinky", &trace_state);
0338     if (ret)
0339         goto out;
0340 
0341     /* ts_ns */
0342     ret = synth_event_add_next_val(1000000, &trace_state);
0343     if (ret)
0344         goto out;
0345 
0346     /* ts_ms */
0347     ret = synth_event_add_next_val(1000, &trace_state);
0348     if (ret)
0349         goto out;
0350 
0351     /* cpu */
0352     ret = synth_event_add_next_val(raw_smp_processor_id(), &trace_state);
0353     if (ret)
0354         goto out;
0355 
0356     /* my_string_field */
0357     ret = synth_event_add_next_val((u64)(long)"thneed_2.01", &trace_state);
0358     if (ret)
0359         goto out;
0360 
0361     /* my_int_field */
0362     ret = synth_event_add_next_val(395, &trace_state);
0363  out:
0364     /* Finally, commit the event */
0365     ret = synth_event_trace_end(&trace_state);
0366 
0367     return ret;
0368 }
0369 
0370 /*
0371  * Test tracing a synthetic event by reserving trace buffer space,
0372  * then filling in fields using field names, which can be done in any
0373  * order.
0374  */
0375 static int __init test_add_synth_val(void)
0376 {
0377     struct synth_event_trace_state trace_state;
0378     int ret;
0379 
0380     /* Start by reserving space in the trace buffer */
0381     ret = synth_event_trace_start(gen_synth_test, &trace_state);
0382     if (ret)
0383         return ret;
0384 
0385     /* Write some bogus values into the trace buffer, using field names */
0386 
0387     ret = synth_event_add_val("ts_ns", 1000000, &trace_state);
0388     if (ret)
0389         goto out;
0390 
0391     ret = synth_event_add_val("ts_ms", 1000, &trace_state);
0392     if (ret)
0393         goto out;
0394 
0395     ret = synth_event_add_val("cpu", raw_smp_processor_id(), &trace_state);
0396     if (ret)
0397         goto out;
0398 
0399     ret = synth_event_add_val("next_pid_field", 777, &trace_state);
0400     if (ret)
0401         goto out;
0402 
0403     ret = synth_event_add_val("next_comm_field", (u64)(long)"silly putty",
0404                   &trace_state);
0405     if (ret)
0406         goto out;
0407 
0408     ret = synth_event_add_val("my_string_field", (u64)(long)"thneed_9",
0409                   &trace_state);
0410     if (ret)
0411         goto out;
0412 
0413     ret = synth_event_add_val("my_int_field", 3999, &trace_state);
0414  out:
0415     /* Finally, commit the event */
0416     ret = synth_event_trace_end(&trace_state);
0417 
0418     return ret;
0419 }
0420 
0421 /*
0422  * Test tracing a synthetic event all at once from array of values.
0423  */
0424 static int __init test_trace_synth_event(void)
0425 {
0426     int ret;
0427 
0428     /* Trace some bogus values just for testing */
0429     ret = synth_event_trace(create_synth_test, 9,   /* number of values */
0430                 (u64)444,       /* next_pid_field */
0431                 (u64)(long)"clackers",  /* next_comm_field */
0432                 (u64)1000000,       /* ts_ns */
0433                 (u64)(long)"viewmaster",/* dynstring_field_1 */
0434                 (u64)1000,      /* ts_ms */
0435                 (u64)raw_smp_processor_id(), /* cpu */
0436                 (u64)(long)"Thneed",    /* my_string_field */
0437                 (u64)(long)"yoyos", /* dynstring_field_2 */
0438                 (u64)999);      /* my_int_field */
0439     return ret;
0440 }
0441 
0442 static int __init synth_event_gen_test_init(void)
0443 {
0444     int ret;
0445 
0446     ret = test_gen_synth_cmd();
0447     if (ret)
0448         return ret;
0449 
0450     ret = test_empty_synth_event();
0451     if (ret) {
0452         WARN_ON(trace_array_set_clr_event(gen_synth_test->tr,
0453                           "synthetic",
0454                           "gen_synth_test", false));
0455         trace_put_event_file(gen_synth_test);
0456         WARN_ON(synth_event_delete("gen_synth_test"));
0457         goto out;
0458     }
0459 
0460     ret = test_create_synth_event();
0461     if (ret) {
0462         WARN_ON(trace_array_set_clr_event(gen_synth_test->tr,
0463                           "synthetic",
0464                           "gen_synth_test", false));
0465         trace_put_event_file(gen_synth_test);
0466         WARN_ON(synth_event_delete("gen_synth_test"));
0467 
0468         WARN_ON(trace_array_set_clr_event(empty_synth_test->tr,
0469                           "synthetic",
0470                           "empty_synth_test", false));
0471         trace_put_event_file(empty_synth_test);
0472         WARN_ON(synth_event_delete("empty_synth_test"));
0473         goto out;
0474     }
0475 
0476     ret = test_add_next_synth_val();
0477     WARN_ON(ret);
0478 
0479     ret = test_add_synth_val();
0480     WARN_ON(ret);
0481 
0482     ret = test_trace_synth_event();
0483     WARN_ON(ret);
0484  out:
0485     return ret;
0486 }
0487 
0488 static void __exit synth_event_gen_test_exit(void)
0489 {
0490     /* Disable the event or you can't remove it */
0491     WARN_ON(trace_array_set_clr_event(gen_synth_test->tr,
0492                       "synthetic",
0493                       "gen_synth_test", false));
0494 
0495     /* Now give the file and instance back */
0496     trace_put_event_file(gen_synth_test);
0497 
0498     /* Now unregister and free the synthetic event */
0499     WARN_ON(synth_event_delete("gen_synth_test"));
0500 
0501     /* Disable the event or you can't remove it */
0502     WARN_ON(trace_array_set_clr_event(empty_synth_test->tr,
0503                       "synthetic",
0504                       "empty_synth_test", false));
0505 
0506     /* Now give the file and instance back */
0507     trace_put_event_file(empty_synth_test);
0508 
0509     /* Now unregister and free the synthetic event */
0510     WARN_ON(synth_event_delete("empty_synth_test"));
0511 
0512     /* Disable the event or you can't remove it */
0513     WARN_ON(trace_array_set_clr_event(create_synth_test->tr,
0514                       "synthetic",
0515                       "create_synth_test", false));
0516 
0517     /* Now give the file and instance back */
0518     trace_put_event_file(create_synth_test);
0519 
0520     /* Now unregister and free the synthetic event */
0521     WARN_ON(synth_event_delete("create_synth_test"));
0522 }
0523 
0524 module_init(synth_event_gen_test_init)
0525 module_exit(synth_event_gen_test_exit)
0526 
0527 MODULE_AUTHOR("Tom Zanussi");
0528 MODULE_DESCRIPTION("synthetic event generation test");
0529 MODULE_LICENSE("GPL v2");