1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(C) 2020 Marvell International Ltd. 3 */ 4 5 #include <inttypes.h> 6 #include <time.h> 7 8 #include <rte_byteorder.h> 9 #include <rte_common.h> 10 #include <rte_time.h> 11 #include <rte_trace.h> 12 #include <rte_version.h> 13 14 #include "eal_trace.h" 15 16 __rte_format_printf(2, 0) 17 static int 18 metadata_printf(char **str, const char *fmt, ...) 19 { 20 va_list ap; 21 int rc; 22 23 *str = NULL; 24 va_start(ap, fmt); 25 rc = vasprintf(str, fmt, ap); 26 va_end(ap); 27 28 return rc; 29 } 30 31 static int 32 meta_copy(char **meta, int *offset, char *str, int rc) 33 { 34 int count = *offset; 35 char *ptr = *meta; 36 37 if (rc < 0) 38 return rc; 39 40 ptr = realloc(ptr, count + rc + 1); 41 if (ptr == NULL) 42 goto free_str; 43 44 memcpy(RTE_PTR_ADD(ptr, count), str, rc); 45 ptr[count + rc] = '\0'; 46 count += rc; 47 free(str); 48 49 *meta = ptr; 50 *offset = count; 51 52 return rc; 53 54 free_str: 55 if (str) 56 free(str); 57 return -ENOMEM; 58 } 59 60 static int 61 meta_data_type_emit(char **meta, int *offset) 62 { 63 char *str = NULL; 64 int rc; 65 66 rc = metadata_printf(&str, 67 "/* CTF 1.8 */\n" 68 "typealias integer {size = 8; base = x;}:= uint8_t;\n" 69 "typealias integer {size = 16; base = x;} := uint16_t;\n" 70 "typealias integer {size = 32; base = x;} := uint32_t;\n" 71 "typealias integer {size = 64; base = x;} := uint64_t;\n" 72 "typealias integer {size = 8; signed = true;} := int8_t;\n" 73 "typealias integer {size = 16; signed = true;} := int16_t;\n" 74 "typealias integer {size = 32; signed = true;} := int32_t;\n" 75 "typealias integer {size = 64; signed = true;} := int64_t;\n" 76 #ifdef RTE_ARCH_64 77 "typealias integer {size = 64; base = x;} := uintptr_t;\n" 78 #else 79 "typealias integer {size = 32; base = x;} := uintptr_t;\n" 80 #endif 81 #ifdef RTE_ARCH_64 82 "typealias integer {size = 64; base = x;} := long;\n" 83 #else 84 "typealias integer {size = 32; base = x;} := long;\n" 85 #endif 86 "typealias integer {size = 8; signed = false; encoding = ASCII; } := string_bounded_t;\n\n" 87 #ifdef RTE_ARCH_64 88 "typealias integer {size = 64; base = x;} := size_t;\n" 89 #else 90 "typealias integer {size = 32; base = x;} := size_t;\n" 91 #endif 92 "typealias floating_point {\n" 93 " exp_dig = 8;\n" 94 " mant_dig = 24;\n" 95 "} := float;\n\n" 96 "typealias floating_point {\n" 97 " exp_dig = 11;\n" 98 " mant_dig = 53;\n" 99 "} := double;\n\n"); 100 101 return meta_copy(meta, offset, str, rc); 102 } 103 104 static int 105 is_be(void) 106 { 107 #if RTE_BYTE_ORDER == RTE_BIG_ENDIAN 108 return 1; 109 #else 110 return 0; 111 #endif 112 } 113 114 static int 115 meta_header_emit(char **meta, int *offset) 116 { 117 struct trace *trace = trace_obj_get(); 118 char uustr[RTE_UUID_STRLEN]; 119 char *str = NULL; 120 int rc; 121 122 rte_uuid_unparse(trace->uuid, uustr, RTE_UUID_STRLEN); 123 rc = metadata_printf(&str, 124 "trace {\n" 125 " major = 1;\n" 126 " minor = 8;\n" 127 " uuid = \"%s\";\n" 128 " byte_order = %s;\n" 129 " packet.header := struct {\n" 130 " uint32_t magic;\n" 131 " uint8_t uuid[16];\n" 132 " };\n" 133 "};\n\n", uustr, is_be() ? "be" : "le"); 134 return meta_copy(meta, offset, str, rc); 135 } 136 137 static int 138 meta_env_emit(char **meta, int *offset) 139 { 140 char *str = NULL; 141 int rc; 142 143 rc = metadata_printf(&str, 144 "env {\n" 145 " dpdk_version = \"%s\";\n" 146 " tracer_name = \"dpdk\";\n" 147 "};\n\n", rte_version()); 148 return meta_copy(meta, offset, str, rc); 149 } 150 151 static int 152 meta_clock_pass1_emit(char **meta, int *offset) 153 { 154 char *str = NULL; 155 int rc; 156 157 rc = metadata_printf(&str, 158 "clock {\n" 159 " name = \"dpdk\";\n" 160 " freq = "); 161 return meta_copy(meta, offset, str, rc); 162 } 163 164 static int 165 meta_clock_pass2_emit(char **meta, int *offset) 166 { 167 char *str = NULL; 168 int rc; 169 170 rc = metadata_printf(&str, 171 "%20"PRIu64";\n" 172 " offset_s =", 0); 173 return meta_copy(meta, offset, str, rc); 174 } 175 176 static int 177 meta_clock_pass3_emit(char **meta, int *offset) 178 { 179 char *str = NULL; 180 int rc; 181 182 rc = metadata_printf(&str, 183 "%20"PRIu64";\n" 184 " offset =", 0); 185 return meta_copy(meta, offset, str, rc); 186 } 187 188 static int 189 meta_clock_pass4_emit(char **meta, int *offset) 190 { 191 char *str = NULL; 192 int rc; 193 194 rc = metadata_printf(&str, 195 "%20"PRIu64";\n};\n\n" 196 "typealias integer {\n" 197 " size = 48; align = 1; signed = false;\n" 198 " map = clock.dpdk.value;\n" 199 "} := uint48_clock_dpdk_t;\n\n", 0); 200 201 return meta_copy(meta, offset, str, rc); 202 } 203 204 static int 205 meta_stream_emit(char **meta, int *offset) 206 { 207 char *str = NULL; 208 int rc; 209 210 rc = metadata_printf(&str, 211 "stream {\n" 212 " packet.context := struct {\n" 213 " uint32_t cpu_id;\n" 214 " string_bounded_t name[32];\n" 215 " };\n" 216 " event.header := struct {\n" 217 " uint48_clock_dpdk_t timestamp;\n" 218 " uint16_t id;\n" 219 " } align(64);\n" 220 "};\n\n"); 221 return meta_copy(meta, offset, str, rc); 222 } 223 224 static int 225 meta_event_emit(char **meta, int *offset, struct trace_point *tp) 226 { 227 char *str = NULL; 228 int rc; 229 230 rc = metadata_printf(&str, 231 "event {\n" 232 " id = %d;\n" 233 " name = \"%s\";\n" 234 " fields := struct {\n" 235 "%s" 236 " };\n" 237 "};\n\n", trace_id_get(tp->handle), tp->name, 238 tp->ctf_field != NULL ? tp->ctf_field : ""); 239 return meta_copy(meta, offset, str, rc); 240 } 241 242 int 243 trace_metadata_create(void) 244 { 245 struct trace_point_head *tp_list = trace_list_head_get(); 246 struct trace *trace = trace_obj_get(); 247 struct trace_point *tp; 248 int rc, offset = 0; 249 char *meta = NULL; 250 251 rc = meta_data_type_emit(&meta, &offset); 252 if (rc < 0) 253 goto fail; 254 255 rc = meta_header_emit(&meta, &offset); 256 if (rc < 0) 257 goto fail; 258 259 rc = meta_env_emit(&meta, &offset); 260 if (rc < 0) 261 goto fail; 262 263 rc = meta_clock_pass1_emit(&meta, &offset); 264 if (rc < 0) 265 goto fail; 266 trace->ctf_meta_offset_freq = offset; 267 268 rc = meta_clock_pass2_emit(&meta, &offset); 269 if (rc < 0) 270 goto fail; 271 trace->ctf_meta_offset_freq_off_s = offset; 272 273 rc = meta_clock_pass3_emit(&meta, &offset); 274 if (rc < 0) 275 goto fail; 276 trace->ctf_meta_offset_freq_off = offset; 277 278 rc = meta_clock_pass4_emit(&meta, &offset); 279 if (rc < 0) 280 goto fail; 281 282 rc = meta_stream_emit(&meta, &offset); 283 if (rc < 0) 284 goto fail; 285 286 STAILQ_FOREACH(tp, tp_list, next) 287 if (meta_event_emit(&meta, &offset, tp) < 0) 288 goto fail; 289 290 trace->ctf_meta = meta; 291 return 0; 292 293 fail: 294 if (meta) 295 free(meta); 296 return -EBADF; 297 } 298 299 void 300 trace_metadata_destroy(void) 301 { 302 struct trace *trace = trace_obj_get(); 303 304 if (trace->ctf_meta) { 305 free(trace->ctf_meta); 306 trace->ctf_meta = NULL; 307 } 308 } 309 310 static void 311 meta_fix_freq(struct trace *trace, char *meta) 312 { 313 char *str; 314 int rc; 315 316 str = RTE_PTR_ADD(meta, trace->ctf_meta_offset_freq); 317 rc = sprintf(str, "%20"PRIu64"", rte_get_timer_hz()); 318 str[rc] = ';'; 319 } 320 321 static void 322 meta_fix_freq_offset(struct trace *trace, char *meta) 323 { 324 uint64_t uptime_tickes_floor, uptime_ticks, freq, uptime_sec; 325 uint64_t offset, offset_s; 326 char *str; 327 int rc; 328 329 uptime_ticks = trace->uptime_ticks & 330 ((1ULL << __RTE_TRACE_EVENT_HEADER_ID_SHIFT) - 1); 331 freq = rte_get_tsc_hz(); 332 uptime_tickes_floor = RTE_ALIGN_MUL_FLOOR(uptime_ticks, freq); 333 334 uptime_sec = uptime_tickes_floor / freq; 335 offset_s = trace->epoch_sec - uptime_sec; 336 337 offset = uptime_ticks - uptime_tickes_floor; 338 offset += trace->epoch_nsec * (freq / NSEC_PER_SEC); 339 340 str = RTE_PTR_ADD(meta, trace->ctf_meta_offset_freq_off_s); 341 rc = sprintf(str, "%20"PRIu64"", offset_s); 342 str[rc] = ';'; 343 str = RTE_PTR_ADD(meta, trace->ctf_meta_offset_freq_off); 344 rc = sprintf(str, "%20"PRIu64"", offset); 345 str[rc] = ';'; 346 } 347 348 static void 349 meta_fixup(struct trace *trace, char *meta) 350 { 351 meta_fix_freq(trace, meta); 352 meta_fix_freq_offset(trace, meta); 353 } 354 355 int 356 rte_trace_metadata_dump(FILE *f) 357 { 358 struct trace *trace = trace_obj_get(); 359 char *ctf_meta = trace->ctf_meta; 360 int rc; 361 362 if (!rte_trace_is_enabled()) 363 return 0; 364 365 if (ctf_meta == NULL) 366 return -EINVAL; 367 368 if (!__atomic_load_n(&trace->ctf_fixup_done, __ATOMIC_SEQ_CST) && 369 rte_get_timer_hz()) { 370 meta_fixup(trace, ctf_meta); 371 __atomic_store_n(&trace->ctf_fixup_done, 1, __ATOMIC_SEQ_CST); 372 } 373 374 rc = fprintf(f, "%s", ctf_meta); 375 return rc < 0 ? rc : 0; 376 } 377 378 char *trace_metadata_fixup_field(const char *field) 379 { 380 const char *ctf_reserved_words[] = { 381 "align", 382 "event", 383 }; 384 unsigned int i; 385 char *out; 386 char *p; 387 388 /* reserved keywords */ 389 for (i = 0; i < RTE_DIM(ctf_reserved_words); i++) { 390 if (strcmp(field, ctf_reserved_words[i]) != 0) 391 continue; 392 if (asprintf(&out, "_%s", ctf_reserved_words[i]) == -1) 393 out = NULL; 394 return out; 395 } 396 397 /* nothing to replace, return early */ 398 if (strstr(field, ".") == NULL && strstr(field, "->") == NULL) 399 return NULL; 400 401 out = strdup(field); 402 if (out == NULL) 403 return NULL; 404 p = out; 405 while ((p = strstr(p, ".")) != NULL) { 406 p[0] = '_'; 407 p++; 408 } 409 p = out; 410 while ((p = strstr(p, "->")) != NULL) { 411 p[0] = '_'; 412 p++; 413 memmove(p, p + 1, strlen(p)); 414 } 415 return out; 416 } 417