| 1 | --- |
| 2 | id: using-tracepoint-classes |
| 3 | --- |
| 4 | |
| 5 | In LTTng-UST, a _tracepoint class_ is a class of tracepoints sharing the |
| 6 | same field types and names. A _tracepoint instance_ is one instance of |
| 7 | such a declared tracepoint class, with its own event name and tracepoint |
| 8 | provider name. |
| 9 | |
| 10 | What is documented in [Defining tracepoints](#doc-defining-tracepoints) |
| 11 | is actually how to declare a _tracepoint class_ and define a |
| 12 | _tracepoint instance_ at the same time. Without revealing the internals |
| 13 | of LTTng-UST too much, it has to be noted that one serialization |
| 14 | function is created for each tracepoint class. A serialization |
| 15 | function is responsible for serializing the fields of a tracepoint |
| 16 | into a sub-buffer when tracing. For various performance reasons, when |
| 17 | your situation requires multiple tracepoints with different names, but |
| 18 | with the same fields layout, the best practice is to manually create |
| 19 | a tracepoint class and instantiate as many tracepoint instances as |
| 20 | needed. One positive effect of such a design, amongst other advantages, |
| 21 | is that all tracepoint instances of the same tracepoint class |
| 22 | reuse the same serialization function, thus reducing cache pollution. |
| 23 | |
| 24 | As an example, here are three tracepoint definitions as we know them: |
| 25 | |
| 26 | ~~~ c |
| 27 | TRACEPOINT_EVENT( |
| 28 | my_app, |
| 29 | get_account, |
| 30 | TP_ARGS( |
| 31 | int, userid, |
| 32 | size_t, len |
| 33 | ), |
| 34 | TP_FIELDS( |
| 35 | ctf_integer(int, userid, userid) |
| 36 | ctf_integer(size_t, len, len) |
| 37 | ) |
| 38 | ) |
| 39 | |
| 40 | TRACEPOINT_EVENT( |
| 41 | my_app, |
| 42 | get_settings, |
| 43 | TP_ARGS( |
| 44 | int, userid, |
| 45 | size_t, len |
| 46 | ), |
| 47 | TP_FIELDS( |
| 48 | ctf_integer(int, userid, userid) |
| 49 | ctf_integer(size_t, len, len) |
| 50 | ) |
| 51 | ) |
| 52 | |
| 53 | TRACEPOINT_EVENT( |
| 54 | my_app, |
| 55 | get_transaction, |
| 56 | TP_ARGS( |
| 57 | int, userid, |
| 58 | size_t, len |
| 59 | ), |
| 60 | TP_FIELDS( |
| 61 | ctf_integer(int, userid, userid) |
| 62 | ctf_integer(size_t, len, len) |
| 63 | ) |
| 64 | ) |
| 65 | ~~~ |
| 66 | |
| 67 | In this case, three tracepoint classes are created, with one tracepoint |
| 68 | instance for each of them: `get_account`, `get_settings` and |
| 69 | `get_transaction`. However, they all share the same field names and |
| 70 | types. Declaring one tracepoint class and three tracepoint instances of |
| 71 | the latter is a better design choice: |
| 72 | |
| 73 | ~~~ c |
| 74 | /* the tracepoint class */ |
| 75 | TRACEPOINT_EVENT_CLASS( |
| 76 | /* tracepoint provider name */ |
| 77 | my_app, |
| 78 | |
| 79 | /* tracepoint class name */ |
| 80 | my_class, |
| 81 | |
| 82 | /* arguments */ |
| 83 | TP_ARGS( |
| 84 | int, userid, |
| 85 | size_t, len |
| 86 | ), |
| 87 | |
| 88 | /* fields */ |
| 89 | TP_FIELDS( |
| 90 | ctf_integer(int, userid, userid) |
| 91 | ctf_integer(size_t, len, len) |
| 92 | ) |
| 93 | ) |
| 94 | |
| 95 | /* the tracepoint instances */ |
| 96 | TRACEPOINT_EVENT_INSTANCE( |
| 97 | /* tracepoint provider name */ |
| 98 | my_app, |
| 99 | |
| 100 | /* tracepoint class name */ |
| 101 | my_class, |
| 102 | |
| 103 | /* tracepoint/event name */ |
| 104 | get_account, |
| 105 | |
| 106 | /* arguments */ |
| 107 | TP_ARGS( |
| 108 | int, userid, |
| 109 | size_t, len |
| 110 | ) |
| 111 | ) |
| 112 | TRACEPOINT_EVENT_INSTANCE( |
| 113 | my_app, |
| 114 | my_class, |
| 115 | get_settings, |
| 116 | TP_ARGS( |
| 117 | int, userid, |
| 118 | size_t, len |
| 119 | ) |
| 120 | ) |
| 121 | TRACEPOINT_EVENT_INSTANCE( |
| 122 | my_app, |
| 123 | my_class, |
| 124 | get_transaction, |
| 125 | TP_ARGS( |
| 126 | int, userid, |
| 127 | size_t, len |
| 128 | ) |
| 129 | ) |
| 130 | ~~~ |
| 131 | |
| 132 | Of course, all those names and `TP_ARGS()` invocations are redundant, |
| 133 | but some C preprocessor magic can solve this: |
| 134 | |
| 135 | ~~~ c |
| 136 | #define MY_TRACEPOINT_ARGS \ |
| 137 | TP_ARGS( \ |
| 138 | int, userid, \ |
| 139 | size_t, len \ |
| 140 | ) |
| 141 | |
| 142 | TRACEPOINT_EVENT_CLASS( |
| 143 | my_app, |
| 144 | my_class, |
| 145 | MY_TRACEPOINT_ARGS, |
| 146 | TP_FIELDS( |
| 147 | ctf_integer(int, userid, userid) |
| 148 | ctf_integer(size_t, len, len) |
| 149 | ) |
| 150 | ) |
| 151 | |
| 152 | #define MY_APP_TRACEPOINT_INSTANCE(name) \ |
| 153 | TRACEPOINT_EVENT_INSTANCE( \ |
| 154 | my_app, \ |
| 155 | my_class, \ |
| 156 | name, \ |
| 157 | MY_TRACEPOINT_ARGS \ |
| 158 | ) |
| 159 | |
| 160 | MY_APP_TRACEPOINT_INSTANCE(get_account) |
| 161 | MY_APP_TRACEPOINT_INSTANCE(get_settings) |
| 162 | MY_APP_TRACEPOINT_INSTANCE(get_transaction) |
| 163 | ~~~ |