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