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