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 static uint64_t 155 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 = 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 = 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 <mask>\n", tmask_arg); 226 fprintf(f, " tracepoint group mask for spdk trace buffers (default 0x0"); 227 228 register_fn = g_reg_fn_head; 229 while (register_fn) { 230 fprintf(f, ", %s 0x%x", register_fn->name, 1 << register_fn->tgroup_id); 231 register_fn = register_fn->next; 232 } 233 234 fprintf(f, ", all 0xffff)\n"); 235 } 236 237 void 238 spdk_trace_register_owner(uint8_t type, char id_prefix) 239 { 240 struct spdk_trace_owner *owner; 241 242 assert(type != OWNER_NONE); 243 244 if (g_trace_flags == NULL) { 245 SPDK_ERRLOG("trace is not initialized\n"); 246 return; 247 } 248 249 /* 'owner' has 256 entries and since 'type' is a uint8_t, it 250 * can't overrun the array. 251 */ 252 owner = &g_trace_flags->owner[type]; 253 assert(owner->type == 0); 254 255 owner->type = type; 256 owner->id_prefix = id_prefix; 257 } 258 259 void 260 spdk_trace_register_object(uint8_t type, char id_prefix) 261 { 262 struct spdk_trace_object *object; 263 264 assert(type != OBJECT_NONE); 265 266 if (g_trace_flags == NULL) { 267 SPDK_ERRLOG("trace is not initialized\n"); 268 return; 269 } 270 271 /* 'object' has 256 entries and since 'type' is a uint8_t, it 272 * can't overrun the array. 273 */ 274 object = &g_trace_flags->object[type]; 275 assert(object->type == 0); 276 277 object->type = type; 278 object->id_prefix = id_prefix; 279 } 280 281 static void 282 trace_register_description(const struct spdk_trace_tpoint_opts *opts) 283 { 284 struct spdk_trace_tpoint *tpoint; 285 size_t i, max_name_length; 286 287 assert(opts->tpoint_id != 0); 288 assert(opts->tpoint_id < SPDK_TRACE_MAX_TPOINT_ID); 289 290 if (strnlen(opts->name, sizeof(tpoint->name)) == sizeof(tpoint->name)) { 291 SPDK_ERRLOG("name (%s) too long\n", opts->name); 292 } 293 294 tpoint = &g_trace_flags->tpoint[opts->tpoint_id]; 295 assert(tpoint->tpoint_id == 0); 296 297 snprintf(tpoint->name, sizeof(tpoint->name), "%s", opts->name); 298 tpoint->tpoint_id = opts->tpoint_id; 299 tpoint->object_type = opts->object_type; 300 tpoint->owner_type = opts->owner_type; 301 tpoint->new_object = opts->new_object; 302 303 max_name_length = sizeof(tpoint->args[0].name); 304 for (i = 0; i < SPDK_TRACE_MAX_ARGS_COUNT; ++i) { 305 if (!opts->args[i].name || opts->args[i].name[0] == '\0') { 306 break; 307 } 308 309 switch (opts->args[i].type) { 310 case SPDK_TRACE_ARG_TYPE_INT: 311 case SPDK_TRACE_ARG_TYPE_PTR: 312 /* The integers and pointers have to be exactly 64b long */ 313 assert(opts->args[i].size == sizeof(uint64_t)); 314 break; 315 case SPDK_TRACE_ARG_TYPE_STR: 316 /* Strings need to have at least one byte for the NULL terminator */ 317 assert(opts->args[i].size > 0); 318 break; 319 default: 320 assert(0 && "invalid trace argument type"); 321 break; 322 } 323 324 if (strnlen(opts->args[i].name, max_name_length) == max_name_length) { 325 SPDK_ERRLOG("argument name (%s) is too long\n", opts->args[i].name); 326 } 327 328 snprintf(tpoint->args[i].name, sizeof(tpoint->args[i].name), 329 "%s", opts->args[i].name); 330 tpoint->args[i].type = opts->args[i].type; 331 tpoint->args[i].size = opts->args[i].size; 332 } 333 334 tpoint->num_args = i; 335 } 336 337 void 338 spdk_trace_register_description_ext(const struct spdk_trace_tpoint_opts *opts, size_t num_opts) 339 { 340 size_t i; 341 342 if (g_trace_flags == NULL) { 343 SPDK_ERRLOG("trace is not initialized\n"); 344 return; 345 } 346 347 for (i = 0; i < num_opts; ++i) { 348 trace_register_description(&opts[i]); 349 } 350 } 351 352 void 353 spdk_trace_register_description(const char *name, uint16_t tpoint_id, uint8_t owner_type, 354 uint8_t object_type, uint8_t new_object, 355 uint8_t arg1_type, const char *arg1_name) 356 { 357 struct spdk_trace_tpoint_opts opts = { 358 .name = name, 359 .tpoint_id = tpoint_id, 360 .owner_type = owner_type, 361 .object_type = object_type, 362 .new_object = new_object, 363 .args = {{ 364 .name = arg1_name, 365 .type = arg1_type, 366 .size = sizeof(uint64_t) 367 } 368 } 369 }; 370 371 spdk_trace_register_description_ext(&opts, 1); 372 } 373 374 void 375 spdk_trace_tpoint_register_relation(uint16_t tpoint_id, uint8_t object_type, uint8_t arg_index) 376 { 377 struct spdk_trace_tpoint *tpoint; 378 uint16_t i; 379 380 assert(object_type != OBJECT_NONE); 381 assert(tpoint_id != OBJECT_NONE); 382 383 if (g_trace_flags == NULL) { 384 SPDK_ERRLOG("trace is not initialized\n"); 385 return; 386 } 387 388 /* We do not check whether a tpoint_id exists here, because 389 * there is no order in which trace definitions are registered. 390 * This way we can create relations between tpoint and objects 391 * that will be declared later. */ 392 tpoint = &g_trace_flags->tpoint[tpoint_id]; 393 for (i = 0; i < SPDK_COUNTOF(tpoint->related_objects); ++i) { 394 if (tpoint->related_objects[i].object_type == OBJECT_NONE) { 395 tpoint->related_objects[i].object_type = object_type; 396 tpoint->related_objects[i].arg_index = arg_index; 397 return; 398 } 399 } 400 SPDK_ERRLOG("Unable to register new relation for tpoint %" PRIu16 ", object %" PRIu8 "\n", 401 tpoint_id, object_type); 402 } 403 404 void 405 spdk_trace_add_register_fn(struct spdk_trace_register_fn *reg_fn) 406 { 407 struct spdk_trace_register_fn *_reg_fn; 408 409 if (reg_fn->name == NULL) { 410 SPDK_ERRLOG("missing name for registering spdk trace tpoint group\n"); 411 assert(false); 412 return; 413 } 414 415 if (strcmp(reg_fn->name, "all") == 0) { 416 SPDK_ERRLOG("illegal name (%s) for tpoint group\n", reg_fn->name); 417 assert(false); 418 return; 419 } 420 421 /* Ensure that no trace point group IDs and names are ever duplicated */ 422 for (_reg_fn = g_reg_fn_head; _reg_fn; _reg_fn = _reg_fn->next) { 423 if (reg_fn->tgroup_id == _reg_fn->tgroup_id) { 424 SPDK_ERRLOG("duplicate tgroup_id (%d) with %s\n", _reg_fn->tgroup_id, _reg_fn->name); 425 assert(false); 426 return; 427 } 428 429 if (strcmp(reg_fn->name, _reg_fn->name) == 0) { 430 SPDK_ERRLOG("duplicate name with %s\n", _reg_fn->name); 431 assert(false); 432 return; 433 } 434 } 435 436 /* Arrange trace registration in order on tgroup_id */ 437 if (g_reg_fn_head == NULL || reg_fn->tgroup_id < g_reg_fn_head->tgroup_id) { 438 reg_fn->next = g_reg_fn_head; 439 g_reg_fn_head = reg_fn; 440 return; 441 } 442 443 for (_reg_fn = g_reg_fn_head; _reg_fn; _reg_fn = _reg_fn->next) { 444 if (_reg_fn->next == NULL || reg_fn->tgroup_id < _reg_fn->next->tgroup_id) { 445 reg_fn->next = _reg_fn->next; 446 _reg_fn->next = reg_fn; 447 return; 448 } 449 } 450 } 451 452 void 453 spdk_trace_flags_init(void) 454 { 455 struct spdk_trace_register_fn *reg_fn; 456 457 reg_fn = g_reg_fn_head; 458 while (reg_fn) { 459 reg_fn->reg_fn(); 460 reg_fn = reg_fn->next; 461 } 462 } 463