Patches contributed by Eötvös Lorand University
commit 53cb8bc2a3d976efd1a800c3de4640a7220afbb3
Author: Ingo Molnar <mingo@elte.hu>
Date: Tue May 26 09:17:18 2009 +0200
perf record: Convert to Git option parsing
Remove getopt usage and use Git's much more advanced and more compact
command option library.
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Corey Ashford <cjashfor@linux.vnet.ibm.com>
Cc: Marcelo Tosatti <mtosatti@redhat.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: John Kacur <jkacur@redhat.com>
LKML-Reference: <new-submission>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
diff --git a/Documentation/perf_counter/builtin-report.c b/Documentation/perf_counter/builtin-report.c
index 21386a8c6f62..9e59d6071ef3 100644
--- a/Documentation/perf_counter/builtin-report.c
+++ b/Documentation/perf_counter/builtin-report.c
@@ -1,52 +1,29 @@
-#define _GNU_SOURCE
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <unistd.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <string.h>
-#include <limits.h>
+#include "util/util.h"
+
+#include <libelf.h>
#include <gelf.h>
#include <elf.h>
-#include <libelf.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <errno.h>
-#include <ctype.h>
-#include <time.h>
-#include <getopt.h>
-#include <assert.h>
-#include <search.h>
-
-#include <sys/ioctl.h>
-#include <sys/poll.h>
-#include <sys/prctl.h>
-#include <sys/wait.h>
-#include <sys/mman.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include <linux/unistd.h>
-#include <linux/types.h>
-
-#include "../../include/linux/perf_counter.h"
+
#include "util/list.h"
#include "util/rbtree.h"
+#include "perf.h"
+
+#include "util/parse-options.h"
+#include "util/parse-events.h"
+
#define SHOW_KERNEL 1
#define SHOW_USER 2
#define SHOW_HV 4
-static char const *input_name = "output.perf";
+static char const *input_name = "output.perf";
static int input;
static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV;
static unsigned long page_size;
static unsigned long mmap_window = 32;
-static const char *perf_event_names[] = {
+const char *perf_event_names[] = {
[PERF_EVENT_MMAP] = " PERF_EVENT_MMAP",
[PERF_EVENT_MUNMAP] = " PERF_EVENT_MUNMAP",
[PERF_EVENT_COMM] = " PERF_EVENT_COMM",
@@ -86,7 +63,7 @@ struct section {
char name[0];
};
-static struct section *section__new(uint64_t start, uint64_t size,
+struct section *section__new(uint64_t start, uint64_t size,
uint64_t offset, char *name)
{
struct section *self = malloc(sizeof(*self) + strlen(name) + 1);
@@ -241,7 +218,7 @@ static inline uint8_t elf_sym__type(const GElf_Sym *sym)
return GELF_ST_TYPE(sym->st_info);
}
-static inline bool elf_sym__is_function(const GElf_Sym *sym)
+static inline int elf_sym__is_function(const GElf_Sym *sym)
{
return elf_sym__type(sym) == STT_FUNC &&
sym->st_name != 0 &&
@@ -393,7 +370,7 @@ static struct dso *dsos__findnew(const char *name)
return NULL;
}
-static void dsos__fprintf(FILE *fp)
+void dsos__fprintf(FILE *fp)
{
struct dso *pos;
@@ -503,7 +480,7 @@ static struct symhist *symhist__new(struct symbol *sym, uint64_t ip,
return self;
}
-static void symhist__delete(struct symhist *self)
+void symhist__delete(struct symhist *self)
{
free(self);
}
@@ -587,7 +564,7 @@ static int thread__set_comm(struct thread *self, const char *comm)
return self->comm ? 0 : -ENOMEM;
}
-static size_t thread__maps_fprintf(struct thread *self, FILE *fp)
+size_t thread__maps_fprintf(struct thread *self, FILE *fp)
{
struct map *pos;
size_t ret = 0;
@@ -668,49 +645,7 @@ static void threads__fprintf(FILE *fp)
}
}
-static void display_help(void)
-{
- printf(
- "Usage: perf-report [<options>]\n"
- " -i file --input=<file> # input file\n"
- );
-
- exit(0);
-}
-
-static void process_options(int argc, char *argv[])
-{
- int error = 0;
-
- for (;;) {
- int option_index = 0;
- /** Options for getopt */
- static struct option long_options[] = {
- {"input", required_argument, NULL, 'i'},
- {"no-user", no_argument, NULL, 'u'},
- {"no-kernel", no_argument, NULL, 'k'},
- {"no-hv", no_argument, NULL, 'h'},
- {NULL, 0, NULL, 0 }
- };
- int c = getopt_long(argc, argv, "+:i:kuh",
- long_options, &option_index);
- if (c == -1)
- break;
-
- switch (c) {
- case 'i': input_name = strdup(optarg); break;
- case 'k': show_mask &= ~SHOW_KERNEL; break;
- case 'u': show_mask &= ~SHOW_USER; break;
- case 'h': show_mask &= ~SHOW_HV; break;
- default: error = 1; break;
- }
- }
-
- if (error)
- display_help();
-}
-
-int cmd_report(int argc, char **argv)
+static int __cmd_report(void)
{
unsigned long offset = 0;
unsigned long head = 0;
@@ -720,12 +655,6 @@ int cmd_report(int argc, char **argv)
int ret, rc = EXIT_FAILURE;
unsigned long total = 0;
- elf_version(EV_CURRENT);
-
- page_size = getpagesize();
-
- process_options(argc, argv);
-
input = open(input_name, O_RDONLY);
if (input < 0) {
perror("failed to open file");
@@ -867,3 +796,24 @@ int cmd_report(int argc, char **argv)
return rc;
}
+static const char * const report_usage[] = {
+ "perf report [<options>] <command>",
+ NULL
+};
+
+static const struct option options[] = {
+ OPT_STRING('i', "input", &input_name, "file",
+ "input file name"),
+ OPT_END()
+};
+
+int cmd_report(int argc, const char **argv, const char *prefix)
+{
+ elf_version(EV_CURRENT);
+
+ page_size = getpagesize();
+
+ parse_options(argc, argv, options, report_usage, 0);
+
+ return __cmd_report();
+}
commit fd4242bb35b70557eee8d0c79f82dacc3f3b89e0
Author: Ingo Molnar <mingo@elte.hu>
Date: Wed May 20 12:45:34 2009 +0200
perf_counter tools: remove the standalone perf-report utility
With a built-in 'perf report' command now available, remove the
standalone implementation for good.
Acked-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Corey Ashford <cjashfor@linux.vnet.ibm.com>
Cc: Marcelo Tosatti <mtosatti@redhat.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
LKML-Reference: <new-submission>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
diff --git a/Documentation/perf_counter/perf-report.cc b/Documentation/perf_counter/perf-report.cc
deleted file mode 100644
index 8855107fe6b3..000000000000
--- a/Documentation/perf_counter/perf-report.cc
+++ /dev/null
@@ -1,515 +0,0 @@
-#define _GNU_SOURCE
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <unistd.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <limits.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <errno.h>
-#include <ctype.h>
-#include <time.h>
-#include <getopt.h>
-#include <assert.h>
-
-#include <sys/ioctl.h>
-#include <sys/poll.h>
-#include <sys/prctl.h>
-#include <sys/wait.h>
-#include <sys/mman.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include <linux/unistd.h>
-#include <linux/types.h>
-
-#include "../../include/linux/perf_counter.h"
-
-#include <set>
-#include <map>
-#include <string>
-
-
-#define SHOW_KERNEL 1
-#define SHOW_USER 2
-#define SHOW_HV 4
-
-static char const *input_name = "output.perf";
-static int input;
-static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV;
-
-static unsigned long page_size;
-static unsigned long mmap_window = 32;
-
-struct ip_event {
- struct perf_event_header header;
- __u64 ip;
- __u32 pid, tid;
-};
-struct mmap_event {
- struct perf_event_header header;
- __u32 pid, tid;
- __u64 start;
- __u64 len;
- __u64 pgoff;
- char filename[PATH_MAX];
-};
-struct comm_event {
- struct perf_event_header header;
- __u32 pid,tid;
- char comm[16];
-};
-
-typedef union event_union {
- struct perf_event_header header;
- struct ip_event ip;
- struct mmap_event mmap;
- struct comm_event comm;
-} event_t;
-
-struct section {
- uint64_t start;
- uint64_t end;
-
- uint64_t offset;
-
- std::string name;
-
- section() { };
-
- section(uint64_t stab) : end(stab) { };
-
- section(uint64_t start, uint64_t size, uint64_t offset, std::string name) :
- start(start), end(start + size), offset(offset), name(name)
- { };
-
- bool operator < (const struct section &s) const {
- return end < s.end;
- };
-};
-
-typedef std::set<struct section> sections_t;
-
-struct symbol {
- uint64_t start;
- uint64_t end;
-
- std::string name;
-
- symbol() { };
-
- symbol(uint64_t ip) : start(ip) { }
-
- symbol(uint64_t start, uint64_t len, std::string name) :
- start(start), end(start + len), name(name)
- { };
-
- bool operator < (const struct symbol &s) const {
- return start < s.start;
- };
-};
-
-typedef std::set<struct symbol> symbols_t;
-
-struct dso {
- sections_t sections;
- symbols_t syms;
-};
-
-static std::map<std::string, struct dso> dsos;
-
-static void load_dso_sections(std::string dso_name)
-{
- struct dso &dso = dsos[dso_name];
-
- std::string cmd = "readelf -DSW " + dso_name;
-
- FILE *file = popen(cmd.c_str(), "r");
- if (!file) {
- perror("failed to open pipe");
- exit(-1);
- }
-
- char *line = NULL;
- size_t n = 0;
-
- while (!feof(file)) {
- uint64_t addr, off, size;
- char name[32];
-
- if (getline(&line, &n, file) < 0)
- break;
- if (!line)
- break;
-
- if (sscanf(line, " [%*2d] %16s %*14s %Lx %Lx %Lx",
- name, &addr, &off, &size) == 4) {
-
- dso.sections.insert(section(addr, size, addr - off, name));
- }
-#if 0
- /*
- * for reading readelf symbols (-s), however these don't seem
- * to include nearly everything, so use nm for that.
- */
- if (sscanf(line, " %*4d %*3d: %Lx %5Lu %*7s %*6s %*7s %3d %s",
- &start, &size, §ion, sym) == 4) {
-
- start -= dso.section_offsets[section];
-
- dso.syms.insert(symbol(start, size, std::string(sym)));
- }
-#endif
- }
- pclose(file);
-}
-
-static void load_dso_symbols(std::string dso_name, std::string args)
-{
- struct dso &dso = dsos[dso_name];
-
- std::string cmd = "nm -nSC " + args + " " + dso_name;
-
- FILE *file = popen(cmd.c_str(), "r");
- if (!file) {
- perror("failed to open pipe");
- exit(-1);
- }
-
- char *line = NULL;
- size_t n = 0;
-
- while (!feof(file)) {
- uint64_t start, size;
- char c;
- char sym[1024];
-
- if (getline(&line, &n, file) < 0)
- break;
- if (!line)
- break;
-
-
- if (sscanf(line, "%Lx %Lx %c %s", &start, &size, &c, sym) == 4) {
- sections_t::const_iterator si =
- dso.sections.upper_bound(section(start));
- if (si == dso.sections.end()) {
- printf("symbol in unknown section: %s\n", sym);
- continue;
- }
-
- start -= si->offset;
-
- dso.syms.insert(symbol(start, size, sym));
- }
- }
- pclose(file);
-}
-
-static void load_dso(std::string dso_name)
-{
- load_dso_sections(dso_name);
- load_dso_symbols(dso_name, "-D"); /* dynamic symbols */
- load_dso_symbols(dso_name, ""); /* regular ones */
-}
-
-void load_kallsyms(void)
-{
- struct dso &dso = dsos["[kernel]"];
-
- FILE *file = fopen("/proc/kallsyms", "r");
- if (!file) {
- perror("failed to open kallsyms");
- exit(-1);
- }
-
- char *line;
- size_t n;
-
- while (!feof(file)) {
- uint64_t start;
- char c;
- char sym[1024000];
-
- if (getline(&line, &n, file) < 0)
- break;
- if (!line)
- break;
-
- if (sscanf(line, "%Lx %c %s", &start, &c, sym) == 3)
- dso.syms.insert(symbol(start, 0x1000000, std::string(sym)));
- }
- fclose(file);
-}
-
-struct map {
- uint64_t start;
- uint64_t end;
- uint64_t pgoff;
-
- std::string dso;
-
- map() { };
-
- map(uint64_t ip) : end(ip) { }
-
- map(mmap_event *mmap) {
- start = mmap->start;
- end = mmap->start + mmap->len;
- pgoff = mmap->pgoff;
-
- dso = std::string(mmap->filename);
-
- if (dsos.find(dso) == dsos.end())
- load_dso(dso);
- };
-
- bool operator < (const struct map &m) const {
- return end < m.end;
- };
-};
-
-typedef std::set<struct map> maps_t;
-
-static std::map<int, maps_t> maps;
-
-static std::map<int, std::string> comms;
-
-static std::map<std::string, int> hist;
-static std::multimap<int, std::string> rev_hist;
-
-static std::string resolve_comm(int pid)
-{
- std::string comm;
-
- std::map<int, std::string>::const_iterator ci = comms.find(pid);
- if (ci != comms.end()) {
- comm = ci->second;
- } else {
- char pid_str[30];
-
- sprintf(pid_str, ":%d", pid);
- comm = pid_str;
- }
-
- return comm;
-}
-
-static std::string resolve_user_symbol(int pid, uint64_t ip)
-{
- std::string sym = "<unknown>";
-
- maps_t &m = maps[pid];
- maps_t::const_iterator mi = m.upper_bound(map(ip));
- if (mi == m.end())
- return sym;
-
- ip -= mi->start + mi->pgoff;
-
- symbols_t &s = dsos[mi->dso].syms;
- symbols_t::const_iterator si = s.upper_bound(symbol(ip));
-
- sym = mi->dso + ": <unknown>";
-
- if (si == s.begin())
- return sym;
- si--;
-
- if (si->start <= ip && ip < si->end)
- sym = mi->dso + ": " + si->name;
-#if 0
- else if (si->start <= ip)
- sym = mi->dso + ": ?" + si->name;
-#endif
-
- return sym;
-}
-
-static std::string resolve_kernel_symbol(uint64_t ip)
-{
- std::string sym = "<unknown>";
-
- symbols_t &s = dsos["[kernel]"].syms;
- symbols_t::const_iterator si = s.upper_bound(symbol(ip));
-
- if (si == s.begin())
- return sym;
- si--;
-
- if (si->start <= ip && ip < si->end)
- sym = si->name;
-
- return sym;
-}
-
-static void display_help(void)
-{
- printf(
- "Usage: perf-report [<options>]\n"
- " -i file --input=<file> # input file\n"
- );
-
- exit(0);
-}
-
-static void process_options(int argc, char *argv[])
-{
- int error = 0;
-
- for (;;) {
- int option_index = 0;
- /** Options for getopt */
- static struct option long_options[] = {
- {"input", required_argument, NULL, 'i'},
- {"no-user", no_argument, NULL, 'u'},
- {"no-kernel", no_argument, NULL, 'k'},
- {"no-hv", no_argument, NULL, 'h'},
- {NULL, 0, NULL, 0 }
- };
- int c = getopt_long(argc, argv, "+:i:kuh",
- long_options, &option_index);
- if (c == -1)
- break;
-
- switch (c) {
- case 'i': input_name = strdup(optarg); break;
- case 'k': show_mask &= ~SHOW_KERNEL; break;
- case 'u': show_mask &= ~SHOW_USER; break;
- case 'h': show_mask &= ~SHOW_HV; break;
- default: error = 1; break;
- }
- }
-
- if (error)
- display_help();
-}
-
-int main(int argc, char *argv[])
-{
- unsigned long offset = 0;
- unsigned long head = 0;
- struct stat stat;
- char *buf;
- event_t *event;
- int ret;
- unsigned long total = 0;
-
- page_size = getpagesize();
-
- process_options(argc, argv);
-
- input = open(input_name, O_RDONLY);
- if (input < 0) {
- perror("failed to open file");
- exit(-1);
- }
-
- ret = fstat(input, &stat);
- if (ret < 0) {
- perror("failed to stat file");
- exit(-1);
- }
-
- if (!stat.st_size) {
- fprintf(stderr, "zero-sized file, nothing to do!\n");
- exit(0);
- }
-
- load_kallsyms();
-
-remap:
- buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
- MAP_SHARED, input, offset);
- if (buf == MAP_FAILED) {
- perror("failed to mmap file");
- exit(-1);
- }
-
-more:
- event = (event_t *)(buf + head);
-
- if (head + event->header.size >= page_size * mmap_window) {
- unsigned long shift = page_size * (head / page_size);
- int ret;
-
- ret = munmap(buf, page_size * mmap_window);
- assert(ret == 0);
-
- offset += shift;
- head -= shift;
- goto remap;
- }
-
-
- if (!event->header.size) {
- fprintf(stderr, "zero-sized event at file offset %ld\n", offset + head);
- fprintf(stderr, "skipping %ld bytes of events.\n", stat.st_size - offset - head);
- goto done;
- }
-
- head += event->header.size;
-
- if (event->header.misc & PERF_EVENT_MISC_OVERFLOW) {
- std::string comm, sym, level;
- int show = 0;
- char output[1024];
-
- if (event->header.misc & PERF_EVENT_MISC_KERNEL) {
- show |= SHOW_KERNEL;
- level = " [k] ";
- sym = resolve_kernel_symbol(event->ip.ip);
- } else if (event->header.misc & PERF_EVENT_MISC_USER) {
- show |= SHOW_USER;
- level = " [.] ";
- sym = resolve_user_symbol(event->ip.pid, event->ip.ip);
- } else {
- show |= SHOW_HV;
- level = " [H] ";
- }
-
- if (show & show_mask) {
- comm = resolve_comm(event->ip.pid);
- snprintf(output, sizeof(output), "%16s %s %s",
- comm.c_str(), level.c_str(), sym.c_str());
- hist[output]++;
- }
-
- total++;
-
- } else switch (event->header.type) {
- case PERF_EVENT_MMAP:
- maps[event->mmap.pid].insert(map(&event->mmap));
- break;
-
- case PERF_EVENT_COMM:
- comms[event->comm.pid] = std::string(event->comm.comm);
- break;
- }
-
- if (offset + head < stat.st_size)
- goto more;
-
-done:
-
- close(input);
-
- std::map<std::string, int>::iterator hi = hist.begin();
-
- while (hi != hist.end()) {
- rev_hist.insert(std::pair<int, std::string>(hi->second, hi->first));
- hist.erase(hi++);
- }
-
- std::multimap<int, std::string>::const_iterator ri = rev_hist.begin();
-
- while (ri != rev_hist.end()) {
- printf(" %5.2f %s\n", (100.0 * ri->first)/total, ri->second.c_str());
- ri++;
- }
-
- return 0;
-}
-
commit b456bae0ff4f3cf91639dd32b2bfc49b1c30b4b0
Author: Ingo Molnar <mingo@elte.hu>
Date: Tue May 26 09:17:18 2009 +0200
perf top: Convert to Git option parsing
Remove getopt usage and use Git's much more advanced and more compact
command option library.
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Corey Ashford <cjashfor@linux.vnet.ibm.com>
Cc: Marcelo Tosatti <mtosatti@redhat.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: John Kacur <jkacur@redhat.com>
LKML-Reference: <new-submission>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
diff --git a/Documentation/perf_counter/builtin-top.c b/Documentation/perf_counter/builtin-top.c
index 626b32076499..87b925c8f8e8 100644
--- a/Documentation/perf_counter/builtin-top.c
+++ b/Documentation/perf_counter/builtin-top.c
@@ -45,8 +45,10 @@
#include "perf.h"
#include "util/util.h"
+#include "util/util.h"
+#include "util/parse-options.h"
+#include "util/parse-events.h"
-#include <getopt.h>
#include <assert.h>
#include <fcntl.h>
@@ -70,8 +72,7 @@
static int system_wide = 0;
-static int nr_counters = 0;
-static __u64 event_id[MAX_COUNTERS] = {
+static __u64 default_event_id[MAX_COUNTERS] = {
EID(PERF_TYPE_SOFTWARE, PERF_COUNT_TASK_CLOCK),
EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CONTEXT_SWITCHES),
EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CPU_MIGRATIONS),
@@ -88,7 +89,7 @@ static int fd[MAX_NR_CPUS][MAX_COUNTERS];
static __u64 count_filter = 100;
-static int tid = -1;
+static int target_pid = -1;
static int profile_cpu = -1;
static int nr_cpus = 0;
static int nmi = 1;
@@ -100,8 +101,6 @@ static int use_mmap = 0;
static int use_munmap = 0;
static int freq = 0;
-static char *vmlinux;
-
static char *sym_filter;
static unsigned long filter_start;
static unsigned long filter_end;
@@ -110,18 +109,6 @@ static int delay_secs = 2;
static int zero;
static int dump_symtab;
-static int scale;
-
-struct source_line {
- uint64_t EIP;
- unsigned long count;
- char *line;
- struct source_line *next;
-};
-
-static struct source_line *lines;
-static struct source_line **lines_tail;
-
static const unsigned int default_count[] = {
1000000,
1000000,
@@ -131,194 +118,6 @@ static const unsigned int default_count[] = {
10000,
};
-static char *hw_event_names[] = {
- "CPU cycles",
- "instructions",
- "cache references",
- "cache misses",
- "branches",
- "branch misses",
- "bus cycles",
-};
-
-static char *sw_event_names[] = {
- "cpu clock ticks",
- "task clock ticks",
- "pagefaults",
- "context switches",
- "CPU migrations",
- "minor faults",
- "major faults",
-};
-
-struct event_symbol {
- __u64 event;
- char *symbol;
-};
-
-static struct event_symbol event_symbols[] = {
- {EID(PERF_TYPE_HARDWARE, PERF_COUNT_CPU_CYCLES), "cpu-cycles", },
- {EID(PERF_TYPE_HARDWARE, PERF_COUNT_CPU_CYCLES), "cycles", },
- {EID(PERF_TYPE_HARDWARE, PERF_COUNT_INSTRUCTIONS), "instructions", },
- {EID(PERF_TYPE_HARDWARE, PERF_COUNT_CACHE_REFERENCES), "cache-references", },
- {EID(PERF_TYPE_HARDWARE, PERF_COUNT_CACHE_MISSES), "cache-misses", },
- {EID(PERF_TYPE_HARDWARE, PERF_COUNT_BRANCH_INSTRUCTIONS), "branch-instructions", },
- {EID(PERF_TYPE_HARDWARE, PERF_COUNT_BRANCH_INSTRUCTIONS), "branches", },
- {EID(PERF_TYPE_HARDWARE, PERF_COUNT_BRANCH_MISSES), "branch-misses", },
- {EID(PERF_TYPE_HARDWARE, PERF_COUNT_BUS_CYCLES), "bus-cycles", },
-
- {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CPU_CLOCK), "cpu-clock", },
- {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_TASK_CLOCK), "task-clock", },
- {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_PAGE_FAULTS), "page-faults", },
- {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_PAGE_FAULTS), "faults", },
- {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_PAGE_FAULTS_MIN), "minor-faults", },
- {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_PAGE_FAULTS_MAJ), "major-faults", },
- {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CONTEXT_SWITCHES), "context-switches", },
- {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CONTEXT_SWITCHES), "cs", },
- {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CPU_MIGRATIONS), "cpu-migrations", },
- {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CPU_MIGRATIONS), "migrations", },
-};
-
-#define __PERF_COUNTER_FIELD(config, name) \
- ((config & PERF_COUNTER_##name##_MASK) >> PERF_COUNTER_##name##_SHIFT)
-
-#define PERF_COUNTER_RAW(config) __PERF_COUNTER_FIELD(config, RAW)
-#define PERF_COUNTER_CONFIG(config) __PERF_COUNTER_FIELD(config, CONFIG)
-#define PERF_COUNTER_TYPE(config) __PERF_COUNTER_FIELD(config, TYPE)
-#define PERF_COUNTER_ID(config) __PERF_COUNTER_FIELD(config, EVENT)
-
-static void display_events_help(void)
-{
- unsigned int i;
- __u64 e;
-
- printf(
- " -e EVENT --event=EVENT # symbolic-name abbreviations");
-
- for (i = 0; i < ARRAY_SIZE(event_symbols); i++) {
- int type, id;
-
- e = event_symbols[i].event;
- type = PERF_COUNTER_TYPE(e);
- id = PERF_COUNTER_ID(e);
-
- printf("\n %d:%d: %-20s",
- type, id, event_symbols[i].symbol);
- }
-
- printf("\n"
- " rNNN: raw PMU events (eventsel+umask)\n\n");
-}
-
-static void display_help(void)
-{
- printf(
- "Usage: kerneltop [<options>]\n"
- " Or: kerneltop -S [<options>] COMMAND [ARGS]\n\n"
- "KernelTop Options (up to %d event types can be specified at once):\n\n",
- MAX_COUNTERS);
-
- display_events_help();
-
- printf(
- " -c CNT --count=CNT # event period to sample\n\n"
- " -C CPU --cpu=CPU # CPU (-1 for all) [default: -1]\n"
- " -p PID --pid=PID # PID of sampled task (-1 for all) [default: -1]\n\n"
- " -l # show scale factor for RR events\n"
- " -d delay --delay=<seconds> # sampling/display delay [default: 2]\n"
- " -f CNT --filter=CNT # min-event-count filter [default: 100]\n\n"
- " -r prio --realtime=<prio> # event acquisition runs with SCHED_FIFO policy\n"
- " -s symbol --symbol=<symbol> # function to be showed annotated one-shot\n"
- " -x path --vmlinux=<path> # the vmlinux binary, required for -s use\n"
- " -z --zero # zero counts after display\n"
- " -D --dump_symtab # dump symbol table to stderr on startup\n"
- " -m pages --mmap_pages=<pages> # number of mmap data pages\n"
- " -M --mmap_info # print mmap info stream\n"
- " -U --munmap_info # print munmap info stream\n"
- );
-
- exit(0);
-}
-
-static char *event_name(int ctr)
-{
- __u64 config = event_id[ctr];
- int type = PERF_COUNTER_TYPE(config);
- int id = PERF_COUNTER_ID(config);
- static char buf[32];
-
- if (PERF_COUNTER_RAW(config)) {
- sprintf(buf, "raw 0x%llx", PERF_COUNTER_CONFIG(config));
- return buf;
- }
-
- switch (type) {
- case PERF_TYPE_HARDWARE:
- if (id < PERF_HW_EVENTS_MAX)
- return hw_event_names[id];
- return "unknown-hardware";
-
- case PERF_TYPE_SOFTWARE:
- if (id < PERF_SW_EVENTS_MAX)
- return sw_event_names[id];
- return "unknown-software";
-
- default:
- break;
- }
-
- return "unknown";
-}
-
-/*
- * Each event can have multiple symbolic names.
- * Symbolic names are (almost) exactly matched.
- */
-static __u64 match_event_symbols(char *str)
-{
- __u64 config, id;
- int type;
- unsigned int i;
-
- if (sscanf(str, "r%llx", &config) == 1)
- return config | PERF_COUNTER_RAW_MASK;
-
- if (sscanf(str, "%d:%llu", &type, &id) == 2)
- return EID(type, id);
-
- for (i = 0; i < ARRAY_SIZE(event_symbols); i++) {
- if (!strncmp(str, event_symbols[i].symbol,
- strlen(event_symbols[i].symbol)))
- return event_symbols[i].event;
- }
-
- return ~0ULL;
-}
-
-static int parse_events(char *str)
-{
- __u64 config;
-
-again:
- if (nr_counters == MAX_COUNTERS)
- return -1;
-
- config = match_event_symbols(str);
- if (config == ~0ULL)
- return -1;
-
- event_id[nr_counters] = config;
- nr_counters++;
-
- str = strstr(str, ",");
- if (str) {
- str++;
- goto again;
- }
-
- return 0;
-}
-
/*
* Symbols
*/
@@ -331,7 +130,6 @@ struct sym_entry {
char *sym;
unsigned long count[MAX_COUNTERS];
int skip;
- struct source_line *source;
};
#define MAX_SYMS 100000
@@ -342,8 +140,6 @@ struct sym_entry *sym_filter_entry;
static struct sym_entry sym_table[MAX_SYMS];
-static void show_details(struct sym_entry *sym);
-
/*
* Ordering weight: count-1 * count-2 * ... / count-n
*/
@@ -419,15 +215,15 @@ static void print_sym_table(void)
printf( "], ");
- if (tid != -1)
- printf(" (tid: %d", tid);
+ if (target_pid != -1)
+ printf(" (target_pid: %d", target_pid);
else
printf(" (all");
if (profile_cpu != -1)
printf(", cpu: %d)\n", profile_cpu);
else {
- if (tid != -1)
+ if (target_pid != -1)
printf(")\n");
else
printf(", %d CPUs)\n", nr_cpus);
@@ -463,9 +259,6 @@ static void print_sym_table(void)
pcnt, tmp[i].addr, tmp[i].sym);
}
- if (sym_filter_entry)
- show_details(sym_filter_entry);
-
{
struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
@@ -628,134 +421,8 @@ static void parse_symbols(void)
}
}
-/*
- * Source lines
- */
-
-static void parse_vmlinux(char *filename)
-{
- FILE *file;
- char command[PATH_MAX*2];
- if (!filename)
- return;
-
- sprintf(command, "objdump --start-address=0x%016lx --stop-address=0x%016lx -dS %s", filter_start, filter_end, filename);
-
- file = popen(command, "r");
- if (!file)
- return;
-
- lines_tail = &lines;
- while (!feof(file)) {
- struct source_line *src;
- size_t dummy = 0;
- char *c;
-
- src = malloc(sizeof(struct source_line));
- assert(src != NULL);
- memset(src, 0, sizeof(struct source_line));
-
- if (getline(&src->line, &dummy, file) < 0)
- break;
- if (!src->line)
- break;
-
- c = strchr(src->line, '\n');
- if (c)
- *c = 0;
-
- src->next = NULL;
- *lines_tail = src;
- lines_tail = &src->next;
-
- if (strlen(src->line)>8 && src->line[8] == ':')
- src->EIP = strtoull(src->line, NULL, 16);
- if (strlen(src->line)>8 && src->line[16] == ':')
- src->EIP = strtoull(src->line, NULL, 16);
- }
- pclose(file);
-}
-
-static void record_precise_ip(uint64_t ip)
-{
- struct source_line *line;
-
- for (line = lines; line; line = line->next) {
- if (line->EIP == ip)
- line->count++;
- if (line->EIP > ip)
- break;
- }
-}
-
-static void lookup_sym_in_vmlinux(struct sym_entry *sym)
-{
- struct source_line *line;
- char pattern[PATH_MAX];
- sprintf(pattern, "<%s>:", sym->sym);
-
- for (line = lines; line; line = line->next) {
- if (strstr(line->line, pattern)) {
- sym->source = line;
- break;
- }
- }
-}
-
-static void show_lines(struct source_line *line_queue, int line_queue_count)
-{
- int i;
- struct source_line *line;
-
- line = line_queue;
- for (i = 0; i < line_queue_count; i++) {
- printf("%8li\t%s\n", line->count, line->line);
- line = line->next;
- }
-}
-
#define TRACE_COUNT 3
-static void show_details(struct sym_entry *sym)
-{
- struct source_line *line;
- struct source_line *line_queue = NULL;
- int displayed = 0;
- int line_queue_count = 0;
-
- if (!sym->source)
- lookup_sym_in_vmlinux(sym);
- if (!sym->source)
- return;
-
- printf("Showing details for %s\n", sym->sym);
-
- line = sym->source;
- while (line) {
- if (displayed && strstr(line->line, ">:"))
- break;
-
- if (!line_queue_count)
- line_queue = line;
- line_queue_count ++;
-
- if (line->count >= count_filter) {
- show_lines(line_queue, line_queue_count);
- line_queue_count = 0;
- line_queue = NULL;
- } else if (line_queue_count > TRACE_COUNT) {
- line_queue = line_queue->next;
- line_queue_count --;
- }
-
- line->count = 0;
- displayed++;
- if (displayed > 300)
- break;
- line = line->next;
- }
-}
-
/*
* Binary search in the histogram table and record the hit:
*/
@@ -764,8 +431,6 @@ static void record_ip(uint64_t ip, int counter)
int left_idx, middle_idx, right_idx, idx;
unsigned long left, middle, right;
- record_precise_ip(ip);
-
left_idx = 0;
right_idx = sym_table_count-1;
assert(ip <= max_ip && ip >= min_ip);
@@ -822,97 +487,6 @@ static void process_event(uint64_t ip, int counter)
record_ip(ip, counter);
}
-static void process_options(int argc, char **argv)
-{
- int error = 0, counter;
-
- for (;;) {
- int option_index = 0;
- /** Options for getopt */
- static struct option long_options[] = {
- {"count", required_argument, NULL, 'c'},
- {"cpu", required_argument, NULL, 'C'},
- {"delay", required_argument, NULL, 'd'},
- {"dump_symtab", no_argument, NULL, 'D'},
- {"event", required_argument, NULL, 'e'},
- {"filter", required_argument, NULL, 'f'},
- {"group", required_argument, NULL, 'g'},
- {"help", no_argument, NULL, 'h'},
- {"nmi", required_argument, NULL, 'n'},
- {"mmap_info", no_argument, NULL, 'M'},
- {"mmap_pages", required_argument, NULL, 'm'},
- {"munmap_info", no_argument, NULL, 'U'},
- {"pid", required_argument, NULL, 'p'},
- {"realtime", required_argument, NULL, 'r'},
- {"scale", no_argument, NULL, 'l'},
- {"symbol", required_argument, NULL, 's'},
- {"stat", no_argument, NULL, 'S'},
- {"vmlinux", required_argument, NULL, 'x'},
- {"zero", no_argument, NULL, 'z'},
- {"freq", required_argument, NULL, 'F'},
- {NULL, 0, NULL, 0 }
- };
- int c = getopt_long(argc, argv, "+:ac:C:d:De:f:g:hln:m:p:r:s:Sx:zMUF:",
- long_options, &option_index);
- if (c == -1)
- break;
-
- switch (c) {
- case 'a': system_wide = 1; break;
- case 'c': default_interval = atoi(optarg); break;
- case 'C':
- /* CPU and PID are mutually exclusive */
- if (tid != -1) {
- printf("WARNING: CPU switch overriding PID\n");
- sleep(1);
- tid = -1;
- }
- profile_cpu = atoi(optarg); break;
- case 'd': delay_secs = atoi(optarg); break;
- case 'D': dump_symtab = 1; break;
-
- case 'e': error = parse_events(optarg); break;
-
- case 'f': count_filter = atoi(optarg); break;
- case 'g': group = atoi(optarg); break;
- case 'h': display_help(); break;
- case 'l': scale = 1; break;
- case 'n': nmi = atoi(optarg); break;
- case 'p':
- /* CPU and PID are mutually exclusive */
- if (profile_cpu != -1) {
- printf("WARNING: PID switch overriding CPU\n");
- sleep(1);
- profile_cpu = -1;
- }
- tid = atoi(optarg); break;
- case 'r': realtime_prio = atoi(optarg); break;
- case 's': sym_filter = strdup(optarg); break;
- case 'x': vmlinux = strdup(optarg); break;
- case 'z': zero = 1; break;
- case 'm': mmap_pages = atoi(optarg); break;
- case 'M': use_mmap = 1; break;
- case 'U': use_munmap = 1; break;
- case 'F': freq = 1; default_interval = atoi(optarg); break;
- default: error = 1; break;
- }
- }
- if (error)
- display_help();
-
- if (!nr_counters) {
- nr_counters = 1;
- event_id[0] = 0;
- }
-
- for (counter = 0; counter < nr_counters; counter++) {
- if (event_count[counter])
- continue;
-
- event_count[counter] = default_interval;
- }
-}
-
struct mmap_data {
int counter;
void *base;
@@ -973,11 +547,11 @@ static void mmap_read(struct mmap_data *md)
struct ip_event {
struct perf_event_header header;
__u64 ip;
- __u32 pid, tid;
+ __u32 pid, target_pid;
};
struct mmap_event {
struct perf_event_header header;
- __u32 pid, tid;
+ __u32 pid, target_pid;
__u64 start;
__u64 len;
__u64 pgoff;
@@ -1043,7 +617,7 @@ static void mmap_read(struct mmap_data *md)
static struct pollfd event_array[MAX_NR_CPUS * MAX_COUNTERS];
static struct mmap_data mmap_array[MAX_NR_CPUS][MAX_COUNTERS];
-int cmd_top(int argc, char **argv, const char *prefix)
+static int __cmd_top(void)
{
struct perf_counter_hw_event hw_event;
pthread_t thread;
@@ -1051,27 +625,12 @@ int cmd_top(int argc, char **argv, const char *prefix)
unsigned int cpu;
int ret;
- page_size = sysconf(_SC_PAGE_SIZE);
-
- process_options(argc, argv);
-
- nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
- assert(nr_cpus <= MAX_NR_CPUS);
- assert(nr_cpus >= 0);
-
- if (tid != -1 || profile_cpu != -1)
- nr_cpus = 1;
-
- parse_symbols();
- if (vmlinux && sym_filter_entry)
- parse_vmlinux(vmlinux);
-
for (i = 0; i < nr_cpus; i++) {
group_fd = -1;
for (counter = 0; counter < nr_counters; counter++) {
cpu = profile_cpu;
- if (tid == -1 && profile_cpu == -1)
+ if (target_pid == -1 && profile_cpu == -1)
cpu = i;
memset(&hw_event, 0, sizeof(hw_event));
@@ -1083,7 +642,7 @@ int cmd_top(int argc, char **argv, const char *prefix)
hw_event.munmap = use_munmap;
hw_event.freq = freq;
- fd[i][counter] = sys_perf_counter_open(&hw_event, tid, cpu, group_fd, 0);
+ fd[i][counter] = sys_perf_counter_open(&hw_event, target_pid, cpu, group_fd, 0);
if (fd[i][counter] < 0) {
int err = errno;
printf("kerneltop error: syscall returned with %d (%s)\n",
@@ -1147,3 +706,95 @@ int cmd_top(int argc, char **argv, const char *prefix)
return 0;
}
+
+static const char * const top_usage[] = {
+ "perf top [<options>]",
+ NULL
+};
+
+static char events_help_msg[EVENTS_HELP_MAX];
+
+static const struct option options[] = {
+ OPT_CALLBACK('e', "event", NULL, "event",
+ events_help_msg, parse_events),
+ OPT_INTEGER('c', "count", &default_interval,
+ "event period to sample"),
+ OPT_INTEGER('p', "pid", &target_pid,
+ "profile events on existing pid"),
+ OPT_BOOLEAN('a', "all-cpus", &system_wide,
+ "system-wide collection from all CPUs"),
+ OPT_INTEGER('C', "CPU", &profile_cpu,
+ "CPU to profile on"),
+ OPT_INTEGER('m', "mmap-pages", &mmap_pages,
+ "number of mmap data pages"),
+ OPT_INTEGER('r', "realtime", &realtime_prio,
+ "collect data with this RT SCHED_FIFO priority"),
+ OPT_INTEGER('d', "delay", &realtime_prio,
+ "number of seconds to delay between refreshes"),
+ OPT_BOOLEAN('D', "dump-symtab", &dump_symtab,
+ "dump the symbol table used for profiling"),
+ OPT_INTEGER('f', "--count-filter", &count_filter,
+ "only display functions with more events than this"),
+ OPT_BOOLEAN('g', "group", &group,
+ "put the counters into a counter group"),
+ OPT_STRING('s', "sym-filter", &sym_filter, "pattern",
+ "only display symbols matchig this pattern"),
+ OPT_BOOLEAN('z', "zero", &group,
+ "zero history across updates"),
+ OPT_BOOLEAN('M', "use-mmap", &use_mmap,
+ "track mmap events"),
+ OPT_BOOLEAN('U', "use-munmap", &use_munmap,
+ "track munmap events"),
+ OPT_INTEGER('F', "--freq", &freq,
+ "profile at this frequency"),
+ OPT_END()
+};
+
+int cmd_top(int argc, const char **argv, const char *prefix)
+{
+ int counter;
+
+ page_size = sysconf(_SC_PAGE_SIZE);
+
+ create_events_help(events_help_msg);
+ memcpy(event_id, default_event_id, sizeof(default_event_id));
+
+ argc = parse_options(argc, argv, options, top_usage, 0);
+ if (argc)
+ usage_with_options(top_usage, options);
+
+ if (freq) {
+ default_interval = freq;
+ freq = 1;
+ }
+
+ /* CPU and PID are mutually exclusive */
+ if (target_pid != -1 && profile_cpu != -1) {
+ printf("WARNING: PID switch overriding CPU\n");
+ sleep(1);
+ profile_cpu = -1;
+ }
+
+ if (!nr_counters) {
+ nr_counters = 1;
+ event_id[0] = 0;
+ }
+
+ for (counter = 0; counter < nr_counters; counter++) {
+ if (event_count[counter])
+ continue;
+
+ event_count[counter] = default_interval;
+ }
+
+ nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
+ assert(nr_cpus <= MAX_NR_CPUS);
+ assert(nr_cpus >= 0);
+
+ if (target_pid != -1 || profile_cpu != -1)
+ nr_cpus = 1;
+
+ parse_symbols();
+
+ return __cmd_top();
+}
commit 5242519b0296d128425368fc6ab17f541d5fa775
Author: Ingo Molnar <mingo@elte.hu>
Date: Tue May 26 09:17:18 2009 +0200
perf stat: Convert to Git option parsing
Remove getopt usage and use Git's much more advanced and more compact
command option library.
Extend the event parser library with the extensions that were in
perf-stat before.
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Corey Ashford <cjashfor@linux.vnet.ibm.com>
Cc: Marcelo Tosatti <mtosatti@redhat.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: John Kacur <jkacur@redhat.com>
LKML-Reference: <new-submission>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
diff --git a/Documentation/perf_counter/builtin-record.c b/Documentation/perf_counter/builtin-record.c
index 6fa6ed664950..ec2b787b23bd 100644
--- a/Documentation/perf_counter/builtin-record.c
+++ b/Documentation/perf_counter/builtin-record.c
@@ -4,7 +4,6 @@
#include "util/util.h"
#include "util/parse-options.h"
#include "util/parse-events.h"
-#include "util/exec_cmd.h"
#include <sched.h>
@@ -400,7 +399,7 @@ static const char * const record_usage[] = {
static char events_help_msg[EVENTS_HELP_MAX];
-const struct option options[] = {
+static const struct option options[] = {
OPT_CALLBACK('e', "event", NULL, "event",
events_help_msg, parse_events),
OPT_INTEGER('c', "count", &default_interval,
diff --git a/Documentation/perf_counter/builtin-stat.c b/Documentation/perf_counter/builtin-stat.c
index c1053d820c1f..e7cb9412212b 100644
--- a/Documentation/perf_counter/builtin-stat.c
+++ b/Documentation/perf_counter/builtin-stat.c
@@ -1,35 +1,5 @@
/*
- * kerneltop.c: show top kernel functions - performance counters showcase
-
- Build with:
-
- cc -O6 -Wall -c -o kerneltop.o kerneltop.c -lrt
-
- Sample output:
-
-------------------------------------------------------------------------------
- KernelTop: 2669 irqs/sec [NMI, cache-misses/cache-refs], (all, cpu: 2)
-------------------------------------------------------------------------------
-
- weight RIP kernel function
- ______ ________________ _______________
-
- 35.20 - ffffffff804ce74b : skb_copy_and_csum_dev
- 33.00 - ffffffff804cb740 : sock_alloc_send_skb
- 31.26 - ffffffff804ce808 : skb_push
- 22.43 - ffffffff80510004 : tcp_established_options
- 19.00 - ffffffff8027d250 : find_get_page
- 15.76 - ffffffff804e4fc9 : eth_type_trans
- 15.20 - ffffffff804d8baa : dst_release
- 14.86 - ffffffff804cf5d8 : skb_release_head_state
- 14.00 - ffffffff802217d5 : read_hpet
- 12.00 - ffffffff804ffb7f : __ip_local_out
- 11.97 - ffffffff804fc0c8 : ip_local_deliver_finish
- 8.54 - ffffffff805001a3 : ip_queue_xmit
- */
-
-/*
- * perfstat: /usr/bin/time -alike performance counter statistics utility
+ * perf stat: /usr/bin/time -alike performance counter statistics utility
It summarizes the counter events of all tasks (and child tasks),
covering all CPUs that the command (or workload) executes on.
@@ -38,59 +8,38 @@
Sample output:
- $ ./perfstat -e 1 -e 3 -e 5 ls -lR /usr/include/ >/dev/null
+ $ perf stat -e 1 -e 3 -e 5 ls -lR /usr/include/ >/dev/null
Performance counter stats for 'ls':
163516953 instructions
2295 cache-misses
2855182 branch-misses
+ *
+ * Copyright (C) 2008, Red Hat Inc, Ingo Molnar <mingo@redhat.com>
+ *
+ * Improvements and fixes by:
+ *
+ * Arjan van de Ven <arjan@linux.intel.com>
+ * Yanmin Zhang <yanmin.zhang@intel.com>
+ * Wu Fengguang <fengguang.wu@intel.com>
+ * Mike Galbraith <efault@gmx.de>
+ * Paul Mackerras <paulus@samba.org>
+ *
+ * Released under the GPL v2. (and only v2, not any later version)
*/
- /*
- * Copyright (C) 2008, Red Hat Inc, Ingo Molnar <mingo@redhat.com>
- *
- * Improvements and fixes by:
- *
- * Arjan van de Ven <arjan@linux.intel.com>
- * Yanmin Zhang <yanmin.zhang@intel.com>
- * Wu Fengguang <fengguang.wu@intel.com>
- * Mike Galbraith <efault@gmx.de>
- * Paul Mackerras <paulus@samba.org>
- *
- * Released under the GPL v2. (and only v2, not any later version)
- */
-
#include "perf.h"
#include "util/util.h"
+#include "util/parse-options.h"
+#include "util/parse-events.h"
-#include <getopt.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <errno.h>
-#include <time.h>
-#include <sched.h>
-#include <pthread.h>
-
-#include <sys/syscall.h>
-#include <sys/ioctl.h>
-#include <sys/poll.h>
#include <sys/prctl.h>
-#include <sys/wait.h>
-#include <sys/uio.h>
-#include <sys/mman.h>
-
-#include <linux/unistd.h>
-#include <linux/types.h>
-
-#define EVENT_MASK_KERNEL 1
-#define EVENT_MASK_USER 2
static int system_wide = 0;
+static int inherit = 1;
-static int nr_counters = 0;
-static __u64 event_id[MAX_COUNTERS] = {
+static __u64 default_event_id[MAX_COUNTERS] = {
EID(PERF_TYPE_SOFTWARE, PERF_COUNT_TASK_CLOCK),
EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CONTEXT_SWITCHES),
EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CPU_MIGRATIONS),
@@ -101,20 +50,15 @@ static __u64 event_id[MAX_COUNTERS] = {
EID(PERF_TYPE_HARDWARE, PERF_COUNT_CACHE_REFERENCES),
EID(PERF_TYPE_HARDWARE, PERF_COUNT_CACHE_MISSES),
};
+
static int default_interval = 100000;
static int event_count[MAX_COUNTERS];
static int fd[MAX_NR_CPUS][MAX_COUNTERS];
-static int event_mask[MAX_COUNTERS];
-static int tid = -1;
-static int profile_cpu = -1;
+static int target_pid = -1;
static int nr_cpus = 0;
-static int nmi = 1;
-static int group = 0;
static unsigned int page_size;
-static int zero;
-
static int scale = 1;
static const unsigned int default_count[] = {
@@ -126,197 +70,6 @@ static const unsigned int default_count[] = {
10000,
};
-static char *hw_event_names[] = {
- "CPU cycles",
- "instructions",
- "cache references",
- "cache misses",
- "branches",
- "branch misses",
- "bus cycles",
-};
-
-static char *sw_event_names[] = {
- "cpu clock ticks",
- "task clock ticks",
- "pagefaults",
- "context switches",
- "CPU migrations",
- "minor faults",
- "major faults",
-};
-
-struct event_symbol {
- __u64 event;
- char *symbol;
-};
-
-static struct event_symbol event_symbols[] = {
- {EID(PERF_TYPE_HARDWARE, PERF_COUNT_CPU_CYCLES), "cpu-cycles", },
- {EID(PERF_TYPE_HARDWARE, PERF_COUNT_CPU_CYCLES), "cycles", },
- {EID(PERF_TYPE_HARDWARE, PERF_COUNT_INSTRUCTIONS), "instructions", },
- {EID(PERF_TYPE_HARDWARE, PERF_COUNT_CACHE_REFERENCES), "cache-references", },
- {EID(PERF_TYPE_HARDWARE, PERF_COUNT_CACHE_MISSES), "cache-misses", },
- {EID(PERF_TYPE_HARDWARE, PERF_COUNT_BRANCH_INSTRUCTIONS), "branch-instructions", },
- {EID(PERF_TYPE_HARDWARE, PERF_COUNT_BRANCH_INSTRUCTIONS), "branches", },
- {EID(PERF_TYPE_HARDWARE, PERF_COUNT_BRANCH_MISSES), "branch-misses", },
- {EID(PERF_TYPE_HARDWARE, PERF_COUNT_BUS_CYCLES), "bus-cycles", },
-
- {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CPU_CLOCK), "cpu-clock", },
- {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_TASK_CLOCK), "task-clock", },
- {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_PAGE_FAULTS), "page-faults", },
- {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_PAGE_FAULTS), "faults", },
- {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_PAGE_FAULTS_MIN), "minor-faults", },
- {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_PAGE_FAULTS_MAJ), "major-faults", },
- {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CONTEXT_SWITCHES), "context-switches", },
- {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CONTEXT_SWITCHES), "cs", },
- {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CPU_MIGRATIONS), "cpu-migrations", },
- {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CPU_MIGRATIONS), "migrations", },
-};
-
-#define __PERF_COUNTER_FIELD(config, name) \
- ((config & PERF_COUNTER_##name##_MASK) >> PERF_COUNTER_##name##_SHIFT)
-
-#define PERF_COUNTER_RAW(config) __PERF_COUNTER_FIELD(config, RAW)
-#define PERF_COUNTER_CONFIG(config) __PERF_COUNTER_FIELD(config, CONFIG)
-#define PERF_COUNTER_TYPE(config) __PERF_COUNTER_FIELD(config, TYPE)
-#define PERF_COUNTER_ID(config) __PERF_COUNTER_FIELD(config, EVENT)
-
-static void display_events_help(void)
-{
- unsigned int i;
- __u64 e;
-
- printf(
- " -e EVENT --event=EVENT # symbolic-name abbreviations");
-
- for (i = 0; i < ARRAY_SIZE(event_symbols); i++) {
- int type, id;
-
- e = event_symbols[i].event;
- type = PERF_COUNTER_TYPE(e);
- id = PERF_COUNTER_ID(e);
-
- printf("\n %d:%d: %-20s",
- type, id, event_symbols[i].symbol);
- }
-
- printf("\n"
- " rNNN: raw PMU events (eventsel+umask)\n\n");
-}
-
-static void display_help(void)
-{
- printf(
- "Usage: perfstat [<events...>] <cmd...>\n\n"
- "PerfStat Options (up to %d event types can be specified):\n\n",
- MAX_COUNTERS);
-
- display_events_help();
-
- printf(
- " -l # scale counter values\n"
- " -a # system-wide collection\n");
- exit(0);
-}
-
-static char *event_name(int ctr)
-{
- __u64 config = event_id[ctr];
- int type = PERF_COUNTER_TYPE(config);
- int id = PERF_COUNTER_ID(config);
- static char buf[32];
-
- if (PERF_COUNTER_RAW(config)) {
- sprintf(buf, "raw 0x%llx", PERF_COUNTER_CONFIG(config));
- return buf;
- }
-
- switch (type) {
- case PERF_TYPE_HARDWARE:
- if (id < PERF_HW_EVENTS_MAX)
- return hw_event_names[id];
- return "unknown-hardware";
-
- case PERF_TYPE_SOFTWARE:
- if (id < PERF_SW_EVENTS_MAX)
- return sw_event_names[id];
- return "unknown-software";
-
- default:
- break;
- }
-
- return "unknown";
-}
-
-/*
- * Each event can have multiple symbolic names.
- * Symbolic names are (almost) exactly matched.
- */
-static __u64 match_event_symbols(char *str)
-{
- __u64 config, id;
- int type;
- unsigned int i;
- char mask_str[4];
-
- if (sscanf(str, "r%llx", &config) == 1)
- return config | PERF_COUNTER_RAW_MASK;
-
- switch (sscanf(str, "%d:%llu:%2s", &type, &id, mask_str)) {
- case 3:
- if (strchr(mask_str, 'k'))
- event_mask[nr_counters] |= EVENT_MASK_USER;
- if (strchr(mask_str, 'u'))
- event_mask[nr_counters] |= EVENT_MASK_KERNEL;
- case 2:
- return EID(type, id);
-
- default:
- break;
- }
-
- for (i = 0; i < ARRAY_SIZE(event_symbols); i++) {
- if (!strncmp(str, event_symbols[i].symbol,
- strlen(event_symbols[i].symbol)))
- return event_symbols[i].event;
- }
-
- return ~0ULL;
-}
-
-static int parse_events(char *str)
-{
- __u64 config;
-
-again:
- if (nr_counters == MAX_COUNTERS)
- return -1;
-
- config = match_event_symbols(str);
- if (config == ~0ULL)
- return -1;
-
- event_id[nr_counters] = config;
- nr_counters++;
-
- str = strstr(str, ",");
- if (str) {
- str++;
- goto again;
- }
-
- return 0;
-}
-
-
-/*
- * perfstat
- */
-
-char fault_here[1000000];
-
static void create_perfstat_counter(int counter)
{
struct perf_counter_hw_event hw_event;
@@ -324,7 +77,7 @@ static void create_perfstat_counter(int counter)
memset(&hw_event, 0, sizeof(hw_event));
hw_event.config = event_id[counter];
hw_event.record_type = 0;
- hw_event.nmi = 0;
+ hw_event.nmi = 1;
hw_event.exclude_kernel = event_mask[counter] & EVENT_MASK_KERNEL;
hw_event.exclude_user = event_mask[counter] & EVENT_MASK_USER;
@@ -343,7 +96,7 @@ static void create_perfstat_counter(int counter)
}
}
} else {
- hw_event.inherit = 1;
+ hw_event.inherit = inherit;
hw_event.disabled = 1;
fd[0][counter] = sys_perf_counter_open(&hw_event, 0, -1, -1, 0);
@@ -355,7 +108,7 @@ static void create_perfstat_counter(int counter)
}
}
-int do_perfstat(int argc, char *argv[])
+int do_perfstat(int argc, const char **argv)
{
unsigned long long t0, t1;
int counter;
@@ -369,12 +122,6 @@ int do_perfstat(int argc, char *argv[])
for (counter = 0; counter < nr_counters; counter++)
create_perfstat_counter(counter);
- argc -= optind;
- argv += optind;
-
- if (!argc)
- display_help();
-
/*
* Enable counters and exec the command:
*/
@@ -384,7 +131,7 @@ int do_perfstat(int argc, char *argv[])
if ((pid = fork()) < 0)
perror("failed to fork");
if (!pid) {
- if (execvp(argv[0], argv)) {
+ if (execvp(argv[0], (char **)argv)) {
perror(argv[0]);
exit(-1);
}
@@ -458,70 +205,45 @@ int do_perfstat(int argc, char *argv[])
return 0;
}
-static void process_options(int argc, char **argv)
+static void skip_signal(int signo)
{
- int error = 0, counter;
-
- for (;;) {
- int option_index = 0;
- /** Options for getopt */
- static struct option long_options[] = {
- {"count", required_argument, NULL, 'c'},
- {"cpu", required_argument, NULL, 'C'},
- {"delay", required_argument, NULL, 'd'},
- {"dump_symtab", no_argument, NULL, 'D'},
- {"event", required_argument, NULL, 'e'},
- {"filter", required_argument, NULL, 'f'},
- {"group", required_argument, NULL, 'g'},
- {"help", no_argument, NULL, 'h'},
- {"nmi", required_argument, NULL, 'n'},
- {"munmap_info", no_argument, NULL, 'U'},
- {"pid", required_argument, NULL, 'p'},
- {"realtime", required_argument, NULL, 'r'},
- {"scale", no_argument, NULL, 'l'},
- {"symbol", required_argument, NULL, 's'},
- {"stat", no_argument, NULL, 'S'},
- {"vmlinux", required_argument, NULL, 'x'},
- {"zero", no_argument, NULL, 'z'},
- {NULL, 0, NULL, 0 }
- };
- int c = getopt_long(argc, argv, "+:ac:C:d:De:f:g:hln:m:p:r:s:Sx:zMU",
- long_options, &option_index);
- if (c == -1)
- break;
-
- switch (c) {
- case 'a': system_wide = 1; break;
- case 'c': default_interval = atoi(optarg); break;
- case 'C':
- /* CPU and PID are mutually exclusive */
- if (tid != -1) {
- printf("WARNING: CPU switch overriding PID\n");
- sleep(1);
- tid = -1;
- }
- profile_cpu = atoi(optarg); break;
-
- case 'e': error = parse_events(optarg); break;
-
- case 'g': group = atoi(optarg); break;
- case 'h': display_help(); break;
- case 'l': scale = 1; break;
- case 'n': nmi = atoi(optarg); break;
- case 'p':
- /* CPU and PID are mutually exclusive */
- if (profile_cpu != -1) {
- printf("WARNING: PID switch overriding CPU\n");
- sleep(1);
- profile_cpu = -1;
- }
- tid = atoi(optarg); break;
- case 'z': zero = 1; break;
- default: error = 1; break;
- }
- }
- if (error)
- display_help();
+}
+
+static const char * const stat_usage[] = {
+ "perf stat [<options>] <command>",
+ NULL
+};
+
+static char events_help_msg[EVENTS_HELP_MAX];
+
+static const struct option options[] = {
+ OPT_CALLBACK('e', "event", NULL, "event",
+ events_help_msg, parse_events),
+ OPT_INTEGER('c', "count", &default_interval,
+ "event period to sample"),
+ OPT_BOOLEAN('i', "inherit", &inherit,
+ "child tasks inherit counters"),
+ OPT_INTEGER('p', "pid", &target_pid,
+ "stat events on existing pid"),
+ OPT_BOOLEAN('a', "all-cpus", &system_wide,
+ "system-wide collection from all CPUs"),
+ OPT_BOOLEAN('l', "scale", &scale,
+ "scale/normalize counters"),
+ OPT_END()
+};
+
+int cmd_stat(int argc, const char **argv, const char *prefix)
+{
+ int counter;
+
+ page_size = sysconf(_SC_PAGE_SIZE);
+
+ create_events_help(events_help_msg);
+ memcpy(event_id, default_event_id, sizeof(default_event_id));
+
+ argc = parse_options(argc, argv, options, stat_usage, 0);
+ if (!argc)
+ usage_with_options(stat_usage, options);
if (!nr_counters) {
nr_counters = 8;
@@ -533,18 +255,6 @@ static void process_options(int argc, char **argv)
event_count[counter] = default_interval;
}
-}
-
-static void skip_signal(int signo)
-{
-}
-
-int cmd_stat(int argc, char **argv, const char *prefix)
-{
- page_size = sysconf(_SC_PAGE_SIZE);
-
- process_options(argc, argv);
-
nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
assert(nr_cpus <= MAX_NR_CPUS);
assert(nr_cpus >= 0);
diff --git a/Documentation/perf_counter/util/parse-events.c b/Documentation/perf_counter/util/parse-events.c
index 77d0917d55d3..88c903eb260a 100644
--- a/Documentation/perf_counter/util/parse-events.c
+++ b/Documentation/perf_counter/util/parse-events.c
@@ -8,6 +8,7 @@
int nr_counters;
__u64 event_id[MAX_COUNTERS] = { };
+int event_mask[MAX_COUNTERS];
struct event_symbol {
__u64 event;
@@ -37,6 +38,64 @@ static struct event_symbol event_symbols[] = {
{EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CPU_MIGRATIONS), "migrations", },
};
+#define __PERF_COUNTER_FIELD(config, name) \
+ ((config & PERF_COUNTER_##name##_MASK) >> PERF_COUNTER_##name##_SHIFT)
+
+#define PERF_COUNTER_RAW(config) __PERF_COUNTER_FIELD(config, RAW)
+#define PERF_COUNTER_CONFIG(config) __PERF_COUNTER_FIELD(config, CONFIG)
+#define PERF_COUNTER_TYPE(config) __PERF_COUNTER_FIELD(config, TYPE)
+#define PERF_COUNTER_ID(config) __PERF_COUNTER_FIELD(config, EVENT)
+
+static char *hw_event_names[] = {
+ "CPU cycles",
+ "instructions",
+ "cache references",
+ "cache misses",
+ "branches",
+ "branch misses",
+ "bus cycles",
+};
+
+static char *sw_event_names[] = {
+ "cpu clock ticks",
+ "task clock ticks",
+ "pagefaults",
+ "context switches",
+ "CPU migrations",
+ "minor faults",
+ "major faults",
+};
+
+char *event_name(int ctr)
+{
+ __u64 config = event_id[ctr];
+ int type = PERF_COUNTER_TYPE(config);
+ int id = PERF_COUNTER_ID(config);
+ static char buf[32];
+
+ if (PERF_COUNTER_RAW(config)) {
+ sprintf(buf, "raw 0x%llx", PERF_COUNTER_CONFIG(config));
+ return buf;
+ }
+
+ switch (type) {
+ case PERF_TYPE_HARDWARE:
+ if (id < PERF_HW_EVENTS_MAX)
+ return hw_event_names[id];
+ return "unknown-hardware";
+
+ case PERF_TYPE_SOFTWARE:
+ if (id < PERF_SW_EVENTS_MAX)
+ return sw_event_names[id];
+ return "unknown-software";
+
+ default:
+ break;
+ }
+
+ return "unknown";
+}
+
/*
* Each event can have multiple symbolic names.
* Symbolic names are (almost) exactly matched.
@@ -46,12 +105,23 @@ static __u64 match_event_symbols(const char *str)
__u64 config, id;
int type;
unsigned int i;
+ char mask_str[4];
if (sscanf(str, "r%llx", &config) == 1)
return config | PERF_COUNTER_RAW_MASK;
- if (sscanf(str, "%d:%llu", &type, &id) == 2)
- return EID(type, id);
+ switch (sscanf(str, "%d:%llu:%2s", &type, &id, mask_str)) {
+ case 3:
+ if (strchr(mask_str, 'k'))
+ event_mask[nr_counters] |= EVENT_MASK_USER;
+ if (strchr(mask_str, 'u'))
+ event_mask[nr_counters] |= EVENT_MASK_KERNEL;
+ case 2:
+ return EID(type, id);
+
+ default:
+ break;
+ }
for (i = 0; i < ARRAY_SIZE(event_symbols); i++) {
if (!strncmp(str, event_symbols[i].symbol,
@@ -86,14 +156,6 @@ int parse_events(const struct option *opt, const char *str, int unset)
return 0;
}
-#define __PERF_COUNTER_FIELD(config, name) \
- ((config & PERF_COUNTER_##name##_MASK) >> PERF_COUNTER_##name##_SHIFT)
-
-#define PERF_COUNTER_RAW(config) __PERF_COUNTER_FIELD(config, RAW)
-#define PERF_COUNTER_CONFIG(config) __PERF_COUNTER_FIELD(config, CONFIG)
-#define PERF_COUNTER_TYPE(config) __PERF_COUNTER_FIELD(config, TYPE)
-#define PERF_COUNTER_ID(config) __PERF_COUNTER_FIELD(config, EVENT)
-
/*
* Create the help text for the event symbols:
*/
diff --git a/Documentation/perf_counter/util/parse-events.h b/Documentation/perf_counter/util/parse-events.h
index 6e2ebe5ff7d7..0da306bb9028 100644
--- a/Documentation/perf_counter/util/parse-events.h
+++ b/Documentation/perf_counter/util/parse-events.h
@@ -1,6 +1,16 @@
+/*
+ * Parse symbolic events/counts passed in as options:
+ */
+
extern int nr_counters;
extern __u64 event_id[MAX_COUNTERS];
+extern int event_mask[MAX_COUNTERS];
+
+#define EVENT_MASK_KERNEL 1
+#define EVENT_MASK_USER 2
+
+extern char *event_name(int ctr);
extern int parse_events(const struct option *opt, const char *str, int unset);
commit 8ad8db3788fd9a449941fb2392ca85af4ee1cde1
Author: Ingo Molnar <mingo@elte.hu>
Date: Tue May 26 11:10:09 2009 +0200
perf_counter tools: Librarize event string parsing
Extract the event string parser from builtin-record.c, and
librarize it - to be reused in other commands.
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Corey Ashford <cjashfor@linux.vnet.ibm.com>
Cc: Marcelo Tosatti <mtosatti@redhat.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: John Kacur <jkacur@redhat.com>
LKML-Reference: <new-submission>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
diff --git a/Documentation/perf_counter/Makefile b/Documentation/perf_counter/Makefile
index 481e4c26cd45..45daa72facdc 100644
--- a/Documentation/perf_counter/Makefile
+++ b/Documentation/perf_counter/Makefile
@@ -290,6 +290,7 @@ LIB_H += ../../include/linux/perf_counter.h
LIB_H += perf.h
LIB_H += util/levenshtein.h
LIB_H += util/parse-options.h
+LIB_H += util/parse-events.h
LIB_H += util/quote.h
LIB_H += util/util.h
LIB_H += util/help.h
@@ -304,6 +305,7 @@ LIB_OBJS += util/exec_cmd.o
LIB_OBJS += util/help.o
LIB_OBJS += util/levenshtein.o
LIB_OBJS += util/parse-options.o
+LIB_OBJS += util/parse-events.o
LIB_OBJS += util/path.o
LIB_OBJS += util/run-command.o
LIB_OBJS += util/quote.o
diff --git a/Documentation/perf_counter/builtin-record.c b/Documentation/perf_counter/builtin-record.c
index f12a7822fcf1..6fa6ed664950 100644
--- a/Documentation/perf_counter/builtin-record.c
+++ b/Documentation/perf_counter/builtin-record.c
@@ -3,44 +3,17 @@
#include "perf.h"
#include "util/util.h"
#include "util/parse-options.h"
+#include "util/parse-events.h"
#include "util/exec_cmd.h"
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <unistd.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <limits.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <errno.h>
-#include <time.h>
#include <sched.h>
-#include <pthread.h>
-
-#include <sys/syscall.h>
-#include <sys/ioctl.h>
-#include <sys/poll.h>
-#include <sys/prctl.h>
-#include <sys/wait.h>
-#include <sys/uio.h>
-#include <sys/mman.h>
-
-#include <linux/unistd.h>
-#include <linux/types.h>
-
-
#define ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a)-1)
#define __ALIGN_MASK(x, mask) (((x)+(mask))&~(mask))
-static int nr_counters = 0;
-static __u64 event_id[MAX_COUNTERS] = { };
static int default_interval = 100000;
static int event_count[MAX_COUNTERS];
+
static int fd[MAX_NR_CPUS][MAX_COUNTERS];
static int nr_cpus = 0;
static unsigned int page_size;
@@ -420,131 +393,16 @@ static int __cmd_record(int argc, const char **argv)
return 0;
}
-struct event_symbol {
- __u64 event;
- char *symbol;
-};
-
-static struct event_symbol event_symbols[] = {
- {EID(PERF_TYPE_HARDWARE, PERF_COUNT_CPU_CYCLES), "cpu-cycles", },
- {EID(PERF_TYPE_HARDWARE, PERF_COUNT_CPU_CYCLES), "cycles", },
- {EID(PERF_TYPE_HARDWARE, PERF_COUNT_INSTRUCTIONS), "instructions", },
- {EID(PERF_TYPE_HARDWARE, PERF_COUNT_CACHE_REFERENCES), "cache-references", },
- {EID(PERF_TYPE_HARDWARE, PERF_COUNT_CACHE_MISSES), "cache-misses", },
- {EID(PERF_TYPE_HARDWARE, PERF_COUNT_BRANCH_INSTRUCTIONS), "branch-instructions", },
- {EID(PERF_TYPE_HARDWARE, PERF_COUNT_BRANCH_INSTRUCTIONS), "branches", },
- {EID(PERF_TYPE_HARDWARE, PERF_COUNT_BRANCH_MISSES), "branch-misses", },
- {EID(PERF_TYPE_HARDWARE, PERF_COUNT_BUS_CYCLES), "bus-cycles", },
-
- {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CPU_CLOCK), "cpu-clock", },
- {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_TASK_CLOCK), "task-clock", },
- {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_PAGE_FAULTS), "page-faults", },
- {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_PAGE_FAULTS), "faults", },
- {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_PAGE_FAULTS_MIN), "minor-faults", },
- {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_PAGE_FAULTS_MAJ), "major-faults", },
- {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CONTEXT_SWITCHES), "context-switches", },
- {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CONTEXT_SWITCHES), "cs", },
- {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CPU_MIGRATIONS), "cpu-migrations", },
- {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CPU_MIGRATIONS), "migrations", },
-};
-
-/*
- * Each event can have multiple symbolic names.
- * Symbolic names are (almost) exactly matched.
- */
-static __u64 match_event_symbols(const char *str)
-{
- __u64 config, id;
- int type;
- unsigned int i;
-
- if (sscanf(str, "r%llx", &config) == 1)
- return config | PERF_COUNTER_RAW_MASK;
-
- if (sscanf(str, "%d:%llu", &type, &id) == 2)
- return EID(type, id);
-
- for (i = 0; i < ARRAY_SIZE(event_symbols); i++) {
- if (!strncmp(str, event_symbols[i].symbol,
- strlen(event_symbols[i].symbol)))
- return event_symbols[i].event;
- }
-
- return ~0ULL;
-}
-
-static int parse_events(const struct option *opt, const char *str, int unset)
-{
- __u64 config;
-
-again:
- if (nr_counters == MAX_COUNTERS)
- return -1;
-
- config = match_event_symbols(str);
- if (config == ~0ULL)
- return -1;
-
- event_id[nr_counters] = config;
- nr_counters++;
-
- str = strstr(str, ",");
- if (str) {
- str++;
- goto again;
- }
-
- return 0;
-}
-
-static char events_help[100000];
-
-#define __PERF_COUNTER_FIELD(config, name) \
- ((config & PERF_COUNTER_##name##_MASK) >> PERF_COUNTER_##name##_SHIFT)
-
-#define PERF_COUNTER_RAW(config) __PERF_COUNTER_FIELD(config, RAW)
-#define PERF_COUNTER_CONFIG(config) __PERF_COUNTER_FIELD(config, CONFIG)
-#define PERF_COUNTER_TYPE(config) __PERF_COUNTER_FIELD(config, TYPE)
-#define PERF_COUNTER_ID(config) __PERF_COUNTER_FIELD(config, EVENT)
-
-
-
-static void create_events_help(void)
-{
- unsigned int i;
- char *str;
- __u64 e;
-
- str = events_help;
-
- str += sprintf(str,
- "event name: [");
-
- for (i = 0; i < ARRAY_SIZE(event_symbols); i++) {
- int type, id;
-
- e = event_symbols[i].event;
- type = PERF_COUNTER_TYPE(e);
- id = PERF_COUNTER_ID(e);
-
- if (i)
- str += sprintf(str, "|");
-
- str += sprintf(str, "%s",
- event_symbols[i].symbol);
- }
-
- str += sprintf(str, "|rNNN]");
-}
-
static const char * const record_usage[] = {
"perf record [<options>] <command>",
NULL
};
+static char events_help_msg[EVENTS_HELP_MAX];
+
const struct option options[] = {
OPT_CALLBACK('e', "event", NULL, "event",
- events_help, parse_events),
+ events_help_msg, parse_events),
OPT_INTEGER('c', "count", &default_interval,
"event period to sample"),
OPT_INTEGER('m', "mmap-pages", &mmap_pages,
@@ -566,7 +424,7 @@ int cmd_record(int argc, const char **argv, const char *prefix)
{
int counter;
- create_events_help();
+ create_events_help(events_help_msg);
argc = parse_options(argc, argv, options, record_usage, 0);
if (!argc)
diff --git a/Documentation/perf_counter/util/parse-events.c b/Documentation/perf_counter/util/parse-events.c
new file mode 100644
index 000000000000..77d0917d55d3
--- /dev/null
+++ b/Documentation/perf_counter/util/parse-events.c
@@ -0,0 +1,127 @@
+
+#include "../perf.h"
+#include "util.h"
+#include "parse-options.h"
+#include "parse-events.h"
+#include "exec_cmd.h"
+
+int nr_counters;
+
+__u64 event_id[MAX_COUNTERS] = { };
+
+struct event_symbol {
+ __u64 event;
+ char *symbol;
+};
+
+static struct event_symbol event_symbols[] = {
+ {EID(PERF_TYPE_HARDWARE, PERF_COUNT_CPU_CYCLES), "cpu-cycles", },
+ {EID(PERF_TYPE_HARDWARE, PERF_COUNT_CPU_CYCLES), "cycles", },
+ {EID(PERF_TYPE_HARDWARE, PERF_COUNT_INSTRUCTIONS), "instructions", },
+ {EID(PERF_TYPE_HARDWARE, PERF_COUNT_CACHE_REFERENCES), "cache-references", },
+ {EID(PERF_TYPE_HARDWARE, PERF_COUNT_CACHE_MISSES), "cache-misses", },
+ {EID(PERF_TYPE_HARDWARE, PERF_COUNT_BRANCH_INSTRUCTIONS), "branch-instructions", },
+ {EID(PERF_TYPE_HARDWARE, PERF_COUNT_BRANCH_INSTRUCTIONS), "branches", },
+ {EID(PERF_TYPE_HARDWARE, PERF_COUNT_BRANCH_MISSES), "branch-misses", },
+ {EID(PERF_TYPE_HARDWARE, PERF_COUNT_BUS_CYCLES), "bus-cycles", },
+
+ {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CPU_CLOCK), "cpu-clock", },
+ {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_TASK_CLOCK), "task-clock", },
+ {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_PAGE_FAULTS), "page-faults", },
+ {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_PAGE_FAULTS), "faults", },
+ {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_PAGE_FAULTS_MIN), "minor-faults", },
+ {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_PAGE_FAULTS_MAJ), "major-faults", },
+ {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CONTEXT_SWITCHES), "context-switches", },
+ {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CONTEXT_SWITCHES), "cs", },
+ {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CPU_MIGRATIONS), "cpu-migrations", },
+ {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CPU_MIGRATIONS), "migrations", },
+};
+
+/*
+ * Each event can have multiple symbolic names.
+ * Symbolic names are (almost) exactly matched.
+ */
+static __u64 match_event_symbols(const char *str)
+{
+ __u64 config, id;
+ int type;
+ unsigned int i;
+
+ if (sscanf(str, "r%llx", &config) == 1)
+ return config | PERF_COUNTER_RAW_MASK;
+
+ if (sscanf(str, "%d:%llu", &type, &id) == 2)
+ return EID(type, id);
+
+ for (i = 0; i < ARRAY_SIZE(event_symbols); i++) {
+ if (!strncmp(str, event_symbols[i].symbol,
+ strlen(event_symbols[i].symbol)))
+ return event_symbols[i].event;
+ }
+
+ return ~0ULL;
+}
+
+int parse_events(const struct option *opt, const char *str, int unset)
+{
+ __u64 config;
+
+again:
+ if (nr_counters == MAX_COUNTERS)
+ return -1;
+
+ config = match_event_symbols(str);
+ if (config == ~0ULL)
+ return -1;
+
+ event_id[nr_counters] = config;
+ nr_counters++;
+
+ str = strstr(str, ",");
+ if (str) {
+ str++;
+ goto again;
+ }
+
+ return 0;
+}
+
+#define __PERF_COUNTER_FIELD(config, name) \
+ ((config & PERF_COUNTER_##name##_MASK) >> PERF_COUNTER_##name##_SHIFT)
+
+#define PERF_COUNTER_RAW(config) __PERF_COUNTER_FIELD(config, RAW)
+#define PERF_COUNTER_CONFIG(config) __PERF_COUNTER_FIELD(config, CONFIG)
+#define PERF_COUNTER_TYPE(config) __PERF_COUNTER_FIELD(config, TYPE)
+#define PERF_COUNTER_ID(config) __PERF_COUNTER_FIELD(config, EVENT)
+
+/*
+ * Create the help text for the event symbols:
+ */
+void create_events_help(char *events_help_msg)
+{
+ unsigned int i;
+ char *str;
+ __u64 e;
+
+ str = events_help_msg;
+
+ str += sprintf(str,
+ "event name: [");
+
+ for (i = 0; i < ARRAY_SIZE(event_symbols); i++) {
+ int type, id;
+
+ e = event_symbols[i].event;
+ type = PERF_COUNTER_TYPE(e);
+ id = PERF_COUNTER_ID(e);
+
+ if (i)
+ str += sprintf(str, "|");
+
+ str += sprintf(str, "%s",
+ event_symbols[i].symbol);
+ }
+
+ str += sprintf(str, "|rNNN]");
+}
+
diff --git a/Documentation/perf_counter/util/parse-events.h b/Documentation/perf_counter/util/parse-events.h
new file mode 100644
index 000000000000..6e2ebe5ff7d7
--- /dev/null
+++ b/Documentation/perf_counter/util/parse-events.h
@@ -0,0 +1,10 @@
+
+extern int nr_counters;
+extern __u64 event_id[MAX_COUNTERS];
+
+extern int parse_events(const struct option *opt, const char *str, int unset);
+
+#define EVENTS_HELP_MAX (128*1024)
+
+extern void create_events_help(char *help_msg);
+
commit 0e9b20b8a1cab6c6ab4f98f917a2d98783103969
Author: Ingo Molnar <mingo@elte.hu>
Date: Tue May 26 09:17:18 2009 +0200
perf record: Convert to Git option parsing
Remove getopt usage and use Git's much more advanced and more compact
command option library.
Git's library (util/parse-options.[ch]) constructs help texts and
error messages automatically, and has a number of other convenience
features as well.
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Corey Ashford <cjashfor@linux.vnet.ibm.com>
Cc: Marcelo Tosatti <mtosatti@redhat.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: John Kacur <jkacur@redhat.com>
LKML-Reference: <new-submission>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
diff --git a/Documentation/perf_counter/builtin-record.c b/Documentation/perf_counter/builtin-record.c
index f225efaff9f5..f12a7822fcf1 100644
--- a/Documentation/perf_counter/builtin-record.c
+++ b/Documentation/perf_counter/builtin-record.c
@@ -2,6 +2,8 @@
#include "perf.h"
#include "util/util.h"
+#include "util/parse-options.h"
+#include "util/exec_cmd.h"
#include <sys/types.h>
#include <sys/stat.h>
@@ -11,7 +13,6 @@
#include <stdlib.h>
#include <string.h>
#include <limits.h>
-#include <getopt.h>
#include <assert.h>
#include <fcntl.h>
#include <stdio.h>
@@ -33,8 +34,8 @@
-#define ALIGN(x,a) __ALIGN_MASK(x,(typeof(x))(a)-1)
-#define __ALIGN_MASK(x,mask) (((x)+(mask))&~(mask))
+#define ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a)-1)
+#define __ALIGN_MASK(x, mask) (((x)+(mask))&~(mask))
static int nr_counters = 0;
static __u64 event_id[MAX_COUNTERS] = { };
@@ -45,7 +46,7 @@ static int nr_cpus = 0;
static unsigned int page_size;
static unsigned int mmap_pages = 16;
static int output;
-static char *output_name = "output.perf";
+static const char *output_name = "output.perf";
static int group = 0;
static unsigned int realtime_prio = 0;
static int system_wide = 0;
@@ -62,192 +63,6 @@ const unsigned int default_count[] = {
10000,
};
-struct event_symbol {
- __u64 event;
- char *symbol;
-};
-
-static struct event_symbol event_symbols[] = {
- {EID(PERF_TYPE_HARDWARE, PERF_COUNT_CPU_CYCLES), "cpu-cycles", },
- {EID(PERF_TYPE_HARDWARE, PERF_COUNT_CPU_CYCLES), "cycles", },
- {EID(PERF_TYPE_HARDWARE, PERF_COUNT_INSTRUCTIONS), "instructions", },
- {EID(PERF_TYPE_HARDWARE, PERF_COUNT_CACHE_REFERENCES), "cache-references", },
- {EID(PERF_TYPE_HARDWARE, PERF_COUNT_CACHE_MISSES), "cache-misses", },
- {EID(PERF_TYPE_HARDWARE, PERF_COUNT_BRANCH_INSTRUCTIONS), "branch-instructions", },
- {EID(PERF_TYPE_HARDWARE, PERF_COUNT_BRANCH_INSTRUCTIONS), "branches", },
- {EID(PERF_TYPE_HARDWARE, PERF_COUNT_BRANCH_MISSES), "branch-misses", },
- {EID(PERF_TYPE_HARDWARE, PERF_COUNT_BUS_CYCLES), "bus-cycles", },
-
- {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CPU_CLOCK), "cpu-clock", },
- {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_TASK_CLOCK), "task-clock", },
- {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_PAGE_FAULTS), "page-faults", },
- {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_PAGE_FAULTS), "faults", },
- {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_PAGE_FAULTS_MIN), "minor-faults", },
- {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_PAGE_FAULTS_MAJ), "major-faults", },
- {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CONTEXT_SWITCHES), "context-switches", },
- {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CONTEXT_SWITCHES), "cs", },
- {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CPU_MIGRATIONS), "cpu-migrations", },
- {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CPU_MIGRATIONS), "migrations", },
-};
-
-/*
- * Each event can have multiple symbolic names.
- * Symbolic names are (almost) exactly matched.
- */
-static __u64 match_event_symbols(char *str)
-{
- __u64 config, id;
- int type;
- unsigned int i;
-
- if (sscanf(str, "r%llx", &config) == 1)
- return config | PERF_COUNTER_RAW_MASK;
-
- if (sscanf(str, "%d:%llu", &type, &id) == 2)
- return EID(type, id);
-
- for (i = 0; i < ARRAY_SIZE(event_symbols); i++) {
- if (!strncmp(str, event_symbols[i].symbol,
- strlen(event_symbols[i].symbol)))
- return event_symbols[i].event;
- }
-
- return ~0ULL;
-}
-
-static int parse_events(char *str)
-{
- __u64 config;
-
-again:
- if (nr_counters == MAX_COUNTERS)
- return -1;
-
- config = match_event_symbols(str);
- if (config == ~0ULL)
- return -1;
-
- event_id[nr_counters] = config;
- nr_counters++;
-
- str = strstr(str, ",");
- if (str) {
- str++;
- goto again;
- }
-
- return 0;
-}
-
-#define __PERF_COUNTER_FIELD(config, name) \
- ((config & PERF_COUNTER_##name##_MASK) >> PERF_COUNTER_##name##_SHIFT)
-
-#define PERF_COUNTER_RAW(config) __PERF_COUNTER_FIELD(config, RAW)
-#define PERF_COUNTER_CONFIG(config) __PERF_COUNTER_FIELD(config, CONFIG)
-#define PERF_COUNTER_TYPE(config) __PERF_COUNTER_FIELD(config, TYPE)
-#define PERF_COUNTER_ID(config) __PERF_COUNTER_FIELD(config, EVENT)
-
-static void display_events_help(void)
-{
- unsigned int i;
- __u64 e;
-
- printf(
- " -e EVENT --event=EVENT # symbolic-name abbreviations");
-
- for (i = 0; i < ARRAY_SIZE(event_symbols); i++) {
- int type, id;
-
- e = event_symbols[i].event;
- type = PERF_COUNTER_TYPE(e);
- id = PERF_COUNTER_ID(e);
-
- printf("\n %d:%d: %-20s",
- type, id, event_symbols[i].symbol);
- }
-
- printf("\n"
- " rNNN: raw PMU events (eventsel+umask)\n\n");
-}
-
-static void display_help(void)
-{
- printf(
- "Usage: perf-record [<options>] <cmd>\n"
- "perf-record Options (up to %d event types can be specified at once):\n\n",
- MAX_COUNTERS);
-
- display_events_help();
-
- printf(
- " -c CNT --count=CNT # event period to sample\n"
- " -m pages --mmap_pages=<pages> # number of mmap data pages\n"
- " -o file --output=<file> # output file\n"
- " -p pid --pid=<pid> # record events on existing pid\n"
- " -r prio --realtime=<prio> # use RT prio\n"
- " -s --system # system wide profiling\n"
- );
-
- exit(0);
-}
-
-static void process_options(int argc, char * const argv[])
-{
- int error = 0, counter;
-
- for (;;) {
- int option_index = 0;
- /** Options for getopt */
- static struct option long_options[] = {
- {"count", required_argument, NULL, 'c'},
- {"event", required_argument, NULL, 'e'},
- {"mmap_pages", required_argument, NULL, 'm'},
- {"output", required_argument, NULL, 'o'},
- {"pid", required_argument, NULL, 'p'},
- {"realtime", required_argument, NULL, 'r'},
- {"system", no_argument, NULL, 's'},
- {"inherit", no_argument, NULL, 'i'},
- {"nmi", no_argument, NULL, 'n'},
- {NULL, 0, NULL, 0 }
- };
- int c = getopt_long(argc, argv, "+:c:e:m:o:p:r:sin",
- long_options, &option_index);
- if (c == -1)
- break;
-
- switch (c) {
- case 'c': default_interval = atoi(optarg); break;
- case 'e': error = parse_events(optarg); break;
- case 'm': mmap_pages = atoi(optarg); break;
- case 'o': output_name = strdup(optarg); break;
- case 'p': target_pid = atoi(optarg); break;
- case 'r': realtime_prio = atoi(optarg); break;
- case 's': system_wide ^= 1; break;
- case 'i': inherit ^= 1; break;
- case 'n': nmi ^= 1; break;
- default: error = 1; break;
- }
- }
-
- if (argc - optind == 0 && target_pid == -1)
- error = 1;
-
- if (error)
- display_help();
-
- if (!nr_counters) {
- nr_counters = 1;
- event_id[0] = 0;
- }
-
- for (counter = 0; counter < nr_counters; counter++) {
- if (event_count[counter])
- continue;
-
- event_count[counter] = default_interval;
- }
-}
-
struct mmap_data {
int counter;
void *base;
@@ -538,16 +353,13 @@ static void open_counters(int cpu, pid_t pid)
nr_cpu++;
}
-int cmd_record(int argc, char * const argv[])
+static int __cmd_record(int argc, const char **argv)
{
int i, counter;
pid_t pid;
int ret;
page_size = sysconf(_SC_PAGE_SIZE);
-
- process_options(argc, argv);
-
nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
assert(nr_cpus <= MAX_NR_CPUS);
assert(nr_cpus >= 0);
@@ -558,9 +370,6 @@ int cmd_record(int argc, char * const argv[])
exit(-1);
}
- argc -= optind;
- argv += optind;
-
if (!system_wide) {
open_counters(-1, target_pid != -1 ? target_pid : 0);
} else for (i = 0; i < nr_cpus; i++)
@@ -575,7 +384,7 @@ int cmd_record(int argc, char * const argv[])
perror("failed to fork");
if (!pid) {
- if (execvp(argv[0], argv)) {
+ if (execvp(argv[0], (char **)argv)) {
perror(argv[0]);
exit(-1);
}
@@ -610,3 +419,170 @@ int cmd_record(int argc, char * const argv[])
return 0;
}
+
+struct event_symbol {
+ __u64 event;
+ char *symbol;
+};
+
+static struct event_symbol event_symbols[] = {
+ {EID(PERF_TYPE_HARDWARE, PERF_COUNT_CPU_CYCLES), "cpu-cycles", },
+ {EID(PERF_TYPE_HARDWARE, PERF_COUNT_CPU_CYCLES), "cycles", },
+ {EID(PERF_TYPE_HARDWARE, PERF_COUNT_INSTRUCTIONS), "instructions", },
+ {EID(PERF_TYPE_HARDWARE, PERF_COUNT_CACHE_REFERENCES), "cache-references", },
+ {EID(PERF_TYPE_HARDWARE, PERF_COUNT_CACHE_MISSES), "cache-misses", },
+ {EID(PERF_TYPE_HARDWARE, PERF_COUNT_BRANCH_INSTRUCTIONS), "branch-instructions", },
+ {EID(PERF_TYPE_HARDWARE, PERF_COUNT_BRANCH_INSTRUCTIONS), "branches", },
+ {EID(PERF_TYPE_HARDWARE, PERF_COUNT_BRANCH_MISSES), "branch-misses", },
+ {EID(PERF_TYPE_HARDWARE, PERF_COUNT_BUS_CYCLES), "bus-cycles", },
+
+ {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CPU_CLOCK), "cpu-clock", },
+ {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_TASK_CLOCK), "task-clock", },
+ {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_PAGE_FAULTS), "page-faults", },
+ {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_PAGE_FAULTS), "faults", },
+ {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_PAGE_FAULTS_MIN), "minor-faults", },
+ {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_PAGE_FAULTS_MAJ), "major-faults", },
+ {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CONTEXT_SWITCHES), "context-switches", },
+ {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CONTEXT_SWITCHES), "cs", },
+ {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CPU_MIGRATIONS), "cpu-migrations", },
+ {EID(PERF_TYPE_SOFTWARE, PERF_COUNT_CPU_MIGRATIONS), "migrations", },
+};
+
+/*
+ * Each event can have multiple symbolic names.
+ * Symbolic names are (almost) exactly matched.
+ */
+static __u64 match_event_symbols(const char *str)
+{
+ __u64 config, id;
+ int type;
+ unsigned int i;
+
+ if (sscanf(str, "r%llx", &config) == 1)
+ return config | PERF_COUNTER_RAW_MASK;
+
+ if (sscanf(str, "%d:%llu", &type, &id) == 2)
+ return EID(type, id);
+
+ for (i = 0; i < ARRAY_SIZE(event_symbols); i++) {
+ if (!strncmp(str, event_symbols[i].symbol,
+ strlen(event_symbols[i].symbol)))
+ return event_symbols[i].event;
+ }
+
+ return ~0ULL;
+}
+
+static int parse_events(const struct option *opt, const char *str, int unset)
+{
+ __u64 config;
+
+again:
+ if (nr_counters == MAX_COUNTERS)
+ return -1;
+
+ config = match_event_symbols(str);
+ if (config == ~0ULL)
+ return -1;
+
+ event_id[nr_counters] = config;
+ nr_counters++;
+
+ str = strstr(str, ",");
+ if (str) {
+ str++;
+ goto again;
+ }
+
+ return 0;
+}
+
+static char events_help[100000];
+
+#define __PERF_COUNTER_FIELD(config, name) \
+ ((config & PERF_COUNTER_##name##_MASK) >> PERF_COUNTER_##name##_SHIFT)
+
+#define PERF_COUNTER_RAW(config) __PERF_COUNTER_FIELD(config, RAW)
+#define PERF_COUNTER_CONFIG(config) __PERF_COUNTER_FIELD(config, CONFIG)
+#define PERF_COUNTER_TYPE(config) __PERF_COUNTER_FIELD(config, TYPE)
+#define PERF_COUNTER_ID(config) __PERF_COUNTER_FIELD(config, EVENT)
+
+
+
+static void create_events_help(void)
+{
+ unsigned int i;
+ char *str;
+ __u64 e;
+
+ str = events_help;
+
+ str += sprintf(str,
+ "event name: [");
+
+ for (i = 0; i < ARRAY_SIZE(event_symbols); i++) {
+ int type, id;
+
+ e = event_symbols[i].event;
+ type = PERF_COUNTER_TYPE(e);
+ id = PERF_COUNTER_ID(e);
+
+ if (i)
+ str += sprintf(str, "|");
+
+ str += sprintf(str, "%s",
+ event_symbols[i].symbol);
+ }
+
+ str += sprintf(str, "|rNNN]");
+}
+
+static const char * const record_usage[] = {
+ "perf record [<options>] <command>",
+ NULL
+};
+
+const struct option options[] = {
+ OPT_CALLBACK('e', "event", NULL, "event",
+ events_help, parse_events),
+ OPT_INTEGER('c', "count", &default_interval,
+ "event period to sample"),
+ OPT_INTEGER('m', "mmap-pages", &mmap_pages,
+ "number of mmap data pages"),
+ OPT_STRING('o', "output", &output_name, "file",
+ "output file name"),
+ OPT_BOOLEAN('i', "inherit", &inherit,
+ "child tasks inherit counters"),
+ OPT_INTEGER('p', "pid", &target_pid,
+ "record events on existing pid"),
+ OPT_INTEGER('r', "realtime", &realtime_prio,
+ "collect data with this RT SCHED_FIFO priority"),
+ OPT_BOOLEAN('a', "all-cpus", &system_wide,
+ "system-wide collection from all CPUs"),
+ OPT_END()
+};
+
+int cmd_record(int argc, const char **argv, const char *prefix)
+{
+ int counter;
+
+ create_events_help();
+
+ argc = parse_options(argc, argv, options, record_usage, 0);
+ if (!argc)
+ usage_with_options(record_usage, options);
+
+ if (!nr_counters) {
+ nr_counters = 1;
+ event_id[0] = 0;
+ }
+
+ for (counter = 0; counter < nr_counters; counter++) {
+ if (event_count[counter])
+ continue;
+
+ event_count[counter] = default_interval;
+ }
+
+ return __cmd_record(argc, argv);
+}
diff --git a/Documentation/perf_counter/builtin-top.c b/Documentation/perf_counter/builtin-top.c
index 4bed265926dd..626b32076499 100644
--- a/Documentation/perf_counter/builtin-top.c
+++ b/Documentation/perf_counter/builtin-top.c
@@ -42,13 +42,16 @@
* Released under the GPL v2. (and only v2, not any later version)
*/
+
#include "perf.h"
#include "util/util.h"
#include <getopt.h>
#include <assert.h>
#include <fcntl.h>
+
#include <stdio.h>
+
#include <errno.h>
#include <time.h>
#include <sched.h>
commit 4e97ddf09ee3ce715fc334399bae4cc0c0a13057
Author: Ingo Molnar <mingo@elte.hu>
Date: Tue May 26 10:07:44 2009 +0200
perf stat: Remove unused variable
[ Impact: cleanup ]
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Corey Ashford <cjashfor@linux.vnet.ibm.com>
Cc: Marcelo Tosatti <mtosatti@redhat.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: John Kacur <jkacur@redhat.com>
LKML-Reference: <new-submission>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
diff --git a/Documentation/perf_counter/builtin-stat.c b/Documentation/perf_counter/builtin-stat.c
index 88c70be99031..c1053d820c1f 100644
--- a/Documentation/perf_counter/builtin-stat.c
+++ b/Documentation/perf_counter/builtin-stat.c
@@ -541,8 +541,6 @@ static void skip_signal(int signo)
int cmd_stat(int argc, char **argv, const char *prefix)
{
- sigset_t blocked;
-
page_size = sysconf(_SC_PAGE_SIZE);
process_options(argc, argv);
commit 69aa48ab82e17299efe2be6c21795945731a6c17
Author: Ingo Molnar <mingo@elte.hu>
Date: Tue May 26 09:02:27 2009 +0200
perf record: Straighten out argv types
[ Impact: cleanup ]
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Corey Ashford <cjashfor@linux.vnet.ibm.com>
Cc: Marcelo Tosatti <mtosatti@redhat.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: John Kacur <jkacur@redhat.com>
LKML-Reference: <new-submission>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
diff --git a/Documentation/perf_counter/builtin-record.c b/Documentation/perf_counter/builtin-record.c
index 1b19f187d352..f225efaff9f5 100644
--- a/Documentation/perf_counter/builtin-record.c
+++ b/Documentation/perf_counter/builtin-record.c
@@ -191,7 +191,7 @@ static void display_help(void)
exit(0);
}
-static void process_options(int argc, const char *argv[])
+static void process_options(int argc, char * const argv[])
{
int error = 0, counter;
@@ -538,7 +538,7 @@ static void open_counters(int cpu, pid_t pid)
nr_cpu++;
}
-int cmd_record(int argc, const char **argv)
+int cmd_record(int argc, char * const argv[])
{
int i, counter;
pid_t pid;
commit 329d876d6fd326109f191ae0fb2798b8834fb70b
Author: Ingo Molnar <mingo@elte.hu>
Date: Tue May 26 08:10:00 2009 +0200
perf_counter: Initialize ->oncpu properly
This shouldnt matter normally (and i have not seen any
misbehavior), because active counters always have a
proper ->oncpu value - but nevertheless initialize the
field properly to -1.
[ Impact: cleanup ]
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Corey Ashford <cjashfor@linux.vnet.ibm.com>
Cc: Marcelo Tosatti <mtosatti@redhat.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: John Kacur <jkacur@redhat.com>
LKML-Reference: <new-submission>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
diff --git a/kernel/perf_counter.c b/kernel/perf_counter.c
index 070f92d3232a..367299f91aaf 100644
--- a/kernel/perf_counter.c
+++ b/kernel/perf_counter.c
@@ -3122,6 +3122,8 @@ perf_counter_alloc(struct perf_counter_hw_event *hw_event,
counter->group_leader = group_leader;
counter->pmu = NULL;
counter->ctx = ctx;
+ counter->oncpu = -1;
+
get_ctx(ctx);
counter->state = PERF_COUNTER_STATE_INACTIVE;
commit aaba98018b8295dfa2119345d17f833d74448cd0
Author: Ingo Molnar <mingo@elte.hu>
Date: Tue May 26 08:10:00 2009 +0200
perf_counter, x86: Make NMI lockups more robust
We have a debug check that detects stuck NMIs and returns with
the PMU disabled in the global ctrl MSR - but i managed to trigger
a situation where this was not enough to deassert the NMI.
So clear/reset the full PMU and keep the disable count balanced when
exiting from here. This way the box produces a debug warning but
stays up and is more debuggable.
[ Impact: in case of PMU related bugs, recover more gracefully ]
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Corey Ashford <cjashfor@linux.vnet.ibm.com>
Cc: Marcelo Tosatti <mtosatti@redhat.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: John Kacur <jkacur@redhat.com>
LKML-Reference: <new-submission>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
diff --git a/arch/x86/kernel/cpu/perf_counter.c b/arch/x86/kernel/cpu/perf_counter.c
index ece3813c7a3c..2eeaa99add1c 100644
--- a/arch/x86/kernel/cpu/perf_counter.c
+++ b/arch/x86/kernel/cpu/perf_counter.c
@@ -724,6 +724,30 @@ static void intel_pmu_save_and_restart(struct perf_counter *counter)
intel_pmu_enable_counter(hwc, idx);
}
+static void intel_pmu_reset(void)
+{
+ unsigned long flags;
+ int idx;
+
+ if (!x86_pmu.num_counters)
+ return;
+
+ local_irq_save(flags);
+
+ printk("clearing PMU state on CPU#%d\n", smp_processor_id());
+
+ for (idx = 0; idx < x86_pmu.num_counters; idx++) {
+ checking_wrmsrl(x86_pmu.eventsel + idx, 0ull);
+ checking_wrmsrl(x86_pmu.perfctr + idx, 0ull);
+ }
+ for (idx = 0; idx < x86_pmu.num_counters_fixed; idx++) {
+ checking_wrmsrl(MSR_ARCH_PERFMON_FIXED_CTR0 + idx, 0ull);
+ }
+
+ local_irq_restore(flags);
+}
+
+
/*
* This handler is triggered by the local APIC, so the APIC IRQ handling
* rules apply:
@@ -750,6 +774,8 @@ static int intel_pmu_handle_irq(struct pt_regs *regs, int nmi)
if (++loops > 100) {
WARN_ONCE(1, "perfcounters: irq loop stuck!\n");
perf_counter_print_debug();
+ intel_pmu_reset();
+ perf_enable();
return 1;
}