summaryrefslogtreecommitdiff
path: root/tools/lib
diff options
context:
space:
mode:
Diffstat (limited to 'tools/lib')
-rw-r--r--tools/lib/bpf/btf.c5
-rw-r--r--tools/lib/bpf/hashmap.h5
-rw-r--r--tools/lib/bpf/libbpf.c67
-rw-r--r--tools/lib/bpf/xsk.c11
-rw-r--r--tools/lib/traceevent/Makefile10
-rw-r--r--tools/lib/traceevent/event-parse-api.c40
-rw-r--r--tools/lib/traceevent/event-parse-local.h6
-rw-r--r--tools/lib/traceevent/event-parse.c391
-rw-r--r--tools/lib/traceevent/event-parse.h30
-rw-r--r--tools/lib/traceevent/event-plugin.c2
10 files changed, 308 insertions, 259 deletions
diff --git a/tools/lib/bpf/btf.c b/tools/lib/bpf/btf.c
index 467224feb43b..d821107f55f9 100644
--- a/tools/lib/bpf/btf.c
+++ b/tools/lib/bpf/btf.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
/* Copyright (c) 2018 Facebook */
+#include <endian.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -419,9 +420,9 @@ done:
static bool btf_check_endianness(const GElf_Ehdr *ehdr)
{
-#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+#if __BYTE_ORDER == __LITTLE_ENDIAN
return ehdr->e_ident[EI_DATA] == ELFDATA2LSB;
-#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+#elif __BYTE_ORDER == __BIG_ENDIAN
return ehdr->e_ident[EI_DATA] == ELFDATA2MSB;
#else
# error "Unrecognized __BYTE_ORDER__"
diff --git a/tools/lib/bpf/hashmap.h b/tools/lib/bpf/hashmap.h
index 03748a742146..bae8879cdf58 100644
--- a/tools/lib/bpf/hashmap.h
+++ b/tools/lib/bpf/hashmap.h
@@ -10,6 +10,11 @@
#include <stdbool.h>
#include <stddef.h>
+#ifdef __GLIBC__
+#include <bits/wordsize.h>
+#else
+#include <bits/reg.h>
+#endif
#include "libbpf_internal.h"
static inline size_t hash_bits(size_t h, int bits)
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index 794dd5064ae8..2b57d7ea7836 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -20,6 +20,7 @@
#include <inttypes.h>
#include <string.h>
#include <unistd.h>
+#include <endian.h>
#include <fcntl.h>
#include <errno.h>
#include <asm/unistd.h>
@@ -181,7 +182,6 @@ struct bpf_program {
bpf_program_clear_priv_t clear_priv;
enum bpf_attach_type expected_attach_type;
- int btf_fd;
void *func_info;
__u32 func_info_rec_size;
__u32 func_info_cnt;
@@ -312,7 +312,6 @@ void bpf_program__unload(struct bpf_program *prog)
prog->instances.nr = -1;
zfree(&prog->instances.fds);
- zclose(prog->btf_fd);
zfree(&prog->func_info);
zfree(&prog->line_info);
}
@@ -391,7 +390,6 @@ bpf_program__init(void *data, size_t size, char *section_name, int idx,
prog->instances.fds = NULL;
prog->instances.nr = -1;
prog->type = BPF_PROG_TYPE_UNSPEC;
- prog->btf_fd = -1;
return 0;
errout:
@@ -612,10 +610,10 @@ errout:
static int bpf_object__check_endianness(struct bpf_object *obj)
{
-#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+#if __BYTE_ORDER == __LITTLE_ENDIAN
if (obj->efile.ehdr.e_ident[EI_DATA] == ELFDATA2LSB)
return 0;
-#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+#elif __BYTE_ORDER == __BIG_ENDIAN
if (obj->efile.ehdr.e_ident[EI_DATA] == ELFDATA2MSB)
return 0;
#else
@@ -1377,8 +1375,13 @@ static void bpf_object__sanitize_btf(struct bpf_object *obj)
if (!has_datasec && kind == BTF_KIND_VAR) {
/* replace VAR with INT */
t->info = BTF_INFO_ENC(BTF_KIND_INT, 0, 0);
- t->size = sizeof(int);
- *(int *)(t+1) = BTF_INT_ENC(0, 0, 32);
+ /*
+ * using size = 1 is the safest choice, 4 will be too
+ * big and cause kernel BTF validation failure if
+ * original variable took less than 4 bytes
+ */
+ t->size = 1;
+ *(int *)(t+1) = BTF_INT_ENC(0, 0, 8);
} else if (!has_datasec && kind == BTF_KIND_DATASEC) {
/* replace DATASEC with STRUCT */
struct btf_var_secinfo *v = (void *)(t + 1);
@@ -1500,6 +1503,12 @@ static int bpf_object__sanitize_and_load_btf(struct bpf_object *obj)
BTF_ELF_SEC, err);
btf__free(obj->btf);
obj->btf = NULL;
+ /* btf_ext can't exist without btf, so free it as well */
+ if (obj->btf_ext) {
+ btf_ext__free(obj->btf_ext);
+ obj->btf_ext = NULL;
+ }
+
if (bpf_object__is_btf_mandatory(obj))
return err;
}
@@ -2276,9 +2285,6 @@ bpf_program_reloc_btf_ext(struct bpf_program *prog, struct bpf_object *obj,
prog->line_info_rec_size = btf_ext__line_info_rec_size(obj->btf_ext);
}
- if (!insn_offset)
- prog->btf_fd = btf__fd(obj->btf);
-
return 0;
}
@@ -2451,7 +2457,7 @@ load_program(struct bpf_program *prog, struct bpf_insn *insns, int insns_cnt,
char *cp, errmsg[STRERR_BUFSIZE];
int log_buf_size = BPF_LOG_BUF_SIZE;
char *log_buf;
- int ret;
+ int btf_fd, ret;
if (!insns || !insns_cnt)
return -EINVAL;
@@ -2466,7 +2472,12 @@ load_program(struct bpf_program *prog, struct bpf_insn *insns, int insns_cnt,
load_attr.license = license;
load_attr.kern_version = kern_version;
load_attr.prog_ifindex = prog->prog_ifindex;
- load_attr.prog_btf_fd = prog->btf_fd >= 0 ? prog->btf_fd : 0;
+ /* if .BTF.ext was loaded, kernel supports associated BTF for prog */
+ if (prog->obj->btf_ext)
+ btf_fd = bpf_object__btf_fd(prog->obj);
+ else
+ btf_fd = -1;
+ load_attr.prog_btf_fd = btf_fd >= 0 ? btf_fd : 0;
load_attr.func_info = prog->func_info;
load_attr.func_info_rec_size = prog->func_info_rec_size;
load_attr.func_info_cnt = prog->func_info_cnt;
@@ -4507,13 +4518,13 @@ struct perf_buffer *perf_buffer__new(int map_fd, size_t page_cnt,
const struct perf_buffer_opts *opts)
{
struct perf_buffer_params p = {};
- struct perf_event_attr attr = {
- .config = PERF_COUNT_SW_BPF_OUTPUT,
- .type = PERF_TYPE_SOFTWARE,
- .sample_type = PERF_SAMPLE_RAW,
- .sample_period = 1,
- .wakeup_events = 1,
- };
+ struct perf_event_attr attr = { 0, };
+
+ attr.config = PERF_COUNT_SW_BPF_OUTPUT,
+ attr.type = PERF_TYPE_SOFTWARE;
+ attr.sample_type = PERF_SAMPLE_RAW;
+ attr.sample_period = 1;
+ attr.wakeup_events = 1;
p.attr = &attr;
p.sample_cb = opts ? opts->sample_cb : NULL;
@@ -4988,13 +4999,15 @@ int libbpf_num_possible_cpus(void)
static const char *fcpu = "/sys/devices/system/cpu/possible";
int len = 0, n = 0, il = 0, ir = 0;
unsigned int start = 0, end = 0;
+ int tmp_cpus = 0;
static int cpus;
char buf[128];
int error = 0;
int fd = -1;
- if (cpus > 0)
- return cpus;
+ tmp_cpus = READ_ONCE(cpus);
+ if (tmp_cpus > 0)
+ return tmp_cpus;
fd = open(fcpu, O_RDONLY);
if (fd < 0) {
@@ -5017,7 +5030,7 @@ int libbpf_num_possible_cpus(void)
}
buf[len] = '\0';
- for (ir = 0, cpus = 0; ir <= len; ir++) {
+ for (ir = 0, tmp_cpus = 0; ir <= len; ir++) {
/* Each sub string separated by ',' has format \d+-\d+ or \d+ */
if (buf[ir] == ',' || buf[ir] == '\0') {
buf[ir] = '\0';
@@ -5029,13 +5042,15 @@ int libbpf_num_possible_cpus(void)
} else if (n == 1) {
end = start;
}
- cpus += end - start + 1;
+ tmp_cpus += end - start + 1;
il = ir + 1;
}
}
- if (cpus <= 0) {
- pr_warning("Invalid #CPUs %d from %s\n", cpus, fcpu);
+ if (tmp_cpus <= 0) {
+ pr_warning("Invalid #CPUs %d from %s\n", tmp_cpus, fcpu);
return -EINVAL;
}
- return cpus;
+
+ WRITE_ONCE(cpus, tmp_cpus);
+ return tmp_cpus;
}
diff --git a/tools/lib/bpf/xsk.c b/tools/lib/bpf/xsk.c
index 5007b5d4fd2c..680e63066cf3 100644
--- a/tools/lib/bpf/xsk.c
+++ b/tools/lib/bpf/xsk.c
@@ -317,17 +317,16 @@ static int xsk_load_xdp_prog(struct xsk_socket *xsk)
static int xsk_get_max_queues(struct xsk_socket *xsk)
{
- struct ethtool_channels channels;
- struct ifreq ifr;
+ struct ethtool_channels channels = { .cmd = ETHTOOL_GCHANNELS };
+ struct ifreq ifr = {};
int fd, err, ret;
fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd < 0)
return -errno;
- channels.cmd = ETHTOOL_GCHANNELS;
ifr.ifr_data = (void *)&channels;
- strncpy(ifr.ifr_name, xsk->ifname, IFNAMSIZ - 1);
+ memcpy(ifr.ifr_name, xsk->ifname, IFNAMSIZ - 1);
ifr.ifr_name[IFNAMSIZ - 1] = '\0';
err = ioctl(fd, SIOCETHTOOL, &ifr);
if (err && errno != EOPNOTSUPP) {
@@ -335,7 +334,7 @@ static int xsk_get_max_queues(struct xsk_socket *xsk)
goto out;
}
- if (channels.max_combined == 0 || errno == EOPNOTSUPP)
+ if (err || channels.max_combined == 0)
/* If the device says it has no channels, then all traffic
* is sent to a single stream, so max queues = 1.
*/
@@ -517,7 +516,7 @@ int xsk_socket__create(struct xsk_socket **xsk_ptr, const char *ifname,
err = -errno;
goto out_socket;
}
- strncpy(xsk->ifname, ifname, IFNAMSIZ - 1);
+ memcpy(xsk->ifname, ifname, IFNAMSIZ - 1);
xsk->ifname[IFNAMSIZ - 1] = '\0';
err = xsk_set_xdp_socket_config(&xsk->config, usr_config);
diff --git a/tools/lib/traceevent/Makefile b/tools/lib/traceevent/Makefile
index 3292c290654f..a39cdd0d890d 100644
--- a/tools/lib/traceevent/Makefile
+++ b/tools/lib/traceevent/Makefile
@@ -62,15 +62,15 @@ set_plugin_dir := 1
# Set plugin_dir to preffered global plugin location
# If we install under $HOME directory we go under
-# $(HOME)/.traceevent/plugins
+# $(HOME)/.local/lib/traceevent/plugins
#
# We dont set PLUGIN_DIR in case we install under $HOME
# directory, because by default the code looks under:
-# $(HOME)/.traceevent/plugins by default.
+# $(HOME)/.local/lib/traceevent/plugins by default.
#
ifeq ($(plugin_dir),)
ifeq ($(prefix),$(HOME))
-override plugin_dir = $(HOME)/.traceevent/plugins
+override plugin_dir = $(HOME)/.local/lib/traceevent/plugins
set_plugin_dir := 0
else
override plugin_dir = $(libdir)/traceevent/plugins
@@ -266,8 +266,8 @@ endef
define do_generate_dynamic_list_file
symbol_type=`$(NM) -u -D $1 | awk 'NF>1 {print $$1}' | \
- xargs echo "U W w" | tr ' ' '\n' | sort -u | xargs echo`;\
- if [ "$$symbol_type" = "U W w" ];then \
+ xargs echo "U w W" | tr 'w ' 'W\n' | sort -u | xargs echo`;\
+ if [ "$$symbol_type" = "U W" ];then \
(echo '{'; \
$(NM) -u -D $1 | awk 'NF>1 {print "\t"$$2";"}' | sort -u;\
echo '};'; \
diff --git a/tools/lib/traceevent/event-parse-api.c b/tools/lib/traceevent/event-parse-api.c
index 988587840c80..4faf52a65791 100644
--- a/tools/lib/traceevent/event-parse-api.c
+++ b/tools/lib/traceevent/event-parse-api.c
@@ -303,33 +303,6 @@ void tep_set_local_bigendian(struct tep_handle *tep, enum tep_endian endian)
}
/**
- * tep_is_latency_format - get if the latency output format is configured
- * @tep: a handle to the tep_handle
- *
- * This returns true if the latency output format is configured
- * If @tep is NULL, false is returned.
- */
-bool tep_is_latency_format(struct tep_handle *tep)
-{
- if (tep)
- return (tep->latency_format);
- return false;
-}
-
-/**
- * tep_set_latency_format - set the latency output format
- * @tep: a handle to the tep_handle
- * @lat: non zero for latency output format
- *
- * This sets the latency output format
- */
-void tep_set_latency_format(struct tep_handle *tep, int lat)
-{
- if (tep)
- tep->latency_format = lat;
-}
-
-/**
* tep_is_old_format - get if an old kernel is used
* @tep: a handle to the tep_handle
*
@@ -345,19 +318,6 @@ bool tep_is_old_format(struct tep_handle *tep)
}
/**
- * tep_set_print_raw - set a flag to force print in raw format
- * @tep: a handle to the tep_handle
- * @print_raw: the new value of the print_raw flag
- *
- * This sets a flag to force print in raw format
- */
-void tep_set_print_raw(struct tep_handle *tep, int print_raw)
-{
- if (tep)
- tep->print_raw = print_raw;
-}
-
-/**
* tep_set_test_filters - set a flag to test a filter string
* @tep: a handle to the tep_handle
* @test_filters: the new value of the test_filters flag
diff --git a/tools/lib/traceevent/event-parse-local.h b/tools/lib/traceevent/event-parse-local.h
index 09aa142f7fdd..cee469803a34 100644
--- a/tools/lib/traceevent/event-parse-local.h
+++ b/tools/lib/traceevent/event-parse-local.h
@@ -28,8 +28,6 @@ struct tep_handle {
enum tep_endian file_bigendian;
enum tep_endian host_bigendian;
- int latency_format;
-
int old_format;
int cpus;
@@ -70,8 +68,6 @@ struct tep_handle {
int ld_offset;
int ld_size;
- int print_raw;
-
int test_filters;
int flags;
@@ -85,8 +81,6 @@ struct tep_handle {
/* cache */
struct tep_event *last_event;
-
- char *trace_clock;
};
void tep_free_event(struct tep_event *event);
diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c
index b36b536a9fcb..bb22238debfe 100644
--- a/tools/lib/traceevent/event-parse.c
+++ b/tools/lib/traceevent/event-parse.c
@@ -142,6 +142,25 @@ static int cmdline_cmp(const void *a, const void *b)
return 0;
}
+/* Looking for where to place the key */
+static int cmdline_slot_cmp(const void *a, const void *b)
+{
+ const struct tep_cmdline *ca = a;
+ const struct tep_cmdline *cb = b;
+ const struct tep_cmdline *cb1 = cb + 1;
+
+ if (ca->pid < cb->pid)
+ return -1;
+
+ if (ca->pid > cb->pid) {
+ if (ca->pid <= cb1->pid)
+ return 0;
+ return 1;
+ }
+
+ return 0;
+}
+
struct cmdline_list {
struct cmdline_list *next;
char *comm;
@@ -239,6 +258,7 @@ static int add_new_comm(struct tep_handle *tep,
struct tep_cmdline *cmdline;
struct tep_cmdline key;
char *new_comm;
+ int cnt;
if (!pid)
return 0;
@@ -269,21 +289,43 @@ static int add_new_comm(struct tep_handle *tep,
errno = ENOMEM;
return -1;
}
+ tep->cmdlines = cmdlines;
- cmdlines[tep->cmdline_count].comm = strdup(comm);
- if (!cmdlines[tep->cmdline_count].comm) {
- free(cmdlines);
+ key.comm = strdup(comm);
+ if (!key.comm) {
errno = ENOMEM;
return -1;
}
- cmdlines[tep->cmdline_count].pid = pid;
-
- if (cmdlines[tep->cmdline_count].comm)
+ if (!tep->cmdline_count) {
+ /* no entries yet */
+ tep->cmdlines[0] = key;
tep->cmdline_count++;
+ return 0;
+ }
- qsort(cmdlines, tep->cmdline_count, sizeof(*cmdlines), cmdline_cmp);
- tep->cmdlines = cmdlines;
+ /* Now find where we want to store the new cmdline */
+ cmdline = bsearch(&key, tep->cmdlines, tep->cmdline_count - 1,
+ sizeof(*tep->cmdlines), cmdline_slot_cmp);
+
+ cnt = tep->cmdline_count;
+ if (cmdline) {
+ /* cmdline points to the one before the spot we want */
+ cmdline++;
+ cnt -= cmdline - tep->cmdlines;
+
+ } else {
+ /* The new entry is either before or after the list */
+ if (key.pid > tep->cmdlines[tep->cmdline_count - 1].pid) {
+ tep->cmdlines[tep->cmdline_count++] = key;
+ return 0;
+ }
+ cmdline = &tep->cmdlines[0];
+ }
+ memmove(cmdline + 1, cmdline, (cnt * sizeof(*cmdline)));
+ *cmdline = key;
+
+ tep->cmdline_count++;
return 0;
}
@@ -351,16 +393,6 @@ int tep_override_comm(struct tep_handle *tep, const char *comm, int pid)
return _tep_register_comm(tep, comm, pid, true);
}
-int tep_register_trace_clock(struct tep_handle *tep, const char *trace_clock)
-{
- tep->trace_clock = strdup(trace_clock);
- if (!tep->trace_clock) {
- errno = ENOMEM;
- return -1;
- }
- return 0;
-}
-
struct func_map {
unsigned long long addr;
char *func;
@@ -5170,24 +5202,20 @@ out_failed:
}
}
-/**
- * tep_data_latency_format - parse the data for the latency format
- * @tep: a handle to the trace event parser context
- * @s: the trace_seq to write to
- * @record: the record to read from
- *
+/*
* This parses out the Latency format (interrupts disabled,
* need rescheduling, in hard/soft interrupt, preempt count
* and lock depth) and places it into the trace_seq.
*/
-void tep_data_latency_format(struct tep_handle *tep,
- struct trace_seq *s, struct tep_record *record)
+static void data_latency_format(struct tep_handle *tep, struct trace_seq *s,
+ char *format, struct tep_record *record)
{
static int check_lock_depth = 1;
static int check_migrate_disable = 1;
static int lock_depth_exists;
static int migrate_disable_exists;
unsigned int lat_flags;
+ struct trace_seq sq;
unsigned int pc;
int lock_depth = 0;
int migrate_disable = 0;
@@ -5195,6 +5223,7 @@ void tep_data_latency_format(struct tep_handle *tep,
int softirq;
void *data = record->data;
+ trace_seq_init(&sq);
lat_flags = parse_common_flags(tep, data);
pc = parse_common_pc(tep, data);
/* lock_depth may not always exist */
@@ -5222,7 +5251,7 @@ void tep_data_latency_format(struct tep_handle *tep,
hardirq = lat_flags & TRACE_FLAG_HARDIRQ;
softirq = lat_flags & TRACE_FLAG_SOFTIRQ;
- trace_seq_printf(s, "%c%c%c",
+ trace_seq_printf(&sq, "%c%c%c",
(lat_flags & TRACE_FLAG_IRQS_OFF) ? 'd' :
(lat_flags & TRACE_FLAG_IRQS_NOSUPPORT) ?
'X' : '.',
@@ -5232,24 +5261,32 @@ void tep_data_latency_format(struct tep_handle *tep,
hardirq ? 'h' : softirq ? 's' : '.');
if (pc)
- trace_seq_printf(s, "%x", pc);
+ trace_seq_printf(&sq, "%x", pc);
else
- trace_seq_putc(s, '.');
+ trace_seq_printf(&sq, ".");
if (migrate_disable_exists) {
if (migrate_disable < 0)
- trace_seq_putc(s, '.');
+ trace_seq_printf(&sq, ".");
else
- trace_seq_printf(s, "%d", migrate_disable);
+ trace_seq_printf(&sq, "%d", migrate_disable);
}
if (lock_depth_exists) {
if (lock_depth < 0)
- trace_seq_putc(s, '.');
+ trace_seq_printf(&sq, ".");
else
- trace_seq_printf(s, "%d", lock_depth);
+ trace_seq_printf(&sq, "%d", lock_depth);
+ }
+
+ if (sq.state == TRACE_SEQ__MEM_ALLOC_FAILED) {
+ s->state = TRACE_SEQ__MEM_ALLOC_FAILED;
+ return;
}
+ trace_seq_terminate(&sq);
+ trace_seq_puts(s, sq.buffer);
+ trace_seq_destroy(&sq);
trace_seq_terminate(s);
}
@@ -5410,21 +5447,16 @@ int tep_cmdline_pid(struct tep_handle *tep, struct tep_cmdline *cmdline)
return cmdline->pid;
}
-/**
- * tep_event_info - parse the data into the print format
- * @s: the trace_seq to write to
- * @event: the handle to the event
- * @record: the record to read from
- *
+/*
* This parses the raw @data using the given @event information and
* writes the print format into the trace_seq.
*/
-void tep_event_info(struct trace_seq *s, struct tep_event *event,
- struct tep_record *record)
+static void print_event_info(struct trace_seq *s, char *format, bool raw,
+ struct tep_event *event, struct tep_record *record)
{
int print_pretty = 1;
- if (event->tep->print_raw || (event->flags & TEP_EVENT_FL_PRINTRAW))
+ if (raw || (event->flags & TEP_EVENT_FL_PRINTRAW))
tep_print_fields(s, record->data, record->size, event);
else {
@@ -5439,20 +5471,6 @@ void tep_event_info(struct trace_seq *s, struct tep_event *event,
trace_seq_terminate(s);
}
-static bool is_timestamp_in_us(char *trace_clock, bool use_trace_clock)
-{
- if (!trace_clock || !use_trace_clock)
- return true;
-
- if (!strcmp(trace_clock, "local") || !strcmp(trace_clock, "global")
- || !strcmp(trace_clock, "uptime") || !strcmp(trace_clock, "perf")
- || !strncmp(trace_clock, "mono", 4))
- return true;
-
- /* trace_clock is setting in tsc or counter mode */
- return false;
-}
-
/**
* tep_find_event_by_record - return the event from a given record
* @tep: a handle to the trace event parser context
@@ -5476,129 +5494,195 @@ tep_find_event_by_record(struct tep_handle *tep, struct tep_record *record)
return tep_find_event(tep, type);
}
-/**
- * tep_print_event_task - Write the event task comm, pid and CPU
- * @tep: a handle to the trace event parser context
- * @s: the trace_seq to write to
- * @event: the handle to the record's event
- * @record: The record to get the event from
- *
- * Writes the tasks comm, pid and CPU to @s.
+/*
+ * Writes the timestamp of the record into @s. Time divisor and precision can be
+ * specified as part of printf @format string. Example:
+ * "%3.1000d" - divide the time by 1000 and print the first 3 digits
+ * before the dot. Thus, the timestamp "123456000" will be printed as
+ * "123.456"
*/
-void tep_print_event_task(struct tep_handle *tep, struct trace_seq *s,
- struct tep_event *event,
- struct tep_record *record)
+static void print_event_time(struct tep_handle *tep, struct trace_seq *s,
+ char *format, struct tep_event *event,
+ struct tep_record *record)
+{
+ unsigned long long time;
+ char *divstr;
+ int prec = 0, pr;
+ int div = 0;
+ int p10 = 1;
+
+ if (isdigit(*(format + 1)))
+ prec = atoi(format + 1);
+ divstr = strchr(format, '.');
+ if (divstr && isdigit(*(divstr + 1)))
+ div = atoi(divstr + 1);
+ time = record->ts;
+ if (div)
+ time /= div;
+ pr = prec;
+ while (pr--)
+ p10 *= 10;
+
+ if (p10 > 1 && p10 < time)
+ trace_seq_printf(s, "%5llu.%0*llu", time / p10, prec, time % p10);
+ else
+ trace_seq_printf(s, "%12llu\n", time);
+}
+
+struct print_event_type {
+ enum {
+ EVENT_TYPE_INT = 1,
+ EVENT_TYPE_STRING,
+ EVENT_TYPE_UNKNOWN,
+ } type;
+ char format[32];
+};
+
+static void print_string(struct tep_handle *tep, struct trace_seq *s,
+ struct tep_record *record, struct tep_event *event,
+ const char *arg, struct print_event_type *type)
{
- void *data = record->data;
const char *comm;
int pid;
- pid = parse_common_pid(tep, data);
- comm = find_cmdline(tep, pid);
+ if (strncmp(arg, TEP_PRINT_LATENCY, strlen(TEP_PRINT_LATENCY)) == 0) {
+ data_latency_format(tep, s, type->format, record);
+ } else if (strncmp(arg, TEP_PRINT_COMM, strlen(TEP_PRINT_COMM)) == 0) {
+ pid = parse_common_pid(tep, record->data);
+ comm = find_cmdline(tep, pid);
+ trace_seq_printf(s, type->format, comm);
+ } else if (strncmp(arg, TEP_PRINT_INFO_RAW, strlen(TEP_PRINT_INFO_RAW)) == 0) {
+ print_event_info(s, type->format, true, event, record);
+ } else if (strncmp(arg, TEP_PRINT_INFO, strlen(TEP_PRINT_INFO)) == 0) {
+ print_event_info(s, type->format, false, event, record);
+ } else if (strncmp(arg, TEP_PRINT_NAME, strlen(TEP_PRINT_NAME)) == 0) {
+ trace_seq_printf(s, type->format, event->name);
+ } else {
+ trace_seq_printf(s, "[UNKNOWN TEP TYPE %s]", arg);
+ }
- if (tep->latency_format)
- trace_seq_printf(s, "%8.8s-%-5d %3d", comm, pid, record->cpu);
- else
- trace_seq_printf(s, "%16s-%-5d [%03d]", comm, pid, record->cpu);
}
-/**
- * tep_print_event_time - Write the event timestamp
- * @tep: a handle to the trace event parser context
- * @s: the trace_seq to write to
- * @event: the handle to the record's event
- * @record: The record to get the event from
- * @use_trace_clock: Set to parse according to the @tep->trace_clock
- *
- * Writes the timestamp of the record into @s.
- */
-void tep_print_event_time(struct tep_handle *tep, struct trace_seq *s,
- struct tep_event *event,
- struct tep_record *record,
- bool use_trace_clock)
+static void print_int(struct tep_handle *tep, struct trace_seq *s,
+ struct tep_record *record, struct tep_event *event,
+ int arg, struct print_event_type *type)
{
- unsigned long secs;
- unsigned long usecs;
- unsigned long nsecs;
- int p;
- bool use_usec_format;
+ int param;
- use_usec_format = is_timestamp_in_us(tep->trace_clock, use_trace_clock);
- if (use_usec_format) {
- secs = record->ts / NSEC_PER_SEC;
- nsecs = record->ts - secs * NSEC_PER_SEC;
+ switch (arg) {
+ case TEP_PRINT_CPU:
+ param = record->cpu;
+ break;
+ case TEP_PRINT_PID:
+ param = parse_common_pid(tep, record->data);
+ break;
+ case TEP_PRINT_TIME:
+ return print_event_time(tep, s, type->format, event, record);
+ default:
+ return;
}
+ trace_seq_printf(s, type->format, param);
+}
- if (tep->latency_format) {
- tep_data_latency_format(tep, s, record);
- }
+static int tep_print_event_param_type(char *format,
+ struct print_event_type *type)
+{
+ char *str = format + 1;
+ int i = 1;
- if (use_usec_format) {
- if (tep->flags & TEP_NSEC_OUTPUT) {
- usecs = nsecs;
- p = 9;
- } else {
- usecs = (nsecs + 500) / NSEC_PER_USEC;
- /* To avoid usecs larger than 1 sec */
- if (usecs >= USEC_PER_SEC) {
- usecs -= USEC_PER_SEC;
- secs++;
- }
- p = 6;
+ type->type = EVENT_TYPE_UNKNOWN;
+ while (*str) {
+ switch (*str) {
+ case 'd':
+ case 'u':
+ case 'i':
+ case 'x':
+ case 'X':
+ case 'o':
+ type->type = EVENT_TYPE_INT;
+ break;
+ case 's':
+ type->type = EVENT_TYPE_STRING;
+ break;
}
-
- trace_seq_printf(s, " %5lu.%0*lu:", secs, p, usecs);
- } else
- trace_seq_printf(s, " %12llu:", record->ts);
+ str++;
+ i++;
+ if (type->type != EVENT_TYPE_UNKNOWN)
+ break;
+ }
+ memset(type->format, 0, 32);
+ memcpy(type->format, format, i < 32 ? i : 31);
+ return i;
}
/**
- * tep_print_event_data - Write the event data section
+ * tep_print_event - Write various event information
* @tep: a handle to the trace event parser context
* @s: the trace_seq to write to
- * @event: the handle to the record's event
* @record: The record to get the event from
- *
- * Writes the parsing of the record's data to @s.
+ * @format: a printf format string. Supported event fileds:
+ * TEP_PRINT_PID, "%d" - event PID
+ * TEP_PRINT_CPU, "%d" - event CPU
+ * TEP_PRINT_COMM, "%s" - event command string
+ * TEP_PRINT_NAME, "%s" - event name
+ * TEP_PRINT_LATENCY, "%s" - event latency
+ * TEP_PRINT_TIME, %d - event time stamp. A divisor and precision
+ * can be specified as part of this format string:
+ * "%precision.divisord". Example:
+ * "%3.1000d" - divide the time by 1000 and print the first
+ * 3 digits before the dot. Thus, the time stamp
+ * "123456000" will be printed as "123.456"
+ * TEP_PRINT_INFO, "%s" - event information. If any width is specified in
+ * the format string, the event information will be printed
+ * in raw format.
+ * Writes the specified event information into @s.
*/
-void tep_print_event_data(struct tep_handle *tep, struct trace_seq *s,
- struct tep_event *event,
- struct tep_record *record)
-{
- static const char *spaces = " "; /* 20 spaces */
- int len;
-
- trace_seq_printf(s, " %s: ", event->name);
-
- /* Space out the event names evenly. */
- len = strlen(event->name);
- if (len < 20)
- trace_seq_printf(s, "%.*s", 20 - len, spaces);
-
- tep_event_info(s, event, record);
-}
-
void tep_print_event(struct tep_handle *tep, struct trace_seq *s,
- struct tep_record *record, bool use_trace_clock)
-{
+ struct tep_record *record, const char *fmt, ...)
+{
+ struct print_event_type type;
+ char *format = strdup(fmt);
+ char *current = format;
+ char *str = format;
+ int offset;
+ va_list args;
struct tep_event *event;
- event = tep_find_event_by_record(tep, record);
- if (!event) {
- int i;
- int type = trace_parse_common_type(tep, record->data);
-
- do_warning("ug! no event found for type %d", type);
- trace_seq_printf(s, "[UNKNOWN TYPE %d]", type);
- for (i = 0; i < record->size; i++)
- trace_seq_printf(s, " %02x",
- ((unsigned char *)record->data)[i]);
+ if (!format)
return;
- }
- tep_print_event_task(tep, s, event, record);
- tep_print_event_time(tep, s, event, record, use_trace_clock);
- tep_print_event_data(tep, s, event, record);
+ event = tep_find_event_by_record(tep, record);
+ va_start(args, fmt);
+ while (*current) {
+ current = strchr(str, '%');
+ if (!current) {
+ trace_seq_puts(s, str);
+ break;
+ }
+ memset(&type, 0, sizeof(type));
+ offset = tep_print_event_param_type(current, &type);
+ *current = '\0';
+ trace_seq_puts(s, str);
+ current += offset;
+ switch (type.type) {
+ case EVENT_TYPE_STRING:
+ print_string(tep, s, record, event,
+ va_arg(args, char*), &type);
+ break;
+ case EVENT_TYPE_INT:
+ print_int(tep, s, record, event,
+ va_arg(args, int), &type);
+ break;
+ case EVENT_TYPE_UNKNOWN:
+ default:
+ trace_seq_printf(s, "[UNKNOWN TYPE]");
+ break;
+ }
+ str = current;
+
+ }
+ va_end(args);
+ free(format);
}
static int events_id_cmp(const void *a, const void *b)
@@ -6963,7 +7047,6 @@ void tep_free(struct tep_handle *tep)
free_handler(handle);
}
- free(tep->trace_clock);
free(tep->events);
free(tep->sort_events);
free(tep->func_resolver);
diff --git a/tools/lib/traceevent/event-parse.h b/tools/lib/traceevent/event-parse.h
index 642f68ab5fb2..d438ee44289f 100644
--- a/tools/lib/traceevent/event-parse.h
+++ b/tools/lib/traceevent/event-parse.h
@@ -435,25 +435,24 @@ int tep_set_function_resolver(struct tep_handle *tep,
void tep_reset_function_resolver(struct tep_handle *tep);
int tep_register_comm(struct tep_handle *tep, const char *comm, int pid);
int tep_override_comm(struct tep_handle *tep, const char *comm, int pid);
-int tep_register_trace_clock(struct tep_handle *tep, const char *trace_clock);
int tep_register_function(struct tep_handle *tep, char *name,
unsigned long long addr, char *mod);
int tep_register_print_string(struct tep_handle *tep, const char *fmt,
unsigned long long addr);
bool tep_is_pid_registered(struct tep_handle *tep, int pid);
-void tep_print_event_task(struct tep_handle *tep, struct trace_seq *s,
- struct tep_event *event,
- struct tep_record *record);
-void tep_print_event_time(struct tep_handle *tep, struct trace_seq *s,
- struct tep_event *event,
- struct tep_record *record,
- bool use_trace_clock);
-void tep_print_event_data(struct tep_handle *tep, struct trace_seq *s,
- struct tep_event *event,
- struct tep_record *record);
+#define TEP_PRINT_INFO "INFO"
+#define TEP_PRINT_INFO_RAW "INFO_RAW"
+#define TEP_PRINT_COMM "COMM"
+#define TEP_PRINT_LATENCY "LATENCY"
+#define TEP_PRINT_NAME "NAME"
+#define TEP_PRINT_PID 1U
+#define TEP_PRINT_TIME 2U
+#define TEP_PRINT_CPU 3U
+
void tep_print_event(struct tep_handle *tep, struct trace_seq *s,
- struct tep_record *record, bool use_trace_clock);
+ struct tep_record *record, const char *fmt, ...)
+ __attribute__ ((format (printf, 4, 5)));
int tep_parse_header_page(struct tep_handle *tep, char *buf, unsigned long size,
int long_size);
@@ -525,8 +524,6 @@ tep_find_event_by_name(struct tep_handle *tep, const char *sys, const char *name
struct tep_event *
tep_find_event_by_record(struct tep_handle *tep, struct tep_record *record);
-void tep_data_latency_format(struct tep_handle *tep,
- struct trace_seq *s, struct tep_record *record);
int tep_data_type(struct tep_handle *tep, struct tep_record *rec);
int tep_data_pid(struct tep_handle *tep, struct tep_record *rec);
int tep_data_preempt_count(struct tep_handle *tep, struct tep_record *rec);
@@ -541,8 +538,6 @@ void tep_print_field(struct trace_seq *s, void *data,
struct tep_format_field *field);
void tep_print_fields(struct trace_seq *s, void *data,
int size __maybe_unused, struct tep_event *event);
-void tep_event_info(struct trace_seq *s, struct tep_event *event,
- struct tep_record *record);
int tep_strerror(struct tep_handle *tep, enum tep_errno errnum,
char *buf, size_t buflen);
@@ -566,12 +561,9 @@ bool tep_is_file_bigendian(struct tep_handle *tep);
void tep_set_file_bigendian(struct tep_handle *tep, enum tep_endian endian);
bool tep_is_local_bigendian(struct tep_handle *tep);
void tep_set_local_bigendian(struct tep_handle *tep, enum tep_endian endian);
-bool tep_is_latency_format(struct tep_handle *tep);
-void tep_set_latency_format(struct tep_handle *tep, int lat);
int tep_get_header_page_size(struct tep_handle *tep);
int tep_get_header_timestamp_size(struct tep_handle *tep);
bool tep_is_old_format(struct tep_handle *tep);
-void tep_set_print_raw(struct tep_handle *tep, int print_raw);
void tep_set_test_filters(struct tep_handle *tep, int test_filters);
struct tep_handle *tep_alloc(void);
diff --git a/tools/lib/traceevent/event-plugin.c b/tools/lib/traceevent/event-plugin.c
index 8ca28de9337a..e1f7ddd5a6cf 100644
--- a/tools/lib/traceevent/event-plugin.c
+++ b/tools/lib/traceevent/event-plugin.c
@@ -18,7 +18,7 @@
#include "event-utils.h"
#include "trace-seq.h"
-#define LOCAL_PLUGIN_DIR ".traceevent/plugins"
+#define LOCAL_PLUGIN_DIR ".local/lib/traceevent/plugins/"
static struct registered_plugin_options {
struct registered_plugin_options *next;