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 void 281 spdk_trace_register_description(const char *name, uint16_t tpoint_id, uint8_t owner_type, 282 uint8_t object_type, uint8_t new_object, 283 uint8_t arg1_type, const char *arg1_name) 284 { 285 struct spdk_trace_tpoint *tpoint; 286 287 assert(tpoint_id != 0); 288 assert(tpoint_id < SPDK_TRACE_MAX_TPOINT_ID); 289 290 if (g_trace_flags == NULL) { 291 SPDK_ERRLOG("trace is not initialized\n"); 292 return; 293 } 294 295 if (strnlen(name, sizeof(tpoint->name)) == sizeof(tpoint->name)) { 296 SPDK_ERRLOG("name (%s) too long\n", name); 297 } 298 299 tpoint = &g_trace_flags->tpoint[tpoint_id]; 300 assert(tpoint->tpoint_id == 0); 301 302 snprintf(tpoint->name, sizeof(tpoint->name), "%s", name); 303 tpoint->tpoint_id = tpoint_id; 304 tpoint->object_type = object_type; 305 tpoint->owner_type = owner_type; 306 tpoint->new_object = new_object; 307 tpoint->arg1_type = arg1_type; 308 snprintf(tpoint->arg1_name, sizeof(tpoint->arg1_name), "%s", arg1_name); 309 } 310 311 void 312 spdk_trace_add_register_fn(struct spdk_trace_register_fn *reg_fn) 313 { 314 struct spdk_trace_register_fn *_reg_fn; 315 316 if (reg_fn->name == NULL) { 317 SPDK_ERRLOG("missing name for registering spdk trace tpoint group\n"); 318 assert(false); 319 return; 320 } 321 322 if (strcmp(reg_fn->name, "all") == 0) { 323 SPDK_ERRLOG("illegal name (%s) for tpoint group\n", reg_fn->name); 324 assert(false); 325 return; 326 } 327 328 /* Ensure that no trace point group IDs and names are ever duplicated */ 329 for (_reg_fn = g_reg_fn_head; _reg_fn; _reg_fn = _reg_fn->next) { 330 if (reg_fn->tgroup_id == _reg_fn->tgroup_id) { 331 SPDK_ERRLOG("duplicate tgroup_id (%d) with %s\n", _reg_fn->tgroup_id, _reg_fn->name); 332 assert(false); 333 return; 334 } 335 336 if (strcmp(reg_fn->name, _reg_fn->name) == 0) { 337 SPDK_ERRLOG("duplicate name with %s\n", _reg_fn->name); 338 assert(false); 339 return; 340 } 341 } 342 343 /* Arrange trace registration in order on tgroup_id */ 344 if (g_reg_fn_head == NULL || reg_fn->tgroup_id < g_reg_fn_head->tgroup_id) { 345 reg_fn->next = g_reg_fn_head; 346 g_reg_fn_head = reg_fn; 347 return; 348 } 349 350 for (_reg_fn = g_reg_fn_head; _reg_fn; _reg_fn = _reg_fn->next) { 351 if (_reg_fn->next == NULL || reg_fn->tgroup_id < _reg_fn->next->tgroup_id) { 352 reg_fn->next = _reg_fn->next; 353 _reg_fn->next = reg_fn; 354 return; 355 } 356 } 357 } 358 359 void 360 spdk_trace_flags_init(void) 361 { 362 struct spdk_trace_register_fn *reg_fn; 363 364 reg_fn = g_reg_fn_head; 365 while (reg_fn) { 366 reg_fn->reg_fn(); 367 reg_fn = reg_fn->next; 368 } 369 } 370