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 #include "spdk/util.h" 40 41 struct spdk_trace_flags *g_trace_flags = NULL; 42 static struct spdk_trace_register_fn *g_reg_fn_head = NULL; 43 44 SPDK_LOG_REGISTER_COMPONENT(trace) 45 46 uint64_t 47 spdk_trace_get_tpoint_mask(uint32_t group_id) 48 { 49 if (group_id >= SPDK_TRACE_MAX_GROUP_ID) { 50 SPDK_ERRLOG("invalid group ID %d\n", group_id); 51 return 0ULL; 52 } 53 54 if (g_trace_flags == NULL) { 55 return 0ULL; 56 } 57 58 return g_trace_flags->tpoint_mask[group_id]; 59 } 60 61 void 62 spdk_trace_set_tpoints(uint32_t group_id, uint64_t tpoint_mask) 63 { 64 if (g_trace_flags == NULL) { 65 SPDK_ERRLOG("trace is not initialized\n"); 66 return; 67 } 68 69 if (group_id >= SPDK_TRACE_MAX_GROUP_ID) { 70 SPDK_ERRLOG("invalid group ID %d\n", group_id); 71 return; 72 } 73 74 g_trace_flags->tpoint_mask[group_id] |= tpoint_mask; 75 } 76 77 void 78 spdk_trace_clear_tpoints(uint32_t group_id, uint64_t tpoint_mask) 79 { 80 if (g_trace_flags == NULL) { 81 SPDK_ERRLOG("trace is not initialized\n"); 82 return; 83 } 84 85 if (group_id >= SPDK_TRACE_MAX_GROUP_ID) { 86 SPDK_ERRLOG("invalid group ID %d\n", group_id); 87 return; 88 } 89 90 g_trace_flags->tpoint_mask[group_id] &= ~tpoint_mask; 91 } 92 93 uint64_t 94 spdk_trace_get_tpoint_group_mask(void) 95 { 96 uint64_t mask = 0x0; 97 int i; 98 99 for (i = 0; i < SPDK_TRACE_MAX_GROUP_ID; i++) { 100 if (spdk_trace_get_tpoint_mask(i) != 0) { 101 mask |= (1ULL << i); 102 } 103 } 104 105 return mask; 106 } 107 108 void 109 spdk_trace_set_tpoint_group_mask(uint64_t tpoint_group_mask) 110 { 111 int i; 112 113 if (g_trace_flags == NULL) { 114 SPDK_ERRLOG("trace is not initialized\n"); 115 return; 116 } 117 118 for (i = 0; i < SPDK_TRACE_MAX_GROUP_ID; i++) { 119 if (tpoint_group_mask & (1ULL << i)) { 120 spdk_trace_set_tpoints(i, -1ULL); 121 } 122 } 123 } 124 125 void 126 spdk_trace_clear_tpoint_group_mask(uint64_t tpoint_group_mask) 127 { 128 int i; 129 130 if (g_trace_flags == NULL) { 131 SPDK_ERRLOG("trace is not initialized\n"); 132 return; 133 } 134 135 for (i = 0; i < SPDK_TRACE_MAX_GROUP_ID; i++) { 136 if (tpoint_group_mask & (1ULL << i)) { 137 spdk_trace_clear_tpoints(i, -1ULL); 138 } 139 } 140 } 141 142 struct spdk_trace_register_fn * 143 spdk_trace_get_first_register_fn(void) 144 { 145 return g_reg_fn_head; 146 } 147 148 struct spdk_trace_register_fn * 149 spdk_trace_get_next_register_fn(struct spdk_trace_register_fn *register_fn) 150 { 151 return register_fn->next; 152 } 153 154 uint64_t 155 spdk_trace_create_tpoint_group_mask(const char *group_name) 156 { 157 uint64_t tpoint_group_mask = 0; 158 struct spdk_trace_register_fn *register_fn; 159 160 register_fn = spdk_trace_get_first_register_fn(); 161 if (strcmp(group_name, "all") == 0) { 162 while (register_fn) { 163 tpoint_group_mask |= (1UL << register_fn->tgroup_id); 164 165 register_fn = spdk_trace_get_next_register_fn(register_fn); 166 } 167 } else { 168 while (register_fn) { 169 if (strcmp(group_name, register_fn->name) == 0) { 170 break; 171 } 172 173 register_fn = spdk_trace_get_next_register_fn(register_fn); 174 } 175 176 if (register_fn != NULL) { 177 tpoint_group_mask |= (1UL << register_fn->tgroup_id); 178 } 179 } 180 181 return tpoint_group_mask; 182 } 183 184 int 185 spdk_trace_enable_tpoint_group(const char *group_name) 186 { 187 uint64_t tpoint_group_mask = 0; 188 189 if (g_trace_flags == NULL) { 190 return -1; 191 } 192 193 tpoint_group_mask = spdk_trace_create_tpoint_group_mask(group_name); 194 if (tpoint_group_mask == 0) { 195 return -1; 196 } 197 198 spdk_trace_set_tpoint_group_mask(tpoint_group_mask); 199 return 0; 200 } 201 202 int 203 spdk_trace_disable_tpoint_group(const char *group_name) 204 { 205 uint64_t tpoint_group_mask = 0; 206 207 if (g_trace_flags == NULL) { 208 return -1; 209 } 210 211 tpoint_group_mask = spdk_trace_create_tpoint_group_mask(group_name); 212 if (tpoint_group_mask == 0) { 213 return -1; 214 } 215 216 spdk_trace_clear_tpoint_group_mask(tpoint_group_mask); 217 return 0; 218 } 219 220 void 221 spdk_trace_mask_usage(FILE *f, const char *tmask_arg) 222 { 223 struct spdk_trace_register_fn *register_fn; 224 225 fprintf(f, " %s, --tpoint-group-mask <group-mask>[:<tpoint_mask>]\n", tmask_arg); 226 fprintf(f, " group_mask - tracepoint group mask "); 227 fprintf(f, "for spdk trace buffers (default 0x0"); 228 229 register_fn = g_reg_fn_head; 230 while (register_fn) { 231 fprintf(f, ", %s 0x%x", register_fn->name, 1 << register_fn->tgroup_id); 232 register_fn = register_fn->next; 233 } 234 235 fprintf(f, ", all 0xffff)\n"); 236 fprintf(f, " tpoint_mask - tracepoint mask for enabling individual"); 237 fprintf(f, " tpoints inside a tracepoint group."); 238 fprintf(f, " First tpoint inside a group can be"); 239 fprintf(f, " enabled by setting tpoint_mask to 1 (e.g. 0x8:1).\n"); 240 fprintf(f, " Masks can be combined (e.g. 0x400,0x8:1).\n"); 241 fprintf(f, " All available tpoints can be found in"); 242 fprintf(f, " /include/spdk_internal/trace_defs.h\n"); 243 } 244 245 void 246 spdk_trace_register_owner(uint8_t type, char id_prefix) 247 { 248 struct spdk_trace_owner *owner; 249 250 assert(type != OWNER_NONE); 251 252 if (g_trace_flags == NULL) { 253 SPDK_ERRLOG("trace is not initialized\n"); 254 return; 255 } 256 257 /* 'owner' has 256 entries and since 'type' is a uint8_t, it 258 * can't overrun the array. 259 */ 260 owner = &g_trace_flags->owner[type]; 261 assert(owner->type == 0); 262 263 owner->type = type; 264 owner->id_prefix = id_prefix; 265 } 266 267 void 268 spdk_trace_register_object(uint8_t type, char id_prefix) 269 { 270 struct spdk_trace_object *object; 271 272 assert(type != OBJECT_NONE); 273 274 if (g_trace_flags == NULL) { 275 SPDK_ERRLOG("trace is not initialized\n"); 276 return; 277 } 278 279 /* 'object' has 256 entries and since 'type' is a uint8_t, it 280 * can't overrun the array. 281 */ 282 object = &g_trace_flags->object[type]; 283 assert(object->type == 0); 284 285 object->type = type; 286 object->id_prefix = id_prefix; 287 } 288 289 static void 290 trace_register_description(const struct spdk_trace_tpoint_opts *opts) 291 { 292 struct spdk_trace_tpoint *tpoint; 293 size_t i, max_name_length; 294 295 assert(opts->tpoint_id != 0); 296 assert(opts->tpoint_id < SPDK_TRACE_MAX_TPOINT_ID); 297 298 if (strnlen(opts->name, sizeof(tpoint->name)) == sizeof(tpoint->name)) { 299 SPDK_ERRLOG("name (%s) too long\n", opts->name); 300 } 301 302 tpoint = &g_trace_flags->tpoint[opts->tpoint_id]; 303 assert(tpoint->tpoint_id == 0); 304 305 snprintf(tpoint->name, sizeof(tpoint->name), "%s", opts->name); 306 tpoint->tpoint_id = opts->tpoint_id; 307 tpoint->object_type = opts->object_type; 308 tpoint->owner_type = opts->owner_type; 309 tpoint->new_object = opts->new_object; 310 311 max_name_length = sizeof(tpoint->args[0].name); 312 for (i = 0; i < SPDK_TRACE_MAX_ARGS_COUNT; ++i) { 313 if (!opts->args[i].name || opts->args[i].name[0] == '\0') { 314 break; 315 } 316 317 switch (opts->args[i].type) { 318 case SPDK_TRACE_ARG_TYPE_INT: 319 case SPDK_TRACE_ARG_TYPE_PTR: 320 /* The integers and pointers have to be exactly 64b long */ 321 assert(opts->args[i].size == sizeof(uint64_t)); 322 break; 323 case SPDK_TRACE_ARG_TYPE_STR: 324 /* Strings need to have at least one byte for the NULL terminator */ 325 assert(opts->args[i].size > 0); 326 break; 327 default: 328 assert(0 && "invalid trace argument type"); 329 break; 330 } 331 332 if (strnlen(opts->args[i].name, max_name_length) == max_name_length) { 333 SPDK_ERRLOG("argument name (%s) is too long\n", opts->args[i].name); 334 } 335 336 snprintf(tpoint->args[i].name, sizeof(tpoint->args[i].name), 337 "%s", opts->args[i].name); 338 tpoint->args[i].type = opts->args[i].type; 339 tpoint->args[i].size = opts->args[i].size; 340 } 341 342 tpoint->num_args = i; 343 } 344 345 void 346 spdk_trace_register_description_ext(const struct spdk_trace_tpoint_opts *opts, size_t num_opts) 347 { 348 size_t i; 349 350 if (g_trace_flags == NULL) { 351 SPDK_ERRLOG("trace is not initialized\n"); 352 return; 353 } 354 355 for (i = 0; i < num_opts; ++i) { 356 trace_register_description(&opts[i]); 357 } 358 } 359 360 void 361 spdk_trace_register_description(const char *name, uint16_t tpoint_id, uint8_t owner_type, 362 uint8_t object_type, uint8_t new_object, 363 uint8_t arg1_type, const char *arg1_name) 364 { 365 struct spdk_trace_tpoint_opts opts = { 366 .name = name, 367 .tpoint_id = tpoint_id, 368 .owner_type = owner_type, 369 .object_type = object_type, 370 .new_object = new_object, 371 .args = {{ 372 .name = arg1_name, 373 .type = arg1_type, 374 .size = sizeof(uint64_t) 375 } 376 } 377 }; 378 379 spdk_trace_register_description_ext(&opts, 1); 380 } 381 382 void 383 spdk_trace_tpoint_register_relation(uint16_t tpoint_id, uint8_t object_type, uint8_t arg_index) 384 { 385 struct spdk_trace_tpoint *tpoint; 386 uint16_t i; 387 388 assert(object_type != OBJECT_NONE); 389 assert(tpoint_id != OBJECT_NONE); 390 391 if (g_trace_flags == NULL) { 392 SPDK_ERRLOG("trace is not initialized\n"); 393 return; 394 } 395 396 /* We do not check whether a tpoint_id exists here, because 397 * there is no order in which trace definitions are registered. 398 * This way we can create relations between tpoint and objects 399 * that will be declared later. */ 400 tpoint = &g_trace_flags->tpoint[tpoint_id]; 401 for (i = 0; i < SPDK_COUNTOF(tpoint->related_objects); ++i) { 402 if (tpoint->related_objects[i].object_type == OBJECT_NONE) { 403 tpoint->related_objects[i].object_type = object_type; 404 tpoint->related_objects[i].arg_index = arg_index; 405 return; 406 } 407 } 408 SPDK_ERRLOG("Unable to register new relation for tpoint %" PRIu16 ", object %" PRIu8 "\n", 409 tpoint_id, object_type); 410 } 411 412 void 413 spdk_trace_add_register_fn(struct spdk_trace_register_fn *reg_fn) 414 { 415 struct spdk_trace_register_fn *_reg_fn; 416 417 if (reg_fn->name == NULL) { 418 SPDK_ERRLOG("missing name for registering spdk trace tpoint group\n"); 419 assert(false); 420 return; 421 } 422 423 if (strcmp(reg_fn->name, "all") == 0) { 424 SPDK_ERRLOG("illegal name (%s) for tpoint group\n", reg_fn->name); 425 assert(false); 426 return; 427 } 428 429 /* Ensure that no trace point group IDs and names are ever duplicated */ 430 for (_reg_fn = g_reg_fn_head; _reg_fn; _reg_fn = _reg_fn->next) { 431 if (reg_fn->tgroup_id == _reg_fn->tgroup_id) { 432 SPDK_ERRLOG("group %d, %s has duplicate tgroup_id with %s\n", 433 reg_fn->tgroup_id, reg_fn->name, _reg_fn->name); 434 assert(false); 435 return; 436 } 437 438 if (strcmp(reg_fn->name, _reg_fn->name) == 0) { 439 SPDK_ERRLOG("name %s is duplicated between groups with ids %d and %d\n", 440 reg_fn->name, reg_fn->tgroup_id, _reg_fn->tgroup_id); 441 assert(false); 442 return; 443 } 444 } 445 446 /* Arrange trace registration in order on tgroup_id */ 447 if (g_reg_fn_head == NULL || reg_fn->tgroup_id < g_reg_fn_head->tgroup_id) { 448 reg_fn->next = g_reg_fn_head; 449 g_reg_fn_head = reg_fn; 450 return; 451 } 452 453 for (_reg_fn = g_reg_fn_head; _reg_fn; _reg_fn = _reg_fn->next) { 454 if (_reg_fn->next == NULL || reg_fn->tgroup_id < _reg_fn->next->tgroup_id) { 455 reg_fn->next = _reg_fn->next; 456 _reg_fn->next = reg_fn; 457 return; 458 } 459 } 460 } 461 462 void 463 spdk_trace_flags_init(void) 464 { 465 struct spdk_trace_register_fn *reg_fn; 466 467 reg_fn = g_reg_fn_head; 468 while (reg_fn) { 469 reg_fn->reg_fn(); 470 reg_fn = reg_fn->next; 471 } 472 } 473