diff options
Diffstat (limited to 'tools')
37 files changed, 525 insertions, 348 deletions
diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 3b8f7b80376..e9d5c271db6 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -30,6 +30,8 @@ endif  # Define EXTRA_CFLAGS=-m64 or EXTRA_CFLAGS=-m32 as appropriate for cross-builds.  #  # Define NO_DWARF if you do not want debug-info analysis feature at all. +# +# Define WERROR=0 to disable treating any warnings as errors.  $(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE  	@$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT) @@ -63,6 +65,11 @@ ifeq ($(ARCH),x86_64)  	endif  endif +# Treat warnings as errors unless directed not to +ifneq ($(WERROR),0) +	CFLAGS_WERROR := -Werror +endif +  #  # Include saner warnings here, which can catch bugs:  # @@ -95,7 +102,7 @@ ifndef PERF_DEBUG    CFLAGS_OPTIMIZE = -O6  endif -CFLAGS = -fno-omit-frame-pointer -ggdb3 -Wall -Wextra -std=gnu99 -Werror $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) +CFLAGS = -fno-omit-frame-pointer -ggdb3 -Wall -Wextra -std=gnu99 $(CFLAGS_WERROR) $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS)  EXTLIBS = -lpthread -lrt -lelf -lm  ALL_CFLAGS = $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64  ALL_LDFLAGS = $(LDFLAGS) diff --git a/tools/perf/arch/arm/util/dwarf-regs.c b/tools/perf/arch/arm/util/dwarf-regs.c index fff6450c8c9..e8d5c551c69 100644 --- a/tools/perf/arch/arm/util/dwarf-regs.c +++ b/tools/perf/arch/arm/util/dwarf-regs.c @@ -8,7 +8,10 @@   * published by the Free Software Foundation.   */ +#include <stdlib.h> +#ifndef __UCLIBC__  #include <libio.h> +#endif  #include <dwarf-regs.h>  struct pt_regs_dwarfnum { diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 6b0519f885e..f4c3fbee4ba 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -161,6 +161,7 @@ static void config_attr(struct perf_evsel *evsel, struct perf_evlist *evlist)  	struct perf_event_attr *attr = &evsel->attr;  	int track = !evsel->idx; /* only the first counter needs these */ +	attr->disabled		= 1;  	attr->inherit		= !no_inherit;  	attr->read_format	= PERF_FORMAT_TOTAL_TIME_ENABLED |  				  PERF_FORMAT_TOTAL_TIME_RUNNING | @@ -671,6 +672,8 @@ static int __cmd_record(int argc, const char **argv)  		}  	} +	perf_evlist__enable(evsel_list); +  	/*  	 * Let the child rip  	 */ diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c index 55f4c76f282..efe696f936e 100644 --- a/tools/perf/builtin-test.c +++ b/tools/perf/builtin-test.c @@ -561,7 +561,7 @@ static int test__basic_mmap(void)  		}  		err = perf_event__parse_sample(event, attr.sample_type, sample_size, -					       false, &sample); +					       false, &sample, false);  		if (err) {  			pr_err("Can't parse sample, err = %d\n", err);  			goto out_munmap; diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index a43433f0830..d28013b7d61 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -191,7 +191,8 @@ static void __zero_source_counters(struct sym_entry *syme)  	symbol__annotate_zero_histograms(sym);  } -static void record_precise_ip(struct sym_entry *syme, int counter, u64 ip) +static void record_precise_ip(struct sym_entry *syme, struct map *map, +			      int counter, u64 ip)  {  	struct annotation *notes;  	struct symbol *sym; @@ -205,8 +206,8 @@ static void record_precise_ip(struct sym_entry *syme, int counter, u64 ip)  	if (pthread_mutex_trylock(¬es->lock))  		return; -	ip = syme->map->map_ip(syme->map, ip); -	symbol__inc_addr_samples(sym, syme->map, counter, ip); +	ip = map->map_ip(map, ip); +	symbol__inc_addr_samples(sym, map, counter, ip);  	pthread_mutex_unlock(¬es->lock);  } @@ -810,7 +811,7 @@ static void perf_event__process_sample(const union perf_event *event,  		evsel = perf_evlist__id2evsel(top.evlist, sample->id);  		assert(evsel != NULL);  		syme->count[evsel->idx]++; -		record_precise_ip(syme, evsel->idx, ip); +		record_precise_ip(syme, al.map, evsel->idx, ip);  		pthread_mutex_lock(&top.active_symbols_lock);  		if (list_empty(&syme->node) || !syme->node.next) {  			static bool first = true; diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c index fe02903f7d0..80d9598db31 100644 --- a/tools/perf/util/config.c +++ b/tools/perf/util/config.c @@ -341,7 +341,7 @@ const char *perf_config_dirname(const char *name, const char *value)  static int perf_default_core_config(const char *var __used, const char *value __used)  { -	/* Add other config variables here and to Documentation/config.txt. */ +	/* Add other config variables here. */  	return 0;  } @@ -350,7 +350,7 @@ int perf_default_config(const char *var, const char *value, void *dummy __used)  	if (!prefixcmp(var, "core."))  		return perf_default_core_config(var, value); -	/* Add other config variables here and to Documentation/config.txt. */ +	/* Add other config variables here. */  	return 0;  } diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 3c1b8a63210..437f8ca679a 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -169,12 +169,17 @@ static int perf_event__synthesize_mmap_events(union perf_event *event,  			continue;  		pbf += n + 3;  		if (*pbf == 'x') { /* vm_exec */ +			char anonstr[] = "//anon\n";  			char *execname = strchr(bf, '/');  			/* Catch VDSO */  			if (execname == NULL)  				execname = strstr(bf, "[vdso]"); +			/* Catch anonymous mmaps */ +			if ((execname == NULL) && !strstr(bf, "[")) +				execname = anonstr; +  			if (execname == NULL)  				continue; diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 1d7f66488a8..357a85b8524 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -186,6 +186,6 @@ const char *perf_event__name(unsigned int id);  int perf_event__parse_sample(const union perf_event *event, u64 type,  			     int sample_size, bool sample_id_all, -			     struct perf_sample *sample); +			     struct perf_sample *sample, bool swapped);  #endif /* __PERF_RECORD_H */ diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index c12bd476c6f..72e9f4886b6 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -113,6 +113,19 @@ void perf_evlist__disable(struct perf_evlist *evlist)  	}  } +void perf_evlist__enable(struct perf_evlist *evlist) +{ +	int cpu, thread; +	struct perf_evsel *pos; + +	for (cpu = 0; cpu < evlist->cpus->nr; cpu++) { +		list_for_each_entry(pos, &evlist->entries, node) { +			for (thread = 0; thread < evlist->threads->nr; thread++) +				ioctl(FD(pos, cpu, thread), PERF_EVENT_IOC_ENABLE); +		} +	} +} +  int perf_evlist__alloc_pollfd(struct perf_evlist *evlist)  {  	int nfds = evlist->cpus->nr * evlist->threads->nr * evlist->nr_entries; diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index ce85ae9ae57..f3491500274 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -54,6 +54,7 @@ int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite);  void perf_evlist__munmap(struct perf_evlist *evlist);  void perf_evlist__disable(struct perf_evlist *evlist); +void perf_evlist__enable(struct perf_evlist *evlist);  static inline void perf_evlist__set_maps(struct perf_evlist *evlist,  					 struct cpu_map *cpus, diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index a03a36b7908..e389815078d 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -7,6 +7,8 @@   * Released under the GPL v2. (and only v2, not any later version)   */ +#include <byteswap.h> +#include "asm/bug.h"  #include "evsel.h"  #include "evlist.h"  #include "util.h" @@ -342,10 +344,20 @@ static bool sample_overlap(const union perf_event *event,  int perf_event__parse_sample(const union perf_event *event, u64 type,  			     int sample_size, bool sample_id_all, -			     struct perf_sample *data) +			     struct perf_sample *data, bool swapped)  {  	const u64 *array; +	/* +	 * used for cross-endian analysis. See git commit 65014ab3 +	 * for why this goofiness is needed. +	 */ +	union { +		u64 val64; +		u32 val32[2]; +	} u; + +  	data->cpu = data->pid = data->tid = -1;  	data->stream_id = data->id = data->time = -1ULL; @@ -366,9 +378,16 @@ int perf_event__parse_sample(const union perf_event *event, u64 type,  	}  	if (type & PERF_SAMPLE_TID) { -		u32 *p = (u32 *)array; -		data->pid = p[0]; -		data->tid = p[1]; +		u.val64 = *array; +		if (swapped) { +			/* undo swap of u64, then swap on individual u32s */ +			u.val64 = bswap_64(u.val64); +			u.val32[0] = bswap_32(u.val32[0]); +			u.val32[1] = bswap_32(u.val32[1]); +		} + +		data->pid = u.val32[0]; +		data->tid = u.val32[1];  		array++;  	} @@ -395,8 +414,15 @@ int perf_event__parse_sample(const union perf_event *event, u64 type,  	}  	if (type & PERF_SAMPLE_CPU) { -		u32 *p = (u32 *)array; -		data->cpu = *p; + +		u.val64 = *array; +		if (swapped) { +			/* undo swap of u64, then swap on individual u32s */ +			u.val64 = bswap_64(u.val64); +			u.val32[0] = bswap_32(u.val32[0]); +		} + +		data->cpu = u.val32[0];  		array++;  	} @@ -423,18 +449,27 @@ int perf_event__parse_sample(const union perf_event *event, u64 type,  	}  	if (type & PERF_SAMPLE_RAW) { -		u32 *p = (u32 *)array; +		const u64 *pdata; + +		u.val64 = *array; +		if (WARN_ONCE(swapped, +			      "Endianness of raw data not corrected!\n")) { +			/* undo swap of u64, then swap on individual u32s */ +			u.val64 = bswap_64(u.val64); +			u.val32[0] = bswap_32(u.val32[0]); +			u.val32[1] = bswap_32(u.val32[1]); +		}  		if (sample_overlap(event, array, sizeof(u32)))  			return -EFAULT; -		data->raw_size = *p; -		p++; +		data->raw_size = u.val32[0]; +		pdata = (void *) array + sizeof(u32); -		if (sample_overlap(event, p, data->raw_size)) +		if (sample_overlap(event, pdata, data->raw_size))  			return -EFAULT; -		data->raw_data = p; +		data->raw_data = (void *) pdata;  	}  	return 0; diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index 555fc3864b9..5d732621a46 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c @@ -659,7 +659,7 @@ static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf)  		if (!die_find_variable_at(&pf->cu_die, pf->pvar->var, 0, &vr_die))  			ret = -ENOENT;  	} -	if (ret == 0) +	if (ret >= 0)  		ret = convert_variable(&vr_die, pf);  	if (ret < 0) diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index cbc8f215d4b..7624324efad 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c @@ -803,7 +803,7 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist,  		first = list_entry(evlist->entries.next, struct perf_evsel, node);  		err = perf_event__parse_sample(event, first->attr.sample_type,  					       perf_evsel__sample_size(first), -					       sample_id_all, &pevent->sample); +					       sample_id_all, &pevent->sample, false);  		if (err)  			return PyErr_Format(PyExc_OSError,  					    "perf: can't parse sample, err=%d", err); diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 170601e67d6..974d0cbee5e 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -162,7 +162,8 @@ static inline int perf_session__parse_sample(struct perf_session *session,  {  	return perf_event__parse_sample(event, session->sample_type,  					session->sample_size, -					session->sample_id_all, sample); +					session->sample_id_all, sample, +					session->header.needs_swap);  }  struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 401e220566f..1ee8f1e40f1 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -151,11 +151,17 @@ sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)  {  	u64 ip_l, ip_r; +	if (!left->ms.sym && !right->ms.sym) +		return right->level - left->level; + +	if (!left->ms.sym || !right->ms.sym) +		return cmp_null(left->ms.sym, right->ms.sym); +  	if (left->ms.sym == right->ms.sym)  		return 0; -	ip_l = left->ms.sym ? left->ms.sym->start : left->ip; -	ip_r = right->ms.sym ? right->ms.sym->start : right->ip; +	ip_l = left->ms.sym->start; +	ip_r = right->ms.sym->start;  	return (int64_t)(ip_r - ip_l);  } diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 469c0264ed2..40eeaf07725 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -74,16 +74,104 @@ static void dso__set_sorted_by_name(struct dso *dso, enum map_type type)  bool symbol_type__is_a(char symbol_type, enum map_type map_type)  { +	symbol_type = toupper(symbol_type); +  	switch (map_type) {  	case MAP__FUNCTION:  		return symbol_type == 'T' || symbol_type == 'W';  	case MAP__VARIABLE: -		return symbol_type == 'D' || symbol_type == 'd'; +		return symbol_type == 'D';  	default:  		return false;  	}  } +static int prefix_underscores_count(const char *str) +{ +	const char *tail = str; + +	while (*tail == '_') +		tail++; + +	return tail - str; +} + +#define SYMBOL_A 0 +#define SYMBOL_B 1 + +static int choose_best_symbol(struct symbol *syma, struct symbol *symb) +{ +	s64 a; +	s64 b; + +	/* Prefer a symbol with non zero length */ +	a = syma->end - syma->start; +	b = symb->end - symb->start; +	if ((b == 0) && (a > 0)) +		return SYMBOL_A; +	else if ((a == 0) && (b > 0)) +		return SYMBOL_B; + +	/* Prefer a non weak symbol over a weak one */ +	a = syma->binding == STB_WEAK; +	b = symb->binding == STB_WEAK; +	if (b && !a) +		return SYMBOL_A; +	if (a && !b) +		return SYMBOL_B; + +	/* Prefer a global symbol over a non global one */ +	a = syma->binding == STB_GLOBAL; +	b = symb->binding == STB_GLOBAL; +	if (a && !b) +		return SYMBOL_A; +	if (b && !a) +		return SYMBOL_B; + +	/* Prefer a symbol with less underscores */ +	a = prefix_underscores_count(syma->name); +	b = prefix_underscores_count(symb->name); +	if (b > a) +		return SYMBOL_A; +	else if (a > b) +		return SYMBOL_B; + +	/* If all else fails, choose the symbol with the longest name */ +	if (strlen(syma->name) >= strlen(symb->name)) +		return SYMBOL_A; +	else +		return SYMBOL_B; +} + +static void symbols__fixup_duplicate(struct rb_root *symbols) +{ +	struct rb_node *nd; +	struct symbol *curr, *next; + +	nd = rb_first(symbols); + +	while (nd) { +		curr = rb_entry(nd, struct symbol, rb_node); +again: +		nd = rb_next(&curr->rb_node); +		next = rb_entry(nd, struct symbol, rb_node); + +		if (!nd) +			break; + +		if (curr->start != next->start) +			continue; + +		if (choose_best_symbol(curr, next) == SYMBOL_A) { +			rb_erase(&next->rb_node, symbols); +			goto again; +		} else { +			nd = rb_next(&curr->rb_node); +			rb_erase(&curr->rb_node, symbols); +		} +	} +} +  static void symbols__fixup_end(struct rb_root *symbols)  {  	struct rb_node *nd, *prevnd = rb_first(symbols); @@ -438,18 +526,11 @@ int kallsyms__parse(const char *filename, void *arg,  	char *line = NULL;  	size_t n;  	int err = -1; -	u64 prev_start = 0; -	char prev_symbol_type = 0; -	char *prev_symbol_name;  	FILE *file = fopen(filename, "r");  	if (file == NULL)  		goto out_failure; -	prev_symbol_name = malloc(KSYM_NAME_LEN); -	if (prev_symbol_name == NULL) -		goto out_close; -  	err = 0;  	while (!feof(file)) { @@ -470,7 +551,7 @@ int kallsyms__parse(const char *filename, void *arg,  		if (len + 2 >= line_len)  			continue; -		symbol_type = toupper(line[len]); +		symbol_type = line[len];  		len += 2;  		symbol_name = line + len;  		len = line_len - len; @@ -480,24 +561,18 @@ int kallsyms__parse(const char *filename, void *arg,  			break;  		} -		if (prev_symbol_type) { -			u64 end = start; -			if (end != prev_start) -				--end; -			err = process_symbol(arg, prev_symbol_name, -					     prev_symbol_type, prev_start, end); -			if (err) -				break; -		} - -		memcpy(prev_symbol_name, symbol_name, len + 1); -		prev_symbol_type = symbol_type; -		prev_start = start; +		/* +		 * module symbols are not sorted so we add all +		 * symbols with zero length and rely on +		 * symbols__fixup_end() to fix it up. +		 */ +		err = process_symbol(arg, symbol_name, +				     symbol_type, start, start); +		if (err) +			break;  	} -	free(prev_symbol_name);  	free(line); -out_close:  	fclose(file);  	return err; @@ -703,6 +778,9 @@ int dso__load_kallsyms(struct dso *dso, const char *filename,  	if (dso__load_all_kallsyms(dso, filename, map) < 0)  		return -1; +	symbols__fixup_duplicate(&dso->symbols[map->type]); +	symbols__fixup_end(&dso->symbols[map->type]); +  	if (dso->kernel == DSO_TYPE_GUEST_KERNEL)  		dso->symtab_type = SYMTAB__GUEST_KALLSYMS;  	else @@ -1092,8 +1170,7 @@ static int dso__load_sym(struct dso *dso, struct map *map, const char *name,  	if (dso->has_build_id) {  		u8 build_id[BUILD_ID_SIZE]; -		if (elf_read_build_id(elf, build_id, -				      BUILD_ID_SIZE) != BUILD_ID_SIZE) +		if (elf_read_build_id(elf, build_id, BUILD_ID_SIZE) < 0)  			goto out_elf_end;  		if (!dso__build_id_equal(dso, build_id)) @@ -1111,6 +1188,8 @@ static int dso__load_sym(struct dso *dso, struct map *map, const char *name,  	}  	opdsec = elf_section_by_name(elf, &ehdr, &opdshdr, ".opd", &opdidx); +	if (opdshdr.sh_type != SHT_PROGBITS) +		opdsec = NULL;  	if (opdsec)  		opddata = elf_rawdata(opdsec, NULL); @@ -1276,6 +1355,7 @@ new_symbol:  	 * For misannotated, zeroed, ASM function sizes.  	 */  	if (nr > 0) { +		symbols__fixup_duplicate(&dso->symbols[map->type]);  		symbols__fixup_end(&dso->symbols[map->type]);  		if (kmap) {  			/* @@ -1362,8 +1442,8 @@ static int elf_read_build_id(Elf *elf, void *bf, size_t size)  	ptr = data->d_buf;  	while (ptr < (data->d_buf + data->d_size)) {  		GElf_Nhdr *nhdr = ptr; -		int namesz = NOTE_ALIGN(nhdr->n_namesz), -		    descsz = NOTE_ALIGN(nhdr->n_descsz); +		size_t namesz = NOTE_ALIGN(nhdr->n_namesz), +		       descsz = NOTE_ALIGN(nhdr->n_descsz);  		const char *name;  		ptr += sizeof(*nhdr); @@ -1372,8 +1452,10 @@ static int elf_read_build_id(Elf *elf, void *bf, size_t size)  		if (nhdr->n_type == NT_GNU_BUILD_ID &&  		    nhdr->n_namesz == sizeof("GNU")) {  			if (memcmp(name, "GNU", sizeof("GNU")) == 0) { -				memcpy(bf, ptr, BUILD_ID_SIZE); -				err = BUILD_ID_SIZE; +				size_t sz = min(size, descsz); +				memcpy(bf, ptr, sz); +				memset(bf + sz, 0, size - sz); +				err = descsz;  				break;  			}  		} @@ -1425,7 +1507,7 @@ int sysfs__read_build_id(const char *filename, void *build_id, size_t size)  	while (1) {  		char bf[BUFSIZ];  		GElf_Nhdr nhdr; -		int namesz, descsz; +		size_t namesz, descsz;  		if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr))  			break; @@ -1434,15 +1516,16 @@ int sysfs__read_build_id(const char *filename, void *build_id, size_t size)  		descsz = NOTE_ALIGN(nhdr.n_descsz);  		if (nhdr.n_type == NT_GNU_BUILD_ID &&  		    nhdr.n_namesz == sizeof("GNU")) { -			if (read(fd, bf, namesz) != namesz) +			if (read(fd, bf, namesz) != (ssize_t)namesz)  				break;  			if (memcmp(bf, "GNU", sizeof("GNU")) == 0) { -				if (read(fd, build_id, -				    BUILD_ID_SIZE) == BUILD_ID_SIZE) { +				size_t sz = min(descsz, size); +				if (read(fd, build_id, sz) == (ssize_t)sz) { +					memset(build_id + sz, 0, size - sz);  					err = 0;  					break;  				} -			} else if (read(fd, bf, descsz) != descsz) +			} else if (read(fd, bf, descsz) != (ssize_t)descsz)  				break;  		} else {  			int n = namesz + descsz; diff --git a/tools/power/cpupower/Makefile b/tools/power/cpupower/Makefile index 94c2cf0a98b..e8a03aceceb 100644 --- a/tools/power/cpupower/Makefile +++ b/tools/power/cpupower/Makefile @@ -24,7 +24,7 @@  # Set the following to `true' to make a unstripped, unoptimized  # binary. Leave this set to `false' for production use. -DEBUG ?=	false +DEBUG ?=	true  # make the build silent. Set this to something else to make it noisy again.  V ?=		false @@ -35,7 +35,7 @@ NLS ?=		true  # Set the following to 'true' to build/install the  # cpufreq-bench benchmarking tool -CPUFRQ_BENCH ?= true +CPUFREQ_BENCH ?= true  # Prefix to the directories we're installing to  DESTDIR ?= @@ -137,9 +137,10 @@ CFLAGS +=	-pipe  ifeq ($(strip $(NLS)),true)  	INSTALL_NLS += install-gmo  	COMPILE_NLS += create-gmo +	CFLAGS += -DNLS  endif -ifeq ($(strip $(CPUFRQ_BENCH)),true) +ifeq ($(strip $(CPUFREQ_BENCH)),true)  	INSTALL_BENCH += install-bench  	COMPILE_BENCH += compile-bench  endif diff --git a/tools/power/cpupower/debug/x86_64/Makefile b/tools/power/cpupower/debug/x86_64/Makefile index dbf13998462..3326217dd31 100644 --- a/tools/power/cpupower/debug/x86_64/Makefile +++ b/tools/power/cpupower/debug/x86_64/Makefile @@ -1,10 +1,10 @@  default: all -centrino-decode: centrino-decode.c -	$(CC) $(CFLAGS) -o centrino-decode centrino-decode.c +centrino-decode: ../i386/centrino-decode.c +	$(CC) $(CFLAGS) -o $@ $< -powernow-k8-decode: powernow-k8-decode.c -	$(CC) $(CFLAGS) -o powernow-k8-decode powernow-k8-decode.c +powernow-k8-decode: ../i386/powernow-k8-decode.c +	$(CC) $(CFLAGS) -o $@ $<  all: centrino-decode powernow-k8-decode diff --git a/tools/power/cpupower/debug/x86_64/centrino-decode.c b/tools/power/cpupower/debug/x86_64/centrino-decode.c deleted file mode 120000 index 26fb3f1d8fc..00000000000 --- a/tools/power/cpupower/debug/x86_64/centrino-decode.c +++ /dev/null @@ -1 +0,0 @@ -../i386/centrino-decode.c
\ No newline at end of file diff --git a/tools/power/cpupower/debug/x86_64/powernow-k8-decode.c b/tools/power/cpupower/debug/x86_64/powernow-k8-decode.c deleted file mode 120000 index eb30c79cf9d..00000000000 --- a/tools/power/cpupower/debug/x86_64/powernow-k8-decode.c +++ /dev/null @@ -1 +0,0 @@ -../i386/powernow-k8-decode.c
\ No newline at end of file diff --git a/tools/power/cpupower/man/cpupower-frequency-info.1 b/tools/power/cpupower/man/cpupower-frequency-info.1 index 3194811d58f..bb60a8d1e45 100644 --- a/tools/power/cpupower/man/cpupower-frequency-info.1 +++ b/tools/power/cpupower/man/cpupower-frequency-info.1 @@ -1,10 +1,10 @@ -.TH "cpufreq-info" "1" "0.1" "Mattia Dongili" "" +.TH "cpupower-frequency-info" "1" "0.1" "Mattia Dongili" ""  .SH "NAME"  .LP  -cpufreq\-info \- Utility to retrieve cpufreq kernel information +cpupower frequency\-info \- Utility to retrieve cpufreq kernel information  .SH "SYNTAX"  .LP  -cpufreq\-info [\fIoptions\fP] +cpupower [ \-c cpulist ] frequency\-info [\fIoptions\fP]  .SH "DESCRIPTION"  .LP   A small tool which prints out cpufreq information helpful to developers and interested users. diff --git a/tools/power/cpupower/man/cpupower-frequency-set.1 b/tools/power/cpupower/man/cpupower-frequency-set.1 index 26e3e13eee3..685f469093a 100644 --- a/tools/power/cpupower/man/cpupower-frequency-set.1 +++ b/tools/power/cpupower/man/cpupower-frequency-set.1 @@ -1,13 +1,13 @@ -.TH "cpufreq-set" "1" "0.1" "Mattia Dongili" "" +.TH "cpupower-freqency-set" "1" "0.1" "Mattia Dongili" ""  .SH "NAME"  .LP  -cpufreq\-set \- A small tool which allows to modify cpufreq settings. +cpupower frequency\-set \- A small tool which allows to modify cpufreq settings.  .SH "SYNTAX"  .LP  -cpufreq\-set [\fIoptions\fP] +cpupower [ \-c cpu ] frequency\-set [\fIoptions\fP]  .SH "DESCRIPTION"  .LP  -cpufreq\-set allows you to modify cpufreq settings without having to type e.g. "/sys/devices/system/cpu/cpu0/cpufreq/scaling_set_speed" all the time. +cpupower frequency\-set allows you to modify cpufreq settings without having to type e.g. "/sys/devices/system/cpu/cpu0/cpufreq/scaling_set_speed" all the time.  .SH "OPTIONS"  .LP   .TP  diff --git a/tools/power/cpupower/man/cpupower.1 b/tools/power/cpupower/man/cpupower.1 index 78c20feab85..baf741d06e8 100644 --- a/tools/power/cpupower/man/cpupower.1 +++ b/tools/power/cpupower/man/cpupower.1 @@ -3,7 +3,7 @@  cpupower \- Shows and sets processor power related values  .SH SYNOPSIS  .ft B -.B cpupower [ \-c cpulist ] subcommand [ARGS] +.B cpupower [ \-c cpulist ] <command> [ARGS]  .B cpupower \-v|\-\-version @@ -13,24 +13,24 @@ cpupower \- Shows and sets processor power related values  \fBcpupower \fP is a collection of tools to examine and tune power saving  related features of your processor. -The manpages of the subcommands (cpupower\-<subcommand>(1)) provide detailed +The manpages of the commands (cpupower\-<command>(1)) provide detailed  descriptions of supported features. Run \fBcpupower help\fP to get an overview -of supported subcommands. +of supported commands.  .SH Options  .PP  \-\-help, \-h  .RS 4 -Shows supported subcommands and general usage. +Shows supported commands and general usage.  .RE  .PP  \-\-cpu cpulist,  \-c cpulist  .RS 4  Only show or set values for specific cores. -This option is not supported by all subcommands, details can be found in the -manpages of the subcommands. +This option is not supported by all commands, details can be found in the +manpages of the commands. -Some subcommands access all cores (typically the *\-set commands), some only +Some commands access all cores (typically the *\-set commands), some only  the first core (typically the *\-info commands) by default.  The syntax for <cpulist> is based on how the kernel exports CPU bitmasks via diff --git a/tools/power/cpupower/utils/builtin.h b/tools/power/cpupower/utils/builtin.h index c870ffba521..c10496fbe3c 100644 --- a/tools/power/cpupower/utils/builtin.h +++ b/tools/power/cpupower/utils/builtin.h @@ -8,11 +8,4 @@ extern int cmd_freq_info(int argc, const char **argv);  extern int cmd_idle_info(int argc, const char **argv);  extern int cmd_monitor(int argc, const char **argv); -extern void set_help(void); -extern void info_help(void); -extern void freq_set_help(void); -extern void freq_info_help(void); -extern void idle_info_help(void); -extern void monitor_help(void); -  #endif diff --git a/tools/power/cpupower/utils/cpufreq-info.c b/tools/power/cpupower/utils/cpufreq-info.c index 5a1d25f056b..28953c9a7bd 100644 --- a/tools/power/cpupower/utils/cpufreq-info.c +++ b/tools/power/cpupower/utils/cpufreq-info.c @@ -510,37 +510,6 @@ static int get_latency(unsigned int cpu, unsigned int human)  	return 0;  } -void freq_info_help(void) -{ -	printf(_("Usage: cpupower freqinfo [options]\n")); -	printf(_("Options:\n")); -	printf(_("  -e, --debug          Prints out debug information [default]\n")); -	printf(_("  -f, --freq           Get frequency the CPU currently runs at, according\n" -	       "                       to the cpufreq core *\n")); -	printf(_("  -w, --hwfreq         Get frequency the CPU currently runs at, by reading\n" -	       "                       it from hardware (only available to root) *\n")); -	printf(_("  -l, --hwlimits       Determine the minimum and maximum CPU frequency allowed *\n")); -	printf(_("  -d, --driver         Determines the used cpufreq kernel driver *\n")); -	printf(_("  -p, --policy         Gets the currently used cpufreq policy *\n")); -	printf(_("  -g, --governors      Determines available cpufreq governors *\n")); -	printf(_("  -r, --related-cpus   Determines which CPUs run at the same hardware frequency *\n")); -	printf(_("  -a, --affected-cpus  Determines which CPUs need to have their frequency\n" -			"                       coordinated by software *\n")); -	printf(_("  -s, --stats          Shows cpufreq statistics if available\n")); -	printf(_("  -y, --latency        Determines the maximum latency on CPU frequency changes *\n")); -	printf(_("  -b, --boost          Checks for turbo or boost modes  *\n")); -	printf(_("  -o, --proc           Prints out information like provided by the /proc/cpufreq\n" -	       "                       interface in 2.4. and early 2.6. kernels\n")); -	printf(_("  -m, --human          human-readable output for the -f, -w, -s and -y parameters\n")); -	printf(_("  -h, --help           Prints out this screen\n")); - -	printf("\n"); -	printf(_("If no argument is given, full output about\n" -	       "cpufreq is printed which is useful e.g. for reporting bugs.\n\n")); -	printf(_("By default info of CPU 0 is shown which can be overridden\n" -		 "with the cpupower --cpu main command option.\n")); -} -  static struct option info_opts[] = {  	{ .name = "debug",	.has_arg = no_argument,		.flag = NULL,	.val = 'e'},  	{ .name = "boost",	.has_arg = no_argument,		.flag = NULL,	.val = 'b'}, @@ -556,7 +525,6 @@ static struct option info_opts[] = {  	{ .name = "latency",	.has_arg = no_argument,		.flag = NULL,	.val = 'y'},  	{ .name = "proc",	.has_arg = no_argument,		.flag = NULL,	.val = 'o'},  	{ .name = "human",	.has_arg = no_argument,		.flag = NULL,	.val = 'm'}, -	{ .name = "help",	.has_arg = no_argument,		.flag = NULL,	.val = 'h'},  	{ },  }; @@ -570,16 +538,12 @@ int cmd_freq_info(int argc, char **argv)  	int output_param = 0;  	do { -		ret = getopt_long(argc, argv, "hoefwldpgrasmyb", info_opts, NULL); +		ret = getopt_long(argc, argv, "oefwldpgrasmyb", info_opts, NULL);  		switch (ret) {  		case '?':  			output_param = '?';  			cont = 0;  			break; -		case 'h': -			output_param = 'h'; -			cont = 0; -			break;  		case -1:  			cont = 0;  			break; @@ -642,11 +606,7 @@ int cmd_freq_info(int argc, char **argv)  		return -EINVAL;  	case '?':  		printf(_("invalid or unknown argument\n")); -		freq_info_help();  		return -EINVAL; -	case 'h': -		freq_info_help(); -		return EXIT_SUCCESS;  	case 'o':  		proc_cpufreq_output();  		return EXIT_SUCCESS; diff --git a/tools/power/cpupower/utils/cpufreq-set.c b/tools/power/cpupower/utils/cpufreq-set.c index 5f783622bf3..dd1539eb8c6 100644 --- a/tools/power/cpupower/utils/cpufreq-set.c +++ b/tools/power/cpupower/utils/cpufreq-set.c @@ -20,34 +20,11 @@  #define NORM_FREQ_LEN 32 -void freq_set_help(void) -{ -	printf(_("Usage: cpupower frequency-set [options]\n")); -	printf(_("Options:\n")); -	printf(_("  -d FREQ, --min FREQ      new minimum CPU frequency the governor may select\n")); -	printf(_("  -u FREQ, --max FREQ      new maximum CPU frequency the governor may select\n")); -	printf(_("  -g GOV, --governor GOV   new cpufreq governor\n")); -	printf(_("  -f FREQ, --freq FREQ     specific frequency to be set. Requires userspace\n" -	       "                           governor to be available and loaded\n")); -	printf(_("  -r, --related            Switches all hardware-related CPUs\n")); -	printf(_("  -h, --help               Prints out this screen\n")); -	printf("\n"); -	printf(_("Notes:\n" -	       "1. Omitting the -c or --cpu argument is equivalent to setting it to \"all\"\n")); -	printf(_("2. The -f FREQ, --freq FREQ parameter cannot be combined with any other parameter\n" -	       "   except the -c CPU, --cpu CPU parameter\n" -	       "3. FREQuencies can be passed in Hz, kHz (default), MHz, GHz, or THz\n" -	       "   by postfixing the value with the wanted unit name, without any space\n" -	       "   (FREQuency in kHz =^ Hz * 0.001 =^ MHz * 1000 =^ GHz * 1000000).\n")); - -} -  static struct option set_opts[] = {  	{ .name = "min",	.has_arg = required_argument,	.flag = NULL,	.val = 'd'},  	{ .name = "max",	.has_arg = required_argument,	.flag = NULL,	.val = 'u'},  	{ .name = "governor",	.has_arg = required_argument,	.flag = NULL,	.val = 'g'},  	{ .name = "freq",	.has_arg = required_argument,	.flag = NULL,	.val = 'f'}, -	{ .name = "help",	.has_arg = no_argument,		.flag = NULL,	.val = 'h'},  	{ .name = "related",	.has_arg = no_argument,		.flag = NULL,	.val='r'},  	{ },  }; @@ -80,7 +57,6 @@ const struct freq_units def_units[] = {  static void print_unknown_arg(void)  {  	printf(_("invalid or unknown argument\n")); -	freq_set_help();  }  static unsigned long string_to_frequency(const char *str) @@ -231,14 +207,11 @@ int cmd_freq_set(int argc, char **argv)  	/* parameter parsing */  	do { -		ret = getopt_long(argc, argv, "d:u:g:f:hr", set_opts, NULL); +		ret = getopt_long(argc, argv, "d:u:g:f:r", set_opts, NULL);  		switch (ret) {  		case '?':  			print_unknown_arg();  			return -EINVAL; -		case 'h': -			freq_set_help(); -			return 0;  		case -1:  			cont = 0;  			break; diff --git a/tools/power/cpupower/utils/cpuidle-info.c b/tools/power/cpupower/utils/cpuidle-info.c index 70da3574f1e..b028267c137 100644 --- a/tools/power/cpupower/utils/cpuidle-info.c +++ b/tools/power/cpupower/utils/cpuidle-info.c @@ -139,30 +139,14 @@ static void proc_cpuidle_cpu_output(unsigned int cpu)  	}  } -/* --freq / -f */ - -void idle_info_help(void) -{ -	printf(_ ("Usage: cpupower idleinfo [options]\n")); -	printf(_ ("Options:\n")); -	printf(_ ("  -s, --silent         Only show general C-state information\n")); -	printf(_ ("  -o, --proc           Prints out information like provided by the /proc/acpi/processor/*/power\n" -	       "                       interface in older kernels\n")); -	printf(_ ("  -h, --help           Prints out this screen\n")); - -	printf("\n"); -} -  static struct option info_opts[] = {  	{ .name = "silent",	.has_arg = no_argument,	.flag = NULL,	.val = 's'},  	{ .name = "proc",	.has_arg = no_argument,	.flag = NULL,	.val = 'o'}, -	{ .name = "help",	.has_arg = no_argument,	.flag = NULL,	.val = 'h'},  	{ },  };  static inline void cpuidle_exit(int fail)  { -	idle_info_help();  	exit(EXIT_FAILURE);  } @@ -174,7 +158,7 @@ int cmd_idle_info(int argc, char **argv)  	unsigned int cpu = 0;  	do { -		ret = getopt_long(argc, argv, "hos", info_opts, NULL); +		ret = getopt_long(argc, argv, "os", info_opts, NULL);  		if (ret == -1)  			break;  		switch (ret) { @@ -182,10 +166,6 @@ int cmd_idle_info(int argc, char **argv)  			output_param = '?';  			cont = 0;  			break; -		case 'h': -			output_param = 'h'; -			cont = 0; -			break;  		case 's':  			verbose = 0;  			break; @@ -211,8 +191,6 @@ int cmd_idle_info(int argc, char **argv)  	case '?':  		printf(_("invalid or unknown argument\n"));  		cpuidle_exit(EXIT_FAILURE); -	case 'h': -		cpuidle_exit(EXIT_SUCCESS);  	}  	/* Default is: show output of CPU 0 only */ diff --git a/tools/power/cpupower/utils/cpupower-info.c b/tools/power/cpupower/utils/cpupower-info.c index 85253cb7600..3f68632c28c 100644 --- a/tools/power/cpupower/utils/cpupower-info.c +++ b/tools/power/cpupower/utils/cpupower-info.c @@ -16,31 +16,16 @@  #include "helpers/helpers.h"  #include "helpers/sysfs.h" -void info_help(void) -{ -	printf(_("Usage: cpupower info [ -b ] [ -m ] [ -s ]\n")); -	printf(_("Options:\n")); -	printf(_("  -b, --perf-bias    Gets CPU's power vs performance policy on some\n" -	       "                           Intel models [0-15], see manpage for details\n")); -	printf(_("  -m, --sched-mc     Gets the kernel's multi core scheduler policy.\n")); -	printf(_("  -s, --sched-smt    Gets the kernel's thread sibling scheduler policy.\n")); -	printf(_("  -h, --help               Prints out this screen\n")); -	printf(_("\nPassing no option will show all info, by default only on core 0\n")); -	printf("\n"); -} -  static struct option set_opts[] = {  	{ .name = "perf-bias",	.has_arg = optional_argument,	.flag = NULL,	.val = 'b'},  	{ .name = "sched-mc",	.has_arg = optional_argument,	.flag = NULL,	.val = 'm'},  	{ .name = "sched-smt",	.has_arg = optional_argument,	.flag = NULL,	.val = 's'}, -	{ .name = "help",	.has_arg = no_argument,		.flag = NULL,	.val = 'h'},  	{ },  };  static void print_wrong_arg_exit(void)  {  	printf(_("invalid or unknown argument\n")); -	info_help();  	exit(EXIT_FAILURE);  } @@ -64,11 +49,8 @@ int cmd_info(int argc, char **argv)  	textdomain(PACKAGE);  	/* parameter parsing */ -	while ((ret = getopt_long(argc, argv, "msbh", set_opts, NULL)) != -1) { +	while ((ret = getopt_long(argc, argv, "msb", set_opts, NULL)) != -1) {  		switch (ret) { -		case 'h': -			info_help(); -			return 0;  		case 'b':  			if (params.perf_bias)  				print_wrong_arg_exit(); diff --git a/tools/power/cpupower/utils/cpupower-set.c b/tools/power/cpupower/utils/cpupower-set.c index bc1b391e46f..dc4de376211 100644 --- a/tools/power/cpupower/utils/cpupower-set.c +++ b/tools/power/cpupower/utils/cpupower-set.c @@ -17,30 +17,16 @@  #include "helpers/sysfs.h"  #include "helpers/bitmask.h" -void set_help(void) -{ -	printf(_("Usage: cpupower set [ -b val ] [ -m val ] [ -s val ]\n")); -	printf(_("Options:\n")); -	printf(_("  -b, --perf-bias [VAL]    Sets CPU's power vs performance policy on some\n" -	       "                           Intel models [0-15], see manpage for details\n")); -	printf(_("  -m, --sched-mc  [VAL]    Sets the kernel's multi core scheduler policy.\n")); -	printf(_("  -s, --sched-smt [VAL]    Sets the kernel's thread sibling scheduler policy.\n")); -	printf(_("  -h, --help               Prints out this screen\n")); -	printf("\n"); -} -  static struct option set_opts[] = {  	{ .name = "perf-bias",	.has_arg = optional_argument,	.flag = NULL,	.val = 'b'},  	{ .name = "sched-mc",	.has_arg = optional_argument,	.flag = NULL,	.val = 'm'},  	{ .name = "sched-smt",	.has_arg = optional_argument,	.flag = NULL,	.val = 's'}, -	{ .name = "help",	.has_arg = no_argument,		.flag = NULL,	.val = 'h'},  	{ },  };  static void print_wrong_arg_exit(void)  {  	printf(_("invalid or unknown argument\n")); -	set_help();  	exit(EXIT_FAILURE);  } @@ -66,12 +52,9 @@ int cmd_set(int argc, char **argv)  	params.params = 0;  	/* parameter parsing */ -	while ((ret = getopt_long(argc, argv, "m:s:b:h", +	while ((ret = getopt_long(argc, argv, "m:s:b:",  						set_opts, NULL)) != -1) {  		switch (ret) { -		case 'h': -			set_help(); -			return 0;  		case 'b':  			if (params.perf_bias)  				print_wrong_arg_exit(); @@ -110,10 +93,8 @@ int cmd_set(int argc, char **argv)  		}  	}; -	if (!params.params) { -		set_help(); -		return -EINVAL; -	} +	if (!params.params) +		print_wrong_arg_exit();  	if (params.sched_mc) {  		ret = sysfs_set_sched("mc", sched_mc); diff --git a/tools/power/cpupower/utils/cpupower.c b/tools/power/cpupower/utils/cpupower.c index 5844ae0f786..52bee591c1c 100644 --- a/tools/power/cpupower/utils/cpupower.c +++ b/tools/power/cpupower/utils/cpupower.c @@ -11,6 +11,7 @@  #include <stdlib.h>  #include <string.h>  #include <unistd.h> +#include <errno.h>  #include "builtin.h"  #include "helpers/helpers.h" @@ -19,13 +20,12 @@  struct cmd_struct {  	const char *cmd;  	int (*main)(int, const char **); -	void (*usage)(void);  	int needs_root;  };  #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) -int cmd_help(int argc, const char **argv); +static int cmd_help(int argc, const char **argv);  /* Global cpu_info object available for all binaries   * Info only retrieved from CPU 0 @@ -44,55 +44,66 @@ int be_verbose;  static void print_help(void);  static struct cmd_struct commands[] = { -	{ "frequency-info",	cmd_freq_info,	freq_info_help,	0	}, -	{ "frequency-set",	cmd_freq_set,	freq_set_help,	1	}, -	{ "idle-info",		cmd_idle_info,	idle_info_help,	0	}, -	{ "set",		cmd_set,	set_help,	1	}, -	{ "info",		cmd_info,	info_help,	0	}, -	{ "monitor",		cmd_monitor,	monitor_help,	0	}, -	{ "help",		cmd_help,	print_help,	0	}, -	/*	{ "bench",	cmd_bench,	NULL,		1	}, */ +	{ "frequency-info",	cmd_freq_info,	0	}, +	{ "frequency-set",	cmd_freq_set,	1	}, +	{ "idle-info",		cmd_idle_info,	0	}, +	{ "set",		cmd_set,	1	}, +	{ "info",		cmd_info,	0	}, +	{ "monitor",		cmd_monitor,	0	}, +	{ "help",		cmd_help,	0	}, +	/*	{ "bench",	cmd_bench,	1	}, */  }; -int cmd_help(int argc, const char **argv) -{ -	unsigned int i; - -	if (argc > 1) { -		for (i = 0; i < ARRAY_SIZE(commands); i++) { -			struct cmd_struct *p = commands + i; -			if (strcmp(p->cmd, argv[1])) -				continue; -			if (p->usage) { -				p->usage(); -				return EXIT_SUCCESS; -			} -		} -	} -	print_help(); -	if (argc == 1) -		return EXIT_SUCCESS; /* cpupower help */ -	return EXIT_FAILURE; -} -  static void print_help(void)  {  	unsigned int i;  #ifdef DEBUG -	printf(_("cpupower [ -d ][ -c cpulist ] subcommand [ARGS]\n")); -	printf(_("  -d, --debug      May increase output (stderr) on some subcommands\n")); +	printf(_("Usage:\tcpupower [-d|--debug] [-c|--cpu cpulist ] <command> [<args>]\n"));  #else -	printf(_("cpupower [ -c cpulist ] subcommand [ARGS]\n")); +	printf(_("Usage:\tcpupower [-c|--cpu cpulist ] <command> [<args>]\n"));  #endif -	printf(_("cpupower --version\n")); -	printf(_("Supported subcommands are:\n")); +	printf(_("Supported commands are:\n"));  	for (i = 0; i < ARRAY_SIZE(commands); i++)  		printf("\t%s\n", commands[i].cmd); -	printf(_("\nSome subcommands can make use of the -c cpulist option.\n")); -	printf(_("Look at the general cpupower manpage how to use it\n")); -	printf(_("and read up the subcommand's manpage whether it is supported.\n")); -	printf(_("\nUse cpupower help subcommand for getting help for above subcommands.\n")); +	printf(_("\nNot all commands can make use of the -c cpulist option.\n")); +	printf(_("\nUse 'cpupower help <command>' for getting help for above commands.\n")); +} + +static int print_man_page(const char *subpage) +{ +	int len; +	char *page; + +	len = 10; /* enough for "cpupower-" */ +	if (subpage != NULL) +		len += strlen(subpage); + +	page = malloc(len); +	if (!page) +		return -ENOMEM; + +	sprintf(page, "cpupower"); +	if ((subpage != NULL) && strcmp(subpage, "help")) { +		strcat(page, "-"); +		strcat(page, subpage); +	} + +	execlp("man", "man", page, NULL); + +	/* should not be reached */ +	return -EINVAL; +} + +static int cmd_help(int argc, const char **argv) +{ +	if (argc > 1) { +		print_man_page(argv[1]); /* exits within execlp() */ +		return EXIT_FAILURE; +	} + +	print_help(); +	return EXIT_SUCCESS;  }  static void print_version(void) diff --git a/tools/power/cpupower/utils/helpers/helpers.h b/tools/power/cpupower/utils/helpers/helpers.h index 592ee362b87..2747e738efb 100644 --- a/tools/power/cpupower/utils/helpers/helpers.h +++ b/tools/power/cpupower/utils/helpers/helpers.h @@ -16,11 +16,20 @@  #include "helpers/bitmask.h"  /* Internationalization ****************************/ +#ifdef NLS +  #define _(String) gettext(String)  #ifndef gettext_noop  #define gettext_noop(String) String  #endif  #define N_(String) gettext_noop(String) + +#else /* !NLS */ + +#define _(String) String +#define N_(String) String + +#endif  /* Internationalization ****************************/  extern int run_as_root; @@ -96,6 +105,9 @@ struct cpupower_topology {  		int pkg;  		int core;  		int cpu; + +		/* flags */ +		unsigned int is_online:1;  	} *core_info;  }; diff --git a/tools/power/cpupower/utils/helpers/sysfs.c b/tools/power/cpupower/utils/helpers/sysfs.c index 55e2466674c..c6343024a61 100644 --- a/tools/power/cpupower/utils/helpers/sysfs.c +++ b/tools/power/cpupower/utils/helpers/sysfs.c @@ -56,6 +56,56 @@ static unsigned int sysfs_write_file(const char *path,  	return (unsigned int) numwrite;  } +/* + * Detect whether a CPU is online + * + * Returns: + *     1 -> if CPU is online + *     0 -> if CPU is offline + *     negative errno values in error case + */ +int sysfs_is_cpu_online(unsigned int cpu) +{ +	char path[SYSFS_PATH_MAX]; +	int fd; +	ssize_t numread; +	unsigned long long value; +	char linebuf[MAX_LINE_LEN]; +	char *endp; +	struct stat statbuf; + +	snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u", cpu); + +	if (stat(path, &statbuf) != 0) +		return 0; + +	/* +	 * kernel without CONFIG_HOTPLUG_CPU +	 * -> cpuX directory exists, but not cpuX/online file +	 */ +	snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/online", cpu); +	if (stat(path, &statbuf) != 0) +		return 1; + +	fd = open(path, O_RDONLY); +	if (fd == -1) +		return -errno; + +	numread = read(fd, linebuf, MAX_LINE_LEN - 1); +	if (numread < 1) { +		close(fd); +		return -EIO; +	} +	linebuf[numread] = '\0'; +	close(fd); + +	value = strtoull(linebuf, &endp, 0); +	if (value > 1 || value < 0) +		return -EINVAL; + +	return value; +} +  /* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */  /* diff --git a/tools/power/cpupower/utils/helpers/sysfs.h b/tools/power/cpupower/utils/helpers/sysfs.h index f9373e09063..8cb797bbceb 100644 --- a/tools/power/cpupower/utils/helpers/sysfs.h +++ b/tools/power/cpupower/utils/helpers/sysfs.h @@ -7,6 +7,8 @@  extern unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen); +extern int sysfs_is_cpu_online(unsigned int cpu); +  extern unsigned long sysfs_get_idlestate_latency(unsigned int cpu,  						unsigned int idlestate);  extern unsigned long sysfs_get_idlestate_usage(unsigned int cpu, diff --git a/tools/power/cpupower/utils/helpers/topology.c b/tools/power/cpupower/utils/helpers/topology.c index 385ee5c7570..4eae2c47ba4 100644 --- a/tools/power/cpupower/utils/helpers/topology.c +++ b/tools/power/cpupower/utils/helpers/topology.c @@ -41,6 +41,8 @@ struct cpuid_core_info {  	unsigned int pkg;  	unsigned int thread;  	unsigned int cpu; +	/* flags */ +	unsigned int is_online:1;  };  static int __compare(const void *t1, const void *t2) @@ -78,6 +80,8 @@ int get_cpu_topology(struct cpupower_topology *cpu_top)  		return -ENOMEM;  	cpu_top->pkgs = cpu_top->cores = 0;  	for (cpu = 0; cpu < cpus; cpu++) { +		cpu_top->core_info[cpu].cpu = cpu; +		cpu_top->core_info[cpu].is_online = sysfs_is_cpu_online(cpu);  		cpu_top->core_info[cpu].pkg =  			sysfs_topology_read_file(cpu, "physical_package_id");  		if ((int)cpu_top->core_info[cpu].pkg != -1 && @@ -85,7 +89,6 @@ int get_cpu_topology(struct cpupower_topology *cpu_top)  			cpu_top->pkgs = cpu_top->core_info[cpu].pkg;  		cpu_top->core_info[cpu].core =  			sysfs_topology_read_file(cpu, "core_id"); -		cpu_top->core_info[cpu].cpu = cpu;  	}  	cpu_top->pkgs++; diff --git a/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c b/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c index d048b96a615..bcd22a1a397 100644 --- a/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c +++ b/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c @@ -134,7 +134,7 @@ static struct cpuidle_monitor *cpuidle_register(void)  	/* Assume idle state count is the same for all CPUs */  	cpuidle_sysfs_monitor.hw_states_num = sysfs_get_idlestate_count(0); -	if (cpuidle_sysfs_monitor.hw_states_num == 0) +	if (cpuidle_sysfs_monitor.hw_states_num <= 0)  		return NULL;  	for (num = 0; num < cpuidle_sysfs_monitor.hw_states_num; num++) { diff --git a/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c b/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c index ba4bf068380..0d6571e418d 100644 --- a/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c +++ b/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c @@ -43,6 +43,12 @@ static struct cpupower_topology cpu_top;  /* ToDo: Document this in the manpage */  static char range_abbr[RANGE_MAX] = { 'T', 'C', 'P', 'M', }; +static void print_wrong_arg_exit(void) +{ +	printf(_("invalid or unknown argument\n")); +	exit(EXIT_FAILURE); +} +  long long timespec_diff_us(struct timespec start, struct timespec end)  {  	struct timespec temp; @@ -56,21 +62,6 @@ long long timespec_diff_us(struct timespec start, struct timespec end)  	return (temp.tv_sec * 1000000) + (temp.tv_nsec / 1000);  } -void monitor_help(void) -{ -	printf(_("cpupower monitor: [-m <mon1>,[<mon2>],.. ] command\n")); -	printf(_("cpupower monitor: [-m <mon1>,[<mon2>],.. ] [ -i interval_sec ]\n")); -	printf(_("cpupower monitor: -l\n")); -	printf(_("\t command: pass an arbitrary command to measure specific workload\n")); -	printf(_("\t -i: time intervall to measure for in seconds (default 1)\n")); -	printf(_("\t -l: list available CPU sleep monitors (for use with -m)\n")); -	printf(_("\t -m: show specific CPU sleep monitors only (in same order)\n")); -	printf(_("\t -h: print this help\n")); -	printf("\n"); -	printf(_("only one of: -l, -m are allowed\nIf none of them is passed,")); -	printf(_(" all supported monitors are shown\n")); -} -  void print_n_spaces(int n)  {  	int x; @@ -149,6 +140,10 @@ void print_results(int topology_depth, int cpu)  	unsigned long long result;  	cstate_t s; +	/* Be careful CPUs may got resorted for pkg value do not just use cpu */ +	if (!bitmask_isbitset(cpus_chosen, cpu_top.core_info[cpu].cpu)) +		return; +  	if (topology_depth > 2)  		printf("%4d|", cpu_top.core_info[cpu].pkg);  	if (topology_depth > 1) @@ -190,9 +185,13 @@ void print_results(int topology_depth, int cpu)  			}  		}  	} -	/* cpu offline */ -	if (cpu_top.core_info[cpu].pkg == -1 || -	    cpu_top.core_info[cpu].core == -1) { +	/* +	 * The monitor could still provide useful data, for example +	 * AMD HW counters partly sit in PCI config space. +	 * It's up to the monitor plug-in to check .is_online, this one +	 * is just for additional info. +	 */ +	if (!cpu_top.core_info[cpu].is_online) {  		printf(_(" *is offline\n"));  		return;  	} else @@ -238,7 +237,6 @@ static void parse_monitor_param(char *param)  	if (hits == 0) {  		printf(_("No matching monitor found in %s, "  			 "try -l option\n"), param); -		monitor_help();  		exit(EXIT_FAILURE);  	}  	/* Override detected/registerd monitors array with requested one */ @@ -335,37 +333,27 @@ static void cmdline(int argc, char *argv[])  	int opt;  	progname = basename(argv[0]); -	while ((opt = getopt(argc, argv, "+hli:m:")) != -1) { +	while ((opt = getopt(argc, argv, "+li:m:")) != -1) {  		switch (opt) { -		case 'h': -			monitor_help(); -			exit(EXIT_SUCCESS);  		case 'l': -			if (mode) { -				monitor_help(); -				exit(EXIT_FAILURE); -			} +			if (mode) +				print_wrong_arg_exit();  			mode = list;  			break;  		case 'i':  			/* only allow -i with -m or no option */ -			if (mode && mode != show) { -				monitor_help(); -				exit(EXIT_FAILURE); -			} +			if (mode && mode != show) +				print_wrong_arg_exit();  			interval = atoi(optarg);  			break;  		case 'm': -			if (mode) { -				monitor_help(); -				exit(EXIT_FAILURE); -			} +			if (mode) +				print_wrong_arg_exit();  			mode = show;  			show_monitors_param = optarg;  			break;  		default: -			monitor_help(); -			exit(EXIT_FAILURE); +			print_wrong_arg_exit();  		}  	}  	if (!mode) @@ -385,6 +373,10 @@ int cmd_monitor(int argc, char **argv)  		return EXIT_FAILURE;  	} +	/* Default is: monitor all CPUs */ +	if (bitmask_isallclear(cpus_chosen)) +		bitmask_setall(cpus_chosen); +  	dprint("System has up to %d CPU cores\n", cpu_count);  	for (num = 0; all_monitors[num]; num++) { diff --git a/tools/power/cpupower/utils/idle_monitor/mperf_monitor.c b/tools/power/cpupower/utils/idle_monitor/mperf_monitor.c index 63ca87a05e5..5650ab5a2c2 100644 --- a/tools/power/cpupower/utils/idle_monitor/mperf_monitor.c +++ b/tools/power/cpupower/utils/idle_monitor/mperf_monitor.c @@ -22,12 +22,15 @@  #define MSR_TSC	0x10 +#define MSR_AMD_HWCR 0xc0010015 +  enum mperf_id { C0 = 0, Cx, AVG_FREQ, MPERF_CSTATE_COUNT };  static int mperf_get_count_percent(unsigned int self_id, double *percent,  				   unsigned int cpu);  static int mperf_get_count_freq(unsigned int id, unsigned long long *count,  				unsigned int cpu); +static struct timespec time_start, time_end;  static cstate_t mperf_cstates[MPERF_CSTATE_COUNT] = {  	{ @@ -54,19 +57,33 @@ static cstate_t mperf_cstates[MPERF_CSTATE_COUNT] = {  	},  }; +enum MAX_FREQ_MODE { MAX_FREQ_SYSFS, MAX_FREQ_TSC_REF }; +static int max_freq_mode; +/* + * The max frequency mperf is ticking at (in C0), either retrieved via: + *   1) calculated after measurements if we know TSC ticks at mperf/P0 frequency + *   2) cpufreq /sys/devices/.../cpu0/cpufreq/cpuinfo_max_freq at init time + * 1. Is preferred as it also works without cpufreq subsystem (e.g. on Xen) + */ +static unsigned long max_frequency; +  static unsigned long long tsc_at_measure_start;  static unsigned long long tsc_at_measure_end; -static unsigned long max_frequency;  static unsigned long long *mperf_previous_count;  static unsigned long long *aperf_previous_count;  static unsigned long long *mperf_current_count;  static unsigned long long *aperf_current_count; +  /* valid flag for all CPUs. If a MSR read failed it will be zero */  static int *is_valid;  static int mperf_get_tsc(unsigned long long *tsc)  { -	return read_msr(0, MSR_TSC, tsc); +	int ret; +	ret = read_msr(0, MSR_TSC, tsc); +	if (ret) +		dprint("Reading TSC MSR failed, returning %llu\n", *tsc); +	return ret;  }  static int mperf_init_stats(unsigned int cpu) @@ -97,36 +114,11 @@ static int mperf_measure_stats(unsigned int cpu)  	return 0;  } -/* - * get_average_perf() - * - * Returns the average performance (also considers boosted frequencies) - * - * Input: - *   aperf_diff: Difference of the aperf register over a time period - *   mperf_diff: Difference of the mperf register over the same time period - *   max_freq:   Maximum frequency (P0) - * - * Returns: - *   Average performance over the time period - */ -static unsigned long get_average_perf(unsigned long long aperf_diff, -				      unsigned long long mperf_diff) -{ -	unsigned int perf_percent = 0; -	if (((unsigned long)(-1) / 100) < aperf_diff) { -		int shift_count = 7; -		aperf_diff >>= shift_count; -		mperf_diff >>= shift_count; -	} -	perf_percent = (aperf_diff * 100) / mperf_diff; -	return (max_frequency * perf_percent) / 100; -} -  static int mperf_get_count_percent(unsigned int id, double *percent,  				   unsigned int cpu)  {  	unsigned long long aperf_diff, mperf_diff, tsc_diff; +	unsigned long long timediff;  	if (!is_valid[cpu])  		return -1; @@ -136,11 +128,19 @@ static int mperf_get_count_percent(unsigned int id, double *percent,  	mperf_diff = mperf_current_count[cpu] - mperf_previous_count[cpu];  	aperf_diff = aperf_current_count[cpu] - aperf_previous_count[cpu]; -	tsc_diff = tsc_at_measure_end - tsc_at_measure_start; -	*percent = 100.0 * mperf_diff / tsc_diff; -	dprint("%s: mperf_diff: %llu, tsc_diff: %llu\n", -	       mperf_cstates[id].name, mperf_diff, tsc_diff); +	if (max_freq_mode == MAX_FREQ_TSC_REF) { +		tsc_diff = tsc_at_measure_end - tsc_at_measure_start; +		*percent = 100.0 * mperf_diff / tsc_diff; +		dprint("%s: TSC Ref - mperf_diff: %llu, tsc_diff: %llu\n", +		       mperf_cstates[id].name, mperf_diff, tsc_diff); +	} else if (max_freq_mode == MAX_FREQ_SYSFS) { +		timediff = timespec_diff_us(time_start, time_end); +		*percent = 100.0 * mperf_diff / timediff; +		dprint("%s: MAXFREQ - mperf_diff: %llu, time_diff: %llu\n", +		       mperf_cstates[id].name, mperf_diff, timediff); +	} else +		return -1;  	if (id == Cx)  		*percent = 100.0 - *percent; @@ -154,7 +154,7 @@ static int mperf_get_count_percent(unsigned int id, double *percent,  static int mperf_get_count_freq(unsigned int id, unsigned long long *count,  				unsigned int cpu)  { -	unsigned long long aperf_diff, mperf_diff; +	unsigned long long aperf_diff, mperf_diff, time_diff, tsc_diff;  	if (id != AVG_FREQ)  		return 1; @@ -165,11 +165,21 @@ static int mperf_get_count_freq(unsigned int id, unsigned long long *count,  	mperf_diff = mperf_current_count[cpu] - mperf_previous_count[cpu];  	aperf_diff = aperf_current_count[cpu] - aperf_previous_count[cpu]; -	/* Return MHz for now, might want to return KHz if column width is more -	   generic */ -	*count = get_average_perf(aperf_diff, mperf_diff) / 1000; -	dprint("%s: %llu\n", mperf_cstates[id].name, *count); +	if (max_freq_mode == MAX_FREQ_TSC_REF) { +		/* Calculate max_freq from TSC count */ +		tsc_diff = tsc_at_measure_end - tsc_at_measure_start; +		time_diff = timespec_diff_us(time_start, time_end); +		max_frequency = tsc_diff / time_diff; +	} +	*count = max_frequency * ((double)aperf_diff / mperf_diff); +	dprint("%s: Average freq based on %s maximum frequency:\n", +	       mperf_cstates[id].name, +	       (max_freq_mode == MAX_FREQ_TSC_REF) ? "TSC calculated" : "sysfs read"); +	dprint("%max_frequency: %lu", max_frequency); +	dprint("aperf_diff: %llu\n", aperf_diff); +	dprint("mperf_diff: %llu\n", mperf_diff); +	dprint("avg freq:   %llu\n", *count);  	return 0;  } @@ -178,6 +188,7 @@ static int mperf_start(void)  	int cpu;  	unsigned long long dbg; +	clock_gettime(CLOCK_REALTIME, &time_start);  	mperf_get_tsc(&tsc_at_measure_start);  	for (cpu = 0; cpu < cpu_count; cpu++) @@ -193,32 +204,104 @@ static int mperf_stop(void)  	unsigned long long dbg;  	int cpu; -	mperf_get_tsc(&tsc_at_measure_end); -  	for (cpu = 0; cpu < cpu_count; cpu++)  		mperf_measure_stats(cpu); +	mperf_get_tsc(&tsc_at_measure_end); +	clock_gettime(CLOCK_REALTIME, &time_end); +  	mperf_get_tsc(&dbg);  	dprint("TSC diff: %llu\n", dbg - tsc_at_measure_end);  	return 0;  } -struct cpuidle_monitor mperf_monitor; - -struct cpuidle_monitor *mperf_register(void) +/* + * Mperf register is defined to tick at P0 (maximum) frequency + * + * Instead of reading out P0 which can be tricky to read out from HW, + * we use TSC counter if it reliably ticks at P0/mperf frequency. + * + * Still try to fall back to: + * /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq + * on older Intel HW without invariant TSC feature. + * Or on AMD machines where TSC does not tick at P0 (do not exist yet, but + * it's still double checked (MSR_AMD_HWCR)). + * + * On these machines the user would still get useful mperf + * stats when acpi-cpufreq driver is loaded. + */ +static int init_maxfreq_mode(void)  { +	int ret; +	unsigned long long hwcr;  	unsigned long min; -	if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_APERF)) -		return NULL; +	if (!cpupower_cpu_info.caps & CPUPOWER_CAP_INV_TSC) +		goto use_sysfs; -	/* Assume min/max all the same on all cores */ +	if (cpupower_cpu_info.vendor == X86_VENDOR_AMD) { +		/* MSR_AMD_HWCR tells us whether TSC runs at P0/mperf +		 * freq. +		 * A test whether hwcr is accessable/available would be: +		 * (cpupower_cpu_info.family > 0x10 || +		 *   cpupower_cpu_info.family == 0x10 && +		 *   cpupower_cpu_info.model >= 0x2)) +		 * This should be the case for all aperf/mperf +		 * capable AMD machines and is therefore safe to test here. +		 * Compare with Linus kernel git commit: acf01734b1747b1ec4 +		 */ +		ret = read_msr(0, MSR_AMD_HWCR, &hwcr); +		/* +		 * If the MSR read failed, assume a Xen system that did +		 * not explicitly provide access to it and assume TSC works +		*/ +		if (ret != 0) { +			dprint("TSC read 0x%x failed - assume TSC working\n", +			       MSR_AMD_HWCR); +			return 0; +		} else if (1 & (hwcr >> 24)) { +			max_freq_mode = MAX_FREQ_TSC_REF; +			return 0; +		} else { /* Use sysfs max frequency if available */ } +	} else if (cpupower_cpu_info.vendor == X86_VENDOR_INTEL) { +		/* +		 * On Intel we assume mperf (in C0) is ticking at same +		 * rate than TSC +		 */ +		max_freq_mode = MAX_FREQ_TSC_REF; +		return 0; +	} +use_sysfs:  	if (cpufreq_get_hardware_limits(0, &min, &max_frequency)) {  		dprint("Cannot retrieve max freq from cpufreq kernel "  		       "subsystem\n"); -		return NULL; +		return -1;  	} +	max_freq_mode = MAX_FREQ_SYSFS; +	return 0; +} + +/* + * This monitor provides: + * + * 1) Average frequency a CPU resided in + *    This always works if the CPU has aperf/mperf capabilities + * + * 2) C0 and Cx (any sleep state) time a CPU resided in + *    Works if mperf timer stops ticking in sleep states which + *    seem to be the case on all current HW. + * Both is directly retrieved from HW registers and is independent + * from kernel statistics. + */ +struct cpuidle_monitor mperf_monitor; +struct cpuidle_monitor *mperf_register(void) +{ +	if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_APERF)) +		return NULL; + +	if (init_maxfreq_mode()) +		return NULL;  	/* Free this at program termination */  	is_valid = calloc(cpu_count, sizeof(int));  |