/* SPDX-License-Identifier: BSD-3-Clause * Copyright(C) 2020 Marvell International Ltd. */ #include #include #include #include #include #include #include #include "eal_trace.h" __rte_format_printf(2, 0) static int metadata_printf(char **str, const char *fmt, ...) { va_list ap; int rc; *str = NULL; va_start(ap, fmt); rc = vasprintf(str, fmt, ap); va_end(ap); return rc; } static int meta_copy(char **meta, int *offset, char *str, int rc) { int count = *offset; char *ptr = *meta; if (rc < 0) return rc; ptr = realloc(ptr, count + rc + 1); if (ptr == NULL) goto free_str; memcpy(RTE_PTR_ADD(ptr, count), str, rc); ptr[count + rc] = '\0'; count += rc; free(str); *meta = ptr; *offset = count; return rc; free_str: if (str) free(str); return -ENOMEM; } static int meta_data_type_emit(char **meta, int *offset) { char *str = NULL; int rc; rc = metadata_printf(&str, "/* CTF 1.8 */\n" "typealias integer {size = 8; base = x;}:= uint8_t;\n" "typealias integer {size = 16; base = x;} := uint16_t;\n" "typealias integer {size = 32; base = x;} := uint32_t;\n" "typealias integer {size = 64; base = x;} := uint64_t;\n" "typealias integer {size = 8; signed = true;} := int8_t;\n" "typealias integer {size = 16; signed = true;} := int16_t;\n" "typealias integer {size = 32; signed = true;} := int32_t;\n" "typealias integer {size = 64; signed = true;} := int64_t;\n" #ifdef RTE_ARCH_64 "typealias integer {size = 64; base = x;} := uintptr_t;\n" #else "typealias integer {size = 32; base = x;} := uintptr_t;\n" #endif #ifdef RTE_ARCH_64 "typealias integer {size = 64; base = x;} := long;\n" #else "typealias integer {size = 32; base = x;} := long;\n" #endif "typealias integer {size = 8; signed = false; encoding = ASCII; } := string_bounded_t;\n\n" #ifdef RTE_ARCH_64 "typealias integer {size = 64; base = x;} := size_t;\n" #else "typealias integer {size = 32; base = x;} := size_t;\n" #endif "typealias floating_point {\n" " exp_dig = 8;\n" " mant_dig = 24;\n" "} := float;\n\n" "typealias floating_point {\n" " exp_dig = 11;\n" " mant_dig = 53;\n" "} := double;\n\n"); return meta_copy(meta, offset, str, rc); } static int is_be(void) { #if RTE_BYTE_ORDER == RTE_BIG_ENDIAN return 1; #else return 0; #endif } static int meta_header_emit(char **meta, int *offset) { struct trace *trace = trace_obj_get(); char uustr[RTE_UUID_STRLEN]; char *str = NULL; int rc; rte_uuid_unparse(trace->uuid, uustr, RTE_UUID_STRLEN); rc = metadata_printf(&str, "trace {\n" " major = 1;\n" " minor = 8;\n" " uuid = \"%s\";\n" " byte_order = %s;\n" " packet.header := struct {\n" " uint32_t magic;\n" " uint8_t uuid[16];\n" " };\n" "};\n\n", uustr, is_be() ? "be" : "le"); return meta_copy(meta, offset, str, rc); } static int meta_env_emit(char **meta, int *offset) { char *str = NULL; int rc; rc = metadata_printf(&str, "env {\n" " dpdk_version = \"%s\";\n" " tracer_name = \"dpdk\";\n" "};\n\n", rte_version()); return meta_copy(meta, offset, str, rc); } static int meta_clock_pass1_emit(char **meta, int *offset) { char *str = NULL; int rc; rc = metadata_printf(&str, "clock {\n" " name = \"dpdk\";\n" " freq = "); return meta_copy(meta, offset, str, rc); } static int meta_clock_pass2_emit(char **meta, int *offset) { char *str = NULL; int rc; rc = metadata_printf(&str, "%20"PRIu64";\n" " offset_s =", 0); return meta_copy(meta, offset, str, rc); } static int meta_clock_pass3_emit(char **meta, int *offset) { char *str = NULL; int rc; rc = metadata_printf(&str, "%20"PRIu64";\n" " offset =", 0); return meta_copy(meta, offset, str, rc); } static int meta_clock_pass4_emit(char **meta, int *offset) { char *str = NULL; int rc; rc = metadata_printf(&str, "%20"PRIu64";\n};\n\n" "typealias integer {\n" " size = 48; align = 1; signed = false;\n" " map = clock.dpdk.value;\n" "} := uint48_clock_dpdk_t;\n\n", 0); return meta_copy(meta, offset, str, rc); } static int meta_stream_emit(char **meta, int *offset) { char *str = NULL; int rc; rc = metadata_printf(&str, "stream {\n" " packet.context := struct {\n" " uint32_t cpu_id;\n" " string_bounded_t name[32];\n" " };\n" " event.header := struct {\n" " uint48_clock_dpdk_t timestamp;\n" " uint16_t id;\n" " } align(64);\n" "};\n\n"); return meta_copy(meta, offset, str, rc); } static int meta_event_emit(char **meta, int *offset, struct trace_point *tp) { char *str = NULL; int rc; rc = metadata_printf(&str, "event {\n" " id = %d;\n" " name = \"%s\";\n" " fields := struct {\n" "%s" " };\n" "};\n\n", trace_id_get(tp->handle), tp->name, tp->ctf_field != NULL ? tp->ctf_field : ""); return meta_copy(meta, offset, str, rc); } int trace_metadata_create(void) { struct trace_point_head *tp_list = trace_list_head_get(); struct trace *trace = trace_obj_get(); struct trace_point *tp; int rc, offset = 0; char *meta = NULL; rc = meta_data_type_emit(&meta, &offset); if (rc < 0) goto fail; rc = meta_header_emit(&meta, &offset); if (rc < 0) goto fail; rc = meta_env_emit(&meta, &offset); if (rc < 0) goto fail; rc = meta_clock_pass1_emit(&meta, &offset); if (rc < 0) goto fail; trace->ctf_meta_offset_freq = offset; rc = meta_clock_pass2_emit(&meta, &offset); if (rc < 0) goto fail; trace->ctf_meta_offset_freq_off_s = offset; rc = meta_clock_pass3_emit(&meta, &offset); if (rc < 0) goto fail; trace->ctf_meta_offset_freq_off = offset; rc = meta_clock_pass4_emit(&meta, &offset); if (rc < 0) goto fail; rc = meta_stream_emit(&meta, &offset); if (rc < 0) goto fail; STAILQ_FOREACH(tp, tp_list, next) if (meta_event_emit(&meta, &offset, tp) < 0) goto fail; trace->ctf_meta = meta; return 0; fail: if (meta) free(meta); return -EBADF; } void trace_metadata_destroy(void) { struct trace *trace = trace_obj_get(); if (trace->ctf_meta) { free(trace->ctf_meta); trace->ctf_meta = NULL; } } static void meta_fix_freq(struct trace *trace, char *meta) { char *str; int rc; str = RTE_PTR_ADD(meta, trace->ctf_meta_offset_freq); rc = sprintf(str, "%20"PRIu64"", rte_get_timer_hz()); str[rc] = ';'; } static void meta_fix_freq_offset(struct trace *trace, char *meta) { uint64_t uptime_tickes_floor, uptime_ticks, freq, uptime_sec; uint64_t offset, offset_s; char *str; int rc; uptime_ticks = trace->uptime_ticks & ((1ULL << __RTE_TRACE_EVENT_HEADER_ID_SHIFT) - 1); freq = rte_get_tsc_hz(); uptime_tickes_floor = RTE_ALIGN_MUL_FLOOR(uptime_ticks, freq); uptime_sec = uptime_tickes_floor / freq; offset_s = trace->epoch_sec - uptime_sec; offset = uptime_ticks - uptime_tickes_floor; offset += trace->epoch_nsec * (freq / NSEC_PER_SEC); str = RTE_PTR_ADD(meta, trace->ctf_meta_offset_freq_off_s); rc = sprintf(str, "%20"PRIu64"", offset_s); str[rc] = ';'; str = RTE_PTR_ADD(meta, trace->ctf_meta_offset_freq_off); rc = sprintf(str, "%20"PRIu64"", offset); str[rc] = ';'; } static void meta_fixup(struct trace *trace, char *meta) { meta_fix_freq(trace, meta); meta_fix_freq_offset(trace, meta); } int rte_trace_metadata_dump(FILE *f) { struct trace *trace = trace_obj_get(); char *ctf_meta = trace->ctf_meta; int rc; if (!rte_trace_is_enabled()) return 0; if (ctf_meta == NULL) return -EINVAL; if (!__atomic_load_n(&trace->ctf_fixup_done, __ATOMIC_SEQ_CST) && rte_get_timer_hz()) { meta_fixup(trace, ctf_meta); __atomic_store_n(&trace->ctf_fixup_done, 1, __ATOMIC_SEQ_CST); } rc = fprintf(f, "%s", ctf_meta); return rc < 0 ? rc : 0; } char *trace_metadata_fixup_field(const char *field) { const char *ctf_reserved_words[] = { "align", "event", }; unsigned int i; char *out; char *p; /* reserved keywords */ for (i = 0; i < RTE_DIM(ctf_reserved_words); i++) { if (strcmp(field, ctf_reserved_words[i]) != 0) continue; if (asprintf(&out, "_%s", ctf_reserved_words[i]) == -1) out = NULL; return out; } /* nothing to replace, return early */ if (strstr(field, ".") == NULL && strstr(field, "->") == NULL) return NULL; out = strdup(field); if (out == NULL) return NULL; p = out; while ((p = strstr(p, ".")) != NULL) { p[0] = '_'; p++; } p = out; while ((p = strstr(p, "->")) != NULL) { p[0] = '_'; p++; memmove(p, p + 1, strlen(p)); } return out; }