From 509051ea8427b2f73f065a1b0a1ef871727c9cb2 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 14 Jan 2014 17:52:14 -0300 Subject: perf record: Rename --no-delay to --no-buffering That is how the option summary describes it and so that we can free --delay to replace --initial-delay and then be consistent with stat's --delay equivalent option. Suggested-by: Ingo Molnar Cc: Adrian Hunter Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-f8hd2010uhjl2zzb34hepbmi@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-record.txt | 3 +-- tools/perf/builtin-record.c | 2 +- tools/perf/builtin-trace.c | 2 +- tools/perf/perf.h | 2 +- tools/perf/tests/open-syscall-tp-fields.c | 8 ++++---- tools/perf/tests/perf-record.c | 6 +++--- tools/perf/util/evsel.c | 2 +- 7 files changed, 12 insertions(+), 13 deletions(-) diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index 82bffac036e1..3a35a8523e6d 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt @@ -68,8 +68,7 @@ OPTIONS --realtime=:: Collect data with this RT SCHED_FIFO priority. --D:: ---no-delay:: +--no-buffering:: Collect data without buffering. -c:: diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 07d4cf8d3fd3..78e790f4c54f 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -838,7 +838,7 @@ const struct option record_options[] = { "record events on existing thread id"), OPT_INTEGER('r', "realtime", &record.realtime_prio, "collect data with this RT SCHED_FIFO priority"), - OPT_BOOLEAN('D', "no-delay", &record.opts.no_delay, + OPT_BOOLEAN(0, "no-buffering", &record.opts.no_buffering, "collect data without buffering"), OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples, "collect raw sample records from all opened counters"), diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 4bd44aba343e..896f27047ed6 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -2258,7 +2258,7 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) }, .user_freq = UINT_MAX, .user_interval = ULLONG_MAX, - .no_delay = true, + .no_buffering = true, .mmap_pages = 1024, }, .output = stdout, diff --git a/tools/perf/perf.h b/tools/perf/perf.h index af1ce6e14a93..3c2f213e979d 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h @@ -252,7 +252,7 @@ struct record_opts { int call_graph; bool group; bool inherit_stat; - bool no_delay; + bool no_buffering; bool no_inherit; bool no_inherit_set; bool no_samples; diff --git a/tools/perf/tests/open-syscall-tp-fields.c b/tools/perf/tests/open-syscall-tp-fields.c index 5a016f66f5d2..c505ef2af245 100644 --- a/tools/perf/tests/open-syscall-tp-fields.c +++ b/tools/perf/tests/open-syscall-tp-fields.c @@ -11,10 +11,10 @@ int test__syscall_open_tp_fields(void) .uid = UINT_MAX, .uses_mmap = true, }, - .no_delay = true, - .freq = 1, - .mmap_pages = 256, - .raw_samples = true, + .no_buffering = true, + .freq = 1, + .mmap_pages = 256, + .raw_samples = true, }; const char *filename = "/etc/passwd"; int flags = O_RDONLY | O_DIRECTORY; diff --git a/tools/perf/tests/perf-record.c b/tools/perf/tests/perf-record.c index 39cc7c3c0d0c..aca1a83dd13a 100644 --- a/tools/perf/tests/perf-record.c +++ b/tools/perf/tests/perf-record.c @@ -39,9 +39,9 @@ int test__PERF_RECORD(void) .uid = UINT_MAX, .uses_mmap = true, }, - .no_delay = true, - .freq = 10, - .mmap_pages = 256, + .no_buffering = true, + .freq = 10, + .mmap_pages = 256, }; cpu_set_t cpu_mask; size_t cpu_mask_size = sizeof(cpu_mask); diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index cd4630abfa43..22e18a26b7e6 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -627,7 +627,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts) if (opts->sample_address) perf_evsel__set_sample_bit(evsel, DATA_SRC); - if (opts->no_delay) { + if (opts->no_buffering) { attr->watermark = 0; attr->wakeup_events = 1; } -- cgit v1.2.3 From a6205a35ba2d56dcfb79b08cc11b8c7d549826aa Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 14 Jan 2014 17:58:12 -0300 Subject: perf record: Rename --initial-delay to --delay To be consistent with the equivalent option in 'stat', also, for the same reason, use -D as the one letter alias. Suggested-by: Ingo Molnar Cc: Adrian Hunter Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-p5yjnopajb3a8x0xha7yl5w8@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-record.txt | 3 ++- tools/perf/builtin-record.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index 3a35a8523e6d..c71b0f36d9e8 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt @@ -208,7 +208,8 @@ overrides that and uses per-thread mmaps. A side-effect of that is that inheritance is automatically disabled. --per-thread is ignored with a warning if combined with -a or -C options. ---initial-delay msecs:: +-D:: +--delay=:: After starting the program, wait msecs before measuring. This is useful to filter out the startup phase of the program, which is often very different. diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 78e790f4c54f..3c394bf16fa8 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -882,7 +882,7 @@ const struct option record_options[] = { OPT_CALLBACK('G', "cgroup", &record.evlist, "name", "monitor event in cgroup name only", parse_cgroups), - OPT_UINTEGER(0, "initial-delay", &record.opts.initial_delay, + OPT_UINTEGER('D', "delay", &record.opts.initial_delay, "ms to wait before starting measurement after program start"), OPT_STRING('u', "uid", &record.opts.target.uid_str, "user", "user to profile"), -- cgit v1.2.3 From 7d16c634233c411f54b89d0f1d51750dc85c5f7e Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Thu, 9 Jan 2014 23:07:59 +0900 Subject: perf tools: Fix build error due to zfree() cast It failed to build perf on my ubuntu 10.04 box (gcc 4.4.3): CC util/strlist.o cc1: warnings being treated as errors util/strlist.c: In function ‘str_node__delete’: util/strlist.c:42: error: dereferencing type-punned pointer will break strict-aliasing rules util/strlist.c:42: error: dereferencing type-punned pointer will break strict-aliasing rules CC util/strfilter.o make: *** [util/strlist.o] Error 1 CC util/srcline.o cc1: warnings being treated as errors util/srcline.c: In function ‘addr2line_init’: util/srcline.c:132: error: dereferencing type-punned pointer will break strict-aliasing rules util/srcline.c:132: error: dereferencing type-punned pointer will break strict-aliasing rules util/srcline.c: In function ‘addr2line_cleanup’: util/srcline.c:143: error: dereferencing type-punned pointer will break strict-aliasing rules util/srcline.c:143: error: dereferencing type-punned pointer will break strict-aliasing rules make: *** [util/srcline.o] Error 1 It seems it only allows to remove 'const' qualifier. Signed-off-by: Namhyung Kim Cc: Ingo Molnar Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1389276479-9047-1-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/srcline.c | 4 ++-- tools/perf/util/strlist.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/perf/util/srcline.c b/tools/perf/util/srcline.c index 7e67879ebd25..f3e4bc5fe5d2 100644 --- a/tools/perf/util/srcline.c +++ b/tools/perf/util/srcline.c @@ -129,7 +129,7 @@ static struct a2l_data *addr2line_init(const char *path) out: if (a2l) { - zfree((void **)&a2l->input); + zfree((char **)&a2l->input); free(a2l); } bfd_close(abfd); @@ -140,7 +140,7 @@ static void addr2line_cleanup(struct a2l_data *a2l) { if (a2l->abfd) bfd_close(a2l->abfd); - zfree((void **)&a2l->input); + zfree((char **)&a2l->input); zfree(&a2l->syms); free(a2l); } diff --git a/tools/perf/util/strlist.c b/tools/perf/util/strlist.c index 61a90bf24b4d..71f9d102b96f 100644 --- a/tools/perf/util/strlist.c +++ b/tools/perf/util/strlist.c @@ -39,7 +39,7 @@ out_delete: static void str_node__delete(struct str_node *snode, bool dupstr) { if (dupstr) - zfree((void **)&snode->s); + zfree((char **)&snode->s); free(snode); } -- cgit v1.2.3 From 3c6d8d84423932f1d9949179c6acdf2405515ee4 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Thu, 19 Dec 2013 18:17:44 +0900 Subject: tools lib traceevent: Add state member to struct trace_seq The trace_seq->state is for tracking errors during the use of trace_seq APIs and getting rid of die() in it. Signed-off-by: Namhyung Kim Reviewed-by: Jiri Olsa Acked-by: Steven Rostedt Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Steven Rostedt Link: http://lkml.kernel.org/r/87fvopalbb.fsf@sejong.aot.lge.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/lib/traceevent/Makefile | 2 +- tools/lib/traceevent/event-parse.h | 7 +++++ tools/lib/traceevent/trace-seq.c | 55 +++++++++++++++++++++++++++++--------- 3 files changed, 50 insertions(+), 14 deletions(-) diff --git a/tools/lib/traceevent/Makefile b/tools/lib/traceevent/Makefile index f778d48ac609..56d52a33a3df 100644 --- a/tools/lib/traceevent/Makefile +++ b/tools/lib/traceevent/Makefile @@ -136,7 +136,7 @@ export Q VERBOSE EVENT_PARSE_VERSION = $(EP_VERSION).$(EP_PATCHLEVEL).$(EP_EXTRAVERSION) -INCLUDES = -I. $(CONFIG_INCLUDES) +INCLUDES = -I. -I $(srctree)/../../include $(CONFIG_INCLUDES) # Set compile option CFLAGS if not set elsewhere CFLAGS ?= -g -Wall diff --git a/tools/lib/traceevent/event-parse.h b/tools/lib/traceevent/event-parse.h index cf5db9013f2c..3c890cb28db7 100644 --- a/tools/lib/traceevent/event-parse.h +++ b/tools/lib/traceevent/event-parse.h @@ -58,6 +58,12 @@ struct pevent_record { #endif }; +enum trace_seq_fail { + TRACE_SEQ__GOOD, + TRACE_SEQ__BUFFER_POISONED, + TRACE_SEQ__MEM_ALLOC_FAILED, +}; + /* * Trace sequences are used to allow a function to call several other functions * to create a string of data to use (up to a max of PAGE_SIZE). @@ -68,6 +74,7 @@ struct trace_seq { unsigned int buffer_size; unsigned int len; unsigned int readpos; + enum trace_seq_fail state; }; void trace_seq_init(struct trace_seq *s); diff --git a/tools/lib/traceevent/trace-seq.c b/tools/lib/traceevent/trace-seq.c index d7f2e68bc5b9..f7112138e6af 100644 --- a/tools/lib/traceevent/trace-seq.c +++ b/tools/lib/traceevent/trace-seq.c @@ -22,6 +22,7 @@ #include #include +#include #include "event-parse.h" #include "event-utils.h" @@ -32,10 +33,21 @@ #define TRACE_SEQ_POISON ((void *)0xdeadbeef) #define TRACE_SEQ_CHECK(s) \ do { \ - if ((s)->buffer == TRACE_SEQ_POISON) \ - die("Usage of trace_seq after it was destroyed"); \ + if (WARN_ONCE((s)->buffer == TRACE_SEQ_POISON, \ + "Usage of trace_seq after it was destroyed")) \ + (s)->state = TRACE_SEQ__BUFFER_POISONED; \ } while (0) +#define TRACE_SEQ_CHECK_RET_N(s, n) \ +do { \ + TRACE_SEQ_CHECK(s); \ + if ((s)->state != TRACE_SEQ__GOOD) \ + return n; \ +} while (0) + +#define TRACE_SEQ_CHECK_RET(s) TRACE_SEQ_CHECK_RET_N(s, ) +#define TRACE_SEQ_CHECK_RET0(s) TRACE_SEQ_CHECK_RET_N(s, 0) + /** * trace_seq_init - initialize the trace_seq structure * @s: a pointer to the trace_seq structure to initialize @@ -46,6 +58,7 @@ void trace_seq_init(struct trace_seq *s) s->readpos = 0; s->buffer_size = TRACE_SEQ_BUF_SIZE; s->buffer = malloc_or_die(s->buffer_size); + s->state = TRACE_SEQ__GOOD; } /** @@ -71,7 +84,7 @@ void trace_seq_destroy(struct trace_seq *s) { if (!s) return; - TRACE_SEQ_CHECK(s); + TRACE_SEQ_CHECK_RET(s); free(s->buffer); s->buffer = TRACE_SEQ_POISON; } @@ -80,8 +93,9 @@ static void expand_buffer(struct trace_seq *s) { s->buffer_size += TRACE_SEQ_BUF_SIZE; s->buffer = realloc(s->buffer, s->buffer_size); - if (!s->buffer) - die("Can't allocate trace_seq buffer memory"); + if (WARN_ONCE(!s->buffer, + "Can't allocate trace_seq buffer memory")) + s->state = TRACE_SEQ__MEM_ALLOC_FAILED; } /** @@ -105,9 +119,9 @@ trace_seq_printf(struct trace_seq *s, const char *fmt, ...) int len; int ret; - TRACE_SEQ_CHECK(s); - try_again: + TRACE_SEQ_CHECK_RET0(s); + len = (s->buffer_size - 1) - s->len; va_start(ap, fmt); @@ -141,9 +155,9 @@ trace_seq_vprintf(struct trace_seq *s, const char *fmt, va_list args) int len; int ret; - TRACE_SEQ_CHECK(s); - try_again: + TRACE_SEQ_CHECK_RET0(s); + len = (s->buffer_size - 1) - s->len; ret = vsnprintf(s->buffer + s->len, len, fmt, args); @@ -172,13 +186,15 @@ int trace_seq_puts(struct trace_seq *s, const char *str) { int len; - TRACE_SEQ_CHECK(s); + TRACE_SEQ_CHECK_RET0(s); len = strlen(str); while (len > ((s->buffer_size - 1) - s->len)) expand_buffer(s); + TRACE_SEQ_CHECK_RET0(s); + memcpy(s->buffer + s->len, str, len); s->len += len; @@ -187,11 +203,13 @@ int trace_seq_puts(struct trace_seq *s, const char *str) int trace_seq_putc(struct trace_seq *s, unsigned char c) { - TRACE_SEQ_CHECK(s); + TRACE_SEQ_CHECK_RET0(s); while (s->len >= (s->buffer_size - 1)) expand_buffer(s); + TRACE_SEQ_CHECK_RET0(s); + s->buffer[s->len++] = c; return 1; @@ -199,7 +217,7 @@ int trace_seq_putc(struct trace_seq *s, unsigned char c) void trace_seq_terminate(struct trace_seq *s) { - TRACE_SEQ_CHECK(s); + TRACE_SEQ_CHECK_RET(s); /* There's always one character left on the buffer */ s->buffer[s->len] = 0; @@ -208,5 +226,16 @@ void trace_seq_terminate(struct trace_seq *s) int trace_seq_do_printf(struct trace_seq *s) { TRACE_SEQ_CHECK(s); - return printf("%.*s", s->len, s->buffer); + + switch (s->state) { + case TRACE_SEQ__GOOD: + return printf("%.*s", s->len, s->buffer); + case TRACE_SEQ__BUFFER_POISONED: + puts("Usage of trace_seq after it was destroyed"); + break; + case TRACE_SEQ__MEM_ALLOC_FAILED: + puts("Can't allocate trace_seq buffer memory"); + break; + } + return -1; } -- cgit v1.2.3 From 3026bba3c37711234771349ca020d9a85e572f60 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 15 Jan 2014 10:45:25 +0900 Subject: tools lib traceevent: Check return value of realloc() If realloc() fails, it'll leak the buffer. Also increate buffer size only if the allocation succeeded. Signed-off-by: Namhyung Kim Reviewed-by: Jiri Olsa Acked-by: Steven Rostedt Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Steven Rostedt Link: http://lkml.kernel.org/r/1389750340-15965-3-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/lib/traceevent/trace-seq.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/tools/lib/traceevent/trace-seq.c b/tools/lib/traceevent/trace-seq.c index f7112138e6af..e454a2c66cac 100644 --- a/tools/lib/traceevent/trace-seq.c +++ b/tools/lib/traceevent/trace-seq.c @@ -91,11 +91,16 @@ void trace_seq_destroy(struct trace_seq *s) static void expand_buffer(struct trace_seq *s) { - s->buffer_size += TRACE_SEQ_BUF_SIZE; - s->buffer = realloc(s->buffer, s->buffer_size); - if (WARN_ONCE(!s->buffer, - "Can't allocate trace_seq buffer memory")) + char *buf; + + buf = realloc(s->buffer, s->buffer_size + TRACE_SEQ_BUF_SIZE); + if (WARN_ONCE(!buf, "Can't allocate trace_seq buffer memory")) { s->state = TRACE_SEQ__MEM_ALLOC_FAILED; + return; + } + + s->buffer = buf; + s->buffer_size += TRACE_SEQ_BUF_SIZE; } /** -- cgit v1.2.3 From 504586e0954bcf9550dfdea37d3234174ed1d68f Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 15 Jan 2014 10:45:26 +0900 Subject: tools lib traceevent: Get rid of malloc_or_die() in trace_seq_init() Use plain malloc() and check its return value. Signed-off-by: Namhyung Kim Reviewed-by: Jiri Olsa Acked-by: Steven Rostedt Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Steven Rostedt Link: http://lkml.kernel.org/r/1389750340-15965-4-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/lib/traceevent/trace-seq.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tools/lib/traceevent/trace-seq.c b/tools/lib/traceevent/trace-seq.c index e454a2c66cac..ec3bd16a5488 100644 --- a/tools/lib/traceevent/trace-seq.c +++ b/tools/lib/traceevent/trace-seq.c @@ -57,8 +57,11 @@ void trace_seq_init(struct trace_seq *s) s->len = 0; s->readpos = 0; s->buffer_size = TRACE_SEQ_BUF_SIZE; - s->buffer = malloc_or_die(s->buffer_size); - s->state = TRACE_SEQ__GOOD; + s->buffer = malloc(s->buffer_size); + if (s->buffer != NULL) + s->state = TRACE_SEQ__GOOD; + else + s->state = TRACE_SEQ__MEM_ALLOC_FAILED; } /** -- cgit v1.2.3 From e825e756f84eab0e68d7d6644c018c3412748406 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 15 Jan 2014 10:45:27 +0900 Subject: tools lib traceevent: Get rid of die() finally!! Now all of its users were gone. :) Signed-off-by: Namhyung Kim Reviewed-by: Jiri Olsa Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Steven Rostedt Link: http://lkml.kernel.org/r/1389750340-15965-5-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/lib/traceevent/event-utils.h | 4 ---- tools/lib/traceevent/parse-utils.c | 44 -------------------------------------- 2 files changed, 48 deletions(-) diff --git a/tools/lib/traceevent/event-utils.h b/tools/lib/traceevent/event-utils.h index e76c9acb92cd..d1dc2170e402 100644 --- a/tools/lib/traceevent/event-utils.h +++ b/tools/lib/traceevent/event-utils.h @@ -23,18 +23,14 @@ #include /* Can be overridden */ -void die(const char *fmt, ...); -void *malloc_or_die(unsigned int size); void warning(const char *fmt, ...); void pr_stat(const char *fmt, ...); void vpr_stat(const char *fmt, va_list ap); /* Always available */ -void __die(const char *fmt, ...); void __warning(const char *fmt, ...); void __pr_stat(const char *fmt, ...); -void __vdie(const char *fmt, ...); void __vwarning(const char *fmt, ...); void __vpr_stat(const char *fmt, ...); diff --git a/tools/lib/traceevent/parse-utils.c b/tools/lib/traceevent/parse-utils.c index bba701cf10e6..eda07fa31dca 100644 --- a/tools/lib/traceevent/parse-utils.c +++ b/tools/lib/traceevent/parse-utils.c @@ -25,40 +25,6 @@ #define __weak __attribute__((weak)) -void __vdie(const char *fmt, va_list ap) -{ - int ret = errno; - - if (errno) - perror("trace-cmd"); - else - ret = -1; - - fprintf(stderr, " "); - vfprintf(stderr, fmt, ap); - - fprintf(stderr, "\n"); - exit(ret); -} - -void __die(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - __vdie(fmt, ap); - va_end(ap); -} - -void __weak die(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - __vdie(fmt, ap); - va_end(ap); -} - void __vwarning(const char *fmt, va_list ap) { if (errno) @@ -117,13 +83,3 @@ void __weak pr_stat(const char *fmt, ...) __vpr_stat(fmt, ap); va_end(ap); } - -void __weak *malloc_or_die(unsigned int size) -{ - void *data; - - data = malloc(size); - if (!data) - die("malloc"); - return data; -} -- cgit v1.2.3 From 8d0c2224ca6e04ba51c403805e7e1e2ca536520b Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 15 Jan 2014 10:45:28 +0900 Subject: tools lib traceevent: Make plugin unload function receive pevent The PEVENT_PLUGIN_UNLOADER function might need some cleanup using pevent like unregister some handlers. So pass pevent as argument. Signed-off-by: Namhyung Kim Reviewed-by: Jiri Olsa Acked-by: Steven Rostedt Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Steven Rostedt Link: http://lkml.kernel.org/r/1389750340-15965-6-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/lib/traceevent/event-parse.h | 7 ++++--- tools/lib/traceevent/event-plugin.c | 4 ++-- tools/lib/traceevent/plugin_function.c | 2 +- tools/perf/util/trace-event.c | 2 +- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/tools/lib/traceevent/event-parse.h b/tools/lib/traceevent/event-parse.h index 3c890cb28db7..a3beca56cb35 100644 --- a/tools/lib/traceevent/event-parse.h +++ b/tools/lib/traceevent/event-parse.h @@ -105,7 +105,7 @@ typedef int (*pevent_event_handler_func)(struct trace_seq *s, void *context); typedef int (*pevent_plugin_load_func)(struct pevent *pevent); -typedef int (*pevent_plugin_unload_func)(void); +typedef int (*pevent_plugin_unload_func)(struct pevent *pevent); struct plugin_option { struct plugin_option *next; @@ -130,7 +130,7 @@ struct plugin_option { * PEVENT_PLUGIN_UNLOADER: (optional) * The function called just before unloading * - * int PEVENT_PLUGIN_UNLOADER(void) + * int PEVENT_PLUGIN_UNLOADER(struct pevent *pevent) * * PEVENT_PLUGIN_OPTIONS: (optional) * Plugin options that can be set before loading @@ -411,7 +411,8 @@ enum pevent_errno { struct plugin_list; struct plugin_list *traceevent_load_plugins(struct pevent *pevent); -void traceevent_unload_plugins(struct plugin_list *plugin_list); +void traceevent_unload_plugins(struct plugin_list *plugin_list, + struct pevent *pevent); struct cmdline; struct cmdline_list; diff --git a/tools/lib/traceevent/event-plugin.c b/tools/lib/traceevent/event-plugin.c index 125f5676bcb5..0c8bf6780e4d 100644 --- a/tools/lib/traceevent/event-plugin.c +++ b/tools/lib/traceevent/event-plugin.c @@ -197,7 +197,7 @@ traceevent_load_plugins(struct pevent *pevent) } void -traceevent_unload_plugins(struct plugin_list *plugin_list) +traceevent_unload_plugins(struct plugin_list *plugin_list, struct pevent *pevent) { pevent_plugin_unload_func func; struct plugin_list *list; @@ -207,7 +207,7 @@ traceevent_unload_plugins(struct plugin_list *plugin_list) plugin_list = list->next; func = dlsym(list->handle, PEVENT_PLUGIN_UNLOADER_NAME); if (func) - func(); + func(pevent); dlclose(list->handle); free(list->name); free(list); diff --git a/tools/lib/traceevent/plugin_function.c b/tools/lib/traceevent/plugin_function.c index aad92ad5e96f..39461485f9a7 100644 --- a/tools/lib/traceevent/plugin_function.c +++ b/tools/lib/traceevent/plugin_function.c @@ -144,7 +144,7 @@ int PEVENT_PLUGIN_LOADER(struct pevent *pevent) return 0; } -void PEVENT_PLUGIN_UNLOADER(void) +void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent) { int i, x; diff --git a/tools/perf/util/trace-event.c b/tools/perf/util/trace-event.c index d9f5f6137ab3..6322d37164c5 100644 --- a/tools/perf/util/trace-event.c +++ b/tools/perf/util/trace-event.c @@ -34,8 +34,8 @@ int trace_event__init(struct trace_event *t) void trace_event__cleanup(struct trace_event *t) { + traceevent_unload_plugins(t->plugin_list, t->pevent); pevent_free(t->pevent); - traceevent_unload_plugins(t->plugin_list); } static struct event_format* -- cgit v1.2.3 From a8a5cd8b472ca20e5b8fa649c43b3756867322f8 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Wed, 15 Jan 2014 10:44:08 +0000 Subject: perf: tools: Fix cross building Currently the feature-checks Makefile does not inherit $(CC), and calls cc rather than $(CROSS_COMPILE)gcc. Thus the feature checks invoke the native toolchain rather than the cross toolchain, and can identify features as available when they are not. This can break the build. Additionally the native pkg-config is always called as opposed to $(CROSS_COMPILE)pkg-config, so the wrong flags and paths may be passed to the cross compiler. This patch passes CROSS_COMPILE down to the feature-checks Makefile, and forces its use. Additionally pkg-config is replaced with $(CROSS_COMPILE)pkg-config via a new $(PKG_CONFIG) variable. This patch has been build tested on x86_64 and arm. Signed-off-by: Mark Rutland Cc: Ingo Molnar Cc: Jiri Olsa Cc: Will Deacon Link: http://lkml.kernel.org/r/1389782648-4417-4-git-send-email-mark.rutland@arm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Makefile.perf | 1 + tools/perf/config/Makefile | 6 +++--- tools/perf/config/feature-checks/Makefile | 9 +++++---- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 87d7726cee2d..7257e7e9e38a 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -76,6 +76,7 @@ $(OUTPUT)PERF-VERSION-FILE: ../../.git/HEAD CC = $(CROSS_COMPILE)gcc AR = $(CROSS_COMPILE)ar +PKG_CONFIG = $(CROSS_COMPILE)pkg-config RM = rm -f LN = ln -f diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index 01dd43df0d04..d604e50fc167 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile @@ -372,7 +372,7 @@ ifndef NO_SLANG endif ifndef NO_GTK2 - FLAGS_GTK2=$(CFLAGS) $(LDFLAGS) $(EXTLIBS) $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null) + FLAGS_GTK2=$(CFLAGS) $(LDFLAGS) $(EXTLIBS) $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null) ifneq ($(feature-gtk2), 1) msg := $(warning GTK2 not found, disables GTK2 support. Please install gtk2-devel or libgtk2.0-dev); NO_GTK2 := 1 @@ -381,8 +381,8 @@ ifndef NO_GTK2 GTK_CFLAGS := -DHAVE_GTK_INFO_BAR_SUPPORT endif CFLAGS += -DHAVE_GTK2_SUPPORT - GTK_CFLAGS += $(shell pkg-config --cflags gtk+-2.0 2>/dev/null) - GTK_LIBS := $(shell pkg-config --libs gtk+-2.0 2>/dev/null) + GTK_CFLAGS += $(shell $(PKG_CONFIG) --cflags gtk+-2.0 2>/dev/null) + GTK_LIBS := $(shell $(PKG_CONFIG) --libs gtk+-2.0 2>/dev/null) EXTLIBS += -ldl endif endif diff --git a/tools/perf/config/feature-checks/Makefile b/tools/perf/config/feature-checks/Makefile index 7cf6fcdacebe..12e551346fa6 100644 --- a/tools/perf/config/feature-checks/Makefile +++ b/tools/perf/config/feature-checks/Makefile @@ -28,7 +28,8 @@ FILES= \ test-stackprotector-all.bin \ test-timerfd.bin -CC := $(CC) -MD +CC := $(CROSS_COMPILE)gcc -MD +PKG_CONFIG := $(CROSS_COMPILE)pkg-config all: $(FILES) @@ -37,7 +38,7 @@ BUILD = $(CC) $(CFLAGS) -o $(OUTPUT)$@ $(patsubst %.bin,%.c,$@) $(LDFLAGS) ############################### test-all.bin: - $(BUILD) -Werror -fstack-protector-all -O2 -Werror -D_FORTIFY_SOURCE=2 -ldw -lelf -lnuma -lelf -laudit -I/usr/include/slang -lslang $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null) $(FLAGS_PERL_EMBED) $(FLAGS_PYTHON_EMBED) -DPACKAGE='"perf"' -lbfd -ldl + $(BUILD) -Werror -fstack-protector-all -O2 -Werror -D_FORTIFY_SOURCE=2 -ldw -lelf -lnuma -lelf -laudit -I/usr/include/slang -lslang $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null) $(FLAGS_PERL_EMBED) $(FLAGS_PYTHON_EMBED) -DPACKAGE='"perf"' -lbfd -ldl test-hello.bin: $(BUILD) @@ -82,10 +83,10 @@ test-libslang.bin: $(BUILD) -I/usr/include/slang -lslang test-gtk2.bin: - $(BUILD) $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null) + $(BUILD) $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null) test-gtk2-infobar.bin: - $(BUILD) $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null) + $(BUILD) $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null) grep-libs = $(filter -l%,$(1)) strip-libs = $(filter-out -l%,$(1)) -- cgit v1.2.3 From 540476de74c9b11403656791838ede91405d3859 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 14 Jan 2014 14:25:34 +0900 Subject: perf tools: Remove symbol_conf.use_callchain check The machine__resolve_callchain() is called only if symbol_conf. use_callchain is set so no need to check it again. Signed-off-by: Namhyung Kim Cc: Andi Kleen Cc: Ingo Molnar Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Rodrigo Campos Link: http://lkml.kernel.org/r/1389677157-30513-2-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/machine.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 0130279aac51..ded74590b92f 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -1314,8 +1314,6 @@ static int machine__resolve_callchain_sample(struct machine *machine, *root_al = al; callchain_cursor_reset(&callchain_cursor); } - if (!symbol_conf.use_callchain) - break; } err = callchain_cursor_append(&callchain_cursor, -- cgit v1.2.3 From 2dc9fb1a7bf013ce24dd34bc25283b60b966f015 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 14 Jan 2014 14:25:35 +0900 Subject: perf tools: Factor out sample__resolve_callchain() The report__resolve_callchain() can be shared with perf top code as it doesn't really depend on the perf report code. Factor it out as sample__resolve_callchain(). The same goes to the hist_entry__append_ callchain() too. Signed-off-by: Namhyung Kim Acked-by: Jiri Olsa Cc: Andi Kleen Cc: Arun Sharma Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Rodrigo Campos Link: http://lkml.kernel.org/r/1389677157-30513-3-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-report.c | 24 +++--------------------- tools/perf/builtin-top.c | 22 +++++++--------------- tools/perf/util/callchain.c | 23 +++++++++++++++++++++++ tools/perf/util/callchain.h | 6 ++++++ 4 files changed, 39 insertions(+), 36 deletions(-) diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 46864dd7eb83..3c53ec268fbc 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -75,24 +75,6 @@ static int report__config(const char *var, const char *value, void *cb) return perf_default_config(var, value, cb); } -static int report__resolve_callchain(struct report *rep, struct symbol **parent, - struct perf_evsel *evsel, struct addr_location *al, - struct perf_sample *sample) -{ - if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) { - return machine__resolve_callchain(al->machine, evsel, al->thread, sample, - parent, al, rep->max_stack); - } - return 0; -} - -static int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample) -{ - if (!symbol_conf.use_callchain) - return 0; - return callchain_append(he->callchain, &callchain_cursor, sample->period); -} - static int report__add_mem_hist_entry(struct perf_tool *tool, struct addr_location *al, struct perf_sample *sample, struct perf_evsel *evsel, union perf_event *event) @@ -103,7 +85,7 @@ static int report__add_mem_hist_entry(struct perf_tool *tool, struct addr_locati struct hist_entry *he; struct mem_info *mi, *mx; uint64_t cost; - int err = report__resolve_callchain(rep, &parent, evsel, al, sample); + int err = sample__resolve_callchain(sample, &parent, evsel, al, rep->max_stack); if (err) return err; @@ -155,7 +137,7 @@ static int report__add_branch_hist_entry(struct perf_tool *tool, struct addr_loc unsigned i; struct hist_entry *he; struct branch_info *bi, *bx; - int err = report__resolve_callchain(rep, &parent, evsel, al, sample); + int err = sample__resolve_callchain(sample, &parent, evsel, al, rep->max_stack); if (err) return err; @@ -208,7 +190,7 @@ static int report__add_hist_entry(struct perf_tool *tool, struct perf_evsel *evs struct report *rep = container_of(tool, struct report, tool); struct symbol *parent = NULL; struct hist_entry *he; - int err = report__resolve_callchain(rep, &parent, evsel, al, sample); + int err = sample__resolve_callchain(sample, &parent, evsel, al, rep->max_stack); if (err) return err; diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 569dd87690ef..76cd510d34d0 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -743,15 +743,10 @@ static void perf_event__process_sample(struct perf_tool *tool, if (al.sym == NULL || !al.sym->ignore) { struct hist_entry *he; - if ((sort__has_parent || symbol_conf.use_callchain) && - sample->callchain) { - err = machine__resolve_callchain(machine, evsel, - al.thread, sample, - &parent, &al, - top->max_stack); - if (err) - return; - } + err = sample__resolve_callchain(sample, &parent, evsel, &al, + top->max_stack); + if (err) + return; he = perf_evsel__add_hist_entry(evsel, &al, sample); if (he == NULL) { @@ -759,12 +754,9 @@ static void perf_event__process_sample(struct perf_tool *tool, return; } - if (symbol_conf.use_callchain) { - err = callchain_append(he->callchain, &callchain_cursor, - sample->period); - if (err) - return; - } + err = hist_entry__append_callchain(he, sample); + if (err) + return; if (sort__has_sym) perf_top__record_precise_ip(top, he, evsel->idx, ip); diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c index e3970e3eaacf..9eb4f57f8663 100644 --- a/tools/perf/util/callchain.c +++ b/tools/perf/util/callchain.c @@ -17,6 +17,8 @@ #include "hist.h" #include "util.h" +#include "sort.h" +#include "machine.h" #include "callchain.h" __thread struct callchain_cursor callchain_cursor; @@ -531,3 +533,24 @@ int callchain_cursor_append(struct callchain_cursor *cursor, return 0; } + +int sample__resolve_callchain(struct perf_sample *sample, struct symbol **parent, + struct perf_evsel *evsel, struct addr_location *al, + int max_stack) +{ + if (sample->callchain == NULL) + return 0; + + if (symbol_conf.use_callchain || sort__has_parent) { + return machine__resolve_callchain(al->machine, evsel, al->thread, + sample, parent, al, max_stack); + } + return 0; +} + +int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample) +{ + if (!symbol_conf.use_callchain) + return 0; + return callchain_append(he->callchain, &callchain_cursor, sample->period); +} diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h index 08b25af9eea1..8ad97e9b119f 100644 --- a/tools/perf/util/callchain.h +++ b/tools/perf/util/callchain.h @@ -145,10 +145,16 @@ static inline void callchain_cursor_advance(struct callchain_cursor *cursor) } struct option; +struct hist_entry; int record_parse_callchain(const char *arg, struct record_opts *opts); int record_parse_callchain_opt(const struct option *opt, const char *arg, int unset); int record_callchain_opt(const struct option *opt, const char *arg, int unset); +int sample__resolve_callchain(struct perf_sample *sample, struct symbol **parent, + struct perf_evsel *evsel, struct addr_location *al, + int max_stack); +int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample); + extern const char record_callchain_help[]; #endif /* __PERF_CALLCHAIN_H */ -- cgit v1.2.3 From f39056f9c3275e648e2fb353561aeb377dd351f7 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 14 Jan 2014 14:25:37 +0900 Subject: perf hists: Convert hist entry functions to use struct he_stat The hist_entry__add_cpumode_period() and hist_entry__decay() functions are dealing with hist_entry's stat fields only. Make them he_stat methods then. Signed-off-by: Namhyung Kim Acked-by: Jiri Olsa Cc: Andi Kleen Cc: Arun Sharma Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Rodrigo Campos Link: http://lkml.kernel.org/r/1389677157-30513-5-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/hist.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 4ed3e883240d..e4e6249b87d4 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -181,21 +181,21 @@ void hists__output_recalc_col_len(struct hists *hists, int max_rows) } } -static void hist_entry__add_cpumode_period(struct hist_entry *he, - unsigned int cpumode, u64 period) +static void he_stat__add_cpumode_period(struct he_stat *he_stat, + unsigned int cpumode, u64 period) { switch (cpumode) { case PERF_RECORD_MISC_KERNEL: - he->stat.period_sys += period; + he_stat->period_sys += period; break; case PERF_RECORD_MISC_USER: - he->stat.period_us += period; + he_stat->period_us += period; break; case PERF_RECORD_MISC_GUEST_KERNEL: - he->stat.period_guest_sys += period; + he_stat->period_guest_sys += period; break; case PERF_RECORD_MISC_GUEST_USER: - he->stat.period_guest_us += period; + he_stat->period_guest_us += period; break; default: break; @@ -222,10 +222,10 @@ static void he_stat__add_stat(struct he_stat *dest, struct he_stat *src) dest->weight += src->weight; } -static void hist_entry__decay(struct hist_entry *he) +static void he_stat__decay(struct he_stat *he_stat) { - he->stat.period = (he->stat.period * 7) / 8; - he->stat.nr_events = (he->stat.nr_events * 7) / 8; + he_stat->period = (he_stat->period * 7) / 8; + he_stat->nr_events = (he_stat->nr_events * 7) / 8; /* XXX need decay for weight too? */ } @@ -236,7 +236,7 @@ static bool hists__decay_entry(struct hists *hists, struct hist_entry *he) if (prev_period == 0) return true; - hist_entry__decay(he); + he_stat__decay(&he->stat); if (!he->filtered) hists->stats.total_period -= prev_period - he->stat.period; @@ -402,7 +402,7 @@ static struct hist_entry *add_hist_entry(struct hists *hists, rb_link_node(&he->rb_node_in, parent, p); rb_insert_color(&he->rb_node_in, hists->entries_in); out: - hist_entry__add_cpumode_period(he, al->cpumode, period); + he_stat__add_cpumode_period(&he->stat, al->cpumode, period); return he; } -- cgit v1.2.3 From 0e9e79a13ab9d56b86db6538305babc23b1445cc Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Wed, 15 Jan 2014 10:44:07 +0000 Subject: tools lib traceevent: fix pointer-integer size mismatch The scsi and cfg80211 plugins cast between unsigned long long and pointers, which is problematic for architectures where unsigned long long is wider than the native pointer size: linux/tools/lib/traceevent/plugin_scsi.c: In function ‘process_scsi_trace_parse_cdb’: linux/tools/lib/traceevent/plugin_scsi.c:408:26: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast] scsi_trace_parse_cdb(s, (unsigned char *) args[1], args[2]); linux/tools/lib/traceevent/plugin_cfg80211.c: In function ‘process___le16_to_cpup’: linux/tools/lib/traceevent/plugin_cfg80211.c:11:18: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast] uint16_t *val = (uint16_t *) args[0]; This patch adds an intermediate cast to unsigned long, silencing the warning. Signed-off-by: Mark Rutland Acked-by: Jiri Olsa Acked-by: Steven Rostedt Cc: Ingo Molnar Cc: Jiri Olsa Cc: Will Deacon Link: http://lkml.kernel.org/r/1389782648-4417-3-git-send-email-mark.rutland@arm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/lib/traceevent/plugin_cfg80211.c | 2 +- tools/lib/traceevent/plugin_scsi.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/lib/traceevent/plugin_cfg80211.c b/tools/lib/traceevent/plugin_cfg80211.c index dcab8e873c21..57e98221db20 100644 --- a/tools/lib/traceevent/plugin_cfg80211.c +++ b/tools/lib/traceevent/plugin_cfg80211.c @@ -8,7 +8,7 @@ static unsigned long long process___le16_to_cpup(struct trace_seq *s, unsigned long long *args) { - uint16_t *val = (uint16_t *) args[0]; + uint16_t *val = (uint16_t *) (unsigned long) args[0]; return val ? (long long) le16toh(*val) : 0; } diff --git a/tools/lib/traceevent/plugin_scsi.c b/tools/lib/traceevent/plugin_scsi.c index 6fb8e3e3fcad..7ef16cc96562 100644 --- a/tools/lib/traceevent/plugin_scsi.c +++ b/tools/lib/traceevent/plugin_scsi.c @@ -405,7 +405,7 @@ scsi_trace_parse_cdb(struct trace_seq *p, unsigned char *cdb, int len) unsigned long long process_scsi_trace_parse_cdb(struct trace_seq *s, unsigned long long *args) { - scsi_trace_parse_cdb(s, (unsigned char *) args[1], args[2]); + scsi_trace_parse_cdb(s, (unsigned char *) (unsigned long) args[1], args[2]); return 0; } -- cgit v1.2.3