diff options
Diffstat (limited to 'tools')
53 files changed, 907 insertions, 265 deletions
diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c index ca9fa4d32e0..07819bfa7db 100644 --- a/tools/hv/hv_kvp_daemon.c +++ b/tools/hv/hv_kvp_daemon.c @@ -1026,9 +1026,10 @@ kvp_get_ip_info(int family, char *if_name, int op, if (sn_offset == 0) strcpy(sn_str, cidr_mask); - else + else { + strcat((char *)ip_buffer->sub_net, ";"); strcat(sn_str, cidr_mask); - strcat((char *)ip_buffer->sub_net, ";"); + } sn_offset += strlen(sn_str) + 1; } diff --git a/tools/include/tools/be_byteshift.h b/tools/include/tools/be_byteshift.h index f4912e2668b..84c17d83657 100644 --- a/tools/include/tools/be_byteshift.h +++ b/tools/include/tools/be_byteshift.h @@ -1,68 +1,68 @@ #ifndef _TOOLS_BE_BYTESHIFT_H #define _TOOLS_BE_BYTESHIFT_H -#include <linux/types.h> +#include <stdint.h> -static inline __u16 __get_unaligned_be16(const __u8 *p) +static inline uint16_t __get_unaligned_be16(const uint8_t *p) { return p[0] << 8 | p[1]; } -static inline __u32 __get_unaligned_be32(const __u8 *p) +static inline uint32_t __get_unaligned_be32(const uint8_t *p) { return p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3]; } -static inline __u64 __get_unaligned_be64(const __u8 *p) +static inline uint64_t __get_unaligned_be64(const uint8_t *p) { - return (__u64)__get_unaligned_be32(p) << 32 | + return (uint64_t)__get_unaligned_be32(p) << 32 | __get_unaligned_be32(p + 4); } -static inline void __put_unaligned_be16(__u16 val, __u8 *p) +static inline void __put_unaligned_be16(uint16_t val, uint8_t *p) { *p++ = val >> 8; *p++ = val; } -static inline void __put_unaligned_be32(__u32 val, __u8 *p) +static inline void __put_unaligned_be32(uint32_t val, uint8_t *p) { __put_unaligned_be16(val >> 16, p); __put_unaligned_be16(val, p + 2); } -static inline void __put_unaligned_be64(__u64 val, __u8 *p) +static inline void __put_unaligned_be64(uint64_t val, uint8_t *p) { __put_unaligned_be32(val >> 32, p); __put_unaligned_be32(val, p + 4); } -static inline __u16 get_unaligned_be16(const void *p) +static inline uint16_t get_unaligned_be16(const void *p) { - return __get_unaligned_be16((const __u8 *)p); + return __get_unaligned_be16((const uint8_t *)p); } -static inline __u32 get_unaligned_be32(const void *p) +static inline uint32_t get_unaligned_be32(const void *p) { - return __get_unaligned_be32((const __u8 *)p); + return __get_unaligned_be32((const uint8_t *)p); } -static inline __u64 get_unaligned_be64(const void *p) +static inline uint64_t get_unaligned_be64(const void *p) { - return __get_unaligned_be64((const __u8 *)p); + return __get_unaligned_be64((const uint8_t *)p); } -static inline void put_unaligned_be16(__u16 val, void *p) +static inline void put_unaligned_be16(uint16_t val, void *p) { __put_unaligned_be16(val, p); } -static inline void put_unaligned_be32(__u32 val, void *p) +static inline void put_unaligned_be32(uint32_t val, void *p) { __put_unaligned_be32(val, p); } -static inline void put_unaligned_be64(__u64 val, void *p) +static inline void put_unaligned_be64(uint64_t val, void *p) { __put_unaligned_be64(val, p); } diff --git a/tools/include/tools/le_byteshift.h b/tools/include/tools/le_byteshift.h index c99d45a68bd..8fe9f2488ec 100644 --- a/tools/include/tools/le_byteshift.h +++ b/tools/include/tools/le_byteshift.h @@ -1,68 +1,68 @@ #ifndef _TOOLS_LE_BYTESHIFT_H #define _TOOLS_LE_BYTESHIFT_H -#include <linux/types.h> +#include <stdint.h> -static inline __u16 __get_unaligned_le16(const __u8 *p) +static inline uint16_t __get_unaligned_le16(const uint8_t *p) { return p[0] | p[1] << 8; } -static inline __u32 __get_unaligned_le32(const __u8 *p) +static inline uint32_t __get_unaligned_le32(const uint8_t *p) { return p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24; } -static inline __u64 __get_unaligned_le64(const __u8 *p) +static inline uint64_t __get_unaligned_le64(const uint8_t *p) { - return (__u64)__get_unaligned_le32(p + 4) << 32 | + return (uint64_t)__get_unaligned_le32(p + 4) << 32 | __get_unaligned_le32(p); } -static inline void __put_unaligned_le16(__u16 val, __u8 *p) +static inline void __put_unaligned_le16(uint16_t val, uint8_t *p) { *p++ = val; *p++ = val >> 8; } -static inline void __put_unaligned_le32(__u32 val, __u8 *p) +static inline void __put_unaligned_le32(uint32_t val, uint8_t *p) { __put_unaligned_le16(val >> 16, p + 2); __put_unaligned_le16(val, p); } -static inline void __put_unaligned_le64(__u64 val, __u8 *p) +static inline void __put_unaligned_le64(uint64_t val, uint8_t *p) { __put_unaligned_le32(val >> 32, p + 4); __put_unaligned_le32(val, p); } -static inline __u16 get_unaligned_le16(const void *p) +static inline uint16_t get_unaligned_le16(const void *p) { - return __get_unaligned_le16((const __u8 *)p); + return __get_unaligned_le16((const uint8_t *)p); } -static inline __u32 get_unaligned_le32(const void *p) +static inline uint32_t get_unaligned_le32(const void *p) { - return __get_unaligned_le32((const __u8 *)p); + return __get_unaligned_le32((const uint8_t *)p); } -static inline __u64 get_unaligned_le64(const void *p) +static inline uint64_t get_unaligned_le64(const void *p) { - return __get_unaligned_le64((const __u8 *)p); + return __get_unaligned_le64((const uint8_t *)p); } -static inline void put_unaligned_le16(__u16 val, void *p) +static inline void put_unaligned_le16(uint16_t val, void *p) { __put_unaligned_le16(val, p); } -static inline void put_unaligned_le32(__u32 val, void *p) +static inline void put_unaligned_le32(uint32_t val, void *p) { __put_unaligned_le32(val, p); } -static inline void put_unaligned_le64(__u64 val, void *p) +static inline void put_unaligned_le64(uint64_t val, void *p) { __put_unaligned_le64(val, p); } diff --git a/tools/lguest/Makefile b/tools/lguest/Makefile index 0ac34206f7a..97bca4871ea 100644 --- a/tools/lguest/Makefile +++ b/tools/lguest/Makefile @@ -1,5 +1,4 @@ # This creates the demonstration utility "lguest" which runs a Linux guest. -# Missing headers? Add "-I../../../include -I../../../arch/x86/include" CFLAGS:=-m32 -Wall -Wmissing-declarations -Wmissing-prototypes -O3 -U_FORTIFY_SOURCE all: lguest diff --git a/tools/lguest/lguest.c b/tools/lguest/lguest.c index 07a03452c22..68f67cf3d31 100644 --- a/tools/lguest/lguest.c +++ b/tools/lguest/lguest.c @@ -42,14 +42,6 @@ #include <pwd.h> #include <grp.h> -#include <linux/virtio_config.h> -#include <linux/virtio_net.h> -#include <linux/virtio_blk.h> -#include <linux/virtio_console.h> -#include <linux/virtio_rng.h> -#include <linux/virtio_ring.h> -#include <asm/bootparam.h> -#include "../../include/linux/lguest_launcher.h" /*L:110 * We can ignore the 43 include files we need for this program, but I do want * to draw attention to the use of kernel-style types. @@ -65,6 +57,15 @@ typedef uint16_t u16; typedef uint8_t u8; /*:*/ +#include <linux/virtio_config.h> +#include <linux/virtio_net.h> +#include <linux/virtio_blk.h> +#include <linux/virtio_console.h> +#include <linux/virtio_rng.h> +#include <linux/virtio_ring.h> +#include <asm/bootparam.h> +#include "../../include/linux/lguest_launcher.h" + #define BRIDGE_PFX "bridge:" #ifndef SIOCBRADDIF #define SIOCBRADDIF 0x89a2 /* add interface to bridge */ @@ -177,7 +178,8 @@ static struct termios orig_term; * in precise order. */ #define wmb() __asm__ __volatile__("" : : : "memory") -#define mb() __asm__ __volatile__("" : : : "memory") +#define rmb() __asm__ __volatile__("lock; addl $0,0(%%esp)" : : : "memory") +#define mb() __asm__ __volatile__("lock; addl $0,0(%%esp)" : : : "memory") /* Wrapper for the last available index. Makes it easier to change. */ #define lg_last_avail(vq) ((vq)->last_avail_idx) @@ -676,6 +678,12 @@ static unsigned wait_for_vq_desc(struct virtqueue *vq, errx(1, "Guest moved used index from %u to %u", last_avail, vq->vring.avail->idx); + /* + * Make sure we read the descriptor number *after* we read the ring + * update; don't let the cpu or compiler change the order. + */ + rmb(); + /* * Grab the next descriptor number they're advertising, and increment * the index we've seen. @@ -695,6 +703,12 @@ static unsigned wait_for_vq_desc(struct virtqueue *vq, i = head; /* + * We have to read the descriptor after we read the descriptor number, + * but there's a data dependency there so the CPU shouldn't reorder + * that: no rmb() required. + */ + + /* * If this is an indirect entry, then this buffer contains a descriptor * table which we handle as if it's any normal descriptor chain. */ diff --git a/tools/lib/lk/Makefile b/tools/lib/lk/Makefile index 2c5a1973335..280dd820543 100644 --- a/tools/lib/lk/Makefile +++ b/tools/lib/lk/Makefile @@ -3,6 +3,21 @@ include ../../scripts/Makefile.include CC = $(CROSS_COMPILE)gcc AR = $(CROSS_COMPILE)ar +# Makefiles suck: This macro sets a default value of $(2) for the +# variable named by $(1), unless the variable has been set by +# environment or command line. This is necessary for CC and AR +# because make sets default values, so the simpler ?= approach +# won't work as expected. +define allow-override + $(if $(or $(findstring environment,$(origin $(1))),\ + $(findstring command line,$(origin $(1)))),,\ + $(eval $(1) = $(2))) +endef + +# Allow setting CC and AR, or setting CROSS_COMPILE as a prefix. +$(call allow-override,CC,$(CROSS_COMPILE)gcc) +$(call allow-override,AR,$(CROSS_COMPILE)ar) + # guard against environment variables LIB_H= LIB_OBJS= @@ -14,7 +29,7 @@ LIB_OBJS += $(OUTPUT)debugfs.o LIBFILE = liblk.a CFLAGS = -ggdb3 -Wall -Wextra -std=gnu99 -Werror -O6 -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) -fPIC -EXTLIBS = -lpthread -lrt -lelf -lm +EXTLIBS = -lelf -lpthread -lrt -lm ALL_CFLAGS = $(CFLAGS) $(BASIC_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 ALL_LDFLAGS = $(LDFLAGS) diff --git a/tools/perf/Documentation/Makefile b/tools/perf/Documentation/Makefile index eb30044a922..5a37a7c84e6 100644 --- a/tools/perf/Documentation/Makefile +++ b/tools/perf/Documentation/Makefile @@ -1,12 +1,6 @@ +include ../../scripts/Makefile.include include ../config/utilities.mak -OUTPUT := ./ -ifeq ("$(origin O)", "command line") - ifneq ($(O),) - OUTPUT := $(O)/ - endif -endif - MAN1_TXT= \ $(filter-out $(addsuffix .txt, $(ARTICLES) $(SP_ARTICLES)), \ $(wildcard perf-*.txt)) \ @@ -150,7 +144,7 @@ NO_SUBDIR = : endif ifneq ($(findstring $(MAKEFLAGS),s),s) -ifndef V +ifneq ($(V),1) QUIET_ASCIIDOC = @echo ' ' ASCIIDOC $@; QUIET_XMLTO = @echo ' ' XMLTO $@; QUIET_DB2TEXI = @echo ' ' DB2TEXI $@; @@ -277,7 +271,7 @@ $(MAN_HTML): $(OUTPUT)%.html : %.txt $(OUTPUT)%.1 $(OUTPUT)%.5 $(OUTPUT)%.7 : $(OUTPUT)%.xml $(QUIET_XMLTO)$(RM) $@ && \ - $(XMLTO) -o $(OUTPUT) -m $(MANPAGE_XSL) $(XMLTO_EXTRA) man $< + $(XMLTO) -o $(OUTPUT). -m $(MANPAGE_XSL) $(XMLTO_EXTRA) man $< $(OUTPUT)%.xml : %.txt $(QUIET_ASCIIDOC)$(RM) $@+ $@ && \ diff --git a/tools/perf/Documentation/examples.txt b/tools/perf/Documentation/examples.txt index 77f95276242..a4e39215648 100644 --- a/tools/perf/Documentation/examples.txt +++ b/tools/perf/Documentation/examples.txt @@ -66,7 +66,7 @@ Furthermore, these tracepoints can be used to sample the workload as well. For example the page allocations done by a 'git gc' can be captured the following way: - titan:~/git> perf record -f -e kmem:mm_page_alloc -c 1 ./git gc + titan:~/git> perf record -e kmem:mm_page_alloc -c 1 ./git gc Counting objects: 1148, done. Delta compression using up to 2 threads. Compressing objects: 100% (450/450), done. @@ -120,7 +120,7 @@ Furthermore, call-graph sampling can be done too, of page allocations - to see precisely what kind of page allocations there are: - titan:~/git> perf record -f -g -e kmem:mm_page_alloc -c 1 ./git gc + titan:~/git> perf record -g -e kmem:mm_page_alloc -c 1 ./git gc Counting objects: 1148, done. Delta compression using up to 2 threads. Compressing objects: 100% (450/450), done. diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index d4da111ef53..e297b74471b 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt @@ -65,16 +65,10 @@ OPTIONS -r:: --realtime=:: Collect data with this RT SCHED_FIFO priority. + -D:: --no-delay:: Collect data without buffering. --A:: ---append:: - Append to the output file to do incremental profiling. - --f:: ---force:: - Overwrite existing data file. (deprecated) -c:: --count=:: diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 203cb0eecff..641fccddb24 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -121,17 +121,16 @@ SCRIPT_SH += perf-archive.sh grep-libs = $(filter -l%,$(1)) strip-libs = $(filter-out -l%,$(1)) -LK_PATH=$(LK_DIR) - ifneq ($(OUTPUT),) TE_PATH=$(OUTPUT) ifneq ($(subdir),) - LK_PATH=$(OUTPUT)$(LK_DIR) + LK_PATH=$(objtree)/lib/lk/ else LK_PATH=$(OUTPUT) endif else TE_PATH=$(TRACE_EVENT_DIR) + LK_PATH=$(LK_DIR) endif LIBTRACEEVENT = $(TE_PATH)libtraceevent.a diff --git a/tools/perf/bench/mem-memcpy.c b/tools/perf/bench/mem-memcpy.c index 93c83e3cb4a..25fd3f1966f 100644 --- a/tools/perf/bench/mem-memcpy.c +++ b/tools/perf/bench/mem-memcpy.c @@ -111,11 +111,11 @@ static double timeval2double(struct timeval *ts) static void alloc_mem(void **dst, void **src, size_t length) { *dst = zalloc(length); - if (!dst) + if (!*dst) die("memory allocation failed - maybe length is too large?\n"); *src = zalloc(length); - if (!src) + if (!*src) die("memory allocation failed - maybe length is too large?\n"); } diff --git a/tools/perf/bench/mem-memset.c b/tools/perf/bench/mem-memset.c index c6e4bc52349..4a2f1208196 100644 --- a/tools/perf/bench/mem-memset.c +++ b/tools/perf/bench/mem-memset.c @@ -111,7 +111,7 @@ static double timeval2double(struct timeval *ts) static void alloc_mem(void **dst, size_t length) { *dst = zalloc(length); - if (!dst) + if (!*dst) die("memory allocation failed - maybe length is too large?\n"); } diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index da8f8eb383a..0aac5f3e594 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -607,7 +607,6 @@ int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused) input_new = "perf.data.guest"; } - symbol_conf.exclude_other = false; if (symbol__init() < 0) return -1; diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index 46878daca5c..0259502638b 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c @@ -708,7 +708,7 @@ static int parse_line_opt(const struct option *opt __maybe_unused, static int __cmd_record(int argc, const char **argv) { const char * const record_args[] = { - "record", "-a", "-R", "-f", "-c", "1", + "record", "-a", "-R", "-c", "1", "-e", "kmem:kmalloc", "-e", "kmem:kmalloc_node", "-e", "kmem:kfree", diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c index 42583006974..76543a4a7a3 100644 --- a/tools/perf/builtin-lock.c +++ b/tools/perf/builtin-lock.c @@ -878,7 +878,7 @@ static int __cmd_report(void) static int __cmd_record(int argc, const char **argv) { const char *record_args[] = { - "record", "-R", "-f", "-m", "1024", "-c", "1", + "record", "-R", "-m", "1024", "-c", "1", }; unsigned int rec_argc, i, j; const char **rec_argv; diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index fff985cf385..ecca62e27b2 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -61,11 +61,6 @@ static void __handle_on_exit_funcs(void) } #endif -enum write_mode_t { - WRITE_FORCE, - WRITE_APPEND -}; - struct perf_record { struct perf_tool tool; struct perf_record_opts opts; @@ -77,12 +72,8 @@ struct perf_record { int output; unsigned int page_size; int realtime_prio; - enum write_mode_t write_mode; bool no_buildid; bool no_buildid_cache; - bool force; - bool file_new; - bool append_file; long samples; off_t post_processing_offset; }; @@ -200,25 +191,6 @@ static void perf_record__sig_exit(int exit_status __maybe_unused, void *arg) signal(signr, SIG_DFL); } -static bool perf_evlist__equal(struct perf_evlist *evlist, - struct perf_evlist *other) -{ - struct perf_evsel *pos, *pair; - - if (evlist->nr_entries != other->nr_entries) - return false; - - pair = perf_evlist__first(other); - - list_for_each_entry(pos, &evlist->entries, node) { - if (memcmp(&pos->attr, &pair->attr, sizeof(pos->attr) != 0)) - return false; - pair = perf_evsel__next(pair); - } - - return true; -} - static int perf_record__open(struct perf_record *rec) { char msg[512]; @@ -273,16 +245,7 @@ try_again: goto out; } - if (rec->file_new) - session->evlist = evlist; - else { - if (!perf_evlist__equal(session->evlist, evlist)) { - fprintf(stderr, "incompatible append\n"); - rc = -1; - goto out; - } - } - + session->evlist = evlist; perf_session__set_id_hdr_size(session); out: return rc; @@ -415,23 +378,15 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) if (!strcmp(output_name, "-")) opts->pipe_output = true; else if (!stat(output_name, &st) && st.st_size) { - if (rec->write_mode == WRITE_FORCE) { - char oldname[PATH_MAX]; - snprintf(oldname, sizeof(oldname), "%s.old", - output_name); - unlink(oldname); - rename(output_name, oldname); - } - } else if (rec->write_mode == WRITE_APPEND) { - rec->write_mode = WRITE_FORCE; + char oldname[PATH_MAX]; + snprintf(oldname, sizeof(oldname), "%s.old", + output_name); + unlink(oldname); + rename(output_name, oldname); } } - flags = O_CREAT|O_RDWR; - if (rec->write_mode == WRITE_APPEND) - rec->file_new = 0; - else - flags |= O_TRUNC; + flags = O_CREAT|O_RDWR|O_TRUNC; if (opts->pipe_output) output = STDOUT_FILENO; @@ -445,7 +400,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) rec->output = output; session = perf_session__new(output_name, O_WRONLY, - rec->write_mode == WRITE_FORCE, false, NULL); + true, false, NULL); if (session == NULL) { pr_err("Not enough memory for reading perf file header\n"); return -1; @@ -465,12 +420,6 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) if (!rec->opts.branch_stack) perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK); - if (!rec->file_new) { - err = perf_session__read_header(session, output); - if (err < 0) - goto out_delete_session; - } - if (forks) { err = perf_evlist__prepare_workload(evsel_list, &opts->target, argv, opts->pipe_output, @@ -498,7 +447,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) err = perf_header__write_pipe(output); if (err < 0) goto out_delete_session; - } else if (rec->file_new) { + } else { err = perf_session__write_header(session, evsel_list, output, false); if (err < 0) @@ -869,8 +818,6 @@ static struct perf_record record = { .uses_mmap = true, }, }, - .write_mode = WRITE_FORCE, - .file_new = true, }; #define CALLCHAIN_HELP "do call-graph (stack chain/backtrace) recording: " @@ -906,12 +853,8 @@ const struct option record_options[] = { "collect raw sample records from all opened counters"), OPT_BOOLEAN('a', "all-cpus", &record.opts.target.system_wide, "system-wide collection from all CPUs"), - OPT_BOOLEAN('A', "append", &record.append_file, - "append to the output file to do incremental profiling"), OPT_STRING('C', "cpu", &record.opts.target.cpu_list, "cpu", "list of cpus to monitor"), - OPT_BOOLEAN('f', "force", &record.force, - "overwrite existing data file (deprecated)"), OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"), OPT_STRING('o', "output", &record.output_name, "file", "output file name"), @@ -977,16 +920,6 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused) if (!argc && perf_target__none(&rec->opts.target)) usage_with_options(record_usage, record_options); - if (rec->force && rec->append_file) { - ui__error("Can't overwrite and append at the same time." - " You need to choose between -f and -A"); - usage_with_options(record_usage, record_options); - } else if (rec->append_file) { - rec->write_mode = WRITE_APPEND; - } else { - rec->write_mode = WRITE_FORCE; - } - if (nr_cgroups && !rec->opts.target.system_wide) { ui__error("cgroup monitoring only available in" " system-wide mode\n"); diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index ca98d34cd58..3662047cc6b 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -939,8 +939,7 @@ repeat: */ if (!strstr(sort_order, "parent")) sort_parent.elide = 1; - } else - symbol_conf.exclude_other = false; + } if (argc) { /* diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index 2da2a6ca22b..fed9ae432c1 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -1632,7 +1632,6 @@ static int __cmd_record(int argc, const char **argv) "record", "-a", "-R", - "-f", "-m", "1024", "-c", "1", "-e", "sched:sched_switch", diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 7e910bab109..352fbd7ff4a 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -87,7 +87,7 @@ static int run_count = 1; static bool no_inherit = false; static bool scale = true; static enum aggr_mode aggr_mode = AGGR_GLOBAL; -static pid_t child_pid = -1; +static volatile pid_t child_pid = -1; static bool null_run = false; static int detailed_run = 0; static bool big_num = true; @@ -924,7 +924,7 @@ static void abs_printout(int cpu, int nr, struct perf_evsel *evsel, double avg) static void print_aggr(char *prefix) { struct perf_evsel *counter; - int cpu, s, s2, id, nr; + int cpu, cpu2, s, s2, id, nr; u64 ena, run, val; if (!(aggr_map || aggr_get_id)) @@ -936,7 +936,8 @@ static void print_aggr(char *prefix) val = ena = run = 0; nr = 0; for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) { - s2 = aggr_get_id(evsel_list->cpus, cpu); + cpu2 = perf_evsel__cpus(counter)->map[cpu]; + s2 = aggr_get_id(evsel_list->cpus, cpu2); if (s2 != id) continue; val += counter->counts->cpu[cpu].val; @@ -948,7 +949,7 @@ static void print_aggr(char *prefix) fprintf(output, "%s", prefix); if (run == 0 || ena == 0) { - aggr_printout(counter, cpu, nr); + aggr_printout(counter, id, nr); fprintf(output, "%*s%s%*s", csv_output ? 0 : 18, @@ -1148,13 +1149,34 @@ static void skip_signal(int signo) done = 1; signr = signo; + /* + * render child_pid harmless + * won't send SIGTERM to a random + * process in case of race condition + * and fast PID recycling + */ + child_pid = -1; } static void sig_atexit(void) { + sigset_t set, oset; + + /* + * avoid race condition with SIGCHLD handler + * in skip_signal() which is modifying child_pid + * goal is to avoid send SIGTERM to a random + * process + */ + sigemptyset(&set); + sigaddset(&set, SIGCHLD); + sigprocmask(SIG_BLOCK, &set, &oset); + if (child_pid != -1) kill(child_pid, SIGTERM); + sigprocmask(SIG_SETMASK, &oset, NULL); + if (signr == -1) return; diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index ab4cf232b85..4536a92b18f 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c @@ -1005,7 +1005,7 @@ static int __cmd_record(int argc, const char **argv) { #ifdef SUPPORT_OLD_POWER_EVENTS const char * const record_old_args[] = { - "record", "-a", "-R", "-f", "-c", "1", + "record", "-a", "-R", "-c", "1", "-e", "power:power_start", "-e", "power:power_end", "-e", "power:power_frequency", @@ -1014,7 +1014,7 @@ static int __cmd_record(int argc, const char **argv) }; #endif const char * const record_new_args[] = { - "record", "-a", "-R", "-f", "-c", "1", + "record", "-a", "-R", "-c", "1", "-e", "power:cpu_frequency", "-e", "power:cpu_idle", "-e", "sched:sched_wakeup", diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index f036af9b6f0..e06c4f86933 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -1130,8 +1130,6 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) if (top.evlist == NULL) return -ENOMEM; - symbol_conf.exclude_other = false; - argc = parse_options(argc, argv, options, top_usage, 0); if (argc) usage_with_options(top_usage, options); diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index f139dcd2796..b5d9238cb18 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile @@ -39,7 +39,7 @@ src-perf := $(srctree)/tools/perf endif ifeq ($(obj-perf),) -obj-perf := $(objtree) +obj-perf := $(OUTPUT) endif ifneq ($(obj-perf),) @@ -85,7 +85,7 @@ CFLAGS += -Wall CFLAGS += -Wextra CFLAGS += -std=gnu99 -EXTLIBS = -lpthread -lrt -lelf -lm +EXTLIBS = -lelf -lpthread -lrt -lm ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -fstack-protector-all,-fstack-protector-all),y) CFLAGS += -fstack-protector-all @@ -165,7 +165,7 @@ else LIBDW_LDFLAGS := -L$(LIBDW_DIR)/lib endif - FLAGS_DWARF=$(CFLAGS) $(LIBDW_CFLAGS) -ldw -lelf $(LIBDW_LDFLAGS) $(LDFLAGS) $(EXTLIBS) + FLAGS_DWARF=$(CFLAGS) $(LIBDW_CFLAGS) -ldw -lz -lelf $(LIBDW_LDFLAGS) $(LDFLAGS) $(EXTLIBS) ifneq ($(call try-cc,$(SOURCE_DWARF),$(FLAGS_DWARF),libdw),y) msg := $(warning No libdw.h found or old libdw.h found or elfutils is older than 0.138, disables dwarf support. Please install new elfutils-devel/libdw-dev); NO_DWARF := 1 diff --git a/tools/perf/config/utilities.mak b/tools/perf/config/utilities.mak index 8ef3bd30a54..94d2d4f9c35 100644 --- a/tools/perf/config/utilities.mak +++ b/tools/perf/config/utilities.mak @@ -173,7 +173,7 @@ _ge-abspath = $(if $(is-executable),$(1)) # Usage: absolute-executable-path-or-empty = $(call get-executable-or-default,variable,default) # define get-executable-or-default -$(if $($(1)),$(call _ge_attempt,$($(1)),$(1)),$(call _ge_attempt,$(2),$(1))) +$(if $($(1)),$(call _ge_attempt,$($(1)),$(1)),$(call _ge_attempt,$(2))) endef _ge_attempt = $(if $(get-executable),$(get-executable),$(_gea_warn)$(call _gea_err,$(2))) _gea_warn = $(warning The path '$(1)' is not executable.) @@ -181,7 +181,7 @@ _gea_err = $(if $(1),$(error Please set '$(1)' appropriately)) # try-cc # Usage: option = $(call try-cc, source-to-build, cc-options, msg) -ifndef V +ifneq ($(V),1) TRY_CC_OUTPUT= > /dev/null 2>&1 endif TRY_CC_MSG=echo " CHK $(3)" 1>&2; diff --git a/tools/perf/scripts/perl/Perf-Trace-Util/Context.xs b/tools/perf/scripts/perl/Perf-Trace-Util/Context.xs index c1e2ed1ed34..8c7ea42444d 100644 --- a/tools/perf/scripts/perl/Perf-Trace-Util/Context.xs +++ b/tools/perf/scripts/perl/Perf-Trace-Util/Context.xs @@ -23,7 +23,7 @@ #include "perl.h" #include "XSUB.h" #include "../../../perf.h" -#include "../../../util/script-event.h" +#include "../../../util/trace-event.h" MODULE = Perf::Trace::Context PACKAGE = Perf::Trace::Context PROTOTYPES: ENABLE diff --git a/tools/perf/util/PERF-VERSION-GEN b/tools/perf/util/PERF-VERSION-GEN index 055fef34b6f..15a77b7c0e3 100755 --- a/tools/perf/util/PERF-VERSION-GEN +++ b/tools/perf/util/PERF-VERSION-GEN @@ -13,13 +13,22 @@ LF=' # First check if there is a .git to get the version from git describe # otherwise try to get the version from the kernel Makefile # -if test -d ../../.git -o -f ../../.git && - VN=$(git tag 2>/dev/null | tail -1 | grep -E "v[0-9].[0-9]*") +CID= +TAG= +if test -d ../../.git -o -f ../../.git then - VN=$(echo $VN"-g"$(git log -1 --abbrev=4 --pretty=format:"%h" HEAD)) - VN=$(echo "$VN" | sed -e 's/-/./g'); -else - VN=$(MAKEFLAGS= make -sC ../.. kernelversion) + TAG=$(git describe --abbrev=0 --match "v[0-9].[0-9]*" 2>/dev/null ) + CID=$(git log -1 --abbrev=4 --pretty=format:"%h" 2>/dev/null) && CID="-g$CID" +fi +if test -z "$TAG" +then + TAG=$(MAKEFLAGS= make -sC ../.. kernelversion) +fi +VN="$TAG$CID" +if test -n "$CID" +then + # format version string, strip trailing zero of sublevel: + VN=$(echo "$VN" | sed -e 's/-/./g;s/\([0-9]*[.][0-9]*\)[.]0/\1/') fi VN=$(expr "$VN" : v*'\(.*\)') diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index 6f7d5a9d6b0..c4374f07603 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c @@ -513,10 +513,16 @@ void dsos__add(struct list_head *head, struct dso *dso) list_add_tail(&dso->node, head); } -struct dso *dsos__find(struct list_head *head, const char *name) +struct dso *dsos__find(struct list_head *head, const char *name, bool cmp_short) { struct dso *pos; + if (cmp_short) { + list_for_each_entry(pos, head, node) + if (strcmp(pos->short_name, name) == 0) + return pos; + return NULL; + } list_for_each_entry(pos, head, node) if (strcmp(pos->long_name, name) == 0) return pos; @@ -525,7 +531,7 @@ struct dso *dsos__find(struct list_head *head, const char *name) struct dso *__dsos__findnew(struct list_head *head, const char *name) { - struct dso *dso = dsos__find(head, name); + struct dso *dso = dsos__find(head, name, false); if (!dso) { dso = dso__new(name); diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h index 450199ab51b..d51aaf272c6 100644 --- a/tools/perf/util/dso.h +++ b/tools/perf/util/dso.h @@ -133,7 +133,8 @@ struct dso *dso__kernel_findnew(struct machine *machine, const char *name, const char *short_name, int dso_type); void dsos__add(struct list_head *head, struct dso *dso); -struct dso *dsos__find(struct list_head *head, const char *name); +struct dso *dsos__find(struct list_head *head, const char *name, + bool cmp_short); struct dso *__dsos__findnew(struct list_head *head, const char *name); bool __dsos__read_build_ids(struct list_head *head, bool with_hits); diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 99b43dd18c5..8065ce8fa9a 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -821,6 +821,7 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist, goto out_close_pipes; } + fcntl(go_pipe[1], F_SETFD, FD_CLOEXEC); evlist->workload.cork_fd = go_pipe[1]; close(child_ready_pipe[0]); return 0; @@ -837,10 +838,17 @@ out_close_ready_pipe: int perf_evlist__start_workload(struct perf_evlist *evlist) { if (evlist->workload.cork_fd > 0) { + char bf; + int ret; /* * Remove the cork, let it rip! */ - return close(evlist->workload.cork_fd); + ret = write(evlist->workload.cork_fd, &bf, 1); + if (ret < 0) + perror("enable to write to pipe"); + + close(evlist->workload.cork_fd); + return ret; } return 0; diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 63b6f8c8edf..c9c7494506a 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -124,7 +124,7 @@ struct event_format *event_format__new(const char *sys, const char *name) bf = nbf; } - n = read(fd, bf + size, BUFSIZ); + n = read(fd, bf + size, alloc_size - size); if (n < 0) goto out_free_bf; size += n; @@ -1170,7 +1170,7 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, } else { data->user_stack.data = (char *)array; array += size / sizeof(*array); - data->user_stack.size = *array; + data->user_stack.size = *array++; } } diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 738d3b8d974..a4dafbee251 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -2303,29 +2303,18 @@ int perf_session__write_header(struct perf_session *session, struct perf_file_header f_header; struct perf_file_attr f_attr; struct perf_header *header = &session->header; - struct perf_evsel *evsel, *pair = NULL; + struct perf_evsel *evsel; int err; lseek(fd, sizeof(f_header), SEEK_SET); - if (session->evlist != evlist) - pair = perf_evlist__first(session->evlist); - list_for_each_entry(evsel, &evlist->entries, node) { evsel->id_offset = lseek(fd, 0, SEEK_CUR); err = do_write(fd, evsel->id, evsel->ids * sizeof(u64)); if (err < 0) { -out_err_write: pr_debug("failed to write perf header\n"); return err; } - if (session->evlist != evlist) { - err = do_write(fd, pair->id, pair->ids * sizeof(u64)); - if (err < 0) - goto out_err_write; - evsel->ids += pair->ids; - pair = perf_evsel__next(pair); - } } header->attr_offset = lseek(fd, 0, SEEK_CUR); @@ -2967,6 +2956,8 @@ int perf_event__process_attr(union perf_event *event, perf_evlist__id_add(evlist, evsel, 0, i, event->attr.id[i]); } + symbol_conf.nr_events = evlist->nr_entries; + return 0; } diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 6c8bb0fb189..995fc25db8c 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -860,7 +860,8 @@ int parse_events_terms(struct list_head *terms, const char *str) return 0; } - parse_events__free_terms(data.terms); + if (data.terms) + parse_events__free_terms(data.terms); return ret; } @@ -1183,6 +1184,7 @@ static int new_term(struct parse_events_term **_term, int type_val, term->val.str = str; break; default: + free(term); return -EINVAL; } diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 8cf3b5426a9..d5528e1cc03 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -32,7 +32,6 @@ int vmlinux_path__nr_entries; char **vmlinux_path; struct symbol_conf symbol_conf = { - .exclude_other = true, .use_modules = true, .try_vmlinux_path = true, .annotate_src = true, diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 7a484c97e50..2732fad0390 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -72,6 +72,7 @@ #include "types.h" #include <sys/ttydefaults.h> #include <lk/debugfs.h> +#include <termios.h> extern const char *graph_line; extern const char *graph_dotted_line; @@ -274,6 +275,5 @@ void dump_stack(void); extern unsigned int page_size; -struct winsize; void get_term_dimensions(struct winsize *ws); #endif /* GIT_COMPAT_UTIL_H */ diff --git a/tools/perf/util/vdso.c b/tools/perf/util/vdso.c index e60951fcdb1..39159822d58 100644 --- a/tools/perf/util/vdso.c +++ b/tools/perf/util/vdso.c @@ -91,7 +91,7 @@ void vdso__exit(void) struct dso *vdso__dso_findnew(struct list_head *head) { - struct dso *dso = dsos__find(head, VDSO__MAP_NAME); + struct dso *dso = dsos__find(head, VDSO__MAP_NAME, true); if (!dso) { char *file; diff --git a/tools/power/cpupower/Makefile b/tools/power/cpupower/Makefile index d875a74a3bd..cbfec92af32 100644 --- a/tools/power/cpupower/Makefile +++ b/tools/power/cpupower/Makefile @@ -128,10 +128,12 @@ UTIL_OBJS = utils/helpers/amd.o utils/helpers/topology.o utils/helpers/msr.o \ utils/helpers/sysfs.o utils/helpers/misc.o utils/helpers/cpuid.o \ utils/helpers/pci.o utils/helpers/bitmask.o \ utils/idle_monitor/nhm_idle.o utils/idle_monitor/snb_idle.o \ + utils/idle_monitor/hsw_ext_idle.o \ utils/idle_monitor/amd_fam14h_idle.o utils/idle_monitor/cpuidle_sysfs.o \ utils/idle_monitor/mperf_monitor.o utils/idle_monitor/cpupower-monitor.o \ utils/cpupower.o utils/cpufreq-info.o utils/cpufreq-set.o \ - utils/cpupower-set.o utils/cpupower-info.o utils/cpuidle-info.o + utils/cpupower-set.o utils/cpupower-info.o utils/cpuidle-info.o \ + utils/cpuidle-set.o UTIL_SRC := $(UTIL_OBJS:.o=.c) diff --git a/tools/power/cpupower/man/cpupower-monitor.1 b/tools/power/cpupower/man/cpupower-monitor.1 index e01c35d13b6..914cbb9d9cd 100644 --- a/tools/power/cpupower/man/cpupower-monitor.1 +++ b/tools/power/cpupower/man/cpupower-monitor.1 @@ -110,13 +110,21 @@ May work poorly on Linux-2.6.20 through 2.6.29, as the \fBacpi-cpufreq \fP kernel frequency driver periodically cleared aperf/mperf registers in those kernels. -.SS "Nehalem" "SandyBridge" +.SS "Nehalem" "SandyBridge" "HaswellExtended" Intel Core and Package sleep state counters. Threads (hyperthreaded cores) may not be able to enter deeper core states if its sibling is utilized. Deepest package sleep states may in reality show up as machine/platform wide sleep states and can only be entered if all cores are idle. Look up Intel manuals (some are provided in the References section) for further details. +The monitors are named after the CPU family where the sleep state capabilities +got introduced and may not match exactly the CPU name of the platform. +For example an IvyBridge processor has sleep state capabilities which got +introduced in Nehalem and SandyBridge processor families. +Thus on an IvyBridge processor one will get Nehalem and SandyBridge sleep +state monitors. +HaswellExtended extra package sleep state capabilities are available only in a +specific Haswell (family 0x45) and probably also other future processors. .SS "Fam_12h" "Fam_14h" AMD laptop and desktop processor (family 12h and 14h) sleep state counters. diff --git a/tools/power/cpupower/utils/builtin.h b/tools/power/cpupower/utils/builtin.h index c10496fbe3c..2284c8ea4e2 100644 --- a/tools/power/cpupower/utils/builtin.h +++ b/tools/power/cpupower/utils/builtin.h @@ -5,6 +5,7 @@ extern int cmd_set(int argc, const char **argv); extern int cmd_info(int argc, const char **argv); extern int cmd_freq_set(int argc, const char **argv); extern int cmd_freq_info(int argc, const char **argv); +extern int cmd_idle_set(int argc, const char **argv); extern int cmd_idle_info(int argc, const char **argv); extern int cmd_monitor(int argc, const char **argv); diff --git a/tools/power/cpupower/utils/cpuidle-info.c b/tools/power/cpupower/utils/cpuidle-info.c index 8145af5f93a..75e66de7e7a 100644 --- a/tools/power/cpupower/utils/cpuidle-info.c +++ b/tools/power/cpupower/utils/cpuidle-info.c @@ -22,7 +22,7 @@ static void cpuidle_cpu_output(unsigned int cpu, int verbose) { - int idlestates, idlestate; + unsigned int idlestates, idlestate; char *tmp; printf(_ ("Analyzing CPU %d:\n"), cpu); @@ -31,10 +31,8 @@ static void cpuidle_cpu_output(unsigned int cpu, int verbose) if (idlestates == 0) { printf(_("CPU %u: No idle states\n"), cpu); return; - } else if (idlestates <= 0) { - printf(_("CPU %u: Can't read idle state info\n"), cpu); - return; } + printf(_("Number of idle states: %d\n"), idlestates); printf(_("Available idle states:")); for (idlestate = 0; idlestate < idlestates; idlestate++) { @@ -50,10 +48,14 @@ static void cpuidle_cpu_output(unsigned int cpu, int verbose) return; for (idlestate = 0; idlestate < idlestates; idlestate++) { + int disabled = sysfs_is_idlestate_disabled(cpu, idlestate); + /* Disabled interface not supported on older kernels */ + if (disabled < 0) + disabled = 0; tmp = sysfs_get_idlestate_name(cpu, idlestate); if (!tmp) continue; - printf("%s:\n", tmp); + printf("%s%s:\n", tmp, (disabled) ? " (DISABLED) " : ""); free(tmp); tmp = sysfs_get_idlestate_desc(cpu, idlestate); @@ -98,21 +100,13 @@ static void cpuidle_general_output(void) static void proc_cpuidle_cpu_output(unsigned int cpu) { long max_allowed_cstate = 2000000000; - int cstates, cstate; + unsigned int cstate, cstates; cstates = sysfs_get_idlestate_count(cpu); if (cstates == 0) { - /* - * Go on and print same useless info as you'd see with - * cat /proc/acpi/processor/../power - * printf(_("CPU %u: No C-states available\n"), cpu); - * return; - */ - } else if (cstates <= 0) { - printf(_("CPU %u: Can't read C-state info\n"), cpu); + printf(_("CPU %u: No C-states info\n"), cpu); return; } - /* printf("Cstates: %d\n", cstates); */ printf(_("active state: C0\n")); printf(_("max_cstate: C%u\n"), cstates-1); diff --git a/tools/power/cpupower/utils/cpuidle-set.c b/tools/power/cpupower/utils/cpuidle-set.c new file mode 100644 index 00000000000..c78141c5dfa --- /dev/null +++ b/tools/power/cpupower/utils/cpuidle-set.c @@ -0,0 +1,118 @@ +#include <unistd.h> +#include <stdio.h> +#include <errno.h> +#include <stdlib.h> +#include <limits.h> +#include <string.h> +#include <ctype.h> + +#include <getopt.h> + +#include "cpufreq.h" +#include "helpers/helpers.h" +#include "helpers/sysfs.h" + +static struct option info_opts[] = { + { .name = "disable", .has_arg = required_argument, .flag = NULL, .val = 'd'}, + { .name = "enable", .has_arg = required_argument, .flag = NULL, .val = 'e'}, + { }, +}; + + +int cmd_idle_set(int argc, char **argv) +{ + extern char *optarg; + extern int optind, opterr, optopt; + int ret = 0, cont = 1, param = 0, idlestate = 0; + unsigned int cpu = 0; + + do { + ret = getopt_long(argc, argv, "d:e:", info_opts, NULL); + if (ret == -1) + break; + switch (ret) { + case '?': + param = '?'; + cont = 0; + break; + case 'd': + if (param) { + param = -1; + cont = 0; + break; + } + param = ret; + idlestate = atoi(optarg); + break; + case 'e': + if (param) { + param = -1; + cont = 0; + break; + } + param = ret; + idlestate = atoi(optarg); + break; + case -1: + cont = 0; + break; + } + } while (cont); + + switch (param) { + case -1: + printf(_("You can't specify more than one " + "output-specific argument\n")); + exit(EXIT_FAILURE); + case '?': + printf(_("invalid or unknown argument\n")); + exit(EXIT_FAILURE); + } + + /* Default is: set all CPUs */ + if (bitmask_isallclear(cpus_chosen)) + bitmask_setall(cpus_chosen); + + for (cpu = bitmask_first(cpus_chosen); + cpu <= bitmask_last(cpus_chosen); cpu++) { + + if (!bitmask_isbitset(cpus_chosen, cpu)) + continue; + + switch (param) { + + case 'd': + ret = sysfs_idlestate_disable(cpu, idlestate, 1); + if (ret == 0) + printf(_("Idlestate %u disabled on CPU %u\n"), idlestate, cpu); + else if (ret == -1) + printf(_("Idlestate %u not available on CPU %u\n"), + idlestate, cpu); + else if (ret == -2) + printf(_("Idlestate disabling not supported by kernel\n")); + else + printf(_("Idlestate %u not disabled on CPU %u\n"), + idlestate, cpu); + break; + case 'e': + ret = sysfs_idlestate_disable(cpu, idlestate, 0); + if (ret == 0) + printf(_("Idlestate %u enabled on CPU %u\n"), idlestate, cpu); + else if (ret == -1) + printf(_("Idlestate %u not available on CPU %u\n"), + idlestate, cpu); + else if (ret == -2) + printf(_("Idlestate enabling not supported by kernel\n")); + else + printf(_("Idlestate %u not enabled on CPU %u\n"), + idlestate, cpu); + break; + default: + /* Not reachable with proper args checking */ + printf(_("Invalid or unknown argument\n")); + exit(EXIT_FAILURE); + break; + } + } + return EXIT_SUCCESS; +} diff --git a/tools/power/cpupower/utils/cpupower.c b/tools/power/cpupower/utils/cpupower.c index 52bee591c1c..7efc570ffba 100644 --- a/tools/power/cpupower/utils/cpupower.c +++ b/tools/power/cpupower/utils/cpupower.c @@ -17,12 +17,6 @@ #include "helpers/helpers.h" #include "helpers/bitmask.h" -struct cmd_struct { - const char *cmd; - int (*main)(int, const char **); - int needs_root; -}; - #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) static int cmd_help(int argc, const char **argv); @@ -43,10 +37,17 @@ int be_verbose; static void print_help(void); +struct cmd_struct { + const char *cmd; + int (*main)(int, const char **); + int needs_root; +}; + static struct cmd_struct commands[] = { { "frequency-info", cmd_freq_info, 0 }, { "frequency-set", cmd_freq_set, 1 }, { "idle-info", cmd_idle_info, 0 }, + { "idle-set", cmd_idle_set, 1 }, { "set", cmd_set, 1 }, { "info", cmd_info, 0 }, { "monitor", cmd_monitor, 0 }, diff --git a/tools/power/cpupower/utils/helpers/sysfs.c b/tools/power/cpupower/utils/helpers/sysfs.c index 38ab9162946..5cdc600e815 100644 --- a/tools/power/cpupower/utils/helpers/sysfs.c +++ b/tools/power/cpupower/utils/helpers/sysfs.c @@ -89,6 +89,33 @@ int sysfs_is_cpu_online(unsigned int cpu) /* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */ + +/* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */ + +/* + * helper function to check whether a file under "../cpuX/cpuidle/stateX/" dir + * exists. + * For example the functionality to disable c-states was introduced in later + * kernel versions, this function can be used to explicitly check for this + * feature. + * + * returns 1 if the file exists, 0 otherwise. + */ +unsigned int sysfs_idlestate_file_exists(unsigned int cpu, + unsigned int idlestate, + const char *fname) +{ + char path[SYSFS_PATH_MAX]; + struct stat statbuf; + + + snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s", + cpu, idlestate, fname); + if (stat(path, &statbuf) != 0) + return 0; + return 1; +} + /* * helper function to read file from /sys into given buffer * fname is a relative path under "cpuX/cpuidle/stateX/" dir @@ -121,6 +148,40 @@ unsigned int sysfs_idlestate_read_file(unsigned int cpu, unsigned int idlestate, return (unsigned int) numread; } +/* + * helper function to write a new value to a /sys file + * fname is a relative path under "../cpuX/cpuidle/cstateY/" dir + * + * Returns the number of bytes written or 0 on error + */ +static +unsigned int sysfs_idlestate_write_file(unsigned int cpu, + unsigned int idlestate, + const char *fname, + const char *value, size_t len) +{ + char path[SYSFS_PATH_MAX]; + int fd; + ssize_t numwrite; + + snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s", + cpu, idlestate, fname); + + fd = open(path, O_WRONLY); + if (fd == -1) + return 0; + + numwrite = write(fd, value, len); + if (numwrite < 1) { + close(fd); + return 0; + } + + close(fd); + + return (unsigned int) numwrite; +} + /* read access to files which contain one numeric value */ enum idlestate_value { @@ -128,6 +189,7 @@ enum idlestate_value { IDLESTATE_POWER, IDLESTATE_LATENCY, IDLESTATE_TIME, + IDLESTATE_DISABLE, MAX_IDLESTATE_VALUE_FILES }; @@ -136,6 +198,7 @@ static const char *idlestate_value_files[MAX_IDLESTATE_VALUE_FILES] = { [IDLESTATE_POWER] = "power", [IDLESTATE_LATENCY] = "latency", [IDLESTATE_TIME] = "time", + [IDLESTATE_DISABLE] = "disable", }; static unsigned long long sysfs_idlestate_get_one_value(unsigned int cpu, @@ -205,8 +268,59 @@ static char *sysfs_idlestate_get_one_string(unsigned int cpu, return result; } +/* + * Returns: + * 1 if disabled + * 0 if enabled + * -1 if idlestate is not available + * -2 if disabling is not supported by the kernel + */ +int sysfs_is_idlestate_disabled(unsigned int cpu, + unsigned int idlestate) +{ + if (sysfs_get_idlestate_count(cpu) < idlestate) + return -1; + + if (!sysfs_idlestate_file_exists(cpu, idlestate, + idlestate_value_files[IDLESTATE_DISABLE])) + return -2; + return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_DISABLE); +} + +/* + * Pass 1 as last argument to disable or 0 to enable the state + * Returns: + * 0 on success + * negative values on error, for example: + * -1 if idlestate is not available + * -2 if disabling is not supported by the kernel + * -3 No write access to disable/enable C-states + */ +int sysfs_idlestate_disable(unsigned int cpu, + unsigned int idlestate, + unsigned int disable) +{ + char value[SYSFS_PATH_MAX]; + int bytes_written; + + if (sysfs_get_idlestate_count(cpu) < idlestate) + return -1; + + if (!sysfs_idlestate_file_exists(cpu, idlestate, + idlestate_value_files[IDLESTATE_DISABLE])) + return -2; + + snprintf(value, SYSFS_PATH_MAX, "%u", disable); + + bytes_written = sysfs_idlestate_write_file(cpu, idlestate, "disable", + value, sizeof(disable)); + if (bytes_written) + return 0; + return -3; +} + unsigned long sysfs_get_idlestate_latency(unsigned int cpu, - unsigned int idlestate) + unsigned int idlestate) { return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_LATENCY); } @@ -238,7 +352,7 @@ char *sysfs_get_idlestate_desc(unsigned int cpu, unsigned int idlestate) * Negativ in error case * Zero if cpuidle does not export any C-states */ -int sysfs_get_idlestate_count(unsigned int cpu) +unsigned int sysfs_get_idlestate_count(unsigned int cpu) { char file[SYSFS_PATH_MAX]; struct stat statbuf; diff --git a/tools/power/cpupower/utils/helpers/sysfs.h b/tools/power/cpupower/utils/helpers/sysfs.h index 8cb797bbceb..d28f11fedbd 100644 --- a/tools/power/cpupower/utils/helpers/sysfs.h +++ b/tools/power/cpupower/utils/helpers/sysfs.h @@ -7,8 +7,16 @@ extern unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen); +extern unsigned int sysfs_idlestate_file_exists(unsigned int cpu, + unsigned int idlestate, + const char *fname); + extern int sysfs_is_cpu_online(unsigned int cpu); +extern int sysfs_is_idlestate_disabled(unsigned int cpu, + unsigned int idlestate); +extern int sysfs_idlestate_disable(unsigned int cpu, unsigned int idlestate, + unsigned int disable); extern unsigned long sysfs_get_idlestate_latency(unsigned int cpu, unsigned int idlestate); extern unsigned long sysfs_get_idlestate_usage(unsigned int cpu, @@ -19,7 +27,7 @@ extern char *sysfs_get_idlestate_name(unsigned int cpu, unsigned int idlestate); extern char *sysfs_get_idlestate_desc(unsigned int cpu, unsigned int idlestate); -extern int sysfs_get_idlestate_count(unsigned int cpu); +extern unsigned int sysfs_get_idlestate_count(unsigned int cpu); extern char *sysfs_get_cpuidle_governor(void); extern char *sysfs_get_cpuidle_driver(void); diff --git a/tools/power/cpupower/utils/idle_monitor/hsw_ext_idle.c b/tools/power/cpupower/utils/idle_monitor/hsw_ext_idle.c new file mode 100644 index 00000000000..ebeaba6571a --- /dev/null +++ b/tools/power/cpupower/utils/idle_monitor/hsw_ext_idle.c @@ -0,0 +1,196 @@ +/* + * (C) 2010,2011 Thomas Renninger <trenn@suse.de>, Novell Inc. + * + * Licensed under the terms of the GNU GPL License version 2. + * + * Based on SandyBridge monitor. Implements the new package C-states + * (PC8, PC9, PC10) coming with a specific Haswell (family 0x45) CPU. + */ + +#if defined(__i386__) || defined(__x86_64__) + +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +#include "helpers/helpers.h" +#include "idle_monitor/cpupower-monitor.h" + +#define MSR_PKG_C8_RESIDENCY 0x00000630 +#define MSR_PKG_C9_RESIDENCY 0x00000631 +#define MSR_PKG_C10_RESIDENCY 0x00000632 + +#define MSR_TSC 0x10 + +enum intel_hsw_ext_id { PC8 = 0, PC9, PC10, HSW_EXT_CSTATE_COUNT, + TSC = 0xFFFF }; + +static int hsw_ext_get_count_percent(unsigned int self_id, double *percent, + unsigned int cpu); + +static cstate_t hsw_ext_cstates[HSW_EXT_CSTATE_COUNT] = { + { + .name = "PC8", + .desc = N_("Processor Package C8"), + .id = PC8, + .range = RANGE_PACKAGE, + .get_count_percent = hsw_ext_get_count_percent, + }, + { + .name = "PC9", + .desc = N_("Processor Package C9"), + .desc = N_("Processor Package C2"), + .id = PC9, + .range = RANGE_PACKAGE, + .get_count_percent = hsw_ext_get_count_percent, + }, + { + .name = "PC10", + .desc = N_("Processor Package C10"), + .id = PC10, + .range = RANGE_PACKAGE, + .get_count_percent = hsw_ext_get_count_percent, + }, +}; + +static unsigned long long tsc_at_measure_start; +static unsigned long long tsc_at_measure_end; +static unsigned long long *previous_count[HSW_EXT_CSTATE_COUNT]; +static unsigned long long *current_count[HSW_EXT_CSTATE_COUNT]; +/* valid flag for all CPUs. If a MSR read failed it will be zero */ +static int *is_valid; + +static int hsw_ext_get_count(enum intel_hsw_ext_id id, unsigned long long *val, + unsigned int cpu) +{ + int msr; + + switch (id) { + case PC8: + msr = MSR_PKG_C8_RESIDENCY; + break; + case PC9: + msr = MSR_PKG_C9_RESIDENCY; + break; + case PC10: + msr = MSR_PKG_C10_RESIDENCY; + break; + case TSC: + msr = MSR_TSC; + break; + default: + return -1; + }; + if (read_msr(cpu, msr, val)) + return -1; + return 0; +} + +static int hsw_ext_get_count_percent(unsigned int id, double *percent, + unsigned int cpu) +{ + *percent = 0.0; + + if (!is_valid[cpu]) + return -1; + + *percent = (100.0 * + (current_count[id][cpu] - previous_count[id][cpu])) / + (tsc_at_measure_end - tsc_at_measure_start); + + dprint("%s: previous: %llu - current: %llu - (%u)\n", + hsw_ext_cstates[id].name, previous_count[id][cpu], + current_count[id][cpu], cpu); + + dprint("%s: tsc_diff: %llu - count_diff: %llu - percent: %2.f (%u)\n", + hsw_ext_cstates[id].name, + (unsigned long long) tsc_at_measure_end - tsc_at_measure_start, + current_count[id][cpu] - previous_count[id][cpu], + *percent, cpu); + + return 0; +} + +static int hsw_ext_start(void) +{ + int num, cpu; + unsigned long long val; + + for (num = 0; num < HSW_EXT_CSTATE_COUNT; num++) { + for (cpu = 0; cpu < cpu_count; cpu++) { + hsw_ext_get_count(num, &val, cpu); + previous_count[num][cpu] = val; + } + } + hsw_ext_get_count(TSC, &tsc_at_measure_start, 0); + return 0; +} + +static int hsw_ext_stop(void) +{ + unsigned long long val; + int num, cpu; + + hsw_ext_get_count(TSC, &tsc_at_measure_end, 0); + + for (num = 0; num < HSW_EXT_CSTATE_COUNT; num++) { + for (cpu = 0; cpu < cpu_count; cpu++) { + is_valid[cpu] = !hsw_ext_get_count(num, &val, cpu); + current_count[num][cpu] = val; + } + } + return 0; +} + +struct cpuidle_monitor intel_hsw_ext_monitor; + +static struct cpuidle_monitor *hsw_ext_register(void) +{ + int num; + + if (cpupower_cpu_info.vendor != X86_VENDOR_INTEL + || cpupower_cpu_info.family != 6) + return NULL; + + switch (cpupower_cpu_info.model) { + case 0x45: /* HSW */ + break; + default: + return NULL; + } + + is_valid = calloc(cpu_count, sizeof(int)); + for (num = 0; num < HSW_EXT_CSTATE_COUNT; num++) { + previous_count[num] = calloc(cpu_count, + sizeof(unsigned long long)); + current_count[num] = calloc(cpu_count, + sizeof(unsigned long long)); + } + intel_hsw_ext_monitor.name_len = strlen(intel_hsw_ext_monitor.name); + return &intel_hsw_ext_monitor; +} + +void hsw_ext_unregister(void) +{ + int num; + free(is_valid); + for (num = 0; num < HSW_EXT_CSTATE_COUNT; num++) { + free(previous_count[num]); + free(current_count[num]); + } +} + +struct cpuidle_monitor intel_hsw_ext_monitor = { + .name = "HaswellExtended", + .hw_states = hsw_ext_cstates, + .hw_states_num = HSW_EXT_CSTATE_COUNT, + .start = hsw_ext_start, + .stop = hsw_ext_stop, + .do_register = hsw_ext_register, + .unregister = hsw_ext_unregister, + .needs_root = 1, + .overflow_s = 922000000 /* 922337203 seconds TSC overflow + at 20GHz */ +}; +#endif /* defined(__i386__) || defined(__x86_64__) */ diff --git a/tools/power/cpupower/utils/idle_monitor/idle_monitors.def b/tools/power/cpupower/utils/idle_monitor/idle_monitors.def index e3f8d9b2b18..0d6ba4dbb9c 100644 --- a/tools/power/cpupower/utils/idle_monitor/idle_monitors.def +++ b/tools/power/cpupower/utils/idle_monitor/idle_monitors.def @@ -2,6 +2,7 @@ DEF(amd_fam14h) DEF(intel_nhm) DEF(intel_snb) +DEF(intel_hsw_ext) DEF(mperf) #endif DEF(cpuidle_sysfs) diff --git a/tools/power/cpupower/utils/idle_monitor/snb_idle.c b/tools/power/cpupower/utils/idle_monitor/snb_idle.c index a99b43b97d6..efc8a69c9ab 100644 --- a/tools/power/cpupower/utils/idle_monitor/snb_idle.c +++ b/tools/power/cpupower/utils/idle_monitor/snb_idle.c @@ -155,6 +155,10 @@ static struct cpuidle_monitor *snb_register(void) case 0x2D: /* SNB Xeon */ case 0x3A: /* IVB */ case 0x3E: /* IVB Xeon */ + case 0x3C: /* HSW */ + case 0x3F: /* HSW */ + case 0x45: /* HSW */ + case 0x46: /* HSW */ break; default: return NULL; diff --git a/tools/scripts/Makefile.include b/tools/scripts/Makefile.include index f03e681f889..0d0506d55c7 100644 --- a/tools/scripts/Makefile.include +++ b/tools/scripts/Makefile.include @@ -59,7 +59,7 @@ QUIET_SUBDIR0 = +$(MAKE) $(COMMAND_O) -C # space to separate -C and subdir QUIET_SUBDIR1 = ifneq ($(findstring $(MAKEFLAGS),s),s) -ifndef V +ifneq ($(V),1) QUIET_CC = @echo ' ' CC $@; QUIET_AR = @echo ' ' AR $@; QUIET_LINK = @echo ' ' LINK $@; diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl index 0d7fd8b5154..999eab1bc64 100755 --- a/tools/testing/ktest/ktest.pl +++ b/tools/testing/ktest/ktest.pl @@ -1796,7 +1796,7 @@ sub monitor { # We already booted into the kernel we are testing, # but now we booted into another kernel? # Consider this a triple fault. - doprint "Aleady booted in Linux kernel $version, but now\n"; + doprint "Already booted in Linux kernel $version, but now\n"; doprint "we booted into Linux kernel $1.\n"; doprint "Assuming that this is a triple fault.\n"; doprint "To disable this: set DETECT_TRIPLE_FAULT to 0\n"; diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index 0a63658065f..4cb14cae379 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile @@ -6,6 +6,7 @@ TARGETS += memory-hotplug TARGETS += mqueue TARGETS += net TARGETS += ptrace +TARGETS += timers TARGETS += vm all: diff --git a/tools/testing/selftests/net/psock_tpacket.c b/tools/testing/selftests/net/psock_tpacket.c index c41b58640a0..24adf709bd9 100644 --- a/tools/testing/selftests/net/psock_tpacket.c +++ b/tools/testing/selftests/net/psock_tpacket.c @@ -1,6 +1,7 @@ /* * Copyright 2013 Red Hat, Inc. * Author: Daniel Borkmann <dborkman@redhat.com> + * Chetan Loke <loke.chetan@gmail.com> (TPACKET_V3 usage example) * * A basic test of packet socket's TPACKET_V1/TPACKET_V2/TPACKET_V3 behavior. * @@ -71,18 +72,8 @@ # define __align_tpacket(x) __attribute__((aligned(TPACKET_ALIGN(x)))) #endif -#define BLOCK_STATUS(x) ((x)->h1.block_status) -#define BLOCK_NUM_PKTS(x) ((x)->h1.num_pkts) -#define BLOCK_O2FP(x) ((x)->h1.offset_to_first_pkt) -#define BLOCK_LEN(x) ((x)->h1.blk_len) -#define BLOCK_SNUM(x) ((x)->h1.seq_num) -#define BLOCK_O2PRIV(x) ((x)->offset_to_priv) -#define BLOCK_PRIV(x) ((void *) ((uint8_t *) (x) + BLOCK_O2PRIV(x))) -#define BLOCK_HDR_LEN (ALIGN_8(sizeof(struct block_desc))) -#define ALIGN_8(x) (((x) + 8 - 1) & ~(8 - 1)) -#define BLOCK_PLUS_PRIV(sz_pri) (BLOCK_HDR_LEN + ALIGN_8((sz_pri))) - #define NUM_PACKETS 100 +#define ALIGN_8(x) (((x) + 8 - 1) & ~(8 - 1)) struct ring { struct iovec *rd; @@ -476,41 +467,30 @@ static uint64_t __v3_prev_block_seq_num = 0; void __v3_test_block_seq_num(struct block_desc *pbd) { - if (__v3_prev_block_seq_num + 1 != BLOCK_SNUM(pbd)) { + if (__v3_prev_block_seq_num + 1 != pbd->h1.seq_num) { fprintf(stderr, "\nprev_block_seq_num:%"PRIu64", expected " "seq:%"PRIu64" != actual seq:%"PRIu64"\n", __v3_prev_block_seq_num, __v3_prev_block_seq_num + 1, - (uint64_t) BLOCK_SNUM(pbd)); + (uint64_t) pbd->h1.seq_num); exit(1); } - __v3_prev_block_seq_num = BLOCK_SNUM(pbd); + __v3_prev_block_seq_num = pbd->h1.seq_num; } static void __v3_test_block_len(struct block_desc *pbd, uint32_t bytes, int block_num) { - if (BLOCK_NUM_PKTS(pbd)) { - if (bytes != BLOCK_LEN(pbd)) { - fprintf(stderr, "\nblock:%u with %upackets, expected " - "len:%u != actual len:%u\n", block_num, - BLOCK_NUM_PKTS(pbd), bytes, BLOCK_LEN(pbd)); - exit(1); - } - } else { - if (BLOCK_LEN(pbd) != BLOCK_PLUS_PRIV(13)) { - fprintf(stderr, "\nblock:%u, expected len:%lu != " - "actual len:%u\n", block_num, BLOCK_HDR_LEN, - BLOCK_LEN(pbd)); - exit(1); - } + if (pbd->h1.num_pkts && bytes != pbd->h1.blk_len) { + fprintf(stderr, "\nblock:%u with %upackets, expected " + "len:%u != actual len:%u\n", block_num, + pbd->h1.num_pkts, bytes, pbd->h1.blk_len); + exit(1); } } static void __v3_test_block_header(struct block_desc *pbd, const int block_num) { - uint32_t block_status = BLOCK_STATUS(pbd); - - if ((block_status & TP_STATUS_USER) == 0) { + if ((pbd->h1.block_status & TP_STATUS_USER) == 0) { fprintf(stderr, "\nblock %u: not in TP_STATUS_USER\n", block_num); exit(1); } @@ -520,14 +500,15 @@ static void __v3_test_block_header(struct block_desc *pbd, const int block_num) static void __v3_walk_block(struct block_desc *pbd, const int block_num) { - int num_pkts = BLOCK_NUM_PKTS(pbd), i; - unsigned long bytes = 0; - unsigned long bytes_with_padding = BLOCK_PLUS_PRIV(13); + int num_pkts = pbd->h1.num_pkts, i; + unsigned long bytes = 0, bytes_with_padding = ALIGN_8(sizeof(*pbd)); struct tpacket3_hdr *ppd; __v3_test_block_header(pbd, block_num); - ppd = (struct tpacket3_hdr *) ((uint8_t *) pbd + BLOCK_O2FP(pbd)); + ppd = (struct tpacket3_hdr *) ((uint8_t *) pbd + + pbd->h1.offset_to_first_pkt); + for (i = 0; i < num_pkts; ++i) { bytes += ppd->tp_snaplen; @@ -551,7 +532,7 @@ static void __v3_walk_block(struct block_desc *pbd, const int block_num) void __v3_flush_block(struct block_desc *pbd) { - BLOCK_STATUS(pbd) = TP_STATUS_KERNEL; + pbd->h1.block_status = TP_STATUS_KERNEL; __sync_synchronize(); } @@ -577,7 +558,7 @@ static void walk_v3_rx(int sock, struct ring *ring) while (total_packets < NUM_PACKETS * 2) { pbd = (struct block_desc *) ring->rd[block_num].iov_base; - while ((BLOCK_STATUS(pbd) & TP_STATUS_USER) == 0) + while ((pbd->h1.block_status & TP_STATUS_USER) == 0) poll(&pfd, 1, 1); __v3_walk_block(pbd, block_num); @@ -624,8 +605,8 @@ static void __v1_v2_fill(struct ring *ring, unsigned int blocks) static void __v3_fill(struct ring *ring, unsigned int blocks) { ring->req3.tp_retire_blk_tov = 64; - ring->req3.tp_sizeof_priv = 13; - ring->req3.tp_feature_req_word |= TP_FT_REQ_FILL_RXHASH; + ring->req3.tp_sizeof_priv = 0; + ring->req3.tp_feature_req_word = TP_FT_REQ_FILL_RXHASH; ring->req3.tp_block_size = getpagesize() << 2; ring->req3.tp_frame_size = TPACKET_ALIGNMENT << 7; diff --git a/tools/testing/selftests/timers/Makefile b/tools/testing/selftests/timers/Makefile new file mode 100644 index 00000000000..eb2859f4ad2 --- /dev/null +++ b/tools/testing/selftests/timers/Makefile @@ -0,0 +1,8 @@ +all: + gcc posix_timers.c -o posix_timers -lrt + +run_tests: all + ./posix_timers + +clean: + rm -f ./posix_timers diff --git a/tools/testing/selftests/timers/posix_timers.c b/tools/testing/selftests/timers/posix_timers.c new file mode 100644 index 00000000000..4fa655d68a8 --- /dev/null +++ b/tools/testing/selftests/timers/posix_timers.c @@ -0,0 +1,221 @@ +/* + * Copyright (C) 2013 Red Hat, Inc., Frederic Weisbecker <fweisbec@redhat.com> + * + * Licensed under the terms of the GNU GPL License version 2 + * + * Selftests for a few posix timers interface. + * + * Kernel loop code stolen from Steven Rostedt <srostedt@redhat.com> + */ + +#include <sys/time.h> +#include <stdio.h> +#include <signal.h> +#include <unistd.h> +#include <time.h> +#include <pthread.h> + +#define DELAY 2 +#define USECS_PER_SEC 1000000 + +static volatile int done; + +/* Busy loop in userspace to elapse ITIMER_VIRTUAL */ +static void user_loop(void) +{ + while (!done); +} + +/* + * Try to spend as much time as possible in kernelspace + * to elapse ITIMER_PROF. + */ +static void kernel_loop(void) +{ + void *addr = sbrk(0); + + while (!done) { + brk(addr + 4096); + brk(addr); + } +} + +/* + * Sleep until ITIMER_REAL expiration. + */ +static void idle_loop(void) +{ + pause(); +} + +static void sig_handler(int nr) +{ + done = 1; +} + +/* + * Check the expected timer expiration matches the GTOD elapsed delta since + * we armed the timer. Keep a 0.5 sec error margin due to various jitter. + */ +static int check_diff(struct timeval start, struct timeval end) +{ + long long diff; + + diff = end.tv_usec - start.tv_usec; + diff += (end.tv_sec - start.tv_sec) * USECS_PER_SEC; + + if (abs(diff - DELAY * USECS_PER_SEC) > USECS_PER_SEC / 2) { + printf("Diff too high: %lld..", diff); + return -1; + } + + return 0; +} + +static int check_itimer(int which) +{ + int err; + struct timeval start, end; + struct itimerval val = { + .it_value.tv_sec = DELAY, + }; + + printf("Check itimer "); + + if (which == ITIMER_VIRTUAL) + printf("virtual... "); + else if (which == ITIMER_PROF) + printf("prof... "); + else if (which == ITIMER_REAL) + printf("real... "); + + fflush(stdout); + + done = 0; + + if (which == ITIMER_VIRTUAL) + signal(SIGVTALRM, sig_handler); + else if (which == ITIMER_PROF) + signal(SIGPROF, sig_handler); + else if (which == ITIMER_REAL) + signal(SIGALRM, sig_handler); + + err = gettimeofday(&start, NULL); + if (err < 0) { + perror("Can't call gettimeofday()\n"); + return -1; + } + + err = setitimer(which, &val, NULL); + if (err < 0) { + perror("Can't set timer\n"); + return -1; + } + + if (which == ITIMER_VIRTUAL) + user_loop(); + else if (which == ITIMER_PROF) + kernel_loop(); + else if (which == ITIMER_REAL) + idle_loop(); + + gettimeofday(&end, NULL); + if (err < 0) { + perror("Can't call gettimeofday()\n"); + return -1; + } + + if (!check_diff(start, end)) + printf("[OK]\n"); + else + printf("[FAIL]\n"); + + return 0; +} + +static int check_timer_create(int which) +{ + int err; + timer_t id; + struct timeval start, end; + struct itimerspec val = { + .it_value.tv_sec = DELAY, + }; + + printf("Check timer_create() "); + if (which == CLOCK_THREAD_CPUTIME_ID) { + printf("per thread... "); + } else if (which == CLOCK_PROCESS_CPUTIME_ID) { + printf("per process... "); + } + fflush(stdout); + + done = 0; + timer_create(which, NULL, &id); + if (err < 0) { + perror("Can't create timer\n"); + return -1; + } + signal(SIGALRM, sig_handler); + + err = gettimeofday(&start, NULL); + if (err < 0) { + perror("Can't call gettimeofday()\n"); + return -1; + } + + err = timer_settime(id, 0, &val, NULL); + if (err < 0) { + perror("Can't set timer\n"); + return -1; + } + + user_loop(); + + gettimeofday(&end, NULL); + if (err < 0) { + perror("Can't call gettimeofday()\n"); + return -1; + } + + if (!check_diff(start, end)) + printf("[OK]\n"); + else + printf("[FAIL]\n"); + + return 0; +} + +int main(int argc, char **argv) +{ + int err; + + printf("Testing posix timers. False negative may happen on CPU execution \n"); + printf("based timers if other threads run on the CPU...\n"); + + if (check_itimer(ITIMER_VIRTUAL) < 0) + return -1; + + if (check_itimer(ITIMER_PROF) < 0) + return -1; + + if (check_itimer(ITIMER_REAL) < 0) + return -1; + + if (check_timer_create(CLOCK_THREAD_CPUTIME_ID) < 0) + return -1; + + /* + * It's unfortunately hard to reliably test a timer expiration + * on parallel multithread cputime. We could arm it to expire + * on DELAY * nr_threads, with nr_threads busy looping, then wait + * the normal DELAY since the time is elapsing nr_threads faster. + * But for that we need to ensure we have real physical free CPUs + * to ensure true parallelism. So test only one thread until we + * find a better solution. + */ + if (check_timer_create(CLOCK_PROCESS_CPUTIME_ID) < 0) + return -1; + + return 0; +} diff --git a/tools/virtio/linux/module.h b/tools/virtio/linux/module.h index 3039a7e972b..28ce95a0599 100644 --- a/tools/virtio/linux/module.h +++ b/tools/virtio/linux/module.h @@ -1 +1,6 @@ #include <linux/export.h> + +#define MODULE_LICENSE(__MODULE_LICENSE_value) \ + static __attribute__((unused)) const char *__MODULE_LICENSE_name = \ + __MODULE_LICENSE_value + diff --git a/tools/virtio/linux/virtio.h b/tools/virtio/linux/virtio.h index cd801838156..84478304070 100644 --- a/tools/virtio/linux/virtio.h +++ b/tools/virtio/linux/virtio.h @@ -45,9 +45,6 @@ struct virtqueue { void *priv; }; -#define MODULE_LICENSE(__MODULE_LICENSE_value) \ - const char *__MODULE_LICENSE_name = __MODULE_LICENSE_value - /* Interfaces exported by virtio_ring. */ int virtqueue_add_sgs(struct virtqueue *vq, struct scatterlist *sgs[], |