1 /*- 2 * BSD LICENSE 3 * 4 * Copyright (c) Intel Corporation. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of Intel Corporation nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include "spdk/stdinc.h" 35 36 #include "spdk/env.h" 37 #include "spdk/trace.h" 38 #include "spdk/log.h" 39 40 struct spdk_trace_flags *g_trace_flags = NULL; 41 static struct spdk_trace_register_fn *g_reg_fn_head = NULL; 42 43 SPDK_LOG_REGISTER_COMPONENT(trace) 44 45 uint64_t 46 spdk_trace_get_tpoint_mask(uint32_t group_id) 47 { 48 if (group_id >= SPDK_TRACE_MAX_GROUP_ID) { 49 SPDK_ERRLOG("invalid group ID %d\n", group_id); 50 return 0ULL; 51 } 52 53 if (g_trace_flags == NULL) { 54 return 0ULL; 55 } 56 57 return g_trace_flags->tpoint_mask[group_id]; 58 } 59 60 void 61 spdk_trace_set_tpoints(uint32_t group_id, uint64_t tpoint_mask) 62 { 63 if (g_trace_flags == NULL) { 64 SPDK_ERRLOG("trace is not initialized\n"); 65 return; 66 } 67 68 if (group_id >= SPDK_TRACE_MAX_GROUP_ID) { 69 SPDK_ERRLOG("invalid group ID %d\n", group_id); 70 return; 71 } 72 73 g_trace_flags->tpoint_mask[group_id] |= tpoint_mask; 74 } 75 76 void 77 spdk_trace_clear_tpoints(uint32_t group_id, uint64_t tpoint_mask) 78 { 79 if (g_trace_flags == NULL) { 80 SPDK_ERRLOG("trace is not initialized\n"); 81 return; 82 } 83 84 if (group_id >= SPDK_TRACE_MAX_GROUP_ID) { 85 SPDK_ERRLOG("invalid group ID %d\n", group_id); 86 return; 87 } 88 89 g_trace_flags->tpoint_mask[group_id] &= ~tpoint_mask; 90 } 91 92 uint64_t 93 spdk_trace_get_tpoint_group_mask(void) 94 { 95 uint64_t mask = 0x0; 96 int i; 97 98 for (i = 0; i < SPDK_TRACE_MAX_GROUP_ID; i++) { 99 if (spdk_trace_get_tpoint_mask(i) != 0) { 100 mask |= (1ULL << i); 101 } 102 } 103 104 return mask; 105 } 106 107 void 108 spdk_trace_set_tpoint_group_mask(uint64_t tpoint_group_mask) 109 { 110 int i; 111 112 if (g_trace_flags == NULL) { 113 SPDK_ERRLOG("trace is not initialized\n"); 114 return; 115 } 116 117 for (i = 0; i < SPDK_TRACE_MAX_GROUP_ID; i++) { 118 if (tpoint_group_mask & (1ULL << i)) { 119 spdk_trace_set_tpoints(i, -1ULL); 120 } 121 } 122 } 123 124 void 125 spdk_trace_clear_tpoint_group_mask(uint64_t tpoint_group_mask) 126 { 127 int i; 128 129 if (g_trace_flags == NULL) { 130 SPDK_ERRLOG("trace is not initialized\n"); 131 return; 132 } 133 134 for (i = 0; i < SPDK_TRACE_MAX_GROUP_ID; i++) { 135 if (tpoint_group_mask & (1ULL << i)) { 136 spdk_trace_clear_tpoints(i, -1ULL); 137 } 138 } 139 } 140 141 struct spdk_trace_register_fn * 142 spdk_trace_get_first_register_fn(void) 143 { 144 return g_reg_fn_head; 145 } 146 147 struct spdk_trace_register_fn * 148 spdk_trace_get_next_register_fn(struct spdk_trace_register_fn *register_fn) 149 { 150 return register_fn->next; 151 } 152 153 static uint64_t 154 trace_create_tpoint_group_mask(const char *group_name) 155 { 156 uint64_t tpoint_group_mask = 0; 157 struct spdk_trace_register_fn *register_fn; 158 159 register_fn = spdk_trace_get_first_register_fn(); 160 if (strcmp(group_name, "all") == 0) { 161 while (register_fn) { 162 tpoint_group_mask |= (1UL << register_fn->tgroup_id); 163 164 register_fn = spdk_trace_get_next_register_fn(register_fn); 165 } 166 } else { 167 while (register_fn) { 168 if (strcmp(group_name, register_fn->name) == 0) { 169 break; 170 } 171 172 register_fn = spdk_trace_get_next_register_fn(register_fn); 173 } 174 175 if (register_fn != NULL) { 176 tpoint_group_mask |= (1UL << register_fn->tgroup_id); 177 } 178 } 179 180 return tpoint_group_mask; 181 } 182 183 int 184 spdk_trace_enable_tpoint_group(const char *group_name) 185 { 186 uint64_t tpoint_group_mask = 0; 187 188 if (g_trace_flags == NULL) { 189 return -1; 190 } 191 192 tpoint_group_mask = trace_create_tpoint_group_mask(group_name); 193 if (tpoint_group_mask == 0) { 194 return -1; 195 } 196 197 spdk_trace_set_tpoint_group_mask(tpoint_group_mask); 198 return 0; 199 } 200 201 int 202 spdk_trace_disable_tpoint_group(const char *group_name) 203 { 204 uint64_t tpoint_group_mask = 0; 205 206 if (g_trace_flags == NULL) { 207 return -1; 208 } 209 210 tpoint_group_mask = trace_create_tpoint_group_mask(group_name); 211 if (tpoint_group_mask == 0) { 212 return -1; 213 } 214 215 spdk_trace_clear_tpoint_group_mask(tpoint_group_mask); 216 return 0; 217 } 218 219 void 220 spdk_trace_mask_usage(FILE *f, const char *tmask_arg) 221 { 222 struct spdk_trace_register_fn *register_fn; 223 224 fprintf(f, " %s, --tpoint-group-mask <mask>\n", tmask_arg); 225 fprintf(f, " tracepoint group mask for spdk trace buffers (default 0x0"); 226 227 register_fn = g_reg_fn_head; 228 while (register_fn) { 229 fprintf(f, ", %s 0x%x", register_fn->name, 1 << register_fn->tgroup_id); 230 register_fn = register_fn->next; 231 } 232 233 fprintf(f, ", all 0xffff)\n"); 234 } 235 236 void 237 spdk_trace_register_owner(uint8_t type, char id_prefix) 238 { 239 struct spdk_trace_owner *owner; 240 241 assert(type != OWNER_NONE); 242 243 if (g_trace_flags == NULL) { 244 SPDK_ERRLOG("trace is not initialized\n"); 245 return; 246 } 247 248 /* 'owner' has 256 entries and since 'type' is a uint8_t, it 249 * can't overrun the array. 250 */ 251 owner = &g_trace_flags->owner[type]; 252 assert(owner->type == 0); 253 254 owner->type = type; 255 owner->id_prefix = id_prefix; 256 } 257 258 void 259 spdk_trace_register_object(uint8_t type, char id_prefix) 260 { 261 struct spdk_trace_object *object; 262 263 assert(type != OBJECT_NONE); 264 265 if (g_trace_flags == NULL) { 266 SPDK_ERRLOG("trace is not initialized\n"); 267 return; 268 } 269 270 /* 'object' has 256 entries and since 'type' is a uint8_t, it 271 * can't overrun the array. 272 */ 273 object = &g_trace_flags->object[type]; 274 assert(object->type == 0); 275 276 object->type = type; 277 object->id_prefix = id_prefix; 278 } 279 280 static void 281 trace_register_description(const struct spdk_trace_tpoint_opts *opts) 282 { 283 struct spdk_trace_tpoint *tpoint; 284 size_t i, max_name_length; 285 286 assert(opts->tpoint_id != 0); 287 assert(opts->tpoint_id < SPDK_TRACE_MAX_TPOINT_ID); 288 289 if (strnlen(opts->name, sizeof(tpoint->name)) == sizeof(tpoint->name)) { 290 SPDK_ERRLOG("name (%s) too long\n", opts->name); 291 } 292 293 tpoint = &g_trace_flags->tpoint[opts->tpoint_id]; 294 assert(tpoint->tpoint_id == 0); 295 296 snprintf(tpoint->name, sizeof(tpoint->name), "%s", opts->name); 297 tpoint->tpoint_id = opts->tpoint_id; 298 tpoint->object_type = opts->object_type; 299 tpoint->owner_type = opts->owner_type; 300 tpoint->new_object = opts->new_object; 301 302 max_name_length = sizeof(tpoint->args[0].name); 303 for (i = 0; i < SPDK_TRACE_MAX_ARGS_COUNT; ++i) { 304 if (!opts->args[i].name || opts->args[i].name[0] == '\0') { 305 break; 306 } 307 308 switch (opts->args[i].type) { 309 case SPDK_TRACE_ARG_TYPE_INT: 310 case SPDK_TRACE_ARG_TYPE_PTR: 311 /* The integers and pointers have to be exactly 64b long */ 312 assert(opts->args[i].size == sizeof(uint64_t)); 313 break; 314 case SPDK_TRACE_ARG_TYPE_STR: 315 /* Strings need to have at least one byte for the NULL terminator */ 316 assert(opts->args[i].size > 0); 317 break; 318 default: 319 assert(0 && "invalid trace argument type"); 320 break; 321 } 322 323 if (strnlen(opts->args[i].name, max_name_length) == max_name_length) { 324 SPDK_ERRLOG("argument name (%s) is too long\n", opts->args[i].name); 325 } 326 327 snprintf(tpoint->args[i].name, sizeof(tpoint->args[i].name), 328 "%s", opts->args[i].name); 329 tpoint->args[i].type = opts->args[i].type; 330 tpoint->args[i].size = opts->args[i].size; 331 } 332 333 tpoint->num_args = i; 334 } 335 336 void 337 spdk_trace_register_description_ext(const struct spdk_trace_tpoint_opts *opts, size_t num_opts) 338 { 339 size_t i; 340 341 if (g_trace_flags == NULL) { 342 SPDK_ERRLOG("trace is not initialized\n"); 343 return; 344 } 345 346 for (i = 0; i < num_opts; ++i) { 347 trace_register_description(&opts[i]); 348 } 349 } 350 351 void 352 spdk_trace_register_description(const char *name, uint16_t tpoint_id, uint8_t owner_type, 353 uint8_t object_type, uint8_t new_object, 354 uint8_t arg1_type, const char *arg1_name) 355 { 356 struct spdk_trace_tpoint_opts opts = { 357 .name = name, 358 .tpoint_id = tpoint_id, 359 .owner_type = owner_type, 360 .object_type = object_type, 361 .new_object = new_object, 362 .args = {{ 363 .name = arg1_name, 364 .type = arg1_type, 365 .size = sizeof(uint64_t) 366 } 367 } 368 }; 369 370 spdk_trace_register_description_ext(&opts, 1); 371 } 372 373 void 374 spdk_trace_add_register_fn(struct spdk_trace_register_fn *reg_fn) 375 { 376 struct spdk_trace_register_fn *_reg_fn; 377 378 if (reg_fn->name == NULL) { 379 SPDK_ERRLOG("missing name for registering spdk trace tpoint group\n"); 380 assert(false); 381 return; 382 } 383 384 if (strcmp(reg_fn->name, "all") == 0) { 385 SPDK_ERRLOG("illegal name (%s) for tpoint group\n", reg_fn->name); 386 assert(false); 387 return; 388 } 389 390 /* Ensure that no trace point group IDs and names are ever duplicated */ 391 for (_reg_fn = g_reg_fn_head; _reg_fn; _reg_fn = _reg_fn->next) { 392 if (reg_fn->tgroup_id == _reg_fn->tgroup_id) { 393 SPDK_ERRLOG("duplicate tgroup_id (%d) with %s\n", _reg_fn->tgroup_id, _reg_fn->name); 394 assert(false); 395 return; 396 } 397 398 if (strcmp(reg_fn->name, _reg_fn->name) == 0) { 399 SPDK_ERRLOG("duplicate name with %s\n", _reg_fn->name); 400 assert(false); 401 return; 402 } 403 } 404 405 /* Arrange trace registration in order on tgroup_id */ 406 if (g_reg_fn_head == NULL || reg_fn->tgroup_id < g_reg_fn_head->tgroup_id) { 407 reg_fn->next = g_reg_fn_head; 408 g_reg_fn_head = reg_fn; 409 return; 410 } 411 412 for (_reg_fn = g_reg_fn_head; _reg_fn; _reg_fn = _reg_fn->next) { 413 if (_reg_fn->next == NULL || reg_fn->tgroup_id < _reg_fn->next->tgroup_id) { 414 reg_fn->next = _reg_fn->next; 415 _reg_fn->next = reg_fn; 416 return; 417 } 418 } 419 } 420 421 void 422 spdk_trace_flags_init(void) 423 { 424 struct spdk_trace_register_fn *reg_fn; 425 426 reg_fn = g_reg_fn_head; 427 while (reg_fn) { 428 reg_fn->reg_fn(); 429 reg_fn = reg_fn->next; 430 } 431 } 432