From 49908a1b25d448d68fd26faca260e1850201575f Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Fri, 4 Nov 2011 16:32:25 -0400 Subject: perf: Fix parsing of __print_flags() in TP_printk() A update is made to the sched:sched_switch event that adds some logic to the first parameter of the __print_flags() that shows the state of tasks. This change cause perf to fail parsing the flags. A simple fix is needed to have the parser be able to process ops within the argument. Cc: stable@vger.kernel.org Reported-by: Andrew Vagin Signed-off-by: Steven Rostedt --- tools/perf/util/trace-event-parse.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'tools') diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index 0a7ed5b5e28..6c164dc9ee9 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c @@ -1537,6 +1537,8 @@ process_flags(struct event *event, struct print_arg *arg, char **tok) field = malloc_or_die(sizeof(*field)); type = process_arg(event, field, &token); + while (type == EVENT_OP) + type = process_op(event, field, &token); if (test_type_token(type, token, EVENT_DELIM, ",")) goto out_free; -- cgit v1.2.3-70-g09d2 From 800b927b38c7cdfbd7df39d7a8a4b065637ab7b6 Mon Sep 17 00:00:00 2001 From: Bryan Schumaker Date: Tue, 1 Nov 2011 13:35:22 -0400 Subject: NFSD: Added fault injection script This script provides a convenient way to use the NFSD fault injection framework. Fault injection writes to dmesg using the KERN_INFO flag, so this script will compare the before and after output of `dmesg` to show the user what happened Signed-off-by: Bryan Schumaker Signed-off-by: J. Bruce Fields --- tools/nfsd/inject_fault.sh | 49 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100755 tools/nfsd/inject_fault.sh (limited to 'tools') diff --git a/tools/nfsd/inject_fault.sh b/tools/nfsd/inject_fault.sh new file mode 100755 index 00000000000..06a399ac8b2 --- /dev/null +++ b/tools/nfsd/inject_fault.sh @@ -0,0 +1,49 @@ +#!/bin/bash +# +# Copyright (c) 2011 Bryan Schumaker +# +# Script for easier NFSD fault injection + +# Check that debugfs has been mounted +DEBUGFS=`cat /proc/mounts | grep debugfs` +if [ "$DEBUGFS" == "" ]; then + echo "debugfs does not appear to be mounted!" + echo "Please mount debugfs and try again" + exit 1 +fi + +# Check that the fault injection directory exists +DEBUGDIR=`echo $DEBUGFS | awk '{print $2}'`/nfsd +if [ ! -d "$DEBUGDIR" ]; then + echo "$DEBUGDIR does not exist" + echo "Check that your .config selects CONFIG_NFSD_FAULT_INJECTION" + exit 1 +fi + +function help() +{ + echo "Usage $0 injection_type [count]" + echo "" + echo "Injection types are:" + ls $DEBUGDIR + exit 1 +} + +if [ $# == 0 ]; then + help +elif [ ! -f $DEBUGDIR/$1 ]; then + help +elif [ $# != 2 ]; then + COUNT=0 +else + COUNT=$2 +fi + +BEFORE=`mktemp` +AFTER=`mktemp` +dmesg > $BEFORE +echo $COUNT > $DEBUGDIR/$1 +dmesg > $AFTER +# Capture lines that only exist in the $AFTER file +diff $BEFORE $AFTER | grep ">" +rm -f $BEFORE $AFTER -- cgit v1.2.3-70-g09d2 From 553575f1ae048aa44682b46b3c51929a0b3ad337 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Fri, 18 Nov 2011 03:32:01 -0500 Subject: tools turbostat: recognize and run properly on IVB Signed-off-by: Len Brown --- tools/power/x86/turbostat/turbostat.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'tools') diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index 8b2d37b59c9..4b05b445969 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c @@ -809,6 +809,8 @@ int has_nehalem_turbo_ratio_limit(unsigned int family, unsigned int model) case 0x2C: /* Westmere EP - Gulftown */ case 0x2A: /* SNB */ case 0x2D: /* SNB Xeon */ + case 0x3A: /* IVB */ + case 0x3D: /* IVB Xeon */ return 1; case 0x2E: /* Nehalem-EX Xeon - Beckton */ case 0x2F: /* Westmere-EX Xeon - Eagleton */ -- cgit v1.2.3-70-g09d2 From a9dd5d631729eea8686703fbb25a7a9d4c75a724 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Fri, 18 Nov 2011 17:05:29 +0530 Subject: ktest: Save test output The test output may contain useful information; save it along with the already-saved buildlog, dmesg, and .config. Link: http://lkml.kernel.org/r/1321616131-21352-1-git-send-email-rabin@rab.in Signed-off-by: Rabin Vincent Signed-off-by: Steven Rostedt --- tools/testing/ktest/ktest.pl | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) (limited to 'tools') diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl index 8b4c2535b26..e93c21cc0aa 100755 --- a/tools/testing/ktest/ktest.pl +++ b/tools/testing/ktest/ktest.pl @@ -103,6 +103,7 @@ my $in_patchcheck = 0; my $run_test; my $redirect; my $buildlog; +my $testlog; my $dmesg; my $monitor_fp; my $monitor_pid; @@ -1021,17 +1022,19 @@ sub fail { mkpath($faildir) or die "can't create $faildir"; } - if (-f "$output_config") { - cp "$output_config", "$faildir/config" or - die "failed to copy .config"; - } - if (-f $buildlog) { - cp $buildlog, "$faildir/buildlog" or - die "failed to move $buildlog"; - } - if (-f $dmesg) { - cp $dmesg, "$faildir/dmesg" or - die "failed to move $dmesg"; + + my %files = ( + "config" => $output_config, + "buildlog" => $buildlog, + "dmesg" => $dmesg, + "testlog" => $testlog, + ); + + while (my ($name, $source) = each(%files)) { + if (-f "$source") { + cp "$source", "$faildir/$name" or + die "failed to copy $source"; + } } doprint "*** Saved info to $faildir ***\n"; @@ -1669,7 +1672,10 @@ sub child_run_test { $poweroff_on_error = 0; $die_on_failure = 1; + $redirect = "$testlog"; run_command $run_test or $failed = 1; + undef $redirect; + exit $failed; } @@ -3169,6 +3175,7 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { $target = "$ssh_user\@$machine"; $buildlog = "$tmpdir/buildlog-$machine"; + $testlog = "$tmpdir/testlog-$machine"; $dmesg = "$tmpdir/dmesg-$machine"; $make = "$makecmd O=$outputdir"; $output_config = "$outputdir/.config"; @@ -3205,6 +3212,7 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { unlink $dmesg; unlink $buildlog; + unlink $testlog; if (defined($addconfig)) { my $min = $minconfig; -- cgit v1.2.3-70-g09d2 From de5b6e3bf5e71532057fb4f1eb8ee29c5c7f11db Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Fri, 18 Nov 2011 17:05:31 +0530 Subject: ktest: Allow success logs to be stored Add a STORE_SUCCESSES option, to allow success logs to be stored, for example to double-check or otherwise post-process the test logs. Link: http://lkml.kernel.org/r/1321616131-21352-3-git-send-email-rabin@rab.in Signed-off-by: Rabin Vincent Signed-off-by: Steven Rostedt --- tools/testing/ktest/ktest.pl | 80 +++++++++++++++++++++++------------------ tools/testing/ktest/sample.conf | 6 ++++ 2 files changed, 52 insertions(+), 34 deletions(-) (limited to 'tools') diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl index e93c21cc0aa..6ef104e87ab 100755 --- a/tools/testing/ktest/ktest.pl +++ b/tools/testing/ktest/ktest.pl @@ -113,6 +113,7 @@ my $bisect_sleep_time; my $patchcheck_sleep_time; my $ignore_warnings; my $store_failures; +my $store_successes; my $test_name; my $timeout; my $booted_timeout; @@ -976,6 +977,43 @@ sub wait_for_monitor { print "** Monitor flushed **\n"; } +sub save_logs { + my ($result, $basedir) = @_; + my @t = localtime; + my $date = sprintf "%04d%02d%02d%02d%02d%02d", + 1900+$t[5],$t[4],$t[3],$t[2],$t[1],$t[0]; + + my $type = $build_type; + if ($type =~ /useconfig/) { + $type = "useconfig"; + } + + my $dir = "$machine-$test_type-$type-$result-$date"; + + $dir = "$basedir/$dir"; + + if (!-d $dir) { + mkpath($dir) or + die "can't create $dir"; + } + + my %files = ( + "config" => $output_config, + "buildlog" => $buildlog, + "dmesg" => $dmesg, + "testlog" => $testlog, + ); + + while (my ($name, $source) = each(%files)) { + if (-f "$source") { + cp "$source", "$dir/$name" or + die "failed to copy $source"; + } + } + + doprint "*** Saved info to $dir ***\n"; +} + sub fail { if ($die_on_failure) { @@ -1004,40 +1042,9 @@ sub fail { doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n"; doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n"; - return 1 if (!defined($store_failures)); - - my @t = localtime; - my $date = sprintf "%04d%02d%02d%02d%02d%02d", - 1900+$t[5],$t[4],$t[3],$t[2],$t[1],$t[0]; - - my $type = $build_type; - if ($type =~ /useconfig/) { - $type = "useconfig"; - } - - my $dir = "$machine-$test_type-$type-fail-$date"; - my $faildir = "$store_failures/$dir"; - - if (!-d $faildir) { - mkpath($faildir) or - die "can't create $faildir"; - } - - my %files = ( - "config" => $output_config, - "buildlog" => $buildlog, - "dmesg" => $dmesg, - "testlog" => $testlog, - ); - - while (my ($name, $source) = each(%files)) { - if (-f "$source") { - cp "$source", "$faildir/$name" or - die "failed to copy $source"; - } - } - - doprint "*** Saved info to $faildir ***\n"; + if (defined($store_failures)) { + save_logs "fail", $store_failures; + } return 1; } @@ -1643,6 +1650,10 @@ sub success { doprint "*******************************************\n"; doprint "*******************************************\n"; + if (defined($store_successes)) { + save_logs "success", $store_successes; + } + if ($i != $opt{"NUM_TESTS"} && !do_not_reboot) { doprint "Reboot and wait $sleep_time seconds\n"; reboot $sleep_time; @@ -3137,6 +3148,7 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { $bisect_skip = set_test_option("BISECT_SKIP", $i); $config_bisect_good = set_test_option("CONFIG_BISECT_GOOD", $i); $store_failures = set_test_option("STORE_FAILURES", $i); + $store_successes = set_test_option("STORE_SUCCESSES", $i); $test_name = set_test_option("TEST_NAME", $i); $timeout = set_test_option("TIMEOUT", $i); $booted_timeout = set_test_option("BOOTED_TIMEOUT", $i); diff --git a/tools/testing/ktest/sample.conf b/tools/testing/ktest/sample.conf index dbedfa19672..42e0eb9442e 100644 --- a/tools/testing/ktest/sample.conf +++ b/tools/testing/ktest/sample.conf @@ -589,6 +589,12 @@ # (default undefined) #STORE_FAILURES = /home/test/failures +# Directory to store success directories on success. If this is not +# set, the .config, dmesg and bootlog will not be saved if a +# test succeeds. +# (default undefined) +#STORE_SUCCESSES = /home/test/successes + # Build without doing a make mrproper, or removing .config # (default 0) #BUILD_NOCLEAN = 0 -- cgit v1.2.3-70-g09d2 From 600bbf0aa2229390ba1c4ca4c5666c593ff9ef56 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Mon, 21 Nov 2011 20:12:04 -0500 Subject: ktest: Add default for ssh-user, build-target and target-image When a user runs ktest without an argument, or the argument given is not a config file that exists, ktest will ask the user a few questions to create a simple ktest config file. A few of the questions should have a default value set, that if anything it will make it easier for the user to know what is suppose to be in that value. These new values are: SSH_USER, BUILD_TARGET and TARGET_IMAGE Signed-off-by: Steven Rostedt --- tools/testing/ktest/ktest.pl | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl index 6ef104e87ab..05f429d6885 100755 --- a/tools/testing/ktest/ktest.pl +++ b/tools/testing/ktest/ktest.pl @@ -22,7 +22,6 @@ my %default; #default opts $default{"NUM_TESTS"} = 1; -$default{"REBOOT_TYPE"} = "grub"; $default{"TEST_TYPE"} = "test"; $default{"BUILD_TYPE"} = "randconfig"; $default{"MAKE_CMD"} = "make"; @@ -51,7 +50,14 @@ $default{"REBOOT"} = "ssh \$SSH_USER\@\$MACHINE reboot"; $default{"STOP_AFTER_SUCCESS"} = 10; $default{"STOP_AFTER_FAILURE"} = 60; $default{"STOP_TEST_AFTER"} = 600; + +# required, and we will ask users if they don't have them but we keep the default +# value something that is common. +$default{"REBOOT_TYPE"} = "grub"; $default{"LOCALVERSION"} = "-test"; +$default{"SSH_USER"} = "root"; +$default{"BUILD_TARGET"} = "arch/x86/boot/bzImage"; +$default{"TARGET_IMAGE"} = "/boot/vmlinuz-test"; my $ktest_config; my $version; -- cgit v1.2.3-70-g09d2 From 0e7a22de25212cfcaa0ba2c957e4e60eaa70fb9d Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Mon, 21 Nov 2011 20:39:33 -0500 Subject: ktest: When creating new config, allow the use of ${THIS_DIR} Typing in a full path when you know that the path exists within the directory your are running is tedious and unnecessary. Allow the user to use ${PWD} if they want a dynamic path name which will be the path that ktest.pl is executed from or use ${THIS_DIR} which is a variable assigned `pwd` and the the variable will exist within the config, allowing the user to change it and affect all other paths using this variable as well Signed-off-by: Steven Rostedt --- tools/testing/ktest/ktest.pl | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'tools') diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl index 05f429d6885..77b464980de 100755 --- a/tools/testing/ktest/ktest.pl +++ b/tools/testing/ktest/ktest.pl @@ -158,11 +158,15 @@ EOF ; $config_help{"BUILD_DIR"} = << "EOF" The directory that contains the Linux source code (full path). + You can use \${PWD} that will be the path where ktest.pl is run, or use + \${THIS_DIR} which is assigned \${PWD} but may be changed later. EOF ; $config_help{"OUTPUT_DIR"} = << "EOF" The directory that the objects will be built (full path). (can not be same as BUILD_DIR) + You can use \${PWD} that will be the path where ktest.pl is run, or use + \${THIS_DIR} which is assigned \${PWD} but may be changed later. EOF ; $config_help{"BUILD_TARGET"} = << "EOF" @@ -282,7 +286,7 @@ sub get_ktest_config { next; } } - $entered_configs{$config} = process_variables($ans); + $entered_configs{$config} = ${ans}; last; } } @@ -3012,6 +3016,17 @@ if (! -f $ktest_config) { print OUT << "EOF" # Generated by ktest.pl # + +# PWD is a ktest.pl variable that will result in the process working +# directory that ktest.pl is executed in. + +# THIS_DIR is automatically assigned the PWD of the path that generated +# the config file. It is best to use this variable when assigning other +# directory paths within this directory. This allows you to easily +# move the test cases to other locations or to other machines. +# +THIS_DIR := $variable{"PWD"} + # Define each test with TEST_START # The config options below it will override the defaults TEST_START @@ -3034,7 +3049,7 @@ if ($#new_configs >= 0) { open(OUT, ">>$ktest_config") or die "Can not append to $ktest_config"; foreach my $config (@new_configs) { print OUT "$config = $entered_configs{$config}\n"; - $opt{$config} = $entered_configs{$config}; + $opt{$config} = process_variables($entered_configs{$config}); } } -- cgit v1.2.3-70-g09d2 From 5182a131ddf988fe4f5cef9964dbfb64a188b0c3 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 23 Aug 2011 02:20:08 +0000 Subject: perf/powerpc: Fix build for PowerPC with uclibc toolchains libio.h is not provided by uClibc, in order to be able to test the definition of __UCLIBC__ we need to include stdlib.h, which also includes stddef.h, providing the definition of 'NULL'. Signed-off-by: Florian Fainelli Signed-off-by: Benjamin Herrenschmidt --- tools/perf/arch/powerpc/util/dwarf-regs.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'tools') diff --git a/tools/perf/arch/powerpc/util/dwarf-regs.c b/tools/perf/arch/powerpc/util/dwarf-regs.c index 48ae0c5e3f7..7cdd61d0e27 100644 --- a/tools/perf/arch/powerpc/util/dwarf-regs.c +++ b/tools/perf/arch/powerpc/util/dwarf-regs.c @@ -9,7 +9,10 @@ * 2 of the License, or (at your option) any later version. */ +#include +#ifndef __UCLIBC__ #include +#endif #include -- cgit v1.2.3-70-g09d2 From c168fbfb93a1c4044287858c6784f0bd1f6cfe33 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 16 Nov 2011 12:55:59 -0200 Subject: perf tools: Eliminate duplicate code and use PATH_MAX consistently No need for multiple definitions for STR() and die(), also use SuSv2's PATH_MAX instead of adding MAX_PATH. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-qpujjkw7u0bf0tr4wt55cr9y@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-probe.c | 1 - tools/perf/util/cgroup.c | 15 +++++++-------- tools/perf/util/debugfs.c | 12 ++++++------ tools/perf/util/debugfs.h | 29 +++++++++-------------------- tools/perf/util/probe-finder.h | 1 - tools/perf/util/trace-event-info.c | 28 ++-------------------------- 6 files changed, 24 insertions(+), 62 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index 710ae3d0a48..59d43abfbfe 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c @@ -46,7 +46,6 @@ #define DEFAULT_VAR_FILTER "!__k???tab_* & !__crc_*" #define DEFAULT_FUNC_FILTER "!_*" -#define MAX_PATH_LEN 256 /* Session management structure */ static struct { diff --git a/tools/perf/util/cgroup.c b/tools/perf/util/cgroup.c index 96bee5c4600..dbe2f16b1a1 100644 --- a/tools/perf/util/cgroup.c +++ b/tools/perf/util/cgroup.c @@ -3,7 +3,6 @@ #include "parse-options.h" #include "evsel.h" #include "cgroup.h" -#include "debugfs.h" /* MAX_PATH, STR() */ #include "evlist.h" int nr_cgroups; @@ -12,7 +11,7 @@ static int cgroupfs_find_mountpoint(char *buf, size_t maxlen) { FILE *fp; - char mountpoint[MAX_PATH+1], tokens[MAX_PATH+1], type[MAX_PATH+1]; + char mountpoint[PATH_MAX + 1], tokens[PATH_MAX + 1], type[PATH_MAX + 1]; char *token, *saved_ptr = NULL; int found = 0; @@ -25,8 +24,8 @@ cgroupfs_find_mountpoint(char *buf, size_t maxlen) * and inspect every cgroupfs mount point to find one that has * perf_event subsystem */ - while (fscanf(fp, "%*s %"STR(MAX_PATH)"s %"STR(MAX_PATH)"s %" - STR(MAX_PATH)"s %*d %*d\n", + while (fscanf(fp, "%*s %"STR(PATH_MAX)"s %"STR(PATH_MAX)"s %" + STR(PATH_MAX)"s %*d %*d\n", mountpoint, type, tokens) == 3) { if (!strcmp(type, "cgroup")) { @@ -57,15 +56,15 @@ cgroupfs_find_mountpoint(char *buf, size_t maxlen) static int open_cgroup(char *name) { - char path[MAX_PATH+1]; - char mnt[MAX_PATH+1]; + char path[PATH_MAX + 1]; + char mnt[PATH_MAX + 1]; int fd; - if (cgroupfs_find_mountpoint(mnt, MAX_PATH+1)) + if (cgroupfs_find_mountpoint(mnt, PATH_MAX + 1)) return -1; - snprintf(path, MAX_PATH, "%s/%s", mnt, name); + snprintf(path, PATH_MAX, "%s/%s", mnt, name); fd = open(path, O_RDONLY); if (fd == -1) diff --git a/tools/perf/util/debugfs.c b/tools/perf/util/debugfs.c index a88fefc0cc0..680be3460e8 100644 --- a/tools/perf/util/debugfs.c +++ b/tools/perf/util/debugfs.c @@ -2,8 +2,10 @@ #include "debugfs.h" #include "cache.h" +#include + static int debugfs_premounted; -static char debugfs_mountpoint[MAX_PATH+1]; +static char debugfs_mountpoint[PATH_MAX + 1]; static const char *debugfs_known_mountpoints[] = { "/sys/kernel/debug/", @@ -64,9 +66,7 @@ const char *debugfs_find_mountpoint(void) if (fp == NULL) die("Can't open /proc/mounts for read"); - while (fscanf(fp, "%*s %" - STR(MAX_PATH) - "s %99s %*s %*d %*d\n", + while (fscanf(fp, "%*s %" STR(PATH_MAX) "s %99s %*s %*d %*d\n", debugfs_mountpoint, type) == 2) { if (strcmp(type, "debugfs") == 0) break; @@ -158,7 +158,7 @@ int debugfs_umount(void) int debugfs_write(const char *entry, const char *value) { - char path[MAX_PATH+1]; + char path[PATH_MAX + 1]; int ret, count; int fd; @@ -203,7 +203,7 @@ int debugfs_write(const char *entry, const char *value) */ int debugfs_read(const char *entry, char *buffer, size_t size) { - char path[MAX_PATH+1]; + char path[PATH_MAX + 1]; int ret; int fd; diff --git a/tools/perf/util/debugfs.h b/tools/perf/util/debugfs.h index 83a02879745..8cd3fa0af88 100644 --- a/tools/perf/util/debugfs.h +++ b/tools/perf/util/debugfs.h @@ -1,25 +1,14 @@ #ifndef __DEBUGFS_H__ #define __DEBUGFS_H__ -#include - -#ifndef MAX_PATH -# define MAX_PATH 256 -#endif - -#ifndef STR -# define _STR(x) #x -# define STR(x) _STR(x) -#endif - -extern const char *debugfs_find_mountpoint(void); -extern int debugfs_valid_mountpoint(const char *debugfs); -extern int debugfs_valid_entry(const char *path); -extern char *debugfs_mount(const char *mountpoint); -extern int debugfs_umount(void); -extern int debugfs_write(const char *entry, const char *value); -extern int debugfs_read(const char *entry, char *buffer, size_t size); -extern void debugfs_force_cleanup(void); -extern int debugfs_make_path(const char *element, char *buffer, int size); +const char *debugfs_find_mountpoint(void); +int debugfs_valid_mountpoint(const char *debugfs); +int debugfs_valid_entry(const char *path); +char *debugfs_mount(const char *mountpoint); +int debugfs_umount(void); +int debugfs_write(const char *entry, const char *value); +int debugfs_read(const char *entry, char *buffer, size_t size); +void debugfs_force_cleanup(void); +int debugfs_make_path(const char *element, char *buffer, int size); #endif /* __DEBUGFS_H__ */ diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h index 1132c8f0ce8..17e94d0c36f 100644 --- a/tools/perf/util/probe-finder.h +++ b/tools/perf/util/probe-finder.h @@ -5,7 +5,6 @@ #include "util.h" #include "probe-event.h" -#define MAX_PATH_LEN 256 #define MAX_PROBE_BUFFER 1024 #define MAX_PROBES 128 diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c index d2655f08bcc..ac6830d8292 100644 --- a/tools/perf/util/trace-event-info.c +++ b/tools/perf/util/trace-event-info.c @@ -18,7 +18,8 @@ * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -#define _GNU_SOURCE +#include +#include "util.h" #include #include #include @@ -31,7 +32,6 @@ #include #include #include -#include #include #include #include @@ -44,10 +44,6 @@ #define VERSION "0.5" -#define _STR(x) #x -#define STR(x) _STR(x) -#define MAX_PATH 256 - #define TRACE_CTRL "tracing_on" #define TRACE "trace" #define AVAILABLE "available_tracers" @@ -73,26 +69,6 @@ struct events { }; - -static void die(const char *fmt, ...) -{ - va_list ap; - int ret = errno; - - if (errno) - perror("perf"); - else - ret = -1; - - va_start(ap, fmt); - fprintf(stderr, " "); - vfprintf(stderr, fmt, ap); - va_end(ap); - - fprintf(stderr, "\n"); - exit(ret); -} - void *malloc_or_die(unsigned int size) { void *data; -- cgit v1.2.3-70-g09d2 From ebf294bf4f147aff29df5a16bfb0f8ebca15feaa Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 16 Nov 2011 14:03:07 -0200 Subject: perf tools: Simplify debugfs mountpoint handling code We don't need to have two PATH_MAX char sized arrays holding it, just one in util/debugfs.c will do. Also rename debugfs_path to tracing_events_path, as it is not the path to debugfs, that is debugfs_mountpoint. Both are now accessible. This will allow accessing this code in the perf python binding without having to drag in perf.c and util/parse-events.c. The defaults for these variables are the canonical "/sys/kernel/debug" and "/sys/kernel/debug/tracing/events/", removing the need for simple tools to call debugfs_mount(NULL). Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-ug9jvtjrsqbluuhqqxpvg30f@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-test.c | 3 ++- tools/perf/perf.c | 33 ++++----------------------------- tools/perf/util/debugfs.c | 25 ++++++++++++++++++++----- tools/perf/util/debugfs.h | 4 ++++ tools/perf/util/parse-events.c | 28 +++++++++++++--------------- tools/perf/util/parse-events.h | 1 - 6 files changed, 43 insertions(+), 51 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c index 831d1baeac3..77d68bfb79d 100644 --- a/tools/perf/builtin-test.c +++ b/tools/perf/builtin-test.c @@ -7,6 +7,7 @@ #include "util/cache.h" #include "util/debug.h" +#include "util/debugfs.h" #include "util/evlist.h" #include "util/parse-options.h" #include "util/parse-events.h" @@ -247,7 +248,7 @@ static int trace_event__id(const char *evname) if (asprintf(&filename, "%s/syscalls/%s/id", - debugfs_path, evname) < 0) + tracing_events_path, evname) < 0) return -1; fd = open(filename, O_RDONLY); diff --git a/tools/perf/perf.c b/tools/perf/perf.c index 73d0cac8b67..2b2e225a4d4 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c @@ -29,8 +29,6 @@ struct pager_config { int val; }; -static char debugfs_mntpt[MAXPATHLEN]; - static int pager_command_config(const char *var, const char *value, void *data) { struct pager_config *c = data; @@ -81,15 +79,6 @@ static void commit_pager_choice(void) } } -static void set_debugfs_path(void) -{ - char *path; - - path = getenv(PERF_DEBUGFS_ENVIRONMENT); - snprintf(debugfs_path, MAXPATHLEN, "%s/%s", path ?: debugfs_mntpt, - "tracing/events"); -} - static int handle_options(const char ***argv, int *argc, int *envchanged) { int handled = 0; @@ -161,15 +150,14 @@ static int handle_options(const char ***argv, int *argc, int *envchanged) fprintf(stderr, "No directory given for --debugfs-dir.\n"); usage(perf_usage_string); } - strncpy(debugfs_mntpt, (*argv)[1], MAXPATHLEN); - debugfs_mntpt[MAXPATHLEN - 1] = '\0'; + debugfs_set_path((*argv)[1]); if (envchanged) *envchanged = 1; (*argv)++; (*argc)--; } else if (!prefixcmp(cmd, CMD_DEBUGFS_DIR)) { - strncpy(debugfs_mntpt, cmd + strlen(CMD_DEBUGFS_DIR), MAXPATHLEN); - debugfs_mntpt[MAXPATHLEN - 1] = '\0'; + debugfs_set_path(cmd + strlen(CMD_DEBUGFS_DIR)); + fprintf(stderr, "dir: %s\n", debugfs_mountpoint); if (envchanged) *envchanged = 1; } else { @@ -281,7 +269,6 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv) if (use_pager == -1 && p->option & USE_PAGER) use_pager = 1; commit_pager_choice(); - set_debugfs_path(); status = p->fn(argc, argv, prefix); exit_browser(status); @@ -416,17 +403,6 @@ static int run_argv(int *argcp, const char ***argv) return done_alias; } -/* mini /proc/mounts parser: searching for "^blah /mount/point debugfs" */ -static void get_debugfs_mntpt(void) -{ - const char *path = debugfs_mount(NULL); - - if (path) - strncpy(debugfs_mntpt, path, sizeof(debugfs_mntpt)); - else - debugfs_mntpt[0] = '\0'; -} - static void pthread__block_sigwinch(void) { sigset_t set; @@ -453,7 +429,7 @@ int main(int argc, const char **argv) if (!cmd) cmd = "perf-help"; /* get debugfs mount point from /proc/mounts */ - get_debugfs_mntpt(); + debugfs_mount(NULL); /* * "perf-xxxx" is the same as "perf xxxx", but we obviously: * @@ -476,7 +452,6 @@ int main(int argc, const char **argv) argc--; handle_options(&argv, &argc, NULL); commit_pager_choice(); - set_debugfs_path(); set_buildid_dir(); if (argc > 0) { diff --git a/tools/perf/util/debugfs.c b/tools/perf/util/debugfs.c index 680be3460e8..ffc35e748e8 100644 --- a/tools/perf/util/debugfs.c +++ b/tools/perf/util/debugfs.c @@ -2,10 +2,12 @@ #include "debugfs.h" #include "cache.h" +#include #include static int debugfs_premounted; -static char debugfs_mountpoint[PATH_MAX + 1]; +char debugfs_mountpoint[PATH_MAX + 1] = "/sys/kernel/debug"; +char tracing_events_path[PATH_MAX + 1] = "/sys/kernel/debug/tracing/events"; static const char *debugfs_known_mountpoints[] = { "/sys/kernel/debug/", @@ -64,7 +66,7 @@ const char *debugfs_find_mountpoint(void) /* give up and parse /proc/mounts */ fp = fopen("/proc/mounts", "r"); if (fp == NULL) - die("Can't open /proc/mounts for read"); + return NULL; while (fscanf(fp, "%*s %" STR(PATH_MAX) "s %99s %*s %*d %*d\n", debugfs_mountpoint, type) == 2) { @@ -106,6 +108,12 @@ int debugfs_valid_entry(const char *path) return 0; } +static void debugfs_set_tracing_events_path(const char *mountpoint) +{ + snprintf(tracing_events_path, sizeof(tracing_events_path), "%s/%s", + mountpoint, "tracing/events"); +} + /* mount the debugfs somewhere if it's not mounted */ char *debugfs_mount(const char *mountpoint) @@ -113,7 +121,7 @@ char *debugfs_mount(const char *mountpoint) /* see if it's already mounted */ if (debugfs_find_mountpoint()) { debugfs_premounted = 1; - return debugfs_mountpoint; + goto out; } /* if not mounted and no argument */ @@ -129,12 +137,19 @@ char *debugfs_mount(const char *mountpoint) return NULL; /* save the mountpoint */ - strncpy(debugfs_mountpoint, mountpoint, sizeof(debugfs_mountpoint)); debugfs_found = 1; - + strncpy(debugfs_mountpoint, mountpoint, sizeof(debugfs_mountpoint)); +out: + debugfs_set_tracing_events_path(debugfs_mountpoint); return debugfs_mountpoint; } +void debugfs_set_path(const char *mountpoint) +{ + snprintf(debugfs_mountpoint, sizeof(debugfs_mountpoint), "%s", mountpoint); + debugfs_set_tracing_events_path(mountpoint); +} + /* umount the debugfs */ int debugfs_umount(void) diff --git a/tools/perf/util/debugfs.h b/tools/perf/util/debugfs.h index 8cd3fa0af88..4a878f735eb 100644 --- a/tools/perf/util/debugfs.h +++ b/tools/perf/util/debugfs.h @@ -6,9 +6,13 @@ int debugfs_valid_mountpoint(const char *debugfs); int debugfs_valid_entry(const char *path); char *debugfs_mount(const char *mountpoint); int debugfs_umount(void); +void debugfs_set_path(const char *mountpoint); int debugfs_write(const char *entry, const char *value); int debugfs_read(const char *entry, char *buffer, size_t size); void debugfs_force_cleanup(void); int debugfs_make_path(const char *element, char *buffer, int size); +extern char debugfs_mountpoint[]; +extern char tracing_events_path[]; + #endif /* __DEBUGFS_H__ */ diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 928918b796b..586ab3fe60f 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -25,8 +25,6 @@ enum event_result { EVT_HANDLED_ALL }; -char debugfs_path[MAXPATHLEN]; - #define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x #define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x @@ -140,7 +138,7 @@ static int tp_event_has_id(struct dirent *sys_dir, struct dirent *evt_dir) char evt_path[MAXPATHLEN]; int fd; - snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", debugfs_path, + snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", tracing_events_path, sys_dir->d_name, evt_dir->d_name); fd = open(evt_path, O_RDONLY); if (fd < 0) @@ -171,16 +169,16 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config) char evt_path[MAXPATHLEN]; char dir_path[MAXPATHLEN]; - if (debugfs_valid_mountpoint(debugfs_path)) + if (debugfs_valid_mountpoint(tracing_events_path)) return NULL; - sys_dir = opendir(debugfs_path); + sys_dir = opendir(tracing_events_path); if (!sys_dir) return NULL; for_each_subsystem(sys_dir, sys_dirent, sys_next) { - snprintf(dir_path, MAXPATHLEN, "%s/%s", debugfs_path, + snprintf(dir_path, MAXPATHLEN, "%s/%s", tracing_events_path, sys_dirent.d_name); evt_dir = opendir(dir_path); if (!evt_dir) @@ -447,7 +445,7 @@ parse_single_tracepoint_event(char *sys_name, u64 id; int fd; - snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", debugfs_path, + snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", tracing_events_path, sys_name, evt_name); fd = open(evt_path, O_RDONLY); @@ -485,7 +483,7 @@ parse_multiple_tracepoint_event(struct perf_evlist *evlist, char *sys_name, struct dirent *evt_ent; DIR *evt_dir; - snprintf(evt_path, MAXPATHLEN, "%s/%s", debugfs_path, sys_name); + snprintf(evt_path, MAXPATHLEN, "%s/%s", tracing_events_path, sys_name); evt_dir = opendir(evt_path); if (!evt_dir) { @@ -528,7 +526,7 @@ parse_tracepoint_event(struct perf_evlist *evlist, const char **strp, char sys_name[MAX_EVENT_LENGTH]; unsigned int sys_length, evt_length; - if (debugfs_valid_mountpoint(debugfs_path)) + if (debugfs_valid_mountpoint(tracing_events_path)) return 0; evt_name = strchr(*strp, ':'); @@ -920,10 +918,10 @@ void print_tracepoint_events(const char *subsys_glob, const char *event_glob) char evt_path[MAXPATHLEN]; char dir_path[MAXPATHLEN]; - if (debugfs_valid_mountpoint(debugfs_path)) + if (debugfs_valid_mountpoint(tracing_events_path)) return; - sys_dir = opendir(debugfs_path); + sys_dir = opendir(tracing_events_path); if (!sys_dir) return; @@ -932,7 +930,7 @@ void print_tracepoint_events(const char *subsys_glob, const char *event_glob) !strglobmatch(sys_dirent.d_name, subsys_glob)) continue; - snprintf(dir_path, MAXPATHLEN, "%s/%s", debugfs_path, + snprintf(dir_path, MAXPATHLEN, "%s/%s", tracing_events_path, sys_dirent.d_name); evt_dir = opendir(dir_path); if (!evt_dir) @@ -964,16 +962,16 @@ int is_valid_tracepoint(const char *event_string) char evt_path[MAXPATHLEN]; char dir_path[MAXPATHLEN]; - if (debugfs_valid_mountpoint(debugfs_path)) + if (debugfs_valid_mountpoint(tracing_events_path)) return 0; - sys_dir = opendir(debugfs_path); + sys_dir = opendir(tracing_events_path); if (!sys_dir) return 0; for_each_subsystem(sys_dir, sys_dirent, sys_next) { - snprintf(dir_path, MAXPATHLEN, "%s/%s", debugfs_path, + snprintf(dir_path, MAXPATHLEN, "%s/%s", tracing_events_path, sys_dirent.d_name); evt_dir = opendir(dir_path); if (!evt_dir) diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index 2f8e375e038..7e0cbe75d5f 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -39,7 +39,6 @@ void print_tracepoint_events(const char *subsys_glob, const char *event_glob); int print_hwcache_events(const char *event_glob); extern int is_valid_tracepoint(const char *event_string); -extern char debugfs_path[]; extern int valid_debugfs_mount(const char *debugfs); #endif /* __PERF_PARSE_EVENTS_H */ -- cgit v1.2.3-70-g09d2 From 50d08e47bc04eb05502f5c86b70bbd19ef1c2778 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 4 Nov 2011 09:10:59 -0200 Subject: perf evlist: Introduce perf_evlist__add_attrs Replacing the open coded equivalents in 'perf stat'. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-1btwadnf2tds2g07hsccsdse@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-stat.c | 40 +++++++--------------------------------- tools/perf/util/evlist.c | 34 ++++++++++++++++++++++++++++++++++ tools/perf/util/evlist.h | 7 +++++++ 3 files changed, 48 insertions(+), 33 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 7d98676808d..227befbecec 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -1107,22 +1107,13 @@ static const struct option options[] = { */ static int add_default_attributes(void) { - struct perf_evsel *pos; - size_t attr_nr = 0; - size_t c; - /* Set attrs if no event is selected and !null_run: */ if (null_run) return 0; if (!evsel_list->nr_entries) { - for (c = 0; c < ARRAY_SIZE(default_attrs); c++) { - pos = perf_evsel__new(default_attrs + c, c + attr_nr); - if (pos == NULL) - return -1; - perf_evlist__add(evsel_list, pos); - } - attr_nr += c; + if (perf_evlist__add_attrs_array(evsel_list, default_attrs) < 0) + return -1; } /* Detailed events get appended to the event list: */ @@ -1131,38 +1122,21 @@ static int add_default_attributes(void) return 0; /* Append detailed run extra attributes: */ - for (c = 0; c < ARRAY_SIZE(detailed_attrs); c++) { - pos = perf_evsel__new(detailed_attrs + c, c + attr_nr); - if (pos == NULL) - return -1; - perf_evlist__add(evsel_list, pos); - } - attr_nr += c; + if (perf_evlist__add_attrs_array(evsel_list, detailed_attrs) < 0) + return -1; if (detailed_run < 2) return 0; /* Append very detailed run extra attributes: */ - for (c = 0; c < ARRAY_SIZE(very_detailed_attrs); c++) { - pos = perf_evsel__new(very_detailed_attrs + c, c + attr_nr); - if (pos == NULL) - return -1; - perf_evlist__add(evsel_list, pos); - } + if (perf_evlist__add_attrs_array(evsel_list, very_detailed_attrs) < 0) + return -1; if (detailed_run < 3) return 0; /* Append very, very detailed run extra attributes: */ - for (c = 0; c < ARRAY_SIZE(very_very_detailed_attrs); c++) { - pos = perf_evsel__new(very_very_detailed_attrs + c, c + attr_nr); - if (pos == NULL) - return -1; - perf_evlist__add(evsel_list, pos); - } - - - return 0; + return perf_evlist__add_attrs_array(evsel_list, very_very_detailed_attrs); } int cmd_stat(int argc, const char **argv, const char *prefix __used) diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index fbb4b4ab9cc..58aa1e0092b 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -13,6 +13,8 @@ #include "evsel.h" #include "util.h" +#include "parse-events.h" + #include #include @@ -76,6 +78,14 @@ void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry) ++evlist->nr_entries; } +static void perf_evlist__splice_list_tail(struct perf_evlist *evlist, + struct list_head *list, + int nr_entries) +{ + list_splice_tail(list, &evlist->entries); + evlist->nr_entries += nr_entries; +} + int perf_evlist__add_default(struct perf_evlist *evlist) { struct perf_event_attr attr = { @@ -100,6 +110,30 @@ error: return -ENOMEM; } +int perf_evlist__add_attrs(struct perf_evlist *evlist, + struct perf_event_attr *attrs, size_t nr_attrs) +{ + struct perf_evsel *evsel, *n; + LIST_HEAD(head); + size_t i; + + for (i = 0; i < nr_attrs; i++) { + evsel = perf_evsel__new(attrs + i, evlist->nr_entries + i); + if (evsel == NULL) + goto out_delete_partial_list; + list_add_tail(&evsel->node, &head); + } + + perf_evlist__splice_list_tail(evlist, &head, nr_attrs); + + return 0; + +out_delete_partial_list: + list_for_each_entry_safe(evsel, n, &head, node) + perf_evsel__delete(evsel); + return -1; +} + void perf_evlist__disable(struct perf_evlist *evlist) { int cpu, thread; diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 1779ffef782..57d91ff2c56 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -2,8 +2,10 @@ #define __PERF_EVLIST_H 1 #include +#include #include "../perf.h" #include "event.h" +#include "util.h" struct pollfd; struct thread_map; @@ -39,6 +41,11 @@ void perf_evlist__delete(struct perf_evlist *evlist); void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry); int perf_evlist__add_default(struct perf_evlist *evlist); +int perf_evlist__add_attrs(struct perf_evlist *evlist, + struct perf_event_attr *attrs, size_t nr_attrs); + +#define perf_evlist__add_attrs_array(evlist, array) \ + perf_evlist__add_attrs(evlist, array, ARRAY_SIZE(array)) void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel, int cpu, int thread, u64 id); -- cgit v1.2.3-70-g09d2 From a8c9ae18d810e1ae12b6ec960907e9af63171d3a Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sat, 5 Nov 2011 08:41:51 -0200 Subject: perf evlist: Introduce add_tracepoints method Convenient way of asking for tracepoint events to be added to an existing evlist. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-0ylj4wrg54791u0baqb9swbb@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evlist.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++- tools/perf/util/evlist.h | 5 +++++ tools/perf/util/setup.py | 3 ++- 3 files changed, 63 insertions(+), 2 deletions(-) (limited to 'tools') diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 58aa1e0092b..3bc5a287a9f 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -6,12 +6,13 @@ * * Released under the GPL v2. (and only v2, not any later version) */ +#include "util.h" +#include "debugfs.h" #include #include "cpumap.h" #include "thread_map.h" #include "evlist.h" #include "evsel.h" -#include "util.h" #include "parse-events.h" @@ -134,6 +135,60 @@ out_delete_partial_list: return -1; } +static int trace_event__id(const char *evname) +{ + char *filename, *colon; + int err = -1, fd; + + if (asprintf(&filename, "%s/%s/id", tracing_events_path, evname) < 0) + return -1; + + colon = strrchr(filename, ':'); + if (colon != NULL) + *colon = '/'; + + fd = open(filename, O_RDONLY); + if (fd >= 0) { + char id[16]; + if (read(fd, id, sizeof(id)) > 0) + err = atoi(id); + close(fd); + } + + free(filename); + return err; +} + +int perf_evlist__add_tracepoints(struct perf_evlist *evlist, + const char *tracepoints[], + size_t nr_tracepoints) +{ + int err; + size_t i; + struct perf_event_attr *attrs = zalloc(nr_tracepoints * sizeof(*attrs)); + + if (attrs == NULL) + return -1; + + for (i = 0; i < nr_tracepoints; i++) { + err = trace_event__id(tracepoints[i]); + + if (err < 0) + goto out_free_attrs; + + attrs[i].type = PERF_TYPE_TRACEPOINT; + attrs[i].config = err; + attrs[i].sample_type = (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | + PERF_SAMPLE_CPU); + attrs[i].sample_period = 1; + } + + err = perf_evlist__add_attrs(evlist, attrs, nr_tracepoints); +out_free_attrs: + free(attrs); + return err; +} + void perf_evlist__disable(struct perf_evlist *evlist) { int cpu, thread; diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 57d91ff2c56..ec71c82935b 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -43,10 +43,15 @@ void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry); int perf_evlist__add_default(struct perf_evlist *evlist); int perf_evlist__add_attrs(struct perf_evlist *evlist, struct perf_event_attr *attrs, size_t nr_attrs); +int perf_evlist__add_tracepoints(struct perf_evlist *evlist, + const char *tracepoints[], size_t nr_tracepoints); #define perf_evlist__add_attrs_array(evlist, array) \ perf_evlist__add_attrs(evlist, array, ARRAY_SIZE(array)) +#define perf_evlist__add_tracepoints_array(evlist, array) \ + perf_evlist__add_tracepoints(evlist, array, ARRAY_SIZE(array)) + void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel, int cpu, int thread, u64 id); diff --git a/tools/perf/util/setup.py b/tools/perf/util/setup.py index 95d37007492..36d4c561957 100644 --- a/tools/perf/util/setup.py +++ b/tools/perf/util/setup.py @@ -27,7 +27,8 @@ build_tmp = getenv('PYTHON_EXTBUILD_TMP') perf = Extension('perf', sources = ['util/python.c', 'util/ctype.c', 'util/evlist.c', 'util/evsel.c', 'util/cpumap.c', 'util/thread_map.c', - 'util/util.c', 'util/xyarray.c', 'util/cgroup.c'], + 'util/util.c', 'util/xyarray.c', 'util/cgroup.c', + 'util/debugfs.c'], include_dirs = ['util/include'], extra_compile_args = cflags, ) -- cgit v1.2.3-70-g09d2 From 0f82ebc452f921590e216b28eee0b41f5e434a48 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 8 Nov 2011 14:41:57 -0200 Subject: perf evsel: Introduce config attr method Out of the code in 'perf record', so that we can share option parsing, etc. Eventually will be used by 'perf top', but first 'trace' will use it. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-hzjqsgnte1esk90ytq0ap98v@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 180 ++++++++++++-------------------------------- tools/perf/perf.h | 20 +++++ tools/perf/util/evlist.c | 16 ++++ tools/perf/util/evlist.h | 4 + tools/perf/util/evsel.c | 70 +++++++++++++++++ tools/perf/util/evsel.h | 4 + 6 files changed, 162 insertions(+), 132 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 6ab58cc99d5..c3ac5415c09 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -35,32 +35,24 @@ enum write_mode_t { WRITE_APPEND }; -static u64 user_interval = ULLONG_MAX; -static u64 default_interval = 0; +static struct perf_record_opts record_opts = { + .target_pid = -1, + .target_tid = -1, + .user_freq = UINT_MAX, + .user_interval = ULLONG_MAX, + .freq = 1000, + .sample_id_all_avail = true, +}; static unsigned int page_size; static unsigned int mmap_pages = UINT_MAX; -static unsigned int user_freq = UINT_MAX; -static int freq = 1000; static int output; static int pipe_output = 0; static const char *output_name = NULL; static bool group = false; static int realtime_prio = 0; -static bool nodelay = false; -static bool raw_samples = false; -static bool sample_id_all_avail = true; -static bool system_wide = false; -static pid_t target_pid = -1; -static pid_t target_tid = -1; static pid_t child_pid = -1; -static bool no_inherit = false; static enum write_mode_t write_mode = WRITE_FORCE; -static bool call_graph = false; -static bool inherit_stat = false; -static bool no_samples = false; -static bool sample_address = false; -static bool sample_time = false; static bool no_buildid = false; static bool no_buildid_cache = false; static struct perf_evlist *evsel_list; @@ -72,7 +64,6 @@ static int file_new = 1; static off_t post_processing_offset; static struct perf_session *session; -static const char *cpu_list; static const char *progname; static void advance_output(size_t size) @@ -169,78 +160,6 @@ static void sig_atexit(void) kill(getpid(), signr); } -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 | - PERF_FORMAT_ID; - - attr->sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID; - - if (evlist->nr_entries > 1) - attr->sample_type |= PERF_SAMPLE_ID; - - /* - * We default some events to a 1 default interval. But keep - * it a weak assumption overridable by the user. - */ - if (!attr->sample_period || (user_freq != UINT_MAX && - user_interval != ULLONG_MAX)) { - if (freq) { - attr->sample_type |= PERF_SAMPLE_PERIOD; - attr->freq = 1; - attr->sample_freq = freq; - } else { - attr->sample_period = default_interval; - } - } - - if (no_samples) - attr->sample_freq = 0; - - if (inherit_stat) - attr->inherit_stat = 1; - - if (sample_address) { - attr->sample_type |= PERF_SAMPLE_ADDR; - attr->mmap_data = track; - } - - if (call_graph) - attr->sample_type |= PERF_SAMPLE_CALLCHAIN; - - if (system_wide) - attr->sample_type |= PERF_SAMPLE_CPU; - - if (sample_id_all_avail && - (sample_time || system_wide || !no_inherit || cpu_list)) - attr->sample_type |= PERF_SAMPLE_TIME; - - if (raw_samples) { - attr->sample_type |= PERF_SAMPLE_TIME; - attr->sample_type |= PERF_SAMPLE_RAW; - attr->sample_type |= PERF_SAMPLE_CPU; - } - - if (nodelay) { - attr->watermark = 0; - attr->wakeup_events = 1; - } - - attr->mmap = track; - attr->comm = track; - - if (target_pid == -1 && target_tid == -1 && !system_wide) { - attr->disabled = 1; - attr->enable_on_exec = 1; - } -} - static bool perf_evlist__equal(struct perf_evlist *evlist, struct perf_evlist *other) { @@ -264,11 +183,10 @@ static void open_counters(struct perf_evlist *evlist) { struct perf_evsel *pos, *first; - if (evlist->cpus->map[0] < 0) - no_inherit = true; - first = list_entry(evlist->entries.next, struct perf_evsel, node); + perf_evlist__config_attrs(evlist, &record_opts); + list_for_each_entry(pos, &evlist->entries, node) { struct perf_event_attr *attr = &pos->attr; struct xyarray *group_fd = NULL; @@ -288,10 +206,8 @@ static void open_counters(struct perf_evlist *evlist) if (group && pos != first) group_fd = first->fd; - - config_attr(pos, evlist); retry_sample_id: - attr->sample_id_all = sample_id_all_avail ? 1 : 0; + attr->sample_id_all = record_opts.sample_id_all_avail ? 1 : 0; try_again: if (perf_evsel__open(pos, evlist->cpus, evlist->threads, group, group_fd) < 0) { @@ -300,15 +216,15 @@ try_again: if (err == EPERM || err == EACCES) { ui__error_paranoid(); exit(EXIT_FAILURE); - } else if (err == ENODEV && cpu_list) { + } else if (err == ENODEV && record_opts.cpu_list) { die("No such device - did you specify" " an out-of-range profile CPU?\n"); - } else if (err == EINVAL && sample_id_all_avail) { + } else if (err == EINVAL && record_opts.sample_id_all_avail) { /* * Old kernel, no attr->sample_id_type_all field */ - sample_id_all_avail = false; - if (!sample_time && !raw_samples && !time_needed) + record_opts.sample_id_all_avail = false; + if (!record_opts.sample_time && !record_opts.raw_samples && !time_needed) attr->sample_type &= ~PERF_SAMPLE_TIME; goto retry_sample_id; @@ -482,13 +398,13 @@ static int __cmd_record(int argc, const char **argv) if (!output_name) { if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode)) - pipe_output = 1; + pipe_output = true; else output_name = "perf.data"; } if (output_name) { if (!strcmp(output_name, "-")) - pipe_output = 1; + pipe_output = true; else if (!stat(output_name, &st) && st.st_size) { if (write_mode == WRITE_FORCE) { char oldname[PATH_MAX]; @@ -592,7 +508,7 @@ static int __cmd_record(int argc, const char **argv) exit(-1); } - if (!system_wide && target_tid == -1 && target_pid == -1) + if (!record_opts.system_wide && record_opts.target_tid == -1 && record_opts.target_pid == -1) evsel_list->threads->map[0] = child_pid; close(child_ready_pipe[1]); @@ -689,7 +605,7 @@ static int __cmd_record(int argc, const char **argv) perf_session__process_machines(session, perf_event__synthesize_guest_os); - if (!system_wide) + if (!record_opts.system_wide) perf_event__synthesize_thread_map(evsel_list->threads, process_synthesized_event, session); @@ -766,44 +682,44 @@ const struct option record_options[] = { parse_events_option), OPT_CALLBACK(0, "filter", &evsel_list, "filter", "event filter", parse_filter), - OPT_INTEGER('p', "pid", &target_pid, + OPT_INTEGER('p', "pid", &record_opts.target_pid, "record events on existing process id"), - OPT_INTEGER('t', "tid", &target_tid, + OPT_INTEGER('t', "tid", &record_opts.target_tid, "record events on existing thread id"), OPT_INTEGER('r', "realtime", &realtime_prio, "collect data with this RT SCHED_FIFO priority"), - OPT_BOOLEAN('D', "no-delay", &nodelay, + OPT_BOOLEAN('D', "no-delay", &record_opts.no_delay, "collect data without buffering"), - OPT_BOOLEAN('R', "raw-samples", &raw_samples, + OPT_BOOLEAN('R', "raw-samples", &record_opts.raw_samples, "collect raw sample records from all opened counters"), - OPT_BOOLEAN('a', "all-cpus", &system_wide, + OPT_BOOLEAN('a', "all-cpus", &record_opts.system_wide, "system-wide collection from all CPUs"), OPT_BOOLEAN('A', "append", &append_file, "append to the output file to do incremental profiling"), - OPT_STRING('C', "cpu", &cpu_list, "cpu", + OPT_STRING('C', "cpu", &record_opts.cpu_list, "cpu", "list of cpus to monitor"), OPT_BOOLEAN('f', "force", &force, "overwrite existing data file (deprecated)"), - OPT_U64('c', "count", &user_interval, "event period to sample"), + OPT_U64('c', "count", &record_opts.user_interval, "event period to sample"), OPT_STRING('o', "output", &output_name, "file", "output file name"), - OPT_BOOLEAN('i', "no-inherit", &no_inherit, + OPT_BOOLEAN('i', "no-inherit", &record_opts.no_inherit, "child tasks do not inherit counters"), - OPT_UINTEGER('F', "freq", &user_freq, "profile at this frequency"), + OPT_UINTEGER('F', "freq", &record_opts.user_freq, "profile at this frequency"), OPT_UINTEGER('m', "mmap-pages", &mmap_pages, "number of mmap data pages"), OPT_BOOLEAN(0, "group", &group, "put the counters into a counter group"), - OPT_BOOLEAN('g', "call-graph", &call_graph, + OPT_BOOLEAN('g', "call-graph", &record_opts.call_graph, "do call-graph (stack chain/backtrace) recording"), OPT_INCR('v', "verbose", &verbose, "be more verbose (show counter open errors, etc)"), OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"), - OPT_BOOLEAN('s', "stat", &inherit_stat, + OPT_BOOLEAN('s', "stat", &record_opts.inherit_stat, "per thread counts"), - OPT_BOOLEAN('d', "data", &sample_address, + OPT_BOOLEAN('d', "data", &record_opts.sample_address, "Sample addresses"), - OPT_BOOLEAN('T', "timestamp", &sample_time, "Sample timestamps"), - OPT_BOOLEAN('n', "no-samples", &no_samples, + OPT_BOOLEAN('T', "timestamp", &record_opts.sample_time, "Sample timestamps"), + OPT_BOOLEAN('n', "no-samples", &record_opts.no_samples, "don't sample"), OPT_BOOLEAN('N', "no-buildid-cache", &no_buildid_cache, "do not update the buildid cache"), @@ -828,8 +744,8 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) argc = parse_options(argc, argv, record_options, record_usage, PARSE_OPT_STOP_AT_NON_OPTION); - if (!argc && target_pid == -1 && target_tid == -1 && - !system_wide && !cpu_list) + if (!argc && record_opts.target_pid == -1 && record_opts.target_tid == -1 && + !record_opts.system_wide && !record_opts.cpu_list) usage_with_options(record_usage, record_options); if (force && append_file) { @@ -842,7 +758,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) write_mode = WRITE_FORCE; } - if (nr_cgroups && !system_wide) { + if (nr_cgroups && !record_opts.system_wide) { fprintf(stderr, "cgroup monitoring only available in" " system-wide mode\n"); usage_with_options(record_usage, record_options); @@ -869,11 +785,11 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) goto out_symbol_exit; } - if (target_pid != -1) - target_tid = target_pid; + if (record_opts.target_pid != -1) + record_opts.target_tid = record_opts.target_pid; - if (perf_evlist__create_maps(evsel_list, target_pid, - target_tid, cpu_list) < 0) + if (perf_evlist__create_maps(evsel_list, record_opts.target_pid, + record_opts.target_tid, record_opts.cpu_list) < 0) usage_with_options(record_usage, record_options); list_for_each_entry(pos, &evsel_list->entries, node) { @@ -887,18 +803,18 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) if (perf_evlist__alloc_pollfd(evsel_list) < 0) goto out_free_fd; - if (user_interval != ULLONG_MAX) - default_interval = user_interval; - if (user_freq != UINT_MAX) - freq = user_freq; + if (record_opts.user_interval != ULLONG_MAX) + record_opts.default_interval = record_opts.user_interval; + if (record_opts.user_freq != UINT_MAX) + record_opts.freq = record_opts.user_freq; /* * User specified count overrides default frequency. */ - if (default_interval) - freq = 0; - else if (freq) { - default_interval = freq; + if (record_opts.default_interval) + record_opts.freq = 0; + else if (record_opts.freq) { + record_opts.default_interval = record_opts.freq; } else { fprintf(stderr, "frequency and count are zero, aborting\n"); err = -EINVAL; diff --git a/tools/perf/perf.h b/tools/perf/perf.h index 914c895510f..eb6a1388188 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h @@ -185,4 +185,24 @@ extern const char perf_version_string[]; void pthread__unblock_sigwinch(void); +struct perf_record_opts { + pid_t target_pid; + pid_t target_tid; + bool call_graph; + bool inherit_stat; + bool no_delay; + bool no_inherit; + bool no_samples; + bool raw_samples; + bool sample_address; + bool sample_time; + bool sample_id_all_avail; + bool system_wide; + unsigned int freq; + unsigned int user_freq; + u64 default_interval; + u64 user_interval; + const char *cpu_list; +}; + #endif diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 3bc5a287a9f..b774341e797 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -46,6 +46,22 @@ struct perf_evlist *perf_evlist__new(struct cpu_map *cpus, return evlist; } +void perf_evlist__config_attrs(struct perf_evlist *evlist, + struct perf_record_opts *opts) +{ + struct perf_evsel *evsel; + + if (evlist->cpus->map[0] < 0) + opts->no_inherit = true; + + list_for_each_entry(evsel, &evlist->entries, node) { + perf_evsel__config(evsel, opts); + + if (evlist->nr_entries > 1) + evsel->attr.sample_type |= PERF_SAMPLE_ID; + } +} + static void perf_evlist__purge(struct perf_evlist *evlist) { struct perf_evsel *pos, *n; diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index ec71c82935b..231c06f8286 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -10,6 +10,7 @@ struct pollfd; struct thread_map; struct cpu_map; +struct perf_record_opts; #define PERF_EVLIST__HLIST_BITS 8 #define PERF_EVLIST__HLIST_SIZE (1 << PERF_EVLIST__HLIST_BITS) @@ -64,6 +65,9 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx); int perf_evlist__open(struct perf_evlist *evlist, bool group); +void perf_evlist__config_attrs(struct perf_evlist *evlist, + struct perf_record_opts *opts); + int perf_evlist__alloc_mmap(struct perf_evlist *evlist); int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite); void perf_evlist__munmap(struct perf_evlist *evlist); diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index e4262642258..b38eaa34b28 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -53,6 +53,76 @@ struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx) return evsel; } +void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts) +{ + struct perf_event_attr *attr = &evsel->attr; + int track = !evsel->idx; /* only the first counter needs these */ + + attr->sample_id_all = opts->sample_id_all_avail ? 1 : 0; + attr->inherit = !opts->no_inherit; + attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | + PERF_FORMAT_TOTAL_TIME_RUNNING | + PERF_FORMAT_ID; + + attr->sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID; + + /* + * We default some events to a 1 default interval. But keep + * it a weak assumption overridable by the user. + */ + if (!attr->sample_period || (opts->user_freq != UINT_MAX && + opts->user_interval != ULLONG_MAX)) { + if (opts->freq) { + attr->sample_type |= PERF_SAMPLE_PERIOD; + attr->freq = 1; + attr->sample_freq = opts->freq; + } else { + attr->sample_period = opts->default_interval; + } + } + + if (opts->no_samples) + attr->sample_freq = 0; + + if (opts->inherit_stat) + attr->inherit_stat = 1; + + if (opts->sample_address) { + attr->sample_type |= PERF_SAMPLE_ADDR; + attr->mmap_data = track; + } + + if (opts->call_graph) + attr->sample_type |= PERF_SAMPLE_CALLCHAIN; + + if (opts->system_wide) + attr->sample_type |= PERF_SAMPLE_CPU; + + if (opts->sample_id_all_avail && + (opts->sample_time || opts->system_wide || + !opts->no_inherit || opts->cpu_list)) + attr->sample_type |= PERF_SAMPLE_TIME; + + if (opts->raw_samples) { + attr->sample_type |= PERF_SAMPLE_TIME; + attr->sample_type |= PERF_SAMPLE_RAW; + attr->sample_type |= PERF_SAMPLE_CPU; + } + + if (opts->no_delay) { + attr->watermark = 0; + attr->wakeup_events = 1; + } + + attr->mmap = track; + attr->comm = track; + + if (opts->target_pid == -1 && opts->target_tid == -1 && !opts->system_wide) { + attr->disabled = 1; + attr->enable_on_exec = 1; + } +} + int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads) { int cpu, thread; diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index b1d15e6f7ae..6421c07f501 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -67,6 +67,7 @@ struct perf_evsel { struct cpu_map; struct thread_map; struct perf_evlist; +struct perf_record_opts; struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx); void perf_evsel__init(struct perf_evsel *evsel, @@ -74,6 +75,9 @@ void perf_evsel__init(struct perf_evsel *evsel, void perf_evsel__exit(struct perf_evsel *evsel); void perf_evsel__delete(struct perf_evsel *evsel); +void perf_evsel__config(struct perf_evsel *evsel, + struct perf_record_opts *opts); + int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads); int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads); int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus); -- cgit v1.2.3-70-g09d2 From 35b9d88ecd8c5fb720ba0dd325262f356d0b03e7 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 9 Nov 2011 08:47:15 -0200 Subject: perf evlist: Introduce {prepare,start}_workload refactored from 'perf record' So that we can easily start a workload in other tools. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-zdsksd4aphu0nltg2lpwsw3x@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 81 ++++++-------------------------------- tools/perf/perf.h | 1 + tools/perf/util/evlist.c | 96 +++++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/evlist.h | 10 +++++ 4 files changed, 120 insertions(+), 68 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index c3ac5415c09..4799195ed24 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -47,11 +47,9 @@ static struct perf_record_opts record_opts = { static unsigned int page_size; static unsigned int mmap_pages = UINT_MAX; static int output; -static int pipe_output = 0; static const char *output_name = NULL; static bool group = false; static int realtime_prio = 0; -static pid_t child_pid = -1; static enum write_mode_t write_mode = WRITE_FORCE; static bool no_buildid = false; static bool no_buildid_cache = false; @@ -144,9 +142,9 @@ static void sig_atexit(void) { int status; - if (child_pid > 0) { + if (evsel_list->workload.pid > 0) { if (!child_finished) - kill(child_pid, SIGTERM); + kill(evsel_list->workload.pid, SIGTERM); wait(&status); if (WIFSIGNALED(status)) @@ -304,7 +302,7 @@ static int process_buildids(void) static void atexit_header(void) { - if (!pipe_output) { + if (!record_opts.pipe_output) { session->header.data_size += bytes_written; if (!no_buildid) @@ -377,9 +375,7 @@ static int __cmd_record(int argc, const char **argv) int flags; int err; unsigned long waking = 0; - int child_ready_pipe[2], go_pipe[2]; const bool forks = argc > 0; - char buf; struct machine *machine; progname = argv[0]; @@ -391,20 +387,15 @@ static int __cmd_record(int argc, const char **argv) signal(SIGINT, sig_handler); signal(SIGUSR1, sig_handler); - if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) { - perror("failed to create pipes"); - exit(-1); - } - if (!output_name) { if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode)) - pipe_output = true; + record_opts.pipe_output = true; else output_name = "perf.data"; } if (output_name) { if (!strcmp(output_name, "-")) - pipe_output = true; + record_opts.pipe_output = true; else if (!stat(output_name, &st) && st.st_size) { if (write_mode == WRITE_FORCE) { char oldname[PATH_MAX]; @@ -424,7 +415,7 @@ static int __cmd_record(int argc, const char **argv) else flags |= O_TRUNC; - if (pipe_output) + if (record_opts.pipe_output) output = STDOUT_FILENO; else output = open(output_name, flags, S_IRUSR | S_IWUSR); @@ -470,57 +461,11 @@ static int __cmd_record(int argc, const char **argv) mmap_pages = (512 * 1024) / page_size; if (forks) { - child_pid = fork(); - if (child_pid < 0) { - perror("failed to fork"); - exit(-1); - } - - if (!child_pid) { - if (pipe_output) - dup2(2, 1); - close(child_ready_pipe[0]); - close(go_pipe[1]); - fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC); - - /* - * Do a dummy execvp to get the PLT entry resolved, - * so we avoid the resolver overhead on the real - * execvp call. - */ - execvp("", (char **)argv); - - /* - * Tell the parent we're ready to go - */ - close(child_ready_pipe[1]); - - /* - * Wait until the parent tells us to go. - */ - if (read(go_pipe[0], &buf, 1) == -1) - perror("unable to read pipe"); - - execvp(argv[0], (char **)argv); - - perror(argv[0]); - kill(getppid(), SIGUSR1); - exit(-1); - } - - if (!record_opts.system_wide && record_opts.target_tid == -1 && record_opts.target_pid == -1) - evsel_list->threads->map[0] = child_pid; - - close(child_ready_pipe[1]); - close(go_pipe[0]); - /* - * wait for child to settle - */ - if (read(child_ready_pipe[0], &buf, 1) == -1) { - perror("unable to read pipe"); - exit(-1); + err = perf_evlist__prepare_workload(evsel_list, &record_opts, argv); + if (err < 0) { + pr_err("Couldn't run the workload!\n"); + goto out_delete_session; } - close(child_ready_pipe[0]); } open_counters(evsel_list); @@ -530,7 +475,7 @@ static int __cmd_record(int argc, const char **argv) */ atexit(atexit_header); - if (pipe_output) { + if (record_opts.pipe_output) { err = perf_header__write_pipe(output); if (err < 0) return err; @@ -543,7 +488,7 @@ static int __cmd_record(int argc, const char **argv) post_processing_offset = lseek(output, 0, SEEK_CUR); - if (pipe_output) { + if (record_opts.pipe_output) { err = perf_session__synthesize_attrs(session, process_synthesized_event); if (err < 0) { @@ -629,7 +574,7 @@ static int __cmd_record(int argc, const char **argv) * Let the child rip */ if (forks) - close(go_pipe[1]); + perf_evlist__start_workload(evsel_list); for (;;) { int hits = samples; diff --git a/tools/perf/perf.h b/tools/perf/perf.h index eb6a1388188..32ee6ca8eab 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h @@ -193,6 +193,7 @@ struct perf_record_opts { bool no_delay; bool no_inherit; bool no_samples; + bool pipe_output; bool raw_samples; bool sample_address; bool sample_time; diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index b774341e797..a472247af19 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -13,6 +13,7 @@ #include "thread_map.h" #include "evlist.h" #include "evsel.h" +#include #include "parse-events.h" @@ -33,6 +34,7 @@ void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus, INIT_HLIST_HEAD(&evlist->heads[i]); INIT_LIST_HEAD(&evlist->entries); perf_evlist__set_maps(evlist, cpus, threads); + evlist->workload.pid = -1; } struct perf_evlist *perf_evlist__new(struct cpu_map *cpus, @@ -674,3 +676,97 @@ out_err: return err; } + +int perf_evlist__prepare_workload(struct perf_evlist *evlist, + struct perf_record_opts *opts, + const char *argv[]) +{ + int child_ready_pipe[2], go_pipe[2]; + char bf; + + if (pipe(child_ready_pipe) < 0) { + perror("failed to create 'ready' pipe"); + return -1; + } + + if (pipe(go_pipe) < 0) { + perror("failed to create 'go' pipe"); + goto out_close_ready_pipe; + } + + evlist->workload.pid = fork(); + if (evlist->workload.pid < 0) { + perror("failed to fork"); + goto out_close_pipes; + } + + if (!evlist->workload.pid) { + if (opts->pipe_output) + dup2(2, 1); + + close(child_ready_pipe[0]); + close(go_pipe[1]); + fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC); + + /* + * Do a dummy execvp to get the PLT entry resolved, + * so we avoid the resolver overhead on the real + * execvp call. + */ + execvp("", (char **)argv); + + /* + * Tell the parent we're ready to go + */ + close(child_ready_pipe[1]); + + /* + * Wait until the parent tells us to go. + */ + if (read(go_pipe[0], &bf, 1) == -1) + perror("unable to read pipe"); + + execvp(argv[0], (char **)argv); + + perror(argv[0]); + kill(getppid(), SIGUSR1); + exit(-1); + } + + if (!opts->system_wide && opts->target_tid == -1 && opts->target_pid == -1) + evlist->threads->map[0] = evlist->workload.pid; + + close(child_ready_pipe[1]); + close(go_pipe[0]); + /* + * wait for child to settle + */ + if (read(child_ready_pipe[0], &bf, 1) == -1) { + perror("unable to read pipe"); + goto out_close_pipes; + } + + evlist->workload.cork_fd = go_pipe[1]; + close(child_ready_pipe[0]); + return 0; + +out_close_pipes: + close(go_pipe[0]); + close(go_pipe[1]); +out_close_ready_pipe: + close(child_ready_pipe[0]); + close(child_ready_pipe[1]); + return -1; +} + +int perf_evlist__start_workload(struct perf_evlist *evlist) +{ + if (evlist->workload.cork_fd > 0) { + /* + * Remove the cork, let it rip! + */ + return close(evlist->workload.cork_fd); + } + + return 0; +} diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 231c06f8286..07d56b3e6d6 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -6,6 +6,7 @@ #include "../perf.h" #include "event.h" #include "util.h" +#include struct pollfd; struct thread_map; @@ -22,6 +23,10 @@ struct perf_evlist { int nr_fds; int nr_mmaps; int mmap_len; + struct { + int cork_fd; + pid_t pid; + } workload; bool overwrite; union perf_event event_copy; struct perf_mmap *mmap; @@ -68,6 +73,11 @@ int perf_evlist__open(struct perf_evlist *evlist, bool group); void perf_evlist__config_attrs(struct perf_evlist *evlist, struct perf_record_opts *opts); +int perf_evlist__prepare_workload(struct perf_evlist *evlist, + struct perf_record_opts *opts, + const char *argv[]); +int perf_evlist__start_workload(struct perf_evlist *evlist); + int perf_evlist__alloc_mmap(struct perf_evlist *evlist); int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite); void perf_evlist__munmap(struct perf_evlist *evlist); -- cgit v1.2.3-70-g09d2 From 50a682ce875f91e04c81ae5680535aba5a770bad Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 9 Nov 2011 09:10:47 -0200 Subject: perf evlist: Handle default value for 'pages' on mmap method Every tool that calls this and allows the user to override the value needs this logic. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-lwscxpg57xfzahz5dmdfp9uz@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 4 ---- tools/perf/util/evlist.c | 12 +++++++++--- tools/perf/util/evlist.h | 3 ++- 3 files changed, 11 insertions(+), 8 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 4799195ed24..749862d57a8 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -456,10 +456,6 @@ static int __cmd_record(int argc, const char **argv) perf_header__set_feat(&session->header, HEADER_NUMA_TOPOLOGY); perf_header__set_feat(&session->header, HEADER_CPUID); - /* 512 kiB: default amount of unprivileged mlocked memory */ - if (mmap_pages == UINT_MAX) - mmap_pages = (512 * 1024) / page_size; - if (forks) { err = perf_evlist__prepare_workload(evsel_list, &record_opts, argv); if (err < 0) { diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index a472247af19..81237dcde1f 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -507,14 +507,20 @@ out_unmap: * * Using perf_evlist__read_on_cpu does this automatically. */ -int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite) +int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, + bool overwrite) { unsigned int page_size = sysconf(_SC_PAGE_SIZE); - int mask = pages * page_size - 1; struct perf_evsel *evsel; const struct cpu_map *cpus = evlist->cpus; const struct thread_map *threads = evlist->threads; - int prot = PROT_READ | (overwrite ? 0 : PROT_WRITE); + int prot = PROT_READ | (overwrite ? 0 : PROT_WRITE), mask; + + /* 512 kiB: default amount of unprivileged mlocked memory */ + if (pages == UINT_MAX) + pages = (512 * 1024) / page_size; + + mask = pages * page_size - 1; if (evlist->mmap == NULL && perf_evlist__alloc_mmap(evlist) < 0) return -ENOMEM; diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 07d56b3e6d6..17e9c80243c 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -79,7 +79,8 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist, int perf_evlist__start_workload(struct perf_evlist *evlist); int perf_evlist__alloc_mmap(struct perf_evlist *evlist); -int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite); +int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, + bool overwrite); void perf_evlist__munmap(struct perf_evlist *evlist); void perf_evlist__disable(struct perf_evlist *evlist); -- cgit v1.2.3-70-g09d2 From 01c2d99bcf6fc7f6ce3fe3d0fb38b124e1f127fc Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 9 Nov 2011 09:16:26 -0200 Subject: perf record: Move mmap_pages to perf_record_opts Tools being developed will need this to allow the user to override this value. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-zydc1yhxfm0z35fuy95bsn1l@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 9 +++++---- tools/perf/perf.h | 1 + 2 files changed, 6 insertions(+), 4 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 749862d57a8..ffb627d4021 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -35,9 +35,10 @@ enum write_mode_t { WRITE_APPEND }; -static struct perf_record_opts record_opts = { +struct perf_record_opts record_opts = { .target_pid = -1, .target_tid = -1, + .mmap_pages = UINT_MAX, .user_freq = UINT_MAX, .user_interval = ULLONG_MAX, .freq = 1000, @@ -45,7 +46,6 @@ static struct perf_record_opts record_opts = { }; static unsigned int page_size; -static unsigned int mmap_pages = UINT_MAX; static int output; static const char *output_name = NULL; static bool group = false; @@ -272,7 +272,7 @@ try_again: exit(-1); } - if (perf_evlist__mmap(evlist, mmap_pages, false) < 0) + if (perf_evlist__mmap(evlist, record_opts.mmap_pages, false) < 0) die("failed to mmap with %d (%s)\n", errno, strerror(errno)); if (file_new) @@ -647,7 +647,8 @@ const struct option record_options[] = { OPT_BOOLEAN('i', "no-inherit", &record_opts.no_inherit, "child tasks do not inherit counters"), OPT_UINTEGER('F', "freq", &record_opts.user_freq, "profile at this frequency"), - OPT_UINTEGER('m', "mmap-pages", &mmap_pages, "number of mmap data pages"), + OPT_UINTEGER('m', "mmap-pages", &record_opts.mmap_pages, + "number of mmap data pages"), OPT_BOOLEAN(0, "group", &group, "put the counters into a counter group"), OPT_BOOLEAN('g', "call-graph", &record_opts.call_graph, diff --git a/tools/perf/perf.h b/tools/perf/perf.h index 32ee6ca8eab..13c42f34e8b 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h @@ -200,6 +200,7 @@ struct perf_record_opts { bool sample_id_all_avail; bool system_wide; unsigned int freq; + unsigned int mmap_pages; unsigned int user_freq; u64 default_interval; u64 user_interval; -- cgit v1.2.3-70-g09d2 From b424eba27160dd19577896d4520b8eebabed919f Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 9 Nov 2011 13:24:25 -0200 Subject: perf session: Move threads to struct machine The 'machine' abstraction was introduced with 'perf kvm' where we could have samples for the host and multiple guests, but at the time we ended up keeping the list of all machines threads all in session->host_machine. Move the threads rb_tree to struct machine to separate the namespaces. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-mdg7sm6j3va09vtgj49gbsrp@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/build-id.c | 4 ++-- tools/perf/util/map.c | 4 ++++ tools/perf/util/map.h | 9 +++++++++ tools/perf/util/session.c | 47 +++++++++++++++++++++++++++++++++++++++------- tools/perf/util/session.h | 3 --- tools/perf/util/thread.c | 6 +++--- 6 files changed, 58 insertions(+), 15 deletions(-) (limited to 'tools') diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c index a91cd99f26e..f2fe6ec0894 100644 --- a/tools/perf/util/build-id.c +++ b/tools/perf/util/build-id.c @@ -48,8 +48,8 @@ static int perf_event__exit_del_thread(union perf_event *event, event->fork.ppid, event->fork.ptid); if (thread) { - rb_erase(&thread->rb_node, &session->threads); - session->last_match = NULL; + rb_erase(&thread->rb_node, &session->host_machine.threads); + session->host_machine.last_match = NULL; thread__delete(thread); } diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index 78284b13e80..316aa0ab712 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c @@ -562,6 +562,10 @@ int machine__init(struct machine *self, const char *root_dir, pid_t pid) INIT_LIST_HEAD(&self->user_dsos); INIT_LIST_HEAD(&self->kernel_dsos); + self->threads = RB_ROOT; + INIT_LIST_HEAD(&self->dead_threads); + self->last_match = NULL; + self->kmaps.machine = self; self->pid = pid; self->root_dir = strdup(root_dir); diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h index 890d85545d0..bde6835ee25 100644 --- a/tools/perf/util/map.h +++ b/tools/perf/util/map.h @@ -62,6 +62,9 @@ struct machine { struct rb_node rb_node; pid_t pid; char *root_dir; + struct rb_root threads; + struct list_head dead_threads; + struct thread *last_match; struct list_head user_dsos; struct list_head kernel_dsos; struct map_groups kmaps; @@ -190,6 +193,12 @@ struct symbol *map_groups__find_symbol_by_name(struct map_groups *mg, struct map **mapp, symbol_filter_t filter); + +struct thread *machine__findnew_thread(struct machine *machine, pid_t pid); +void machine__remove_thread(struct machine *machine, struct thread *th); + +size_t machine__fprintf(struct machine *machine, FILE *fp); + static inline struct symbol *machine__find_kernel_symbol(struct machine *self, enum map_type type, u64 addr, diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 85c1e6b76f0..a76666f1776 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -139,9 +139,6 @@ struct perf_session *perf_session__new(const char *filename, int mode, goto out; memcpy(self->filename, filename, len); - self->threads = RB_ROOT; - INIT_LIST_HEAD(&self->dead_threads); - self->last_match = NULL; /* * On 64bit we can mmap the data file in one go. No need for tiny mmap * slices. On 32bit we use 32MB. @@ -184,17 +181,22 @@ out_delete: return NULL; } -static void perf_session__delete_dead_threads(struct perf_session *self) +static void machine__delete_dead_threads(struct machine *machine) { struct thread *n, *t; - list_for_each_entry_safe(t, n, &self->dead_threads, node) { + list_for_each_entry_safe(t, n, &machine->dead_threads, node) { list_del(&t->node); thread__delete(t); } } -static void perf_session__delete_threads(struct perf_session *self) +static void perf_session__delete_dead_threads(struct perf_session *session) +{ + machine__delete_dead_threads(&session->host_machine); +} + +static void machine__delete_threads(struct machine *self) { struct rb_node *nd = rb_first(&self->threads); @@ -207,6 +209,11 @@ static void perf_session__delete_threads(struct perf_session *self) } } +static void perf_session__delete_threads(struct perf_session *session) +{ + machine__delete_threads(&session->host_machine); +} + void perf_session__delete(struct perf_session *self) { perf_session__destroy_kernel_maps(self); @@ -217,7 +224,7 @@ void perf_session__delete(struct perf_session *self) free(self); } -void perf_session__remove_thread(struct perf_session *self, struct thread *th) +void machine__remove_thread(struct machine *self, struct thread *th) { self->last_match = NULL; rb_erase(&th->rb_node, &self->threads); @@ -884,6 +891,11 @@ void perf_event_header__bswap(struct perf_event_header *self) self->size = bswap_16(self->size); } +struct thread *perf_session__findnew(struct perf_session *session, pid_t pid) +{ + return machine__findnew_thread(&session->host_machine, pid); +} + static struct thread *perf_session__register_idle_thread(struct perf_session *self) { struct thread *thread = perf_session__findnew(self, 0); @@ -1224,6 +1236,27 @@ size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp) return ret; } +size_t perf_session__fprintf(struct perf_session *session, FILE *fp) +{ + /* + * FIXME: Here we have to actually print all the machines in this + * session, not just the host... + */ + return machine__fprintf(&session->host_machine, fp); +} + +void perf_session__remove_thread(struct perf_session *session, + struct thread *th) +{ + /* + * FIXME: This one makes no sense, we need to remove the thread from + * the machine it belongs to, perf_session can have many machines, so + * doing it always on ->host_machine is wrong. Fix when auditing all + * the 'perf kvm' code. + */ + machine__remove_thread(&session->host_machine, th); +} + struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, unsigned int type) { diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 6e393c98eb3..76d462d3bef 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -30,9 +30,6 @@ struct perf_session { struct perf_header header; unsigned long size; unsigned long mmap_window; - struct rb_root threads; - struct list_head dead_threads; - struct thread *last_match; struct machine host_machine; struct rb_root machines; struct perf_evlist *evlist; diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index d5d3b22250f..fb4b7ea6752 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -61,7 +61,7 @@ static size_t thread__fprintf(struct thread *self, FILE *fp) map_groups__fprintf(&self->mg, verbose, fp); } -struct thread *perf_session__findnew(struct perf_session *self, pid_t pid) +struct thread *machine__findnew_thread(struct machine *self, pid_t pid) { struct rb_node **p = &self->threads.rb_node; struct rb_node *parent = NULL; @@ -125,12 +125,12 @@ int thread__fork(struct thread *self, struct thread *parent) return 0; } -size_t perf_session__fprintf(struct perf_session *self, FILE *fp) +size_t machine__fprintf(struct machine *machine, FILE *fp) { size_t ret = 0; struct rb_node *nd; - for (nd = rb_first(&self->threads); nd; nd = rb_next(nd)) { + for (nd = rb_first(&machine->threads); nd; nd = rb_next(nd)) { struct thread *pos = rb_entry(nd, struct thread, rb_node); ret += thread__fprintf(pos, fp); -- cgit v1.2.3-70-g09d2 From ed80f5813fd6ecc6d74250681910a4214f699d4e Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 11 Nov 2011 15:12:56 -0200 Subject: perf record: Move 'group' to perf_event_ops Will be used in other tools to share the command line parsing code. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-8x0yr77r6lrd2t699s499m8n@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 9 ++++----- tools/perf/perf.h | 1 + 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index ffb627d4021..ba6777a147c 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -48,7 +48,6 @@ struct perf_record_opts record_opts = { static unsigned int page_size; static int output; static const char *output_name = NULL; -static bool group = false; static int realtime_prio = 0; static enum write_mode_t write_mode = WRITE_FORCE; static bool no_buildid = false; @@ -202,13 +201,13 @@ static void open_counters(struct perf_evlist *evlist) */ bool time_needed = attr->sample_type & PERF_SAMPLE_TIME; - if (group && pos != first) + if (record_opts.group && pos != first) group_fd = first->fd; retry_sample_id: attr->sample_id_all = record_opts.sample_id_all_avail ? 1 : 0; try_again: - if (perf_evsel__open(pos, evlist->cpus, evlist->threads, group, - group_fd) < 0) { + if (perf_evsel__open(pos, evlist->cpus, evlist->threads, + record_opts.group, group_fd) < 0) { int err = errno; if (err == EPERM || err == EACCES) { @@ -649,7 +648,7 @@ const struct option record_options[] = { OPT_UINTEGER('F', "freq", &record_opts.user_freq, "profile at this frequency"), OPT_UINTEGER('m', "mmap-pages", &record_opts.mmap_pages, "number of mmap data pages"), - OPT_BOOLEAN(0, "group", &group, + OPT_BOOLEAN(0, "group", &record_opts.group, "put the counters into a counter group"), OPT_BOOLEAN('g', "call-graph", &record_opts.call_graph, "do call-graph (stack chain/backtrace) recording"), diff --git a/tools/perf/perf.h b/tools/perf/perf.h index 13c42f34e8b..ea804f5a8cc 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h @@ -189,6 +189,7 @@ struct perf_record_opts { pid_t target_pid; pid_t target_tid; bool call_graph; + bool group; bool inherit_stat; bool no_delay; bool no_inherit; -- cgit v1.2.3-70-g09d2 From 18b552350515188a732db6ccdb81e9cefb8b58c9 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 11 Nov 2011 22:08:07 -0200 Subject: perf ui progress: Fix divide by zero Happens in a perf.data file where one of the events had no samples. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-j7st3oyiotvfxqde2nc41kxb@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/ui/progress.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'tools') diff --git a/tools/perf/util/ui/progress.c b/tools/perf/util/ui/progress.c index 295e366b631..13aa64e50e1 100644 --- a/tools/perf/util/ui/progress.c +++ b/tools/perf/util/ui/progress.c @@ -14,6 +14,9 @@ void ui_progress__update(u64 curr, u64 total, const char *title) if (use_browser <= 0) return; + if (total == 0) + return; + ui__refresh_dimensions(true); pthread_mutex_lock(&ui__lock); y = SLtt_Screen_Rows / 2 - 2; -- cgit v1.2.3-70-g09d2 From d04b35f8085f0d4c5c874515b8f65e7664357148 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 11 Nov 2011 22:17:32 -0200 Subject: perf symbols: Add nr_events to symbol_conf Since symbol__alloc_hists need it, to avoid passing it around in many functions have it in the symbol_conf struct. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-cwv8ysvpywzjq4v3xtbd4zwv@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-annotate.c | 22 ++++++++-------------- tools/perf/builtin-report.c | 3 +-- tools/perf/builtin-top.c | 7 ++++--- tools/perf/util/annotate.c | 6 +++--- tools/perf/util/annotate.h | 5 ++--- tools/perf/util/header.c | 2 ++ tools/perf/util/hist.h | 3 +-- tools/perf/util/symbol.h | 1 + tools/perf/util/ui/browsers/annotate.c | 16 +++++++--------- tools/perf/util/ui/browsers/hists.c | 2 +- 10 files changed, 30 insertions(+), 37 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 46b4c24f338..8b9091bce98 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -43,10 +43,9 @@ static const char *sym_hist_filter; static const char *cpu_list; static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); -static int perf_evlist__add_sample(struct perf_evlist *evlist, - struct perf_sample *sample, - struct perf_evsel *evsel, - struct addr_location *al) +static int perf_evsel__add_sample(struct perf_evsel *evsel, + struct perf_sample *sample, + struct addr_location *al) { struct hist_entry *he; int ret; @@ -69,8 +68,7 @@ static int perf_evlist__add_sample(struct perf_evlist *evlist, ret = 0; if (he->ms.sym != NULL) { struct annotation *notes = symbol__annotation(he->ms.sym); - if (notes->src == NULL && - symbol__alloc_hist(he->ms.sym, evlist->nr_entries) < 0) + if (notes->src == NULL && symbol__alloc_hist(he->ms.sym) < 0) return -ENOMEM; ret = hist_entry__inc_addr_samples(he, evsel->idx, al->addr); @@ -98,8 +96,7 @@ static int process_sample_event(union perf_event *event, if (cpu_list && !test_bit(sample->cpu, cpu_bitmap)) return 0; - if (!al.filtered && - perf_evlist__add_sample(session->evlist, sample, evsel, &al)) { + if (!al.filtered && perf_evsel__add_sample(evsel, sample, &al)) { pr_warning("problem incrementing symbol count, " "skipping event\n"); return -1; @@ -114,8 +111,7 @@ static int hist_entry__tty_annotate(struct hist_entry *he, int evidx) print_line, full_paths, 0, 0); } -static void hists__find_annotations(struct hists *self, int evidx, - int nr_events) +static void hists__find_annotations(struct hists *self, int evidx) { struct rb_node *nd = rb_first(&self->entries), *next; int key = K_RIGHT; @@ -138,8 +134,7 @@ find_next: } if (use_browser > 0) { - key = hist_entry__tui_annotate(he, evidx, nr_events, - NULL, NULL, 0); + key = hist_entry__tui_annotate(he, evidx, NULL, NULL, 0); switch (key) { case K_RIGHT: next = rb_next(nd); @@ -217,8 +212,7 @@ static int __cmd_annotate(void) total_nr_samples += nr_samples; hists__collapse_resort(hists); hists__output_resort(hists); - hists__find_annotations(hists, pos->idx, - session->evlist->nr_entries); + hists__find_annotations(hists, pos->idx); } } diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 4d7c8340c32..758a287fc07 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -92,8 +92,7 @@ static int perf_session__add_hist_entry(struct perf_session *session, assert(evsel != NULL); err = -ENOMEM; - if (notes->src == NULL && - symbol__alloc_hist(he->ms.sym, session->evlist->nr_entries) < 0) + if (notes->src == NULL && symbol__alloc_hist(he->ms.sym) < 0) goto out; err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr); diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index c9cdedb5813..04288ee223e 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -170,7 +170,7 @@ static int parse_source(struct hist_entry *he) pthread_mutex_lock(¬es->lock); - if (symbol__alloc_hist(sym, top.evlist->nr_entries) < 0) { + if (symbol__alloc_hist(sym) < 0) { pthread_mutex_unlock(¬es->lock); pr_err("Not enough memory for annotating '%s' symbol!\n", sym->name); @@ -210,8 +210,7 @@ static void record_precise_ip(struct hist_entry *he, int counter, u64 ip) if (pthread_mutex_trylock(¬es->lock)) return; - if (notes->src == NULL && - symbol__alloc_hist(sym, top.evlist->nr_entries) < 0) { + if (notes->src == NULL && symbol__alloc_hist(sym) < 0) { pthread_mutex_unlock(¬es->lock); pr_err("Not enough memory for annotating '%s' symbol!\n", sym->name); @@ -1215,6 +1214,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) return -ENOMEM; } + symbol_conf.nr_events = top.evlist->nr_entries; + if (top.delay_secs < 1) top.delay_secs = 1; diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 119e996035c..376e643f706 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -25,17 +25,17 @@ int symbol__annotate_init(struct map *map __used, struct symbol *sym) return 0; } -int symbol__alloc_hist(struct symbol *sym, int nevents) +int symbol__alloc_hist(struct symbol *sym) { struct annotation *notes = symbol__annotation(sym); size_t sizeof_sym_hist = (sizeof(struct sym_hist) + (sym->end - sym->start) * sizeof(u64)); - notes->src = zalloc(sizeof(*notes->src) + nevents * sizeof_sym_hist); + notes->src = zalloc(sizeof(*notes->src) + symbol_conf.nr_events * sizeof_sym_hist); if (notes->src == NULL) return -1; notes->src->sizeof_sym_hist = sizeof_sym_hist; - notes->src->nr_histograms = nevents; + notes->src->nr_histograms = symbol_conf.nr_events; INIT_LIST_HEAD(¬es->src->source); return 0; } diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index d9072523d34..efa5dc82bfa 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -72,7 +72,7 @@ static inline struct annotation *symbol__annotation(struct symbol *sym) int symbol__inc_addr_samples(struct symbol *sym, struct map *map, int evidx, u64 addr); -int symbol__alloc_hist(struct symbol *sym, int nevents); +int symbol__alloc_hist(struct symbol *sym); void symbol__annotate_zero_histograms(struct symbol *sym); int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize); @@ -99,8 +99,7 @@ static inline int symbol__tui_annotate(struct symbol *sym __used, } #else int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, - int nr_events, void(*timer)(void *arg), void *arg, - int delay_secs); + void(*timer)(void *arg), void *arg, int delay_secs); #endif extern const char *disassembler_style; diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index bcd05d05b4f..41424a16be8 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -2041,6 +2041,8 @@ int perf_session__read_header(struct perf_session *session, int fd) lseek(fd, tmp, SEEK_SET); } + symbol_conf.nr_events = nr_attrs; + if (f_header.event_types.size) { lseek(fd, f_header.event_types.offset, SEEK_SET); events = malloc(f_header.event_types.size); diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index c86c1d27bd1..6676d558b2a 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -119,7 +119,6 @@ int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __used, static inline int hist_entry__tui_annotate(struct hist_entry *self __used, int evidx __used, - int nr_events __used, void(*timer)(void *arg) __used, void *arg __used, int delay_secs __used) @@ -130,7 +129,7 @@ static inline int hist_entry__tui_annotate(struct hist_entry *self __used, #define K_RIGHT -2 #else #include "ui/keysyms.h" -int hist_entry__tui_annotate(struct hist_entry *he, int evidx, int nr_events, +int hist_entry__tui_annotate(struct hist_entry *he, int evidx, void(*timer)(void *arg), void *arg, int delay_secs); int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 29f8d742e92..123c2e14353 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -68,6 +68,7 @@ struct strlist; struct symbol_conf { unsigned short priv_size; + unsigned short nr_events; bool try_vmlinux_path, use_modules, sort_by_name, diff --git a/tools/perf/util/ui/browsers/annotate.c b/tools/perf/util/ui/browsers/annotate.c index 0575905d120..295a9c93f94 100644 --- a/tools/perf/util/ui/browsers/annotate.c +++ b/tools/perf/util/ui/browsers/annotate.c @@ -224,7 +224,7 @@ static bool annotate_browser__toggle_source(struct annotate_browser *browser) } static int annotate_browser__run(struct annotate_browser *self, int evidx, - int nr_events, void(*timer)(void *arg), + void(*timer)(void *arg), void *arg, int delay_secs) { struct rb_node *nd = NULL; @@ -328,8 +328,7 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx, notes = symbol__annotation(target); pthread_mutex_lock(¬es->lock); - if (notes->src == NULL && - symbol__alloc_hist(target, nr_events) < 0) { + if (notes->src == NULL && symbol__alloc_hist(target) < 0) { pthread_mutex_unlock(¬es->lock); ui__warning("Not enough memory for annotating '%s' symbol!\n", target->name); @@ -337,7 +336,7 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx, } pthread_mutex_unlock(¬es->lock); - symbol__tui_annotate(target, ms->map, evidx, nr_events, + symbol__tui_annotate(target, ms->map, evidx, timer, arg, delay_secs); } continue; @@ -358,15 +357,15 @@ out: return key; } -int hist_entry__tui_annotate(struct hist_entry *he, int evidx, int nr_events, +int hist_entry__tui_annotate(struct hist_entry *he, int evidx, void(*timer)(void *arg), void *arg, int delay_secs) { - return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx, nr_events, + return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx, timer, arg, delay_secs); } int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, - int nr_events, void(*timer)(void *arg), void *arg, + void(*timer)(void *arg), void *arg, int delay_secs) { struct objdump_line *pos, *n; @@ -419,8 +418,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, browser.b.nr_entries = browser.nr_entries; browser.b.entries = ¬es->src->source, browser.b.width += 18; /* Percentage */ - ret = annotate_browser__run(&browser, evidx, nr_events, - timer, arg, delay_secs); + ret = annotate_browser__run(&browser, evidx, timer, arg, delay_secs); list_for_each_entry_safe(pos, n, ¬es->src->source, node) { list_del(&pos->node); objdump_line__free(pos); diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c index d0c94b45968..1212a386a03 100644 --- a/tools/perf/util/ui/browsers/hists.c +++ b/tools/perf/util/ui/browsers/hists.c @@ -1020,7 +1020,7 @@ do_annotate: * Don't let this be freed, say, by hists__decay_entry. */ he->used = true; - err = hist_entry__tui_annotate(he, evsel->idx, nr_events, + err = hist_entry__tui_annotate(he, evsel->idx, timer, arg, delay_secs); he->used = false; ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries); -- cgit v1.2.3-70-g09d2 From 81e36bffad95e015af9741b5b1ee16afe08aab05 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 11 Nov 2011 22:28:50 -0200 Subject: perf evlist: Introduce id_hdr_size method out of perf_session We will need this when not using perf_session in cases like 'perf top' and strace where no perf.data file is created nor consumed. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-za923wjc41q5xot5vrhuhj3j@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evlist.c | 32 ++++++++++++++++++++++++++++++++ tools/perf/util/evlist.h | 1 + tools/perf/util/session.c | 29 +---------------------------- 3 files changed, 34 insertions(+), 28 deletions(-) (limited to 'tools') diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 81237dcde1f..d44e3df13a8 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -625,6 +625,38 @@ u64 perf_evlist__sample_type(const struct perf_evlist *evlist) return first->attr.sample_type; } +u16 perf_evlist__id_hdr_size(const struct perf_evlist *evlist) +{ + struct perf_evsel *first; + struct perf_sample *data; + u64 sample_type; + u16 size = 0; + + first = list_entry(evlist->entries.next, struct perf_evsel, node); + + if (!first->attr.sample_id_all) + goto out; + + sample_type = first->attr.sample_type; + + if (sample_type & PERF_SAMPLE_TID) + size += sizeof(data->tid) * 2; + + if (sample_type & PERF_SAMPLE_TIME) + size += sizeof(data->time); + + if (sample_type & PERF_SAMPLE_ID) + size += sizeof(data->id); + + if (sample_type & PERF_SAMPLE_STREAM_ID) + size += sizeof(data->stream_id); + + if (sample_type & PERF_SAMPLE_CPU) + size += sizeof(data->cpu) * 2; +out: + return size; +} + bool perf_evlist__valid_sample_id_all(const struct perf_evlist *evlist) { struct perf_evsel *pos, *first; diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 17e9c80243c..2202e7b0410 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -104,6 +104,7 @@ int perf_evlist__set_filters(struct perf_evlist *evlist); u64 perf_evlist__sample_type(const struct perf_evlist *evlist); bool perf_evlist__sample_id_all(const const struct perf_evlist *evlist); +u16 perf_evlist__id_hdr_size(const struct perf_evlist *evlist); bool perf_evlist__valid_sample_type(const struct perf_evlist *evlist); bool perf_evlist__valid_sample_id_all(const struct perf_evlist *evlist); diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index a76666f1776..675e080f66b 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -78,39 +78,12 @@ out_close: return -1; } -static void perf_session__id_header_size(struct perf_session *session) -{ - struct perf_sample *data; - u64 sample_type = session->sample_type; - u16 size = 0; - - if (!session->sample_id_all) - goto out; - - if (sample_type & PERF_SAMPLE_TID) - size += sizeof(data->tid) * 2; - - if (sample_type & PERF_SAMPLE_TIME) - size += sizeof(data->time); - - if (sample_type & PERF_SAMPLE_ID) - size += sizeof(data->id); - - if (sample_type & PERF_SAMPLE_STREAM_ID) - size += sizeof(data->stream_id); - - if (sample_type & PERF_SAMPLE_CPU) - size += sizeof(data->cpu) * 2; -out: - session->id_hdr_size = size; -} - void perf_session__update_sample_type(struct perf_session *self) { self->sample_type = perf_evlist__sample_type(self->evlist); self->sample_size = __perf_evsel__sample_size(self->sample_type); self->sample_id_all = perf_evlist__sample_id_all(self->evlist); - perf_session__id_header_size(self); + self->id_hdr_size = perf_evlist__id_hdr_size(self->evlist); } int perf_session__create_kernel_maps(struct perf_session *self) -- cgit v1.2.3-70-g09d2 From 10d0f086df77f3ff259b46cb501362dbaf2c7989 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 11 Nov 2011 22:45:41 -0200 Subject: perf event: perf_event_ops->attr() manipulates only an evlist Removing another case where a perf_session is required when processing events. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-ug1wtjbnva4bxwknflkkrlrh@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-inject.c | 8 +++++++- tools/perf/util/header.c | 19 ++++++++----------- tools/perf/util/header.h | 2 +- tools/perf/util/session.c | 16 ++++++++++++++-- tools/perf/util/session.h | 6 ++++-- 5 files changed, 34 insertions(+), 17 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index 8dfc12bb119..978751ec64c 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c @@ -36,6 +36,12 @@ static int perf_event__repipe_synth(union perf_event *event, return 0; } +static int perf_event__repipe_attr(union perf_event *event, + struct perf_evlist **pevlist __used) +{ + return perf_event__repipe_synth(event, NULL); +} + static int perf_event__repipe(union perf_event *event, struct perf_sample *sample __used, struct perf_session *session) @@ -182,7 +188,7 @@ struct perf_event_ops inject_ops = { .read = perf_event__repipe, .throttle = perf_event__repipe, .unthrottle = perf_event__repipe, - .attr = perf_event__repipe_synth, + .attr = perf_event__repipe_attr, .event_type = perf_event__repipe_synth, .tracing_data = perf_event__repipe_synth, .build_id = perf_event__repipe_synth, diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 41424a16be8..1fa97dd2120 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -2120,23 +2120,23 @@ int perf_session__synthesize_attrs(struct perf_session *session, } int perf_event__process_attr(union perf_event *event, - struct perf_session *session) + struct perf_evlist **pevlist) { unsigned int i, ids, n_ids; struct perf_evsel *evsel; + struct perf_evlist *evlist = *pevlist; - if (session->evlist == NULL) { - session->evlist = perf_evlist__new(NULL, NULL); - if (session->evlist == NULL) + if (evlist == NULL) { + *pevlist = evlist = perf_evlist__new(NULL, NULL); + if (evlist == NULL) return -ENOMEM; } - evsel = perf_evsel__new(&event->attr.attr, - session->evlist->nr_entries); + evsel = perf_evsel__new(&event->attr.attr, evlist->nr_entries); if (evsel == NULL) return -ENOMEM; - perf_evlist__add(session->evlist, evsel); + perf_evlist__add(evlist, evsel); ids = event->header.size; ids -= (void *)&event->attr.id - (void *)event; @@ -2150,12 +2150,9 @@ int perf_event__process_attr(union perf_event *event, return -ENOMEM; for (i = 0; i < n_ids; i++) { - perf_evlist__id_add(session->evlist, evsel, 0, i, - event->attr.id[i]); + perf_evlist__id_add(evlist, evsel, 0, i, event->attr.id[i]); } - perf_session__update_sample_type(session); - return 0; } diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index 3d5a742f4a2..0a88982bc39 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h @@ -101,7 +101,7 @@ int perf_event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id, struct perf_session *session); int perf_session__synthesize_attrs(struct perf_session *session, perf_event__handler_t process); -int perf_event__process_attr(union perf_event *event, struct perf_session *session); +int perf_event__process_attr(union perf_event *event, struct perf_evlist **pevlist); int perf_event__synthesize_event_type(u64 event_id, char *name, perf_event__handler_t process, diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 675e080f66b..6e7d5f54b37 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -277,6 +277,13 @@ static int process_event_synth_stub(union perf_event *event __used, return 0; } +static int process_event_synth_attr_stub(union perf_event *event __used, + struct perf_evlist **pevlist __used) +{ + dump_printf(": unhandled!\n"); + return 0; +} + static int process_event_sample_stub(union perf_event *event __used, struct perf_sample *sample __used, struct perf_evsel *evsel __used, @@ -327,7 +334,7 @@ static void perf_event_ops__fill_defaults(struct perf_event_ops *handler) if (handler->unthrottle == NULL) handler->unthrottle = process_event_stub; if (handler->attr == NULL) - handler->attr = process_event_synth_stub; + handler->attr = process_event_synth_attr_stub; if (handler->event_type == NULL) handler->event_type = process_event_synth_stub; if (handler->tracing_data == NULL) @@ -794,12 +801,17 @@ static int perf_session__preprocess_sample(struct perf_session *session, static int perf_session__process_user_event(struct perf_session *session, union perf_event *event, struct perf_event_ops *ops, u64 file_offset) { + int err; + dump_event(session, event, file_offset, NULL); /* These events are processed right away */ switch (event->header.type) { case PERF_RECORD_HEADER_ATTR: - return ops->attr(event, session); + err = ops->attr(event, &session->evlist); + if (err == 0) + perf_session__update_sample_type(session); + return err; case PERF_RECORD_HEADER_EVENT_TYPE: return ops->event_type(event, session); case PERF_RECORD_HEADER_TRACING_DATA: diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 76d462d3bef..13bd5e0a069 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -63,6 +63,8 @@ typedef int (*event_op)(union perf_event *self, struct perf_sample *sample, struct perf_session *session); typedef int (*event_synth_op)(union perf_event *self, struct perf_session *session); +typedef int (*event_attr_op)(union perf_event *event, + struct perf_evlist **pevlist); typedef int (*event_op2)(union perf_event *self, struct perf_session *session, struct perf_event_ops *ops); @@ -76,8 +78,8 @@ struct perf_event_ops { read, throttle, unthrottle; - event_synth_op attr, - event_type, + event_attr_op attr; + event_synth_op event_type, tracing_data, build_id; event_op2 finished_round; -- cgit v1.2.3-70-g09d2 From 246d4ce8107ea16521384c8b2a8fcff354ef2b7c Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 11 Nov 2011 23:10:26 -0200 Subject: perf session: Remove superfluous callchain_cursor member Since we have it in evsel->hists.callchain_cursor, remove it from perf_session. One more step in disentangling several places from requiring a perf_session pointer. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-rxr5dj3di7ckyfmnz0naku1z@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-report.c | 5 +++-- tools/perf/builtin-script.c | 2 +- tools/perf/builtin-top.c | 4 ++-- tools/perf/util/session.c | 12 ++++++------ tools/perf/util/session.h | 5 ++--- 5 files changed, 14 insertions(+), 14 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 758a287fc07..b7ab373b9ac 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -65,7 +65,7 @@ static int perf_session__add_hist_entry(struct perf_session *session, struct hist_entry *he; if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) { - err = perf_session__resolve_callchain(session, al->thread, + err = perf_session__resolve_callchain(session, evsel, al->thread, sample->callchain, &parent); if (err) return err; @@ -76,7 +76,8 @@ static int perf_session__add_hist_entry(struct perf_session *session, return -ENOMEM; if (symbol_conf.use_callchain) { - err = callchain_append(he->callchain, &session->callchain_cursor, + err = callchain_append(he->callchain, + &evsel->hists.callchain_cursor, sample->period); if (err) return err; diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 2f62a295226..47545e9c9b2 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -384,7 +384,7 @@ static void process_event(union perf_event *event __unused, printf(" "); else printf("\n"); - perf_session__print_ip(event, sample, session, + perf_session__print_ip(event, evsel, sample, session, PRINT_FIELD(SYM), PRINT_FIELD(DSO)); } diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 04288ee223e..9b3bbb40d46 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -777,7 +777,7 @@ static void perf_event__process_sample(const union perf_event *event, if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) { - err = perf_session__resolve_callchain(session, al.thread, + err = perf_session__resolve_callchain(session, evsel, al.thread, sample->callchain, &parent); if (err) return; @@ -790,7 +790,7 @@ static void perf_event__process_sample(const union perf_event *event, } if (symbol_conf.use_callchain) { - err = callchain_append(he->callchain, &session->callchain_cursor, + err = callchain_append(he->callchain, &evsel->hists.callchain_cursor, sample->period); if (err) return; diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 6e7d5f54b37..734358b51ed 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -216,7 +216,7 @@ static bool symbol__match_parent_regex(struct symbol *sym) return 0; } -int perf_session__resolve_callchain(struct perf_session *self, +int perf_session__resolve_callchain(struct perf_session *self, struct perf_evsel *evsel, struct thread *thread, struct ip_callchain *chain, struct symbol **parent) @@ -225,7 +225,7 @@ int perf_session__resolve_callchain(struct perf_session *self, unsigned int i; int err; - callchain_cursor_reset(&self->callchain_cursor); + callchain_cursor_reset(&evsel->hists.callchain_cursor); for (i = 0; i < chain->nr; i++) { u64 ip; @@ -261,7 +261,7 @@ int perf_session__resolve_callchain(struct perf_session *self, break; } - err = callchain_cursor_append(&self->callchain_cursor, + err = callchain_cursor_append(&evsel->hists.callchain_cursor, ip, al.map, al.sym); if (err) return err; @@ -1254,14 +1254,14 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, return NULL; } -void perf_session__print_ip(union perf_event *event, +void perf_session__print_ip(union perf_event *event, struct perf_evsel *evsel, struct perf_sample *sample, struct perf_session *session, int print_sym, int print_dso) { struct addr_location al; const char *symname, *dsoname; - struct callchain_cursor *cursor = &session->callchain_cursor; + struct callchain_cursor *cursor = &evsel->hists.callchain_cursor; struct callchain_cursor_node *node; if (perf_event__preprocess_sample(event, session, &al, sample, @@ -1273,7 +1273,7 @@ void perf_session__print_ip(union perf_event *event, if (symbol_conf.use_callchain && sample->callchain) { - if (perf_session__resolve_callchain(session, al.thread, + if (perf_session__resolve_callchain(session, evsel, al.thread, sample->callchain, NULL) != 0) { if (verbose) error("Failed to resolve callchain. Skipping\n"); diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 13bd5e0a069..d2f43036771 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -50,7 +50,6 @@ struct perf_session { int cwdlen; char *cwd; struct ordered_samples ordered_samples; - struct callchain_cursor callchain_cursor; char filename[0]; }; @@ -100,7 +99,7 @@ int __perf_session__process_events(struct perf_session *self, int perf_session__process_events(struct perf_session *self, struct perf_event_ops *event_ops); -int perf_session__resolve_callchain(struct perf_session *self, +int perf_session__resolve_callchain(struct perf_session *self, struct perf_evsel *evsel, struct thread *thread, struct ip_callchain *chain, struct symbol **parent); @@ -169,7 +168,7 @@ static inline int perf_session__parse_sample(struct perf_session *session, struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, unsigned int type); -void perf_session__print_ip(union perf_event *event, +void perf_session__print_ip(union perf_event *event, struct perf_evsel *evsel, struct perf_sample *sample, struct perf_session *session, int print_sym, int print_dso); -- cgit v1.2.3-70-g09d2 From e3f42609628a20da92ecbc2d81053cc82c90a071 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 16 Nov 2011 17:02:54 -0200 Subject: perf tools: Use evsel->attr.sample_type instead of session->sample_type Eventually session->sample_type will go away as we want to support multiple sample types per session, so use it from the evsel which is a step in that direction. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-0vwdpjcwbjezw459lw5n3ew1@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-sched.c | 5 +++-- tools/perf/builtin-timechart.c | 9 +++++---- 2 files changed, 8 insertions(+), 6 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index 5177964943e..d51af0beab1 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -3,6 +3,7 @@ #include "util/util.h" #include "util/cache.h" +#include "util/evsel.h" #include "util/symbol.h" #include "util/thread.h" #include "util/header.h" @@ -1603,12 +1604,12 @@ static void process_raw_event(union perf_event *raw_event __used, static int process_sample_event(union perf_event *event, struct perf_sample *sample, - struct perf_evsel *evsel __used, + struct perf_evsel *evsel, struct perf_session *session) { struct thread *thread; - if (!(session->sample_type & PERF_SAMPLE_RAW)) + if (!(evsel->attr.sample_type & PERF_SAMPLE_RAW)) return 0; thread = perf_session__findnew(session, sample->pid); diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index aa26f4d66d1..3fc52b1aa43 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c @@ -19,6 +19,7 @@ #include "util/color.h" #include #include "util/cache.h" +#include "util/evsel.h" #include #include "util/symbol.h" #include "util/callchain.h" @@ -488,12 +489,12 @@ static void sched_switch(int cpu, u64 timestamp, struct trace_entry *te) static int process_sample_event(union perf_event *event __used, struct perf_sample *sample, - struct perf_evsel *evsel __used, - struct perf_session *session) + struct perf_evsel *evsel, + struct perf_session *session __used) { struct trace_entry *te; - if (session->sample_type & PERF_SAMPLE_TIME) { + if (evsel->attr.sample_type & PERF_SAMPLE_TIME) { if (!first_time || first_time > sample->time) first_time = sample->time; if (last_time < sample->time) @@ -501,7 +502,7 @@ static int process_sample_event(union perf_event *event __used, } te = (void *)sample->raw_data; - if (session->sample_type & PERF_SAMPLE_RAW && sample->raw_size > 0) { + if ((evsel->attr.sample_type & PERF_SAMPLE_RAW) && sample->raw_size > 0) { char *event_str; #ifdef SUPPORT_OLD_POWER_EVENTS struct power_entry_old *peo; -- cgit v1.2.3-70-g09d2 From fa372aae335c6dfbe808d5a728fe10cd202dde45 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 17 Nov 2011 12:19:04 -0200 Subject: perf report: Group options in a struct Paving the way to remove these globals when we change the perf_event_ops to receive as a first parameter a pointer to a perf_event_ops that will then provide access to perf_report via container_of. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-2eh2vi2nb5z3tg1lvoxv09xu@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-report.c | 111 +++++++++++++++++++++++--------------------- 1 file changed, 59 insertions(+), 52 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index b7ab373b9ac..5d2e819dfc4 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -35,25 +35,25 @@ #include -static char const *input_name = "perf.data"; - -static bool force, use_tui, use_stdio; -static bool hide_unresolved; -static bool dont_use_callchains; -static bool show_full_info; - -static bool show_threads; -static struct perf_read_values show_threads_values; - -static const char default_pretty_printing_style[] = "normal"; -static const char *pretty_printing_style = default_pretty_printing_style; - -static char callchain_default_opt[] = "fractal,0.5,callee"; -static bool inverted_callchain; -static symbol_filter_t annotate_init; - -static const char *cpu_list; -static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); +static struct perf_report { + char const *input_name; + bool force, use_tui, use_stdio; + bool hide_unresolved; + bool dont_use_callchains; + bool show_full_info; + bool show_threads; + bool inverted_callchain; + struct perf_read_values show_threads_values; + const char *pretty_printing_style; + symbol_filter_t annotate_init; + const char *cpu_list; + DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); +} report = { + .input_name = "perf.data", + .pretty_printing_style = "normal", +}, *rep = &report; + +static char callchain_default_opt[] = "fractal,0.5,callee"; static int perf_session__add_hist_entry(struct perf_session *session, struct addr_location *al, @@ -114,16 +114,16 @@ static int process_sample_event(union perf_event *event, struct addr_location al; if (perf_event__preprocess_sample(event, session, &al, sample, - annotate_init) < 0) { + rep->annotate_init) < 0) { fprintf(stderr, "problem processing %d event, skipping it.\n", event->header.type); return -1; } - if (al.filtered || (hide_unresolved && al.sym == NULL)) + if (al.filtered || (rep->hide_unresolved && al.sym == NULL)) return 0; - if (cpu_list && !test_bit(sample->cpu, cpu_bitmap)) + if (rep->cpu_list && !test_bit(sample->cpu, rep->cpu_bitmap)) return 0; if (al.map != NULL) @@ -143,9 +143,9 @@ static int process_read_event(union perf_event *event, { struct perf_evsel *evsel = perf_evlist__id2evsel(session->evlist, event->read.id); - if (show_threads) { + if (rep->show_threads) { const char *name = evsel ? event_name(evsel) : "unknown"; - perf_read_values_add_value(&show_threads_values, + perf_read_values_add_value(&rep->show_threads_values, event->read.pid, event->read.tid, event->read.id, name, @@ -173,7 +173,8 @@ static int perf_session__setup_sample_type(struct perf_session *self) "you call 'perf record' without -g?\n"); return -1; } - } else if (!dont_use_callchains && callchain_param.mode != CHAIN_NONE && + } else if (!rep->dont_use_callchains && + callchain_param.mode != CHAIN_NONE && !symbol_conf.use_callchain) { symbol_conf.use_callchain = true; if (callchain_register_param(&callchain_param) < 0) { @@ -241,11 +242,11 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist, parent_pattern == default_parent_pattern) { fprintf(stdout, "#\n# (%s)\n#\n", help); - if (show_threads) { - bool style = !strcmp(pretty_printing_style, "raw"); - perf_read_values_display(stdout, &show_threads_values, + if (rep->show_threads) { + bool style = !strcmp(rep->pretty_printing_style, "raw"); + perf_read_values_display(stdout, &rep->show_threads_values, style); - perf_read_values_destroy(&show_threads_values); + perf_read_values_destroy(&rep->show_threads_values); } } @@ -264,21 +265,23 @@ static int __cmd_report(void) signal(SIGINT, sig_handler); - session = perf_session__new(input_name, O_RDONLY, force, false, &event_ops); + session = perf_session__new(rep->input_name, O_RDONLY, + rep->force, false, &event_ops); if (session == NULL) return -ENOMEM; - if (cpu_list) { - ret = perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap); + if (rep->cpu_list) { + ret = perf_session__cpu_bitmap(session, rep->cpu_list, + rep->cpu_bitmap); if (ret) goto out_delete; } if (use_browser <= 0) - perf_session__fprintf_info(session, stdout, show_full_info); + perf_session__fprintf_info(session, stdout, rep->show_full_info); - if (show_threads) - perf_read_values_init(&show_threads_values); + if (rep->show_threads) + perf_read_values_init(&rep->show_threads_values); ret = perf_session__setup_sample_type(session); if (ret) @@ -327,7 +330,8 @@ static int __cmd_report(void) } if (nr_samples == 0) { - ui__warning("The %s file has no samples!\n", input_name); + ui__warning("The %s file has no samples!\n", + rep->input_name); goto out_delete; } @@ -364,7 +368,7 @@ parse_callchain_opt(const struct option *opt __used, const char *arg, * --no-call-graph */ if (unset) { - dont_use_callchains = true; + rep->dont_use_callchains = true; return 0; } @@ -439,7 +443,7 @@ static const char * const report_usage[] = { }; static const struct option options[] = { - OPT_STRING('i', "input", &input_name, "file", + OPT_STRING('i', "input", &report.input_name, "file", "input file name"), OPT_INCR('v', "verbose", &verbose, "be more verbose (show symbol address, etc)"), @@ -449,17 +453,18 @@ static const struct option options[] = { "file", "vmlinux pathname"), OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name, "file", "kallsyms pathname"), - OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), + OPT_BOOLEAN('f', "force", &report.force, "don't complain, do it"), OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules, "load module symbols - WARNING: use only with -k and LIVE kernel"), OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples, "Show a column with the number of samples"), - OPT_BOOLEAN('T', "threads", &show_threads, + OPT_BOOLEAN('T', "threads", &report.show_threads, "Show per-thread event counters"), - OPT_STRING(0, "pretty", &pretty_printing_style, "key", + OPT_STRING(0, "pretty", &report.pretty_printing_style, "key", "pretty printing style key: normal raw"), - OPT_BOOLEAN(0, "tui", &use_tui, "Use the TUI interface"), - OPT_BOOLEAN(0, "stdio", &use_stdio, "Use the stdio interface"), + OPT_BOOLEAN(0, "tui", &report.use_tui, "Use the TUI interface"), + OPT_BOOLEAN(0, "stdio", &report.use_stdio, + "Use the stdio interface"), OPT_STRING('s', "sort", &sort_order, "key[,key2...]", "sort by key(s): pid, comm, dso, symbol, parent"), OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization, @@ -471,7 +476,8 @@ static const struct option options[] = { OPT_CALLBACK_DEFAULT('g', "call-graph", NULL, "output_type,min_percent, call_order", "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold and callchain order. " "Default: fractal,0.5,callee", &parse_callchain_opt, callchain_default_opt), - OPT_BOOLEAN('G', "inverted", &inverted_callchain, "alias for inverted call graph"), + OPT_BOOLEAN('G', "inverted", &report.inverted_callchain, + "alias for inverted call graph"), OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", "only consider symbols in these dsos"), OPT_STRING('C', "comms", &symbol_conf.comm_list_str, "comm[,comm...]", @@ -484,12 +490,13 @@ static const struct option options[] = { OPT_STRING('t', "field-separator", &symbol_conf.field_sep, "separator", "separator for columns, no spaces will be added between " "columns '.' is reserved."), - OPT_BOOLEAN('U', "hide-unresolved", &hide_unresolved, + OPT_BOOLEAN('U', "hide-unresolved", &report.hide_unresolved, "Only display entries resolved to a symbol"), OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", "Look for files with symbols relative to this directory"), - OPT_STRING('c', "cpu", &cpu_list, "cpu", "list of cpus to profile"), - OPT_BOOLEAN('I', "show-info", &show_full_info, + OPT_STRING('c', "cpu", &report.cpu_list, "cpu", + "list of cpus to profile"), + OPT_BOOLEAN('I', "show-info", &report.show_full_info, "Display extended information about perf.data file"), OPT_BOOLEAN(0, "source", &symbol_conf.annotate_src, "Interleave source code with assembly code (default)"), @@ -506,15 +513,15 @@ int cmd_report(int argc, const char **argv, const char *prefix __used) { argc = parse_options(argc, argv, options, report_usage, 0); - if (use_stdio) + if (report.use_stdio) use_browser = 0; - else if (use_tui) + else if (report.use_tui) use_browser = 1; - if (inverted_callchain) + if (report.inverted_callchain) callchain_param.order = ORDER_CALLER; - if (strcmp(input_name, "-") != 0) + if (strcmp(report.input_name, "-") != 0) setup_browser(true); else use_browser = 0; @@ -525,7 +532,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __used) */ if (use_browser > 0) { symbol_conf.priv_size = sizeof(struct annotation); - annotate_init = symbol__annotate_init; + report.annotate_init = symbol__annotate_init; /* * For searching by name on the "Browse map details". * providing it only in verbose mode not to bloat too -- cgit v1.2.3-70-g09d2 From 7009cc34b964939815160d7de64cf0215cdbf8bb Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 17 Nov 2011 12:33:21 -0200 Subject: perf annotate: Group options in a struct Paving the way to remove these globals when we change the perf_event_ops to receive as a first parameter a pointer to a perf_event_ops that will then provide access to perf_annotate via container_of. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-xduzibqrdg3h5cttmk6p5wwc@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-annotate.c | 64 ++++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 31 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 8b9091bce98..4f0c3d98352 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -30,18 +30,17 @@ #include -static char const *input_name = "perf.data"; - -static bool force, use_tui, use_stdio; - -static bool full_paths; - -static bool print_line; - -static const char *sym_hist_filter; - -static const char *cpu_list; -static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); +static struct perf_annotate { + char const *input_name; + bool force, use_tui, use_stdio; + bool full_paths; + bool print_line; + const char *sym_hist_filter; + const char *cpu_list; + DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); +} annotate = { + .input_name = "perf.data", +}, *ann = &annotate; static int perf_evsel__add_sample(struct perf_evsel *evsel, struct perf_sample *sample, @@ -50,8 +49,9 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel, struct hist_entry *he; int ret; - if (sym_hist_filter != NULL && - (al->sym == NULL || strcmp(sym_hist_filter, al->sym->name) != 0)) { + if (ann->sym_hist_filter != NULL && + (al->sym == NULL || + strcmp(ann->sym_hist_filter, al->sym->name) != 0)) { /* We're only interested in a symbol named sym_hist_filter */ if (al->sym != NULL) { rb_erase(&al->sym->rb_node, @@ -93,7 +93,7 @@ static int process_sample_event(union perf_event *event, return -1; } - if (cpu_list && !test_bit(sample->cpu, cpu_bitmap)) + if (ann->cpu_list && !test_bit(sample->cpu, ann->cpu_bitmap)) return 0; if (!al.filtered && perf_evsel__add_sample(evsel, sample, &al)) { @@ -108,7 +108,7 @@ static int process_sample_event(union perf_event *event, static int hist_entry__tty_annotate(struct hist_entry *he, int evidx) { return symbol__tty_annotate(he->ms.sym, he->ms.map, evidx, - print_line, full_paths, 0, 0); + ann->print_line, ann->full_paths, 0, 0); } static void hists__find_annotations(struct hists *self, int evidx) @@ -178,12 +178,14 @@ static int __cmd_annotate(void) struct perf_evsel *pos; u64 total_nr_samples; - session = perf_session__new(input_name, O_RDONLY, force, false, &event_ops); + session = perf_session__new(ann->input_name, O_RDONLY, + ann->force, false, &event_ops); if (session == NULL) return -ENOMEM; - if (cpu_list) { - ret = perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap); + if (ann->cpu_list) { + ret = perf_session__cpu_bitmap(session, ann->cpu_list, + ann->cpu_bitmap); if (ret) goto out_delete; } @@ -217,7 +219,7 @@ static int __cmd_annotate(void) } if (total_nr_samples == 0) { - ui__warning("The %s file has no samples!\n", input_name); + ui__warning("The %s file has no samples!\n", ann->input_name); goto out_delete; } out_delete: @@ -242,28 +244,28 @@ static const char * const annotate_usage[] = { }; static const struct option options[] = { - OPT_STRING('i', "input", &input_name, "file", + OPT_STRING('i', "input", &annotate.input_name, "file", "input file name"), OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", "only consider symbols in these dsos"), - OPT_STRING('s', "symbol", &sym_hist_filter, "symbol", + OPT_STRING('s', "symbol", &annotate.sym_hist_filter, "symbol", "symbol to annotate"), - OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), + OPT_BOOLEAN('f', "force", &annotate.force, "don't complain, do it"), OPT_INCR('v', "verbose", &verbose, "be more verbose (show symbol address, etc)"), OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, "dump raw trace in ASCII"), - OPT_BOOLEAN(0, "tui", &use_tui, "Use the TUI interface"), - OPT_BOOLEAN(0, "stdio", &use_stdio, "Use the stdio interface"), + OPT_BOOLEAN(0, "tui", &annotate.use_tui, "Use the TUI interface"), + OPT_BOOLEAN(0, "stdio", &annotate.use_stdio, "Use the stdio interface"), OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, "file", "vmlinux pathname"), OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules, "load module symbols - WARNING: use only with -k and LIVE kernel"), - OPT_BOOLEAN('l', "print-line", &print_line, + OPT_BOOLEAN('l', "print-line", &annotate.print_line, "print matching source lines (may be slow)"), - OPT_BOOLEAN('P', "full-paths", &full_paths, + OPT_BOOLEAN('P', "full-paths", &annotate.full_paths, "Don't shorten the displayed pathnames"), - OPT_STRING('c', "cpu", &cpu_list, "cpu", "list of cpus to profile"), + OPT_STRING('c', "cpu", &annotate.cpu_list, "cpu", "list of cpus to profile"), OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", "Look for files with symbols relative to this directory"), OPT_BOOLEAN(0, "source", &symbol_conf.annotate_src, @@ -279,9 +281,9 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __used) { argc = parse_options(argc, argv, options, annotate_usage, 0); - if (use_stdio) + if (annotate.use_stdio) use_browser = 0; - else if (use_tui) + else if (annotate.use_tui) use_browser = 1; setup_browser(true); @@ -302,7 +304,7 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __used) if (argc > 1) usage_with_options(annotate_usage, options); - sym_hist_filter = argv[0]; + annotate.sym_hist_filter = argv[0]; } if (field_sep && *field_sep == '.') { -- cgit v1.2.3-70-g09d2 From d20deb64e0490ee9442b5181bc08a62d2cadcb90 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 25 Nov 2011 08:19:45 -0200 Subject: perf tools: Pass tool context in the the perf_event_ops functions So that we don't need to have that many globals. Next steps will remove the 'session' pointer, that in most cases is not needed. Then we can rename perf_event_ops to 'perf_tool' that better describes this class hierarchy. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-wp4djox7x6w1i2bab1pt4xxp@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-annotate.c | 62 ++++--- tools/perf/builtin-diff.c | 3 +- tools/perf/builtin-inject.c | 55 +++--- tools/perf/builtin-kmem.c | 3 +- tools/perf/builtin-lock.c | 3 +- tools/perf/builtin-record.c | 383 +++++++++++++++++++++++------------------ tools/perf/builtin-report.c | 97 ++++++----- tools/perf/builtin-sched.c | 3 +- tools/perf/builtin-script.c | 3 +- tools/perf/builtin-timechart.c | 12 +- tools/perf/builtin-top.c | 6 +- tools/perf/util/build-id.c | 7 +- tools/perf/util/callchain.h | 3 + tools/perf/util/event.c | 66 ++++--- tools/perf/util/event.h | 38 ++-- tools/perf/util/header.c | 36 ++-- tools/perf/util/header.h | 27 ++- tools/perf/util/session.c | 60 ++++--- tools/perf/util/session.h | 23 +-- tools/perf/util/top.h | 3 +- 20 files changed, 520 insertions(+), 373 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 4f0c3d98352..483cb946644 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -30,7 +30,8 @@ #include -static struct perf_annotate { +struct perf_annotate { + struct perf_event_ops ops; char const *input_name; bool force, use_tui, use_stdio; bool full_paths; @@ -38,13 +39,12 @@ static struct perf_annotate { const char *sym_hist_filter; const char *cpu_list; DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); -} annotate = { - .input_name = "perf.data", -}, *ann = &annotate; +}; static int perf_evsel__add_sample(struct perf_evsel *evsel, struct perf_sample *sample, - struct addr_location *al) + struct addr_location *al, + struct perf_annotate *ann) { struct hist_entry *he; int ret; @@ -79,11 +79,13 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel, return ret; } -static int process_sample_event(union perf_event *event, +static int process_sample_event(struct perf_event_ops *ops, + union perf_event *event, struct perf_sample *sample, struct perf_evsel *evsel, struct perf_session *session) { + struct perf_annotate *ann = container_of(ops, struct perf_annotate, ops); struct addr_location al; if (perf_event__preprocess_sample(event, session, &al, sample, @@ -96,7 +98,7 @@ static int process_sample_event(union perf_event *event, if (ann->cpu_list && !test_bit(sample->cpu, ann->cpu_bitmap)) return 0; - if (!al.filtered && perf_evsel__add_sample(evsel, sample, &al)) { + if (!al.filtered && perf_evsel__add_sample(evsel, sample, &al, ann)) { pr_warning("problem incrementing symbol count, " "skipping event\n"); return -1; @@ -105,13 +107,15 @@ static int process_sample_event(union perf_event *event, return 0; } -static int hist_entry__tty_annotate(struct hist_entry *he, int evidx) +static int hist_entry__tty_annotate(struct hist_entry *he, int evidx, + struct perf_annotate *ann) { return symbol__tty_annotate(he->ms.sym, he->ms.map, evidx, ann->print_line, ann->full_paths, 0, 0); } -static void hists__find_annotations(struct hists *self, int evidx) +static void hists__find_annotations(struct hists *self, int evidx, + struct perf_annotate *ann) { struct rb_node *nd = rb_first(&self->entries), *next; int key = K_RIGHT; @@ -149,7 +153,7 @@ find_next: if (next != NULL) nd = next; } else { - hist_entry__tty_annotate(he, evidx); + hist_entry__tty_annotate(he, evidx, ann); nd = rb_next(nd); /* * Since we have a hist_entry per IP for the same @@ -162,16 +166,7 @@ find_next: } } -static struct perf_event_ops event_ops = { - .sample = process_sample_event, - .mmap = perf_event__process_mmap, - .comm = perf_event__process_comm, - .fork = perf_event__process_task, - .ordered_samples = true, - .ordering_requires_timestamps = true, -}; - -static int __cmd_annotate(void) +static int __cmd_annotate(struct perf_annotate *ann) { int ret; struct perf_session *session; @@ -179,7 +174,7 @@ static int __cmd_annotate(void) u64 total_nr_samples; session = perf_session__new(ann->input_name, O_RDONLY, - ann->force, false, &event_ops); + ann->force, false, &ann->ops); if (session == NULL) return -ENOMEM; @@ -190,7 +185,7 @@ static int __cmd_annotate(void) goto out_delete; } - ret = perf_session__process_events(session, &event_ops); + ret = perf_session__process_events(session, &ann->ops); if (ret) goto out_delete; @@ -214,7 +209,7 @@ static int __cmd_annotate(void) total_nr_samples += nr_samples; hists__collapse_resort(hists); hists__output_resort(hists); - hists__find_annotations(hists, pos->idx); + hists__find_annotations(hists, pos->idx, ann); } } @@ -243,7 +238,20 @@ static const char * const annotate_usage[] = { NULL }; -static const struct option options[] = { +int cmd_annotate(int argc, const char **argv, const char *prefix __used) +{ + struct perf_annotate annotate = { + .ops = { + .sample = process_sample_event, + .mmap = perf_event__process_mmap, + .comm = perf_event__process_comm, + .fork = perf_event__process_task, + .ordered_samples = true, + .ordering_requires_timestamps = true, + }, + .input_name = "perf.data", + }; + const struct option options[] = { OPT_STRING('i', "input", &annotate.input_name, "file", "input file name"), OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", @@ -275,10 +283,8 @@ static const struct option options[] = { OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", "Specify disassembler style (e.g. -M intel for intel syntax)"), OPT_END() -}; + }; -int cmd_annotate(int argc, const char **argv, const char *prefix __used) -{ argc = parse_options(argc, argv, options, annotate_usage, 0); if (annotate.use_stdio) @@ -312,5 +318,5 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __used) return -1; } - return __cmd_annotate(); + return __cmd_annotate(&annotate); } diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index b39f3a1ee7d..9a0872f9e83 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -30,7 +30,8 @@ static int hists__add_entry(struct hists *self, return -ENOMEM; } -static int diff__process_sample_event(union perf_event *event, +static int diff__process_sample_event(struct perf_event_ops *ops __used, + union perf_event *event, struct perf_sample *sample, struct perf_evsel *evsel __used, struct perf_session *session) diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index 978751ec64c..6ce6d80b59d 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c @@ -16,7 +16,8 @@ static char const *input_name = "-"; static bool inject_build_ids; -static int perf_event__repipe_synth(union perf_event *event, +static int perf_event__repipe_synth(struct perf_event_ops *ops __used, + union perf_event *event, struct perf_session *session __used) { uint32_t size; @@ -36,47 +37,57 @@ static int perf_event__repipe_synth(union perf_event *event, return 0; } +static int perf_event__repipe_tracing_data_synth(union perf_event *event, + struct perf_session *session) +{ + return perf_event__repipe_synth(NULL, event, session); +} + static int perf_event__repipe_attr(union perf_event *event, struct perf_evlist **pevlist __used) { - return perf_event__repipe_synth(event, NULL); + return perf_event__repipe_synth(NULL, event, NULL); } -static int perf_event__repipe(union perf_event *event, +static int perf_event__repipe(struct perf_event_ops *ops, + union perf_event *event, struct perf_sample *sample __used, struct perf_session *session) { - return perf_event__repipe_synth(event, session); + return perf_event__repipe_synth(ops, event, session); } -static int perf_event__repipe_sample(union perf_event *event, +static int perf_event__repipe_sample(struct perf_event_ops *ops, + union perf_event *event, struct perf_sample *sample __used, struct perf_evsel *evsel __used, struct perf_session *session) { - return perf_event__repipe_synth(event, session); + return perf_event__repipe_synth(ops, event, session); } -static int perf_event__repipe_mmap(union perf_event *event, +static int perf_event__repipe_mmap(struct perf_event_ops *ops, + union perf_event *event, struct perf_sample *sample, struct perf_session *session) { int err; - err = perf_event__process_mmap(event, sample, session); - perf_event__repipe(event, sample, session); + err = perf_event__process_mmap(ops, event, sample, session); + perf_event__repipe(ops, event, sample, session); return err; } -static int perf_event__repipe_task(union perf_event *event, +static int perf_event__repipe_task(struct perf_event_ops *ops, + union perf_event *event, struct perf_sample *sample, struct perf_session *session) { int err; - err = perf_event__process_task(event, sample, session); - perf_event__repipe(event, sample, session); + err = perf_event__process_task(ops, event, sample, session); + perf_event__repipe(ops, event, sample, session); return err; } @@ -86,7 +97,7 @@ static int perf_event__repipe_tracing_data(union perf_event *event, { int err; - perf_event__repipe_synth(event, session); + perf_event__repipe_synth(NULL, event, session); err = perf_event__process_tracing_data(event, session); return err; @@ -106,7 +117,8 @@ static int dso__read_build_id(struct dso *self) return -1; } -static int dso__inject_build_id(struct dso *self, struct perf_session *session) +static int dso__inject_build_id(struct dso *self, struct perf_event_ops *ops, + struct perf_session *session) { u16 misc = PERF_RECORD_MISC_USER; struct machine *machine; @@ -126,7 +138,7 @@ static int dso__inject_build_id(struct dso *self, struct perf_session *session) if (self->kernel) misc = PERF_RECORD_MISC_KERNEL; - err = perf_event__synthesize_build_id(self, misc, perf_event__repipe, + err = perf_event__synthesize_build_id(ops, self, misc, perf_event__repipe, machine, session); if (err) { pr_err("Can't synthesize build_id event for %s\n", self->long_name); @@ -136,7 +148,8 @@ static int dso__inject_build_id(struct dso *self, struct perf_session *session) return 0; } -static int perf_event__inject_buildid(union perf_event *event, +static int perf_event__inject_buildid(struct perf_event_ops *ops, + union perf_event *event, struct perf_sample *sample, struct perf_evsel *evsel __used, struct perf_session *session) @@ -161,7 +174,7 @@ static int perf_event__inject_buildid(union perf_event *event, if (!al.map->dso->hit) { al.map->dso->hit = 1; if (map__load(al.map, NULL) >= 0) { - dso__inject_build_id(al.map->dso, session); + dso__inject_build_id(al.map->dso, ops, session); /* * If this fails, too bad, let the other side * account this as unresolved. @@ -174,7 +187,7 @@ static int perf_event__inject_buildid(union perf_event *event, } repipe: - perf_event__repipe(event, sample, session); + perf_event__repipe(ops, event, sample, session); return 0; } @@ -189,9 +202,9 @@ struct perf_event_ops inject_ops = { .throttle = perf_event__repipe, .unthrottle = perf_event__repipe, .attr = perf_event__repipe_attr, - .event_type = perf_event__repipe_synth, - .tracing_data = perf_event__repipe_synth, - .build_id = perf_event__repipe_synth, + .event_type = perf_event__repipe_synth, + .tracing_data = perf_event__repipe_tracing_data_synth, + .build_id = perf_event__repipe_synth, }; extern volatile int session_done; diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index 225e963df10..5d01218e50e 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c @@ -303,7 +303,8 @@ static void process_raw_event(union perf_event *raw_event __used, void *data, } } -static int process_sample_event(union perf_event *event, +static int process_sample_event(struct perf_event_ops *ops __used, + union perf_event *event, struct perf_sample *sample, struct perf_evsel *evsel __used, struct perf_session *session) diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c index 899080ace26..f06b0a44c7c 100644 --- a/tools/perf/builtin-lock.c +++ b/tools/perf/builtin-lock.c @@ -845,7 +845,8 @@ static void dump_info(void) die("Unknown type of information\n"); } -static int process_sample_event(union perf_event *event, +static int process_sample_event(struct perf_event_ops *ops __used, + union perf_event *event, struct perf_sample *sample, struct perf_evsel *evsel __used, struct perf_session *s) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index ba6777a147c..4642d38b8d1 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -35,43 +35,36 @@ enum write_mode_t { WRITE_APPEND }; -struct perf_record_opts record_opts = { - .target_pid = -1, - .target_tid = -1, - .mmap_pages = UINT_MAX, - .user_freq = UINT_MAX, - .user_interval = ULLONG_MAX, - .freq = 1000, - .sample_id_all_avail = true, +struct perf_record { + struct perf_event_ops ops; + struct perf_record_opts opts; + u64 bytes_written; + const char *output_name; + struct perf_evlist *evlist; + struct perf_session *session; + const char *progname; + int output; + unsigned int page_size; + int realtime_prio; + enum write_mode_t write_mode; + bool no_buildid; + bool no_buildid_cache; + bool force; + bool file_new; + bool append_file; + long samples; + off_t post_processing_offset; }; -static unsigned int page_size; -static int output; -static const char *output_name = NULL; -static int realtime_prio = 0; -static enum write_mode_t write_mode = WRITE_FORCE; -static bool no_buildid = false; -static bool no_buildid_cache = false; -static struct perf_evlist *evsel_list; - -static long samples = 0; -static u64 bytes_written = 0; - -static int file_new = 1; -static off_t post_processing_offset; - -static struct perf_session *session; -static const char *progname; - -static void advance_output(size_t size) +static void advance_output(struct perf_record *rec, size_t size) { - bytes_written += size; + rec->bytes_written += size; } -static void write_output(void *buf, size_t size) +static void write_output(struct perf_record *rec, void *buf, size_t size) { while (size) { - int ret = write(output, buf, size); + int ret = write(rec->output, buf, size); if (ret < 0) die("failed to write"); @@ -79,30 +72,33 @@ static void write_output(void *buf, size_t size) size -= ret; buf += ret; - bytes_written += ret; + rec->bytes_written += ret; } } -static int process_synthesized_event(union perf_event *event, +static int process_synthesized_event(struct perf_event_ops *ops, + union perf_event *event, struct perf_sample *sample __used, struct perf_session *self __used) { - write_output(event, event->header.size); + struct perf_record *rec = container_of(ops, struct perf_record, ops); + write_output(rec, event, event->header.size); return 0; } -static void mmap_read(struct perf_mmap *md) +static void perf_record__mmap_read(struct perf_record *rec, + struct perf_mmap *md) { unsigned int head = perf_mmap__read_head(md); unsigned int old = md->prev; - unsigned char *data = md->base + page_size; + unsigned char *data = md->base + rec->page_size; unsigned long size; void *buf; if (old == head) return; - samples++; + rec->samples++; size = head - old; @@ -111,14 +107,14 @@ static void mmap_read(struct perf_mmap *md) size = md->mask + 1 - (old & md->mask); old += size; - write_output(buf, size); + write_output(rec, buf, size); } buf = &data[old & md->mask]; size = head - old; old += size; - write_output(buf, size); + write_output(rec, buf, size); md->prev = old; perf_mmap__write_tail(md, old); @@ -137,17 +133,18 @@ static void sig_handler(int sig) signr = sig; } -static void sig_atexit(void) +static void perf_record__sig_exit(int exit_status __used, void *arg) { + struct perf_record *rec = arg; int status; - if (evsel_list->workload.pid > 0) { + if (rec->evlist->workload.pid > 0) { if (!child_finished) - kill(evsel_list->workload.pid, SIGTERM); + kill(rec->evlist->workload.pid, SIGTERM); wait(&status); if (WIFSIGNALED(status)) - psignal(WTERMSIG(status), progname); + psignal(WTERMSIG(status), rec->progname); } if (signr == -1 || signr == SIGUSR1) @@ -176,13 +173,16 @@ static bool perf_evlist__equal(struct perf_evlist *evlist, return true; } -static void open_counters(struct perf_evlist *evlist) +static void perf_record__open(struct perf_record *rec) { struct perf_evsel *pos, *first; + struct perf_evlist *evlist = rec->evlist; + struct perf_session *session = rec->session; + struct perf_record_opts *opts = &rec->opts; first = list_entry(evlist->entries.next, struct perf_evsel, node); - perf_evlist__config_attrs(evlist, &record_opts); + perf_evlist__config_attrs(evlist, opts); list_for_each_entry(pos, &evlist->entries, node) { struct perf_event_attr *attr = &pos->attr; @@ -201,27 +201,27 @@ static void open_counters(struct perf_evlist *evlist) */ bool time_needed = attr->sample_type & PERF_SAMPLE_TIME; - if (record_opts.group && pos != first) + if (opts->group && pos != first) group_fd = first->fd; retry_sample_id: - attr->sample_id_all = record_opts.sample_id_all_avail ? 1 : 0; + attr->sample_id_all = opts->sample_id_all_avail ? 1 : 0; try_again: if (perf_evsel__open(pos, evlist->cpus, evlist->threads, - record_opts.group, group_fd) < 0) { + opts->group, group_fd) < 0) { int err = errno; if (err == EPERM || err == EACCES) { ui__error_paranoid(); exit(EXIT_FAILURE); - } else if (err == ENODEV && record_opts.cpu_list) { + } else if (err == ENODEV && opts->cpu_list) { die("No such device - did you specify" " an out-of-range profile CPU?\n"); - } else if (err == EINVAL && record_opts.sample_id_all_avail) { + } else if (err == EINVAL && opts->sample_id_all_avail) { /* * Old kernel, no attr->sample_id_type_all field */ - record_opts.sample_id_all_avail = false; - if (!record_opts.sample_time && !record_opts.raw_samples && !time_needed) + opts->sample_id_all_avail = false; + if (!opts->sample_time && !opts->raw_samples && !time_needed) attr->sample_type &= ~PERF_SAMPLE_TIME; goto retry_sample_id; @@ -271,10 +271,10 @@ try_again: exit(-1); } - if (perf_evlist__mmap(evlist, record_opts.mmap_pages, false) < 0) + if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) die("failed to mmap with %d (%s)\n", errno, strerror(errno)); - if (file_new) + if (rec->file_new) session->evlist = evlist; else { if (!perf_evlist__equal(session->evlist, evlist)) { @@ -286,29 +286,32 @@ try_again: perf_session__update_sample_type(session); } -static int process_buildids(void) +static int process_buildids(struct perf_record *rec) { - u64 size = lseek(output, 0, SEEK_CUR); + u64 size = lseek(rec->output, 0, SEEK_CUR); if (size == 0) return 0; - session->fd = output; - return __perf_session__process_events(session, post_processing_offset, - size - post_processing_offset, + rec->session->fd = rec->output; + return __perf_session__process_events(rec->session, rec->post_processing_offset, + size - rec->post_processing_offset, size, &build_id__mark_dso_hit_ops); } -static void atexit_header(void) +static void perf_record__exit(int status __used, void *arg) { - if (!record_opts.pipe_output) { - session->header.data_size += bytes_written; - - if (!no_buildid) - process_buildids(); - perf_session__write_header(session, evsel_list, output, true); - perf_session__delete(session); - perf_evlist__delete(evsel_list); + struct perf_record *rec = arg; + + if (!rec->opts.pipe_output) { + rec->session->header.data_size += rec->bytes_written; + + if (!rec->no_buildid) + process_buildids(rec); + perf_session__write_header(rec->session, rec->evlist, + rec->output, true); + perf_session__delete(rec->session); + perf_evlist__delete(rec->evlist); symbol__exit(); } } @@ -316,7 +319,9 @@ static void atexit_header(void) static void perf_event__synthesize_guest_os(struct machine *machine, void *data) { int err; - struct perf_session *psession = data; + struct perf_event_ops *ops = data; + struct perf_record *rec = container_of(ops, struct perf_record, ops); + struct perf_session *psession = rec->session; if (machine__is_host(machine)) return; @@ -329,7 +334,7 @@ static void perf_event__synthesize_guest_os(struct machine *machine, void *data) *method is used to avoid symbol missing when the first addr is *in module instead of in guest kernel. */ - err = perf_event__synthesize_modules(process_synthesized_event, + err = perf_event__synthesize_modules(ops, process_synthesized_event, psession, machine); if (err < 0) pr_err("Couldn't record guest kernel [%d]'s reference" @@ -339,10 +344,10 @@ static void perf_event__synthesize_guest_os(struct machine *machine, void *data) * We use _stext for guest kernel because guest kernel's /proc/kallsyms * have no _text sometimes. */ - err = perf_event__synthesize_kernel_mmap(process_synthesized_event, + err = perf_event__synthesize_kernel_mmap(ops, process_synthesized_event, psession, machine, "_text"); if (err < 0) - err = perf_event__synthesize_kernel_mmap(process_synthesized_event, + err = perf_event__synthesize_kernel_mmap(ops, process_synthesized_event, psession, machine, "_stext"); if (err < 0) @@ -355,66 +360,71 @@ static struct perf_event_header finished_round_event = { .type = PERF_RECORD_FINISHED_ROUND, }; -static void mmap_read_all(void) +static void perf_record__mmap_read_all(struct perf_record *rec) { int i; - for (i = 0; i < evsel_list->nr_mmaps; i++) { - if (evsel_list->mmap[i].base) - mmap_read(&evsel_list->mmap[i]); + for (i = 0; i < rec->evlist->nr_mmaps; i++) { + if (rec->evlist->mmap[i].base) + perf_record__mmap_read(rec, &rec->evlist->mmap[i]); } - if (perf_header__has_feat(&session->header, HEADER_TRACE_INFO)) - write_output(&finished_round_event, sizeof(finished_round_event)); + if (perf_header__has_feat(&rec->session->header, HEADER_TRACE_INFO)) + write_output(rec, &finished_round_event, sizeof(finished_round_event)); } -static int __cmd_record(int argc, const char **argv) +static int __cmd_record(struct perf_record *rec, int argc, const char **argv) { struct stat st; int flags; - int err; + int err, output; unsigned long waking = 0; const bool forks = argc > 0; struct machine *machine; + struct perf_event_ops *ops = &rec->ops; + struct perf_record_opts *opts = &rec->opts; + struct perf_evlist *evsel_list = rec->evlist; + const char *output_name = rec->output_name; + struct perf_session *session; - progname = argv[0]; + rec->progname = argv[0]; - page_size = sysconf(_SC_PAGE_SIZE); + rec->page_size = sysconf(_SC_PAGE_SIZE); - atexit(sig_atexit); + on_exit(perf_record__sig_exit, rec); signal(SIGCHLD, sig_handler); signal(SIGINT, sig_handler); signal(SIGUSR1, sig_handler); if (!output_name) { if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode)) - record_opts.pipe_output = true; + opts->pipe_output = true; else - output_name = "perf.data"; + rec->output_name = output_name = "perf.data"; } if (output_name) { if (!strcmp(output_name, "-")) - record_opts.pipe_output = true; + opts->pipe_output = true; else if (!stat(output_name, &st) && st.st_size) { - if (write_mode == WRITE_FORCE) { + if (rec->write_mode == WRITE_FORCE) { char oldname[PATH_MAX]; snprintf(oldname, sizeof(oldname), "%s.old", output_name); unlink(oldname); rename(output_name, oldname); } - } else if (write_mode == WRITE_APPEND) { - write_mode = WRITE_FORCE; + } else if (rec->write_mode == WRITE_APPEND) { + rec->write_mode = WRITE_FORCE; } } flags = O_CREAT|O_RDWR; - if (write_mode == WRITE_APPEND) - file_new = 0; + if (rec->write_mode == WRITE_APPEND) + rec->file_new = 0; else flags |= O_TRUNC; - if (record_opts.pipe_output) + if (opts->pipe_output) output = STDOUT_FILENO; else output = open(output_name, flags, S_IRUSR | S_IWUSR); @@ -423,17 +433,21 @@ static int __cmd_record(int argc, const char **argv) exit(-1); } + rec->output = output; + session = perf_session__new(output_name, O_WRONLY, - write_mode == WRITE_FORCE, false, NULL); + rec->write_mode == WRITE_FORCE, false, NULL); if (session == NULL) { pr_err("Not enough memory for reading perf file header\n"); return -1; } - if (!no_buildid) + rec->session = session; + + if (!rec->no_buildid) perf_header__set_feat(&session->header, HEADER_BUILD_ID); - if (!file_new) { + if (!rec->file_new) { err = perf_session__read_header(session, output); if (err < 0) goto out_delete_session; @@ -456,42 +470,42 @@ static int __cmd_record(int argc, const char **argv) perf_header__set_feat(&session->header, HEADER_CPUID); if (forks) { - err = perf_evlist__prepare_workload(evsel_list, &record_opts, argv); + err = perf_evlist__prepare_workload(evsel_list, opts, argv); if (err < 0) { pr_err("Couldn't run the workload!\n"); goto out_delete_session; } } - open_counters(evsel_list); + perf_record__open(rec); /* - * perf_session__delete(session) will be called at atexit_header() + * perf_session__delete(session) will be called at perf_record__exit() */ - atexit(atexit_header); + on_exit(perf_record__exit, rec); - if (record_opts.pipe_output) { + if (opts->pipe_output) { err = perf_header__write_pipe(output); if (err < 0) return err; - } else if (file_new) { + } else if (rec->file_new) { err = perf_session__write_header(session, evsel_list, output, false); if (err < 0) return err; } - post_processing_offset = lseek(output, 0, SEEK_CUR); + rec->post_processing_offset = lseek(output, 0, SEEK_CUR); - if (record_opts.pipe_output) { - err = perf_session__synthesize_attrs(session, - process_synthesized_event); + if (opts->pipe_output) { + err = perf_event__synthesize_attrs(ops, session, + process_synthesized_event); if (err < 0) { pr_err("Couldn't synthesize attrs.\n"); return err; } - err = perf_event__synthesize_event_types(process_synthesized_event, + err = perf_event__synthesize_event_types(ops, process_synthesized_event, session); if (err < 0) { pr_err("Couldn't synthesize event_types.\n"); @@ -507,14 +521,14 @@ static int __cmd_record(int argc, const char **argv) * return this more properly and also * propagate errors that now are calling die() */ - err = perf_event__synthesize_tracing_data(output, evsel_list, + err = perf_event__synthesize_tracing_data(ops, output, evsel_list, process_synthesized_event, session); if (err <= 0) { pr_err("Couldn't record tracing data.\n"); return err; } - advance_output(err); + advance_output(rec, err); } } @@ -524,17 +538,17 @@ static int __cmd_record(int argc, const char **argv) return -1; } - err = perf_event__synthesize_kernel_mmap(process_synthesized_event, + err = perf_event__synthesize_kernel_mmap(ops, process_synthesized_event, session, machine, "_text"); if (err < 0) - err = perf_event__synthesize_kernel_mmap(process_synthesized_event, + err = perf_event__synthesize_kernel_mmap(ops, process_synthesized_event, session, machine, "_stext"); if (err < 0) pr_err("Couldn't record kernel reference relocation symbol\n" "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n" "Check /proc/kallsyms permission or run as root.\n"); - err = perf_event__synthesize_modules(process_synthesized_event, + err = perf_event__synthesize_modules(ops, process_synthesized_event, session, machine); if (err < 0) pr_err("Couldn't record kernel module information.\n" @@ -542,21 +556,21 @@ static int __cmd_record(int argc, const char **argv) "Check /proc/modules permission or run as root.\n"); if (perf_guest) - perf_session__process_machines(session, + perf_session__process_machines(session, ops, perf_event__synthesize_guest_os); - if (!record_opts.system_wide) - perf_event__synthesize_thread_map(evsel_list->threads, + if (!opts->system_wide) + perf_event__synthesize_thread_map(ops, evsel_list->threads, process_synthesized_event, session); else - perf_event__synthesize_threads(process_synthesized_event, + perf_event__synthesize_threads(ops, process_synthesized_event, session); - if (realtime_prio) { + if (rec->realtime_prio) { struct sched_param param; - param.sched_priority = realtime_prio; + param.sched_priority = rec->realtime_prio; if (sched_setscheduler(0, SCHED_FIFO, ¶m)) { pr_err("Could not set realtime priority.\n"); exit(-1); @@ -572,11 +586,11 @@ static int __cmd_record(int argc, const char **argv) perf_evlist__start_workload(evsel_list); for (;;) { - int hits = samples; + int hits = rec->samples; - mmap_read_all(); + perf_record__mmap_read_all(rec); - if (hits == samples) { + if (hits == rec->samples) { if (done) break; err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1); @@ -597,9 +611,9 @@ static int __cmd_record(int argc, const char **argv) */ fprintf(stderr, "[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n", - (double)bytes_written / 1024.0 / 1024.0, + (double)rec->bytes_written / 1024.0 / 1024.0, output_name, - bytes_written / 24); + rec->bytes_written / 24); return 0; @@ -614,59 +628,88 @@ static const char * const record_usage[] = { NULL }; -static bool force, append_file; +/* + * XXX Ideally would be local to cmd_record() and passed to a perf_record__new + * because we need to have access to it in perf_record__exit, that is called + * after cmd_record() exits, but since record_options need to be accessible to + * builtin-script, leave it here. + * + * At least we don't ouch it in all the other functions here directly. + * + * Just say no to tons of global variables, sigh. + */ +static struct perf_record record = { + .opts = { + .target_pid = -1, + .target_tid = -1, + .mmap_pages = UINT_MAX, + .user_freq = UINT_MAX, + .user_interval = ULLONG_MAX, + .freq = 1000, + .sample_id_all_avail = true, + }, + .write_mode = WRITE_FORCE, + .file_new = true, +}; +/* + * XXX Will stay a global variable till we fix builtin-script.c to stop messing + * with it and switch to use the library functions in perf_evlist that came + * from builtin-record.c, i.e. use perf_record_opts, + * perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record', + * using pipes, etc. + */ const struct option record_options[] = { - OPT_CALLBACK('e', "event", &evsel_list, "event", + OPT_CALLBACK('e', "event", &record.evlist, "event", "event selector. use 'perf list' to list available events", parse_events_option), - OPT_CALLBACK(0, "filter", &evsel_list, "filter", + OPT_CALLBACK(0, "filter", &record.evlist, "filter", "event filter", parse_filter), - OPT_INTEGER('p', "pid", &record_opts.target_pid, + OPT_INTEGER('p', "pid", &record.opts.target_pid, "record events on existing process id"), - OPT_INTEGER('t', "tid", &record_opts.target_tid, + OPT_INTEGER('t', "tid", &record.opts.target_tid, "record events on existing thread id"), - OPT_INTEGER('r', "realtime", &realtime_prio, + OPT_INTEGER('r', "realtime", &record.realtime_prio, "collect data with this RT SCHED_FIFO priority"), - OPT_BOOLEAN('D', "no-delay", &record_opts.no_delay, + OPT_BOOLEAN('D', "no-delay", &record.opts.no_delay, "collect data without buffering"), - OPT_BOOLEAN('R', "raw-samples", &record_opts.raw_samples, + OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples, "collect raw sample records from all opened counters"), - OPT_BOOLEAN('a', "all-cpus", &record_opts.system_wide, + OPT_BOOLEAN('a', "all-cpus", &record.opts.system_wide, "system-wide collection from all CPUs"), - OPT_BOOLEAN('A', "append", &append_file, + OPT_BOOLEAN('A', "append", &record.append_file, "append to the output file to do incremental profiling"), - OPT_STRING('C', "cpu", &record_opts.cpu_list, "cpu", + OPT_STRING('C', "cpu", &record.opts.cpu_list, "cpu", "list of cpus to monitor"), - OPT_BOOLEAN('f', "force", &force, + OPT_BOOLEAN('f', "force", &record.force, "overwrite existing data file (deprecated)"), - OPT_U64('c', "count", &record_opts.user_interval, "event period to sample"), - OPT_STRING('o', "output", &output_name, "file", + OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"), + OPT_STRING('o', "output", &record.output_name, "file", "output file name"), - OPT_BOOLEAN('i', "no-inherit", &record_opts.no_inherit, + OPT_BOOLEAN('i', "no-inherit", &record.opts.no_inherit, "child tasks do not inherit counters"), - OPT_UINTEGER('F', "freq", &record_opts.user_freq, "profile at this frequency"), - OPT_UINTEGER('m', "mmap-pages", &record_opts.mmap_pages, + OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"), + OPT_UINTEGER('m', "mmap-pages", &record.opts.mmap_pages, "number of mmap data pages"), - OPT_BOOLEAN(0, "group", &record_opts.group, + OPT_BOOLEAN(0, "group", &record.opts.group, "put the counters into a counter group"), - OPT_BOOLEAN('g', "call-graph", &record_opts.call_graph, + OPT_BOOLEAN('g', "call-graph", &record.opts.call_graph, "do call-graph (stack chain/backtrace) recording"), OPT_INCR('v', "verbose", &verbose, "be more verbose (show counter open errors, etc)"), OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"), - OPT_BOOLEAN('s', "stat", &record_opts.inherit_stat, + OPT_BOOLEAN('s', "stat", &record.opts.inherit_stat, "per thread counts"), - OPT_BOOLEAN('d', "data", &record_opts.sample_address, + OPT_BOOLEAN('d', "data", &record.opts.sample_address, "Sample addresses"), - OPT_BOOLEAN('T', "timestamp", &record_opts.sample_time, "Sample timestamps"), - OPT_BOOLEAN('n', "no-samples", &record_opts.no_samples, + OPT_BOOLEAN('T', "timestamp", &record.opts.sample_time, "Sample timestamps"), + OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples, "don't sample"), - OPT_BOOLEAN('N', "no-buildid-cache", &no_buildid_cache, + OPT_BOOLEAN('N', "no-buildid-cache", &record.no_buildid_cache, "do not update the buildid cache"), - OPT_BOOLEAN('B', "no-buildid", &no_buildid, + OPT_BOOLEAN('B', "no-buildid", &record.no_buildid, "do not collect buildids in perf.data"), - OPT_CALLBACK('G', "cgroup", &evsel_list, "name", + OPT_CALLBACK('G', "cgroup", &record.evlist, "name", "monitor event in cgroup name only", parse_cgroups), OPT_END() @@ -676,6 +719,8 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) { int err = -ENOMEM; struct perf_evsel *pos; + struct perf_evlist *evsel_list; + struct perf_record *rec = &record; perf_header__set_cmdline(argc, argv); @@ -683,23 +728,25 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) if (evsel_list == NULL) return -ENOMEM; + rec->evlist = evsel_list; + argc = parse_options(argc, argv, record_options, record_usage, PARSE_OPT_STOP_AT_NON_OPTION); - if (!argc && record_opts.target_pid == -1 && record_opts.target_tid == -1 && - !record_opts.system_wide && !record_opts.cpu_list) + if (!argc && rec->opts.target_pid == -1 && rec->opts.target_tid == -1 && + !rec->opts.system_wide && !rec->opts.cpu_list) usage_with_options(record_usage, record_options); - if (force && append_file) { + if (rec->force && rec->append_file) { fprintf(stderr, "Can't overwrite and append at the same time." " You need to choose between -f and -A"); usage_with_options(record_usage, record_options); - } else if (append_file) { - write_mode = WRITE_APPEND; + } else if (rec->append_file) { + rec->write_mode = WRITE_APPEND; } else { - write_mode = WRITE_FORCE; + rec->write_mode = WRITE_FORCE; } - if (nr_cgroups && !record_opts.system_wide) { + if (nr_cgroups && !rec->opts.system_wide) { fprintf(stderr, "cgroup monitoring only available in" " system-wide mode\n"); usage_with_options(record_usage, record_options); @@ -717,7 +764,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) "If some relocation was applied (e.g. kexec) symbols may be misresolved\n" "even with a suitable vmlinux or kallsyms file.\n\n"); - if (no_buildid_cache || no_buildid) + if (rec->no_buildid_cache || rec->no_buildid) disable_buildid_cache(); if (evsel_list->nr_entries == 0 && @@ -726,11 +773,11 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) goto out_symbol_exit; } - if (record_opts.target_pid != -1) - record_opts.target_tid = record_opts.target_pid; + if (rec->opts.target_pid != -1) + rec->opts.target_tid = rec->opts.target_pid; - if (perf_evlist__create_maps(evsel_list, record_opts.target_pid, - record_opts.target_tid, record_opts.cpu_list) < 0) + if (perf_evlist__create_maps(evsel_list, rec->opts.target_pid, + rec->opts.target_tid, rec->opts.cpu_list) < 0) usage_with_options(record_usage, record_options); list_for_each_entry(pos, &evsel_list->entries, node) { @@ -744,25 +791,25 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) if (perf_evlist__alloc_pollfd(evsel_list) < 0) goto out_free_fd; - if (record_opts.user_interval != ULLONG_MAX) - record_opts.default_interval = record_opts.user_interval; - if (record_opts.user_freq != UINT_MAX) - record_opts.freq = record_opts.user_freq; + if (rec->opts.user_interval != ULLONG_MAX) + rec->opts.default_interval = rec->opts.user_interval; + if (rec->opts.user_freq != UINT_MAX) + rec->opts.freq = rec->opts.user_freq; /* * User specified count overrides default frequency. */ - if (record_opts.default_interval) - record_opts.freq = 0; - else if (record_opts.freq) { - record_opts.default_interval = record_opts.freq; + if (rec->opts.default_interval) + rec->opts.freq = 0; + else if (rec->opts.freq) { + rec->opts.default_interval = rec->opts.freq; } else { fprintf(stderr, "frequency and count are zero, aborting\n"); err = -EINVAL; goto out_free_fd; } - err = __cmd_record(argc, argv); + err = __cmd_record(&record, argc, argv); out_free_fd: perf_evlist__delete_maps(evsel_list); out_symbol_exit: diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 5d2e819dfc4..8795520f6e1 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -35,7 +35,9 @@ #include -static struct perf_report { +struct perf_report { + struct perf_event_ops ops; + struct perf_session *session; char const *input_name; bool force, use_tui, use_stdio; bool hide_unresolved; @@ -48,12 +50,7 @@ static struct perf_report { symbol_filter_t annotate_init; const char *cpu_list; DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); -} report = { - .input_name = "perf.data", - .pretty_printing_style = "normal", -}, *rep = &report; - -static char callchain_default_opt[] = "fractal,0.5,callee"; +}; static int perf_session__add_hist_entry(struct perf_session *session, struct addr_location *al, @@ -106,11 +103,13 @@ out: } -static int process_sample_event(union perf_event *event, +static int process_sample_event(struct perf_event_ops *ops, + union perf_event *event, struct perf_sample *sample, struct perf_evsel *evsel, struct perf_session *session) { + struct perf_report *rep = container_of(ops, struct perf_report, ops); struct addr_location al; if (perf_event__preprocess_sample(event, session, &al, sample, @@ -137,10 +136,12 @@ static int process_sample_event(union perf_event *event, return 0; } -static int process_read_event(union perf_event *event, +static int process_read_event(struct perf_event_ops *ops, + union perf_event *event, struct perf_sample *sample __used, struct perf_session *session) { + struct perf_report *rep = container_of(ops, struct perf_report, ops); struct perf_evsel *evsel = perf_evlist__id2evsel(session->evlist, event->read.id); if (rep->show_threads) { @@ -159,8 +160,10 @@ static int process_read_event(union perf_event *event, return 0; } -static int perf_session__setup_sample_type(struct perf_session *self) +static int perf_report__setup_sample_type(struct perf_report *rep) { + struct perf_session *self = rep->session; + if (!(self->sample_type & PERF_SAMPLE_CALLCHAIN)) { if (sort__has_parent) { ui__warning("Selected --sort parent, but no " @@ -187,22 +190,6 @@ static int perf_session__setup_sample_type(struct perf_session *self) return 0; } -static struct perf_event_ops event_ops = { - .sample = process_sample_event, - .mmap = perf_event__process_mmap, - .comm = perf_event__process_comm, - .exit = perf_event__process_task, - .fork = perf_event__process_task, - .lost = perf_event__process_lost, - .read = process_read_event, - .attr = perf_event__process_attr, - .event_type = perf_event__process_event_type, - .tracing_data = perf_event__process_tracing_data, - .build_id = perf_event__process_build_id, - .ordered_samples = true, - .ordering_requires_timestamps = true, -}; - extern volatile int session_done; static void sig_handler(int sig __used) @@ -225,6 +212,7 @@ static size_t hists__fprintf_nr_sample_events(struct hists *self, } static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist, + struct perf_report *rep, const char *help) { struct perf_evsel *pos; @@ -253,7 +241,7 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist, return 0; } -static int __cmd_report(void) +static int __cmd_report(struct perf_report *rep) { int ret = -EINVAL; u64 nr_samples; @@ -266,10 +254,12 @@ static int __cmd_report(void) signal(SIGINT, sig_handler); session = perf_session__new(rep->input_name, O_RDONLY, - rep->force, false, &event_ops); + rep->force, false, &rep->ops); if (session == NULL) return -ENOMEM; + rep->session = session; + if (rep->cpu_list) { ret = perf_session__cpu_bitmap(session, rep->cpu_list, rep->cpu_bitmap); @@ -283,11 +273,11 @@ static int __cmd_report(void) if (rep->show_threads) perf_read_values_init(&rep->show_threads_values); - ret = perf_session__setup_sample_type(session); + ret = perf_report__setup_sample_type(rep); if (ret) goto out_delete; - ret = perf_session__process_events(session, &event_ops); + ret = perf_session__process_events(session, &rep->ops); if (ret) goto out_delete; @@ -339,7 +329,7 @@ static int __cmd_report(void) perf_evlist__tui_browse_hists(session->evlist, help, NULL, NULL, 0); } else - perf_evlist__tty_browse_hists(session->evlist, help); + perf_evlist__tty_browse_hists(session->evlist, rep, help); out_delete: /* @@ -358,9 +348,9 @@ out_delete: } static int -parse_callchain_opt(const struct option *opt __used, const char *arg, - int unset) +parse_callchain_opt(const struct option *opt, const char *arg, int unset) { + struct perf_report *rep = (struct perf_report *)opt->value; char *tok, *tok2; char *endptr; @@ -437,12 +427,33 @@ setup: return 0; } -static const char * const report_usage[] = { - "perf report [] ", - NULL -}; - -static const struct option options[] = { +int cmd_report(int argc, const char **argv, const char *prefix __used) +{ + char callchain_default_opt[] = "fractal,0.5,callee"; + const char * const report_usage[] = { + "perf report [] ", + NULL + }; + struct perf_report report = { + .ops = { + .sample = process_sample_event, + .mmap = perf_event__process_mmap, + .comm = perf_event__process_comm, + .exit = perf_event__process_task, + .fork = perf_event__process_task, + .lost = perf_event__process_lost, + .read = process_read_event, + .attr = perf_event__process_attr, + .event_type = perf_event__process_event_type, + .tracing_data = perf_event__process_tracing_data, + .build_id = perf_event__process_build_id, + .ordered_samples = true, + .ordering_requires_timestamps = true, + }, + .input_name = "perf.data", + .pretty_printing_style = "normal", + }; + const struct option options[] = { OPT_STRING('i', "input", &report.input_name, "file", "input file name"), OPT_INCR('v', "verbose", &verbose, @@ -473,7 +484,7 @@ static const struct option options[] = { "regex filter to identify parent, see: '--sort parent'"), OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other, "Only display entries with parent-match"), - OPT_CALLBACK_DEFAULT('g', "call-graph", NULL, "output_type,min_percent, call_order", + OPT_CALLBACK_DEFAULT('g', "call-graph", &report, "output_type,min_percent, call_order", "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold and callchain order. " "Default: fractal,0.5,callee", &parse_callchain_opt, callchain_default_opt), OPT_BOOLEAN('G', "inverted", &report.inverted_callchain, @@ -507,10 +518,8 @@ static const struct option options[] = { OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period, "Show a column with the sum of periods"), OPT_END() -}; + }; -int cmd_report(int argc, const char **argv, const char *prefix __used) -{ argc = parse_options(argc, argv, options, report_usage, 0); if (report.use_stdio) @@ -579,5 +588,5 @@ int cmd_report(int argc, const char **argv, const char *prefix __used) sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", stdout); sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", stdout); - return __cmd_report(); + return __cmd_report(&report); } diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index d51af0beab1..b11d6283fed 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -1602,7 +1602,8 @@ static void process_raw_event(union perf_event *raw_event __used, process_sched_migrate_task_event(data, session, event, cpu, timestamp, thread); } -static int process_sample_event(union perf_event *event, +static int process_sample_event(struct perf_event_ops *ops __used, + union perf_event *event, struct perf_sample *sample, struct perf_evsel *evsel, struct perf_session *session) diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 47545e9c9b2..3b7820612eb 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -434,7 +434,8 @@ static int cleanup_scripting(void) static char const *input_name = "perf.data"; -static int process_sample_event(union perf_event *event, +static int process_sample_event(struct perf_event_ops *ops __used, + union perf_event *event, struct perf_sample *sample, struct perf_evsel *evsel, struct perf_session *session) diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index 3fc52b1aa43..62298a0d7dc 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c @@ -274,7 +274,8 @@ static int cpus_cstate_state[MAX_CPUS]; static u64 cpus_pstate_start_times[MAX_CPUS]; static u64 cpus_pstate_state[MAX_CPUS]; -static int process_comm_event(union perf_event *event, +static int process_comm_event(struct perf_event_ops *ops __used, + union perf_event *event, struct perf_sample *sample __used, struct perf_session *session __used) { @@ -282,7 +283,8 @@ static int process_comm_event(union perf_event *event, return 0; } -static int process_fork_event(union perf_event *event, +static int process_fork_event(struct perf_event_ops *ops __used, + union perf_event *event, struct perf_sample *sample __used, struct perf_session *session __used) { @@ -290,7 +292,8 @@ static int process_fork_event(union perf_event *event, return 0; } -static int process_exit_event(union perf_event *event, +static int process_exit_event(struct perf_event_ops *ops __used, + union perf_event *event, struct perf_sample *sample __used, struct perf_session *session __used) { @@ -487,7 +490,8 @@ static void sched_switch(int cpu, u64 timestamp, struct trace_entry *te) } -static int process_sample_event(union perf_event *event __used, +static int process_sample_event(struct perf_event_ops *ops __used, + union perf_event *event __used, struct perf_sample *sample, struct perf_evsel *evsel, struct perf_session *session __used) diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 9b3bbb40d46..e8e3320602b 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -824,7 +824,7 @@ static void perf_session__mmap_read_idx(struct perf_session *self, int idx) perf_event__process_sample(event, evsel, &sample, self); else if (event->header.type < PERF_RECORD_MAX) { hists__inc_nr_events(&evsel->hists, event->header.type); - perf_event__process(event, &sample, self); + perf_event__process(&top.ops, event, &sample, self); } else ++self->hists.stats.nr_unknown_events; } @@ -966,10 +966,10 @@ static int __cmd_top(void) goto out_delete; if (top.target_tid != -1) - perf_event__synthesize_thread_map(top.evlist->threads, + perf_event__synthesize_thread_map(&top.ops, top.evlist->threads, perf_event__process, top.session); else - perf_event__synthesize_threads(perf_event__process, top.session); + perf_event__synthesize_threads(&top.ops, perf_event__process, top.session); start_counters(top.evlist); top.session->evlist = top.evlist; diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c index f2fe6ec0894..0e4de186501 100644 --- a/tools/perf/util/build-id.c +++ b/tools/perf/util/build-id.c @@ -13,8 +13,10 @@ #include "symbol.h" #include #include "debug.h" +#include "session.h" -static int build_id__mark_dso_hit(union perf_event *event, +static int build_id__mark_dso_hit(struct perf_event_ops *ops __used, + union perf_event *event, struct perf_sample *sample __used, struct perf_evsel *evsel __used, struct perf_session *session) @@ -38,7 +40,8 @@ static int build_id__mark_dso_hit(union perf_event *event, return 0; } -static int perf_event__exit_del_thread(union perf_event *event, +static int perf_event__exit_del_thread(struct perf_event_ops *ops __used, + union perf_event *event, struct perf_sample *sample __used, struct perf_session *session) { diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h index 9b4ff16cac9..7f9c0f1ae3a 100644 --- a/tools/perf/util/callchain.h +++ b/tools/perf/util/callchain.h @@ -101,6 +101,9 @@ int callchain_append(struct callchain_root *root, int callchain_merge(struct callchain_cursor *cursor, struct callchain_root *dst, struct callchain_root *src); +struct ip_callchain; +union perf_event; + bool ip_callchain__valid(struct ip_callchain *chain, const union perf_event *event); /* diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 437f8ca679a..4800f38c727 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -44,7 +44,8 @@ static struct perf_sample synth_sample = { .period = 1, }; -static pid_t perf_event__synthesize_comm(union perf_event *event, pid_t pid, +static pid_t perf_event__synthesize_comm(struct perf_event_ops *ops, + union perf_event *event, pid_t pid, int full, perf_event__handler_t process, struct perf_session *session) { @@ -99,7 +100,7 @@ out_race: if (!full) { event->comm.tid = pid; - process(event, &synth_sample, session); + process(ops, event, &synth_sample, session); goto out; } @@ -117,7 +118,7 @@ out_race: event->comm.tid = pid; - process(event, &synth_sample, session); + process(ops, event, &synth_sample, session); } closedir(tasks); @@ -127,7 +128,8 @@ out: return tgid; } -static int perf_event__synthesize_mmap_events(union perf_event *event, +static int perf_event__synthesize_mmap_events(struct perf_event_ops *ops, + union perf_event *event, pid_t pid, pid_t tgid, perf_event__handler_t process, struct perf_session *session) @@ -198,7 +200,7 @@ static int perf_event__synthesize_mmap_events(union perf_event *event, event->mmap.pid = tgid; event->mmap.tid = pid; - process(event, &synth_sample, session); + process(ops, event, &synth_sample, session); } } @@ -206,7 +208,8 @@ static int perf_event__synthesize_mmap_events(union perf_event *event, return 0; } -int perf_event__synthesize_modules(perf_event__handler_t process, +int perf_event__synthesize_modules(struct perf_event_ops *ops, + perf_event__handler_t process, struct perf_session *session, struct machine *machine) { @@ -251,7 +254,7 @@ int perf_event__synthesize_modules(perf_event__handler_t process, memcpy(event->mmap.filename, pos->dso->long_name, pos->dso->long_name_len + 1); - process(event, &synth_sample, session); + process(ops, event, &synth_sample, session); } free(event); @@ -261,17 +264,19 @@ int perf_event__synthesize_modules(perf_event__handler_t process, static int __event__synthesize_thread(union perf_event *comm_event, union perf_event *mmap_event, pid_t pid, perf_event__handler_t process, + struct perf_event_ops *ops, struct perf_session *session) { - pid_t tgid = perf_event__synthesize_comm(comm_event, pid, 1, process, + pid_t tgid = perf_event__synthesize_comm(ops, comm_event, pid, 1, process, session); if (tgid == -1) return -1; - return perf_event__synthesize_mmap_events(mmap_event, pid, tgid, + return perf_event__synthesize_mmap_events(ops, mmap_event, pid, tgid, process, session); } -int perf_event__synthesize_thread_map(struct thread_map *threads, +int perf_event__synthesize_thread_map(struct perf_event_ops *ops, + struct thread_map *threads, perf_event__handler_t process, struct perf_session *session) { @@ -290,7 +295,7 @@ int perf_event__synthesize_thread_map(struct thread_map *threads, for (thread = 0; thread < threads->nr; ++thread) { if (__event__synthesize_thread(comm_event, mmap_event, threads->map[thread], - process, session)) { + process, ops, session)) { err = -1; break; } @@ -302,7 +307,8 @@ out: return err; } -int perf_event__synthesize_threads(perf_event__handler_t process, +int perf_event__synthesize_threads(struct perf_event_ops *ops, + perf_event__handler_t process, struct perf_session *session) { DIR *proc; @@ -330,7 +336,7 @@ int perf_event__synthesize_threads(perf_event__handler_t process, continue; __event__synthesize_thread(comm_event, mmap_event, pid, - process, session); + process, ops, session); } closedir(proc); @@ -365,7 +371,8 @@ static int find_symbol_cb(void *arg, const char *name, char type, return 1; } -int perf_event__synthesize_kernel_mmap(perf_event__handler_t process, +int perf_event__synthesize_kernel_mmap(struct perf_event_ops *ops, + perf_event__handler_t process, struct perf_session *session, struct machine *machine, const char *symbol_name) @@ -423,13 +430,14 @@ int perf_event__synthesize_kernel_mmap(perf_event__handler_t process, event->mmap.len = map->end - event->mmap.start; event->mmap.pid = machine->pid; - err = process(event, &synth_sample, session); + err = process(ops, event, &synth_sample, session); free(event); return err; } -int perf_event__process_comm(union perf_event *event, +int perf_event__process_comm(struct perf_event_ops *ops __used, + union perf_event *event, struct perf_sample *sample __used, struct perf_session *session) { @@ -445,7 +453,8 @@ int perf_event__process_comm(union perf_event *event, return 0; } -int perf_event__process_lost(union perf_event *event, +int perf_event__process_lost(struct perf_event_ops *ops __used, + union perf_event *event, struct perf_sample *sample __used, struct perf_session *session) { @@ -468,7 +477,8 @@ static void perf_event__set_kernel_mmap_len(union perf_event *event, maps[MAP__FUNCTION]->end = ~0ULL; } -static int perf_event__process_kernel_mmap(union perf_event *event, +static int perf_event__process_kernel_mmap(struct perf_event_ops *ops __used, + union perf_event *event, struct perf_session *session) { struct map *map; @@ -567,7 +577,8 @@ out_problem: return -1; } -int perf_event__process_mmap(union perf_event *event, +int perf_event__process_mmap(struct perf_event_ops *ops, + union perf_event *event, struct perf_sample *sample __used, struct perf_session *session) { @@ -583,7 +594,7 @@ int perf_event__process_mmap(union perf_event *event, if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL || cpumode == PERF_RECORD_MISC_KERNEL) { - ret = perf_event__process_kernel_mmap(event, session); + ret = perf_event__process_kernel_mmap(ops, event, session); if (ret < 0) goto out_problem; return 0; @@ -610,7 +621,8 @@ out_problem: return 0; } -int perf_event__process_task(union perf_event *event, +int perf_event__process_task(struct perf_event_ops *ops __used, + union perf_event *event, struct perf_sample *sample __used, struct perf_session *session) { @@ -634,22 +646,22 @@ int perf_event__process_task(union perf_event *event, return 0; } -int perf_event__process(union perf_event *event, struct perf_sample *sample, - struct perf_session *session) +int perf_event__process(struct perf_event_ops *ops, union perf_event *event, + struct perf_sample *sample, struct perf_session *session) { switch (event->header.type) { case PERF_RECORD_COMM: - perf_event__process_comm(event, sample, session); + perf_event__process_comm(ops, event, sample, session); break; case PERF_RECORD_MMAP: - perf_event__process_mmap(event, sample, session); + perf_event__process_mmap(ops, event, sample, session); break; case PERF_RECORD_FORK: case PERF_RECORD_EXIT: - perf_event__process_task(event, sample, session); + perf_event__process_task(ops, event, sample, session); break; case PERF_RECORD_LOST: - perf_event__process_lost(event, sample, session); + perf_event__process_lost(ops, event, sample, session); default: break; } diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 357a85b8524..669409d3571 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -141,38 +141,52 @@ union perf_event { void perf_event__print_totals(void); +struct perf_event_ops; struct perf_session; struct thread_map; -typedef int (*perf_event__handler_synth_t)(union perf_event *event, - struct perf_session *session); -typedef int (*perf_event__handler_t)(union perf_event *event, +typedef int (*perf_event__handler_t)(struct perf_event_ops *ops, + union perf_event *event, struct perf_sample *sample, struct perf_session *session); -int perf_event__synthesize_thread_map(struct thread_map *threads, +int perf_event__synthesize_thread_map(struct perf_event_ops *ops, + struct thread_map *threads, perf_event__handler_t process, struct perf_session *session); -int perf_event__synthesize_threads(perf_event__handler_t process, +int perf_event__synthesize_threads(struct perf_event_ops *ops, + perf_event__handler_t process, struct perf_session *session); -int perf_event__synthesize_kernel_mmap(perf_event__handler_t process, +int perf_event__synthesize_kernel_mmap(struct perf_event_ops *ops, + perf_event__handler_t process, struct perf_session *session, struct machine *machine, const char *symbol_name); -int perf_event__synthesize_modules(perf_event__handler_t process, +int perf_event__synthesize_modules(struct perf_event_ops *ops, + perf_event__handler_t process, struct perf_session *session, struct machine *machine); -int perf_event__process_comm(union perf_event *event, struct perf_sample *sample, +int perf_event__process_comm(struct perf_event_ops *ops, + union perf_event *event, + struct perf_sample *sample, struct perf_session *session); -int perf_event__process_lost(union perf_event *event, struct perf_sample *sample, +int perf_event__process_lost(struct perf_event_ops *ops, + union perf_event *event, + struct perf_sample *sample, struct perf_session *session); -int perf_event__process_mmap(union perf_event *event, struct perf_sample *sample, +int perf_event__process_mmap(struct perf_event_ops *ops, + union perf_event *event, + struct perf_sample *sample, struct perf_session *session); -int perf_event__process_task(union perf_event *event, struct perf_sample *sample, +int perf_event__process_task(struct perf_event_ops *ops, + union perf_event *event, + struct perf_sample *sample, struct perf_session *session); -int perf_event__process(union perf_event *event, struct perf_sample *sample, +int perf_event__process(struct perf_event_ops *ops, + union perf_event *event, + struct perf_sample *sample, struct perf_session *session); struct addr_location; diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 1fa97dd2120..ab3a2b0e8f0 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -2070,7 +2070,8 @@ out_delete_evlist: return -ENOMEM; } -int perf_event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id, +int perf_event__synthesize_attr(struct perf_event_ops *ops, + struct perf_event_attr *attr, u16 ids, u64 *id, perf_event__handler_t process, struct perf_session *session) { @@ -2094,21 +2095,22 @@ int perf_event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id, ev->attr.header.type = PERF_RECORD_HEADER_ATTR; ev->attr.header.size = size; - err = process(ev, NULL, session); + err = process(ops, ev, NULL, session); free(ev); return err; } -int perf_session__synthesize_attrs(struct perf_session *session, +int perf_event__synthesize_attrs(struct perf_event_ops *ops, + struct perf_session *session, perf_event__handler_t process) { struct perf_evsel *attr; int err = 0; list_for_each_entry(attr, &session->evlist->entries, node) { - err = perf_event__synthesize_attr(&attr->attr, attr->ids, + err = perf_event__synthesize_attr(ops, &attr->attr, attr->ids, attr->id, process, session); if (err) { pr_debug("failed to create perf header attribute\n"); @@ -2156,7 +2158,8 @@ int perf_event__process_attr(union perf_event *event, return 0; } -int perf_event__synthesize_event_type(u64 event_id, char *name, +int perf_event__synthesize_event_type(struct perf_event_ops *ops, + u64 event_id, char *name, perf_event__handler_t process, struct perf_session *session) { @@ -2176,12 +2179,13 @@ int perf_event__synthesize_event_type(u64 event_id, char *name, ev.event_type.header.size = sizeof(ev.event_type) - (sizeof(ev.event_type.event_type.name) - size); - err = process(&ev, NULL, session); + err = process(ops, &ev, NULL, session); return err; } -int perf_event__synthesize_event_types(perf_event__handler_t process, +int perf_event__synthesize_event_types(struct perf_event_ops *ops, + perf_event__handler_t process, struct perf_session *session) { struct perf_trace_event_type *type; @@ -2190,7 +2194,7 @@ int perf_event__synthesize_event_types(perf_event__handler_t process, for (i = 0; i < event_count; i++) { type = &events[i]; - err = perf_event__synthesize_event_type(type->event_id, + err = perf_event__synthesize_event_type(ops, type->event_id, type->name, process, session); if (err) { @@ -2202,7 +2206,8 @@ int perf_event__synthesize_event_types(perf_event__handler_t process, return err; } -int perf_event__process_event_type(union perf_event *event, +int perf_event__process_event_type(struct perf_event_ops *ops __unused, + union perf_event *event, struct perf_session *session __unused) { if (perf_header__push_event(event->event_type.event_type.event_id, @@ -2212,7 +2217,8 @@ int perf_event__process_event_type(union perf_event *event, return 0; } -int perf_event__synthesize_tracing_data(int fd, struct perf_evlist *evlist, +int perf_event__synthesize_tracing_data(struct perf_event_ops *ops, int fd, + struct perf_evlist *evlist, perf_event__handler_t process, struct perf_session *session __unused) { @@ -2245,7 +2251,7 @@ int perf_event__synthesize_tracing_data(int fd, struct perf_evlist *evlist, ev.tracing_data.header.size = sizeof(ev.tracing_data); ev.tracing_data.size = aligned_size; - process(&ev, NULL, session); + process(ops, &ev, NULL, session); /* * The put function will copy all the tracing data @@ -2287,7 +2293,8 @@ int perf_event__process_tracing_data(union perf_event *event, return size_read + padding; } -int perf_event__synthesize_build_id(struct dso *pos, u16 misc, +int perf_event__synthesize_build_id(struct perf_event_ops *ops, + struct dso *pos, u16 misc, perf_event__handler_t process, struct machine *machine, struct perf_session *session) @@ -2310,12 +2317,13 @@ int perf_event__synthesize_build_id(struct dso *pos, u16 misc, ev.build_id.header.size = sizeof(ev.build_id) + len; memcpy(&ev.build_id.filename, pos->long_name, pos->long_name_len); - err = process(&ev, NULL, session); + err = process(ops, &ev, NULL, session); return err; } -int perf_event__process_build_id(union perf_event *event, +int perf_event__process_build_id(struct perf_event_ops *ops __used, + union perf_event *event, struct perf_session *session) { __event_process_build_id(&event->build_id, diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index 0a88982bc39..54dae5f0955 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h @@ -68,6 +68,7 @@ struct perf_header { }; struct perf_evlist; +struct perf_session; int perf_session__read_header(struct perf_session *session, int fd); int perf_session__write_header(struct perf_session *session, @@ -96,32 +97,40 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir, const char *name, bool is_kallsyms); int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir); -int perf_event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id, +int perf_event__synthesize_attr(struct perf_event_ops *ops, + struct perf_event_attr *attr, u16 ids, u64 *id, perf_event__handler_t process, struct perf_session *session); -int perf_session__synthesize_attrs(struct perf_session *session, - perf_event__handler_t process); +int perf_event__synthesize_attrs(struct perf_event_ops *ops, + struct perf_session *session, + perf_event__handler_t process); int perf_event__process_attr(union perf_event *event, struct perf_evlist **pevlist); -int perf_event__synthesize_event_type(u64 event_id, char *name, +int perf_event__synthesize_event_type(struct perf_event_ops *ops, + u64 event_id, char *name, perf_event__handler_t process, struct perf_session *session); -int perf_event__synthesize_event_types(perf_event__handler_t process, +int perf_event__synthesize_event_types(struct perf_event_ops *ops, + perf_event__handler_t process, struct perf_session *session); -int perf_event__process_event_type(union perf_event *event, +int perf_event__process_event_type(struct perf_event_ops *ops, + union perf_event *event, struct perf_session *session); -int perf_event__synthesize_tracing_data(int fd, struct perf_evlist *evlist, +int perf_event__synthesize_tracing_data(struct perf_event_ops *ops, + int fd, struct perf_evlist *evlist, perf_event__handler_t process, struct perf_session *session); int perf_event__process_tracing_data(union perf_event *event, struct perf_session *session); -int perf_event__synthesize_build_id(struct dso *pos, u16 misc, +int perf_event__synthesize_build_id(struct perf_event_ops *ops, + struct dso *pos, u16 misc, perf_event__handler_t process, struct machine *machine, struct perf_session *session); -int perf_event__process_build_id(union perf_event *event, +int perf_event__process_build_id(struct perf_event_ops *ops, + union perf_event *event, struct perf_session *session); /* diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 734358b51ed..a36023a6677 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -270,13 +270,21 @@ int perf_session__resolve_callchain(struct perf_session *self, struct perf_evsel return 0; } -static int process_event_synth_stub(union perf_event *event __used, +static int process_event_synth_stub(struct perf_event_ops *ops __used, + union perf_event *event __used, struct perf_session *session __used) { dump_printf(": unhandled!\n"); return 0; } +static int process_event_synth_tracing_data_stub(union perf_event *event __used, + struct perf_session *session __used) +{ + dump_printf(": unhandled!\n"); + return 0; +} + static int process_event_synth_attr_stub(union perf_event *event __used, struct perf_evlist **pevlist __used) { @@ -284,7 +292,8 @@ static int process_event_synth_attr_stub(union perf_event *event __used, return 0; } -static int process_event_sample_stub(union perf_event *event __used, +static int process_event_sample_stub(struct perf_event_ops *ops __used, + union perf_event *event __used, struct perf_sample *sample __used, struct perf_evsel *evsel __used, struct perf_session *session __used) @@ -293,7 +302,8 @@ static int process_event_sample_stub(union perf_event *event __used, return 0; } -static int process_event_stub(union perf_event *event __used, +static int process_event_stub(struct perf_event_ops *ops __used, + union perf_event *event __used, struct perf_sample *sample __used, struct perf_session *session __used) { @@ -301,17 +311,17 @@ static int process_event_stub(union perf_event *event __used, return 0; } -static int process_finished_round_stub(union perf_event *event __used, - struct perf_session *session __used, - struct perf_event_ops *ops __used) +static int process_finished_round_stub(struct perf_event_ops *ops __used, + union perf_event *event __used, + struct perf_session *session __used) { dump_printf(": unhandled!\n"); return 0; } -static int process_finished_round(union perf_event *event, - struct perf_session *session, - struct perf_event_ops *ops); +static int process_finished_round(struct perf_event_ops *ops, + union perf_event *event, + struct perf_session *session); static void perf_event_ops__fill_defaults(struct perf_event_ops *handler) { @@ -338,7 +348,7 @@ static void perf_event_ops__fill_defaults(struct perf_event_ops *handler) if (handler->event_type == NULL) handler->event_type = process_event_synth_stub; if (handler->tracing_data == NULL) - handler->tracing_data = process_event_synth_stub; + handler->tracing_data = process_event_synth_tracing_data_stub; if (handler->build_id == NULL) handler->build_id = process_event_synth_stub; if (handler->finished_round == NULL) { @@ -565,9 +575,9 @@ static void flush_sample_queue(struct perf_session *s, * Flush every events below timestamp 7 * etc... */ -static int process_finished_round(union perf_event *event __used, - struct perf_session *session, - struct perf_event_ops *ops) +static int process_finished_round(struct perf_event_ops *ops, + union perf_event *event __used, + struct perf_session *session) { flush_sample_queue(session, ops); session->ordered_samples.next_flush = session->ordered_samples.max_timestamp; @@ -759,23 +769,23 @@ static int perf_session_deliver_event(struct perf_session *session, ++session->hists.stats.nr_unknown_id; return -1; } - return ops->sample(event, sample, evsel, session); + return ops->sample(ops, event, sample, evsel, session); case PERF_RECORD_MMAP: - return ops->mmap(event, sample, session); + return ops->mmap(ops, event, sample, session); case PERF_RECORD_COMM: - return ops->comm(event, sample, session); + return ops->comm(ops, event, sample, session); case PERF_RECORD_FORK: - return ops->fork(event, sample, session); + return ops->fork(ops, event, sample, session); case PERF_RECORD_EXIT: - return ops->exit(event, sample, session); + return ops->exit(ops, event, sample, session); case PERF_RECORD_LOST: - return ops->lost(event, sample, session); + return ops->lost(ops, event, sample, session); case PERF_RECORD_READ: - return ops->read(event, sample, session); + return ops->read(ops, event, sample, session); case PERF_RECORD_THROTTLE: - return ops->throttle(event, sample, session); + return ops->throttle(ops, event, sample, session); case PERF_RECORD_UNTHROTTLE: - return ops->unthrottle(event, sample, session); + return ops->unthrottle(ops, event, sample, session); default: ++session->hists.stats.nr_unknown_events; return -1; @@ -813,15 +823,15 @@ static int perf_session__process_user_event(struct perf_session *session, union perf_session__update_sample_type(session); return err; case PERF_RECORD_HEADER_EVENT_TYPE: - return ops->event_type(event, session); + return ops->event_type(ops, event, session); case PERF_RECORD_HEADER_TRACING_DATA: /* setup for reading amidst mmap */ lseek(session->fd, file_offset, SEEK_SET); return ops->tracing_data(event, session); case PERF_RECORD_HEADER_BUILD_ID: - return ops->build_id(event, session); + return ops->build_id(ops, event, session); case PERF_RECORD_FINISHED_ROUND: - return ops->finished_round(event, session, ops); + return ops->finished_round(ops, event, session); default: return -EINVAL; } diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index d2f43036771..6de3d136890 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -56,16 +56,18 @@ struct perf_session { struct perf_evsel; struct perf_event_ops; -typedef int (*event_sample)(union perf_event *event, struct perf_sample *sample, +typedef int (*event_sample)(struct perf_event_ops *ops, + union perf_event *event, struct perf_sample *sample, struct perf_evsel *evsel, struct perf_session *session); -typedef int (*event_op)(union perf_event *self, struct perf_sample *sample, +typedef int (*event_op)(struct perf_event_ops *ops, union perf_event *event, + struct perf_sample *sample, struct perf_session *session); typedef int (*event_synth_op)(union perf_event *self, struct perf_session *session); typedef int (*event_attr_op)(union perf_event *event, struct perf_evlist **pevlist); -typedef int (*event_op2)(union perf_event *self, struct perf_session *session, - struct perf_event_ops *ops); +typedef int (*event_op2)(struct perf_event_ops *ops, union perf_event *event, + struct perf_session *session); struct perf_event_ops { event_sample sample; @@ -78,10 +80,10 @@ struct perf_event_ops { throttle, unthrottle; event_attr_op attr; - event_synth_op event_type, - tracing_data, - build_id; - event_op2 finished_round; + event_synth_op tracing_data; + event_op2 event_type, + build_id, + finished_round; bool ordered_samples; bool ordering_requires_timestamps; }; @@ -142,10 +144,11 @@ struct machine *perf_session__findnew_machine(struct perf_session *self, pid_t p static inline void perf_session__process_machines(struct perf_session *self, + struct perf_event_ops *ops, machine__process_t process) { - process(&self->host_machine, self); - return machines__process(&self->machines, process, self); + process(&self->host_machine, ops); + return machines__process(&self->machines, process, ops); } size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp); diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h index 39965096795..44eda6fc6b3 100644 --- a/tools/perf/util/top.h +++ b/tools/perf/util/top.h @@ -2,14 +2,15 @@ #define __PERF_TOP_H 1 #include "types.h" +#include "session.h" #include "../perf.h" #include struct perf_evlist; struct perf_evsel; -struct perf_session; struct perf_top { + struct perf_event_ops ops; struct perf_evlist *evlist; /* * Symbols will be added here in perf_event__process_sample and will -- cgit v1.2.3-70-g09d2 From 743eb868657bdb1b26c7b24077ca21c67c82c777 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 28 Nov 2011 07:56:39 -0200 Subject: perf tools: Resolve machine earlier and pass it to perf_event_ops Reducing the exposure of perf_session further, so that we can use the classes in cases where no perf.data file is created. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-stua66dcscsezzrcdugvbmvd@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-annotate.c | 4 +- tools/perf/builtin-diff.c | 9 +- tools/perf/builtin-inject.c | 70 +++++----- tools/perf/builtin-kmem.c | 4 +- tools/perf/builtin-lock.c | 4 +- tools/perf/builtin-record.c | 38 +++--- tools/perf/builtin-report.c | 24 ++-- tools/perf/builtin-sched.c | 70 +++++----- tools/perf/builtin-script.c | 26 ++-- tools/perf/builtin-timechart.c | 8 +- tools/perf/builtin-top.c | 99 +++++++------- tools/perf/util/build-id.c | 16 +-- tools/perf/util/event.c | 151 +++++++++------------ tools/perf/util/event.h | 21 ++- tools/perf/util/header.c | 28 ++-- tools/perf/util/header.h | 16 +-- tools/perf/util/map.h | 10 ++ .../perf/util/scripting-engines/trace-event-perl.c | 4 +- .../util/scripting-engines/trace-event-python.c | 4 +- tools/perf/util/session.c | 91 +++++++------ tools/perf/util/session.h | 30 ++-- tools/perf/util/thread.h | 14 +- tools/perf/util/trace-event-scripting.c | 2 +- tools/perf/util/trace-event.h | 8 +- 24 files changed, 376 insertions(+), 375 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 483cb946644..dff081a388b 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -83,12 +83,12 @@ static int process_sample_event(struct perf_event_ops *ops, union perf_event *event, struct perf_sample *sample, struct perf_evsel *evsel, - struct perf_session *session) + struct machine *machine) { struct perf_annotate *ann = container_of(ops, struct perf_annotate, ops); struct addr_location al; - if (perf_event__preprocess_sample(event, session, &al, sample, + if (perf_event__preprocess_sample(event, machine, &al, sample, symbol__annotate_init) < 0) { pr_warning("problem processing %d event, skipping it.\n", event->header.type); diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 9a0872f9e83..478b0aeb2a6 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -9,6 +9,7 @@ #include "util/debug.h" #include "util/event.h" #include "util/hist.h" +#include "util/evsel.h" #include "util/session.h" #include "util/sort.h" #include "util/symbol.h" @@ -34,11 +35,11 @@ static int diff__process_sample_event(struct perf_event_ops *ops __used, union perf_event *event, struct perf_sample *sample, struct perf_evsel *evsel __used, - struct perf_session *session) + struct machine *machine) { struct addr_location al; - if (perf_event__preprocess_sample(event, session, &al, sample, NULL) < 0) { + if (perf_event__preprocess_sample(event, machine, &al, sample, NULL) < 0) { pr_warning("problem processing %d event, skipping it.\n", event->header.type); return -1; @@ -47,12 +48,12 @@ static int diff__process_sample_event(struct perf_event_ops *ops __used, if (al.filtered || al.sym == NULL) return 0; - if (hists__add_entry(&session->hists, &al, sample->period)) { + if (hists__add_entry(&evsel->hists, &al, sample->period)) { pr_warning("problem incrementing symbol period, skipping event\n"); return -1; } - session->hists.stats.total_period += sample->period; + evsel->hists.stats.total_period += sample->period; return 0; } diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index 6ce6d80b59d..a5bcf81776f 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c @@ -18,7 +18,7 @@ static bool inject_build_ids; static int perf_event__repipe_synth(struct perf_event_ops *ops __used, union perf_event *event, - struct perf_session *session __used) + struct machine *machine __used) { uint32_t size; void *buf = event; @@ -37,10 +37,23 @@ static int perf_event__repipe_synth(struct perf_event_ops *ops __used, return 0; } +static int perf_event__repipe_op2_synth(struct perf_event_ops *ops, + union perf_event *event, + struct perf_session *session __used) +{ + return perf_event__repipe_synth(ops, event, NULL); +} + +static int perf_event__repipe_event_type_synth(struct perf_event_ops *ops, + union perf_event *event) +{ + return perf_event__repipe_synth(ops, event, NULL); +} + static int perf_event__repipe_tracing_data_synth(union perf_event *event, - struct perf_session *session) + struct perf_session *session __used) { - return perf_event__repipe_synth(NULL, event, session); + return perf_event__repipe_synth(NULL, event, NULL); } static int perf_event__repipe_attr(union perf_event *event, @@ -52,29 +65,29 @@ static int perf_event__repipe_attr(union perf_event *event, static int perf_event__repipe(struct perf_event_ops *ops, union perf_event *event, struct perf_sample *sample __used, - struct perf_session *session) + struct machine *machine) { - return perf_event__repipe_synth(ops, event, session); + return perf_event__repipe_synth(ops, event, machine); } static int perf_event__repipe_sample(struct perf_event_ops *ops, union perf_event *event, struct perf_sample *sample __used, struct perf_evsel *evsel __used, - struct perf_session *session) + struct machine *machine) { - return perf_event__repipe_synth(ops, event, session); + return perf_event__repipe_synth(ops, event, machine); } static int perf_event__repipe_mmap(struct perf_event_ops *ops, union perf_event *event, struct perf_sample *sample, - struct perf_session *session) + struct machine *machine) { int err; - err = perf_event__process_mmap(ops, event, sample, session); - perf_event__repipe(ops, event, sample, session); + err = perf_event__process_mmap(ops, event, sample, machine); + perf_event__repipe(ops, event, sample, machine); return err; } @@ -82,12 +95,12 @@ static int perf_event__repipe_mmap(struct perf_event_ops *ops, static int perf_event__repipe_task(struct perf_event_ops *ops, union perf_event *event, struct perf_sample *sample, - struct perf_session *session) + struct machine *machine) { int err; - err = perf_event__process_task(ops, event, sample, session); - perf_event__repipe(ops, event, sample, session); + err = perf_event__process_task(ops, event, sample, machine); + perf_event__repipe(ops, event, sample, machine); return err; } @@ -97,7 +110,7 @@ static int perf_event__repipe_tracing_data(union perf_event *event, { int err; - perf_event__repipe_synth(NULL, event, session); + perf_event__repipe_synth(NULL, event, NULL); err = perf_event__process_tracing_data(event, session); return err; @@ -118,10 +131,9 @@ static int dso__read_build_id(struct dso *self) } static int dso__inject_build_id(struct dso *self, struct perf_event_ops *ops, - struct perf_session *session) + struct machine *machine) { u16 misc = PERF_RECORD_MISC_USER; - struct machine *machine; int err; if (dso__read_build_id(self) < 0) { @@ -129,17 +141,11 @@ static int dso__inject_build_id(struct dso *self, struct perf_event_ops *ops, return -1; } - machine = perf_session__find_host_machine(session); - if (machine == NULL) { - pr_err("Can't find machine for session\n"); - return -1; - } - if (self->kernel) misc = PERF_RECORD_MISC_KERNEL; err = perf_event__synthesize_build_id(ops, self, misc, perf_event__repipe, - machine, session); + machine); if (err) { pr_err("Can't synthesize build_id event for %s\n", self->long_name); return -1; @@ -152,7 +158,7 @@ static int perf_event__inject_buildid(struct perf_event_ops *ops, union perf_event *event, struct perf_sample *sample, struct perf_evsel *evsel __used, - struct perf_session *session) + struct machine *machine) { struct addr_location al; struct thread *thread; @@ -160,21 +166,21 @@ static int perf_event__inject_buildid(struct perf_event_ops *ops, cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; - thread = perf_session__findnew(session, event->ip.pid); + thread = machine__findnew_thread(machine, event->ip.pid); if (thread == NULL) { pr_err("problem processing %d event, skipping it.\n", event->header.type); goto repipe; } - thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION, - event->ip.pid, event->ip.ip, &al); + thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION, + event->ip.ip, &al); if (al.map != NULL) { if (!al.map->dso->hit) { al.map->dso->hit = 1; if (map__load(al.map, NULL) >= 0) { - dso__inject_build_id(al.map->dso, ops, session); + dso__inject_build_id(al.map->dso, ops, machine); /* * If this fails, too bad, let the other side * account this as unresolved. @@ -187,7 +193,7 @@ static int perf_event__inject_buildid(struct perf_event_ops *ops, } repipe: - perf_event__repipe(ops, event, sample, session); + perf_event__repipe(ops, event, sample, machine); return 0; } @@ -198,13 +204,13 @@ struct perf_event_ops inject_ops = { .fork = perf_event__repipe, .exit = perf_event__repipe, .lost = perf_event__repipe, - .read = perf_event__repipe, + .read = perf_event__repipe_sample, .throttle = perf_event__repipe, .unthrottle = perf_event__repipe, .attr = perf_event__repipe_attr, - .event_type = perf_event__repipe_synth, + .event_type = perf_event__repipe_event_type_synth, .tracing_data = perf_event__repipe_tracing_data_synth, - .build_id = perf_event__repipe_synth, + .build_id = perf_event__repipe_op2_synth, }; extern volatile int session_done; diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index 5d01218e50e..27b2a15dc7b 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c @@ -307,9 +307,9 @@ static int process_sample_event(struct perf_event_ops *ops __used, union perf_event *event, struct perf_sample *sample, struct perf_evsel *evsel __used, - struct perf_session *session) + struct machine *machine) { - struct thread *thread = perf_session__findnew(session, event->ip.pid); + struct thread *thread = machine__findnew_thread(machine, event->ip.pid); if (thread == NULL) { pr_debug("problem processing %d event, skipping it.\n", diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c index f06b0a44c7c..99b032adb83 100644 --- a/tools/perf/builtin-lock.c +++ b/tools/perf/builtin-lock.c @@ -849,9 +849,9 @@ static int process_sample_event(struct perf_event_ops *ops __used, union perf_event *event, struct perf_sample *sample, struct perf_evsel *evsel __used, - struct perf_session *s) + struct machine *machine) { - struct thread *thread = perf_session__findnew(s, sample->tid); + struct thread *thread = machine__findnew_thread(machine, sample->tid); if (thread == NULL) { pr_debug("problem processing %d event, skipping it.\n", diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 4642d38b8d1..0af598a1059 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -79,7 +79,7 @@ static void write_output(struct perf_record *rec, void *buf, size_t size) static int process_synthesized_event(struct perf_event_ops *ops, union perf_event *event, struct perf_sample *sample __used, - struct perf_session *self __used) + struct machine *machine __used) { struct perf_record *rec = container_of(ops, struct perf_record, ops); write_output(rec, event, event->header.size); @@ -320,8 +320,6 @@ static void perf_event__synthesize_guest_os(struct machine *machine, void *data) { int err; struct perf_event_ops *ops = data; - struct perf_record *rec = container_of(ops, struct perf_record, ops); - struct perf_session *psession = rec->session; if (machine__is_host(machine)) return; @@ -335,7 +333,7 @@ static void perf_event__synthesize_guest_os(struct machine *machine, void *data) *in module instead of in guest kernel. */ err = perf_event__synthesize_modules(ops, process_synthesized_event, - psession, machine); + machine); if (err < 0) pr_err("Couldn't record guest kernel [%d]'s reference" " relocation symbol.\n", machine->pid); @@ -345,11 +343,10 @@ static void perf_event__synthesize_guest_os(struct machine *machine, void *data) * have no _text sometimes. */ err = perf_event__synthesize_kernel_mmap(ops, process_synthesized_event, - psession, machine, "_text"); + machine, "_text"); if (err < 0) err = perf_event__synthesize_kernel_mmap(ops, process_synthesized_event, - psession, machine, - "_stext"); + machine, "_stext"); if (err < 0) pr_err("Couldn't record guest kernel [%d]'s reference" " relocation symbol.\n", machine->pid); @@ -497,6 +494,12 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) rec->post_processing_offset = lseek(output, 0, SEEK_CUR); + machine = perf_session__find_host_machine(session); + if (!machine) { + pr_err("Couldn't find native kernel information.\n"); + return -1; + } + if (opts->pipe_output) { err = perf_event__synthesize_attrs(ops, session, process_synthesized_event); @@ -506,7 +509,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) } err = perf_event__synthesize_event_types(ops, process_synthesized_event, - session); + machine); if (err < 0) { pr_err("Couldn't synthesize event_types.\n"); return err; @@ -522,8 +525,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) * propagate errors that now are calling die() */ err = perf_event__synthesize_tracing_data(ops, output, evsel_list, - process_synthesized_event, - session); + process_synthesized_event); if (err <= 0) { pr_err("Couldn't record tracing data.\n"); return err; @@ -532,24 +534,18 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) } } - machine = perf_session__find_host_machine(session); - if (!machine) { - pr_err("Couldn't find native kernel information.\n"); - return -1; - } - err = perf_event__synthesize_kernel_mmap(ops, process_synthesized_event, - session, machine, "_text"); + machine, "_text"); if (err < 0) err = perf_event__synthesize_kernel_mmap(ops, process_synthesized_event, - session, machine, "_stext"); + machine, "_stext"); if (err < 0) pr_err("Couldn't record kernel reference relocation symbol\n" "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n" "Check /proc/kallsyms permission or run as root.\n"); err = perf_event__synthesize_modules(ops, process_synthesized_event, - session, machine); + machine); if (err < 0) pr_err("Couldn't record kernel module information.\n" "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n" @@ -562,10 +558,10 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) if (!opts->system_wide) perf_event__synthesize_thread_map(ops, evsel_list->threads, process_synthesized_event, - session); + machine); else perf_event__synthesize_threads(ops, process_synthesized_event, - session); + machine); if (rec->realtime_prio) { struct sched_param param; diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 8795520f6e1..ea64fbbdff4 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -52,18 +52,18 @@ struct perf_report { DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); }; -static int perf_session__add_hist_entry(struct perf_session *session, - struct addr_location *al, - struct perf_sample *sample, - struct perf_evsel *evsel) +static int perf_evsel__add_hist_entry(struct perf_evsel *evsel, + struct addr_location *al, + struct perf_sample *sample, + struct machine *machine) { struct symbol *parent = NULL; int err = 0; struct hist_entry *he; if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) { - err = perf_session__resolve_callchain(session, evsel, al->thread, - sample->callchain, &parent); + err = machine__resolve_callchain(machine, evsel, al->thread, + sample->callchain, &parent); if (err) return err; } @@ -107,12 +107,12 @@ static int process_sample_event(struct perf_event_ops *ops, union perf_event *event, struct perf_sample *sample, struct perf_evsel *evsel, - struct perf_session *session) + struct machine *machine) { struct perf_report *rep = container_of(ops, struct perf_report, ops); struct addr_location al; - if (perf_event__preprocess_sample(event, session, &al, sample, + if (perf_event__preprocess_sample(event, machine, &al, sample, rep->annotate_init) < 0) { fprintf(stderr, "problem processing %d event, skipping it.\n", event->header.type); @@ -128,7 +128,7 @@ static int process_sample_event(struct perf_event_ops *ops, if (al.map != NULL) al.map->dso->hit = 1; - if (perf_session__add_hist_entry(session, &al, sample, evsel)) { + if (perf_evsel__add_hist_entry(evsel, &al, sample, machine)) { pr_debug("problem incrementing symbol period, skipping event\n"); return -1; } @@ -139,11 +139,11 @@ static int process_sample_event(struct perf_event_ops *ops, static int process_read_event(struct perf_event_ops *ops, union perf_event *event, struct perf_sample *sample __used, - struct perf_session *session) + struct perf_evsel *evsel, + struct machine *machine __used) { struct perf_report *rep = container_of(ops, struct perf_report, ops); - struct perf_evsel *evsel = perf_evlist__id2evsel(session->evlist, - event->read.id); + if (rep->show_threads) { const char *name = evsel ? event_name(evsel) : "unknown"; perf_read_values_add_value(&rep->show_threads_values, diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index b11d6283fed..6a771f822e5 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -724,21 +724,21 @@ struct trace_migrate_task_event { struct trace_sched_handler { void (*switch_event)(struct trace_switch_event *, - struct perf_session *, + struct machine *, struct event *, int cpu, u64 timestamp, struct thread *thread); void (*runtime_event)(struct trace_runtime_event *, - struct perf_session *, + struct machine *, struct event *, int cpu, u64 timestamp, struct thread *thread); void (*wakeup_event)(struct trace_wakeup_event *, - struct perf_session *, + struct machine *, struct event *, int cpu, u64 timestamp, @@ -751,7 +751,7 @@ struct trace_sched_handler { struct thread *thread); void (*migrate_task_event)(struct trace_migrate_task_event *, - struct perf_session *session, + struct machine *machine, struct event *, int cpu, u64 timestamp, @@ -761,7 +761,7 @@ struct trace_sched_handler { static void replay_wakeup_event(struct trace_wakeup_event *wakeup_event, - struct perf_session *session __used, + struct machine *machine __used, struct event *event, int cpu __used, u64 timestamp __used, @@ -788,7 +788,7 @@ static u64 cpu_last_switched[MAX_CPUS]; static void replay_switch_event(struct trace_switch_event *switch_event, - struct perf_session *session __used, + struct machine *machine __used, struct event *event, int cpu, u64 timestamp, @@ -1022,7 +1022,7 @@ add_sched_in_event(struct work_atoms *atoms, u64 timestamp) static void latency_switch_event(struct trace_switch_event *switch_event, - struct perf_session *session, + struct machine *machine, struct event *event __used, int cpu, u64 timestamp, @@ -1046,8 +1046,8 @@ latency_switch_event(struct trace_switch_event *switch_event, die("hm, delta: %" PRIu64 " < 0 ?\n", delta); - sched_out = perf_session__findnew(session, switch_event->prev_pid); - sched_in = perf_session__findnew(session, switch_event->next_pid); + sched_out = machine__findnew_thread(machine, switch_event->prev_pid); + sched_in = machine__findnew_thread(machine, switch_event->next_pid); out_events = thread_atoms_search(&atom_root, sched_out, &cmp_pid); if (!out_events) { @@ -1075,13 +1075,13 @@ latency_switch_event(struct trace_switch_event *switch_event, static void latency_runtime_event(struct trace_runtime_event *runtime_event, - struct perf_session *session, + struct machine *machine, struct event *event __used, int cpu, u64 timestamp, struct thread *this_thread __used) { - struct thread *thread = perf_session__findnew(session, runtime_event->pid); + struct thread *thread = machine__findnew_thread(machine, runtime_event->pid); struct work_atoms *atoms = thread_atoms_search(&atom_root, thread, &cmp_pid); BUG_ON(cpu >= MAX_CPUS || cpu < 0); @@ -1098,7 +1098,7 @@ latency_runtime_event(struct trace_runtime_event *runtime_event, static void latency_wakeup_event(struct trace_wakeup_event *wakeup_event, - struct perf_session *session, + struct machine *machine, struct event *__event __used, int cpu __used, u64 timestamp, @@ -1112,7 +1112,7 @@ latency_wakeup_event(struct trace_wakeup_event *wakeup_event, if (!wakeup_event->success) return; - wakee = perf_session__findnew(session, wakeup_event->pid); + wakee = machine__findnew_thread(machine, wakeup_event->pid); atoms = thread_atoms_search(&atom_root, wakee, &cmp_pid); if (!atoms) { thread_atoms_insert(wakee); @@ -1146,7 +1146,7 @@ latency_wakeup_event(struct trace_wakeup_event *wakeup_event, static void latency_migrate_task_event(struct trace_migrate_task_event *migrate_task_event, - struct perf_session *session, + struct machine *machine, struct event *__event __used, int cpu __used, u64 timestamp, @@ -1162,7 +1162,7 @@ latency_migrate_task_event(struct trace_migrate_task_event *migrate_task_event, if (profile_cpu == -1) return; - migrant = perf_session__findnew(session, migrate_task_event->pid); + migrant = machine__findnew_thread(machine, migrate_task_event->pid); atoms = thread_atoms_search(&atom_root, migrant, &cmp_pid); if (!atoms) { thread_atoms_insert(migrant); @@ -1357,7 +1357,7 @@ static void sort_lat(void) static struct trace_sched_handler *trace_handler; static void -process_sched_wakeup_event(void *data, struct perf_session *session, +process_sched_wakeup_event(void *data, struct machine *machine, struct event *event, int cpu __used, u64 timestamp __used, @@ -1374,7 +1374,7 @@ process_sched_wakeup_event(void *data, struct perf_session *session, FILL_FIELD(wakeup_event, cpu, event, data); if (trace_handler->wakeup_event) - trace_handler->wakeup_event(&wakeup_event, session, event, + trace_handler->wakeup_event(&wakeup_event, machine, event, cpu, timestamp, thread); } @@ -1393,7 +1393,7 @@ static char next_shortname2 = '0'; static void map_switch_event(struct trace_switch_event *switch_event, - struct perf_session *session, + struct machine *machine, struct event *event __used, int this_cpu, u64 timestamp, @@ -1421,8 +1421,8 @@ map_switch_event(struct trace_switch_event *switch_event, die("hm, delta: %" PRIu64 " < 0 ?\n", delta); - sched_out = perf_session__findnew(session, switch_event->prev_pid); - sched_in = perf_session__findnew(session, switch_event->next_pid); + sched_out = machine__findnew_thread(machine, switch_event->prev_pid); + sched_in = machine__findnew_thread(machine, switch_event->next_pid); curr_thread[this_cpu] = sched_in; @@ -1472,7 +1472,7 @@ map_switch_event(struct trace_switch_event *switch_event, static void -process_sched_switch_event(void *data, struct perf_session *session, +process_sched_switch_event(void *data, struct machine *machine, struct event *event, int this_cpu, u64 timestamp __used, @@ -1499,14 +1499,14 @@ process_sched_switch_event(void *data, struct perf_session *session, nr_context_switch_bugs++; } if (trace_handler->switch_event) - trace_handler->switch_event(&switch_event, session, event, + trace_handler->switch_event(&switch_event, machine, event, this_cpu, timestamp, thread); curr_pid[this_cpu] = switch_event.next_pid; } static void -process_sched_runtime_event(void *data, struct perf_session *session, +process_sched_runtime_event(void *data, struct machine *machine, struct event *event, int cpu __used, u64 timestamp __used, @@ -1520,7 +1520,7 @@ process_sched_runtime_event(void *data, struct perf_session *session, FILL_FIELD(runtime_event, vruntime, event, data); if (trace_handler->runtime_event) - trace_handler->runtime_event(&runtime_event, session, event, cpu, timestamp, thread); + trace_handler->runtime_event(&runtime_event, machine, event, cpu, timestamp, thread); } static void @@ -1555,7 +1555,7 @@ process_sched_exit_event(struct event *event, } static void -process_sched_migrate_task_event(void *data, struct perf_session *session, +process_sched_migrate_task_event(void *data, struct machine *machine, struct event *event, int cpu __used, u64 timestamp __used, @@ -1571,12 +1571,12 @@ process_sched_migrate_task_event(void *data, struct perf_session *session, FILL_FIELD(migrate_task_event, cpu, event, data); if (trace_handler->migrate_task_event) - trace_handler->migrate_task_event(&migrate_task_event, session, + trace_handler->migrate_task_event(&migrate_task_event, machine, event, cpu, timestamp, thread); } static void process_raw_event(union perf_event *raw_event __used, - struct perf_session *session, void *data, int cpu, + struct machine *machine, void *data, int cpu, u64 timestamp, struct thread *thread) { struct event *event; @@ -1587,33 +1587,33 @@ static void process_raw_event(union perf_event *raw_event __used, event = trace_find_event(type); if (!strcmp(event->name, "sched_switch")) - process_sched_switch_event(data, session, event, cpu, timestamp, thread); + process_sched_switch_event(data, machine, event, cpu, timestamp, thread); if (!strcmp(event->name, "sched_stat_runtime")) - process_sched_runtime_event(data, session, event, cpu, timestamp, thread); + process_sched_runtime_event(data, machine, event, cpu, timestamp, thread); if (!strcmp(event->name, "sched_wakeup")) - process_sched_wakeup_event(data, session, event, cpu, timestamp, thread); + process_sched_wakeup_event(data, machine, event, cpu, timestamp, thread); if (!strcmp(event->name, "sched_wakeup_new")) - process_sched_wakeup_event(data, session, event, cpu, timestamp, thread); + process_sched_wakeup_event(data, machine, event, cpu, timestamp, thread); if (!strcmp(event->name, "sched_process_fork")) process_sched_fork_event(data, event, cpu, timestamp, thread); if (!strcmp(event->name, "sched_process_exit")) process_sched_exit_event(event, cpu, timestamp, thread); if (!strcmp(event->name, "sched_migrate_task")) - process_sched_migrate_task_event(data, session, event, cpu, timestamp, thread); + process_sched_migrate_task_event(data, machine, event, cpu, timestamp, thread); } static int process_sample_event(struct perf_event_ops *ops __used, union perf_event *event, struct perf_sample *sample, struct perf_evsel *evsel, - struct perf_session *session) + struct machine *machine) { struct thread *thread; if (!(evsel->attr.sample_type & PERF_SAMPLE_RAW)) return 0; - thread = perf_session__findnew(session, sample->pid); + thread = machine__findnew_thread(machine, sample->pid); if (thread == NULL) { pr_debug("problem processing %d event, skipping it.\n", event->header.type); @@ -1625,7 +1625,7 @@ static int process_sample_event(struct perf_event_ops *ops __used, if (profile_cpu != -1 && profile_cpu != (int)sample->cpu) return 0; - process_raw_event(event, session, sample->raw_data, sample->cpu, + process_raw_event(event, machine, sample->raw_data, sample->cpu, sample->time, thread); return 0; diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 3b7820612eb..31a8d14e5fb 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -315,7 +315,7 @@ static bool sample_addr_correlates_sym(struct perf_event_attr *attr) static void print_sample_addr(union perf_event *event, struct perf_sample *sample, - struct perf_session *session, + struct machine *machine, struct thread *thread, struct perf_event_attr *attr) { @@ -328,11 +328,11 @@ static void print_sample_addr(union perf_event *event, if (!sample_addr_correlates_sym(attr)) return; - thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION, - event->ip.pid, sample->addr, &al); + thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION, + sample->addr, &al); if (!al.map) - thread__find_addr_map(thread, session, cpumode, MAP__VARIABLE, - event->ip.pid, sample->addr, &al); + thread__find_addr_map(thread, machine, cpumode, MAP__VARIABLE, + sample->addr, &al); al.cpu = sample->cpu; al.sym = NULL; @@ -362,7 +362,7 @@ static void print_sample_addr(union perf_event *event, static void process_event(union perf_event *event __unused, struct perf_sample *sample, struct perf_evsel *evsel, - struct perf_session *session, + struct machine *machine, struct thread *thread) { struct perf_event_attr *attr = &evsel->attr; @@ -377,15 +377,15 @@ static void process_event(union perf_event *event __unused, sample->raw_size); if (PRINT_FIELD(ADDR)) - print_sample_addr(event, sample, session, thread, attr); + print_sample_addr(event, sample, machine, thread, attr); if (PRINT_FIELD(IP)) { if (!symbol_conf.use_callchain) printf(" "); else printf("\n"); - perf_session__print_ip(event, evsel, sample, session, - PRINT_FIELD(SYM), PRINT_FIELD(DSO)); + perf_event__print_ip(event, sample, machine, evsel, + PRINT_FIELD(SYM), PRINT_FIELD(DSO)); } printf("\n"); @@ -438,9 +438,9 @@ static int process_sample_event(struct perf_event_ops *ops __used, union perf_event *event, struct perf_sample *sample, struct perf_evsel *evsel, - struct perf_session *session) + struct machine *machine) { - struct thread *thread = perf_session__findnew(session, event->ip.pid); + struct thread *thread = machine__findnew_thread(machine, event->ip.pid); if (thread == NULL) { pr_debug("problem processing %d event, skipping it.\n", @@ -462,9 +462,9 @@ static int process_sample_event(struct perf_event_ops *ops __used, if (cpu_list && !test_bit(sample->cpu, cpu_bitmap)) return 0; - scripting_ops->process_event(event, sample, evsel, session, thread); + scripting_ops->process_event(event, sample, evsel, machine, thread); - session->hists.stats.total_period += sample->period; + evsel->hists.stats.total_period += sample->period; return 0; } diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index 62298a0d7dc..8e6539625bc 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c @@ -277,7 +277,7 @@ static u64 cpus_pstate_state[MAX_CPUS]; static int process_comm_event(struct perf_event_ops *ops __used, union perf_event *event, struct perf_sample *sample __used, - struct perf_session *session __used) + struct machine *machine __used) { pid_set_comm(event->comm.tid, event->comm.comm); return 0; @@ -286,7 +286,7 @@ static int process_comm_event(struct perf_event_ops *ops __used, static int process_fork_event(struct perf_event_ops *ops __used, union perf_event *event, struct perf_sample *sample __used, - struct perf_session *session __used) + struct machine *machine __used) { pid_fork(event->fork.pid, event->fork.ppid, event->fork.time); return 0; @@ -295,7 +295,7 @@ static int process_fork_event(struct perf_event_ops *ops __used, static int process_exit_event(struct perf_event_ops *ops __used, union perf_event *event, struct perf_sample *sample __used, - struct perf_session *session __used) + struct machine *machine __used) { pid_exit(event->fork.pid, event->fork.time); return 0; @@ -494,7 +494,7 @@ static int process_sample_event(struct perf_event_ops *ops __used, union perf_event *event __used, struct perf_sample *sample, struct perf_evsel *evsel, - struct perf_session *session __used) + struct machine *machine __used) { struct trace_entry *te; diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index e8e3320602b..31d497368cc 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -258,11 +258,9 @@ out_unlock: static const char CONSOLE_CLEAR[] = ""; -static struct hist_entry * - perf_session__add_hist_entry(struct perf_session *session, - struct addr_location *al, - struct perf_sample *sample, - struct perf_evsel *evsel) +static struct hist_entry *perf_evsel__add_hist_entry(struct perf_evsel *evsel, + struct addr_location *al, + struct perf_sample *sample) { struct hist_entry *he; @@ -270,7 +268,7 @@ static struct hist_entry * if (he == NULL) return NULL; - session->hists.stats.total_period += sample->period; + evsel->hists.stats.total_period += sample->period; hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); return he; } @@ -675,44 +673,12 @@ static int symbol_filter(struct map *map __used, struct symbol *sym) static void perf_event__process_sample(const union perf_event *event, struct perf_evsel *evsel, struct perf_sample *sample, - struct perf_session *session) + struct machine *machine) { struct symbol *parent = NULL; u64 ip = event->ip.ip; struct addr_location al; - struct machine *machine; int err; - u8 origin = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; - - ++top.samples; - - switch (origin) { - case PERF_RECORD_MISC_USER: - ++top.us_samples; - if (top.hide_user_symbols) - return; - machine = perf_session__find_host_machine(session); - break; - case PERF_RECORD_MISC_KERNEL: - ++top.kernel_samples; - if (top.hide_kernel_symbols) - return; - machine = perf_session__find_host_machine(session); - break; - case PERF_RECORD_MISC_GUEST_KERNEL: - ++top.guest_kernel_samples; - machine = perf_session__find_machine(session, event->ip.pid); - break; - case PERF_RECORD_MISC_GUEST_USER: - ++top.guest_us_samples; - /* - * TODO: we don't process guest user from host side - * except simple counting. - */ - return; - default: - return; - } if (!machine && perf_guest) { pr_err("Can't find guest [%d]'s kernel information\n", @@ -723,7 +689,7 @@ static void perf_event__process_sample(const union perf_event *event, if (event->header.misc & PERF_RECORD_MISC_EXACT_IP) top.exact_samples++; - if (perf_event__preprocess_sample(event, session, &al, sample, + if (perf_event__preprocess_sample(event, machine, &al, sample, symbol_filter) < 0 || al.filtered) return; @@ -777,13 +743,13 @@ static void perf_event__process_sample(const union perf_event *event, if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) { - err = perf_session__resolve_callchain(session, evsel, al.thread, - sample->callchain, &parent); + err = machine__resolve_callchain(machine, evsel, al.thread, + sample->callchain, &parent); if (err) return; } - he = perf_session__add_hist_entry(session, &al, sample, evsel); + he = perf_evsel__add_hist_entry(evsel, &al, sample); if (he == NULL) { pr_err("Problem incrementing symbol period, skipping event\n"); return; @@ -808,6 +774,8 @@ static void perf_session__mmap_read_idx(struct perf_session *self, int idx) struct perf_sample sample; struct perf_evsel *evsel; union perf_event *event; + struct machine *machine; + u8 origin; int ret; while ((event = perf_evlist__mmap_read(top.evlist, idx)) != NULL) { @@ -820,11 +788,45 @@ static void perf_session__mmap_read_idx(struct perf_session *self, int idx) evsel = perf_evlist__id2evsel(self->evlist, sample.id); assert(evsel != NULL); + origin = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; + if (event->header.type == PERF_RECORD_SAMPLE) - perf_event__process_sample(event, evsel, &sample, self); + ++top.samples; + + switch (origin) { + case PERF_RECORD_MISC_USER: + ++top.us_samples; + if (top.hide_user_symbols) + continue; + machine = perf_session__find_host_machine(self); + break; + case PERF_RECORD_MISC_KERNEL: + ++top.kernel_samples; + if (top.hide_kernel_symbols) + continue; + machine = perf_session__find_host_machine(self); + break; + case PERF_RECORD_MISC_GUEST_KERNEL: + ++top.guest_kernel_samples; + machine = perf_session__find_machine(self, event->ip.pid); + break; + case PERF_RECORD_MISC_GUEST_USER: + ++top.guest_us_samples; + /* + * TODO: we don't process guest user from host side + * except simple counting. + */ + /* Fall thru */ + default: + continue; + } + + + if (event->header.type == PERF_RECORD_SAMPLE) + perf_event__process_sample(event, evsel, &sample, machine); else if (event->header.type < PERF_RECORD_MAX) { hists__inc_nr_events(&evsel->hists, event->header.type); - perf_event__process(&top.ops, event, &sample, self); + perf_event__process(&top.ops, event, &sample, machine); } else ++self->hists.stats.nr_unknown_events; } @@ -967,10 +969,11 @@ static int __cmd_top(void) if (top.target_tid != -1) perf_event__synthesize_thread_map(&top.ops, top.evlist->threads, - perf_event__process, top.session); + perf_event__process, + &top.session->host_machine); else - perf_event__synthesize_threads(&top.ops, perf_event__process, top.session); - + perf_event__synthesize_threads(&top.ops, perf_event__process, + &top.session->host_machine); start_counters(top.evlist); top.session->evlist = top.evlist; perf_session__update_sample_type(top.session); diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c index 0e4de186501..2f84c4802ac 100644 --- a/tools/perf/util/build-id.c +++ b/tools/perf/util/build-id.c @@ -19,11 +19,11 @@ static int build_id__mark_dso_hit(struct perf_event_ops *ops __used, union perf_event *event, struct perf_sample *sample __used, struct perf_evsel *evsel __used, - struct perf_session *session) + struct machine *machine) { struct addr_location al; u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; - struct thread *thread = perf_session__findnew(session, event->ip.pid); + struct thread *thread = machine__findnew_thread(machine, event->ip.pid); if (thread == NULL) { pr_err("problem processing %d event, skipping it.\n", @@ -31,8 +31,8 @@ static int build_id__mark_dso_hit(struct perf_event_ops *ops __used, return -1; } - thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION, - event->ip.pid, event->ip.ip, &al); + thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION, + event->ip.ip, &al); if (al.map != NULL) al.map->dso->hit = 1; @@ -43,16 +43,16 @@ static int build_id__mark_dso_hit(struct perf_event_ops *ops __used, static int perf_event__exit_del_thread(struct perf_event_ops *ops __used, union perf_event *event, struct perf_sample *sample __used, - struct perf_session *session) + struct machine *machine) { - struct thread *thread = perf_session__findnew(session, event->fork.tid); + struct thread *thread = machine__findnew_thread(machine, event->fork.tid); dump_printf("(%d:%d):(%d:%d)\n", event->fork.pid, event->fork.tid, event->fork.ppid, event->fork.ptid); if (thread) { - rb_erase(&thread->rb_node, &session->host_machine.threads); - session->host_machine.last_match = NULL; + rb_erase(&thread->rb_node, &machine->threads); + machine->last_match = NULL; thread__delete(thread); } diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 4800f38c727..0cdc811c48e 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -1,7 +1,6 @@ #include #include "event.h" #include "debug.h" -#include "session.h" #include "sort.h" #include "string.h" #include "strlist.h" @@ -47,7 +46,7 @@ static struct perf_sample synth_sample = { static pid_t perf_event__synthesize_comm(struct perf_event_ops *ops, union perf_event *event, pid_t pid, int full, perf_event__handler_t process, - struct perf_session *session) + struct machine *machine) { char filename[PATH_MAX]; char bf[BUFSIZ]; @@ -93,14 +92,14 @@ out_race: event->comm.header.type = PERF_RECORD_COMM; size = ALIGN(size, sizeof(u64)); - memset(event->comm.comm + size, 0, session->id_hdr_size); + memset(event->comm.comm + size, 0, machine->id_hdr_size); event->comm.header.size = (sizeof(event->comm) - (sizeof(event->comm.comm) - size) + - session->id_hdr_size); + machine->id_hdr_size); if (!full) { event->comm.tid = pid; - process(ops, event, &synth_sample, session); + process(ops, event, &synth_sample, machine); goto out; } @@ -118,7 +117,7 @@ out_race: event->comm.tid = pid; - process(ops, event, &synth_sample, session); + process(ops, event, &synth_sample, machine); } closedir(tasks); @@ -132,7 +131,7 @@ static int perf_event__synthesize_mmap_events(struct perf_event_ops *ops, union perf_event *event, pid_t pid, pid_t tgid, perf_event__handler_t process, - struct perf_session *session) + struct machine *machine) { char filename[PATH_MAX]; FILE *fp; @@ -195,12 +194,12 @@ static int perf_event__synthesize_mmap_events(struct perf_event_ops *ops, event->mmap.len -= event->mmap.start; event->mmap.header.size = (sizeof(event->mmap) - (sizeof(event->mmap.filename) - size)); - memset(event->mmap.filename + size, 0, session->id_hdr_size); - event->mmap.header.size += session->id_hdr_size; + memset(event->mmap.filename + size, 0, machine->id_hdr_size); + event->mmap.header.size += machine->id_hdr_size; event->mmap.pid = tgid; event->mmap.tid = pid; - process(ops, event, &synth_sample, session); + process(ops, event, &synth_sample, machine); } } @@ -210,13 +209,12 @@ static int perf_event__synthesize_mmap_events(struct perf_event_ops *ops, int perf_event__synthesize_modules(struct perf_event_ops *ops, perf_event__handler_t process, - struct perf_session *session, struct machine *machine) { struct rb_node *nd; struct map_groups *kmaps = &machine->kmaps; union perf_event *event = zalloc((sizeof(event->mmap) + - session->id_hdr_size)); + machine->id_hdr_size)); if (event == NULL) { pr_debug("Not enough memory synthesizing mmap event " "for kernel modules\n"); @@ -246,15 +244,15 @@ int perf_event__synthesize_modules(struct perf_event_ops *ops, event->mmap.header.type = PERF_RECORD_MMAP; event->mmap.header.size = (sizeof(event->mmap) - (sizeof(event->mmap.filename) - size)); - memset(event->mmap.filename + size, 0, session->id_hdr_size); - event->mmap.header.size += session->id_hdr_size; + memset(event->mmap.filename + size, 0, machine->id_hdr_size); + event->mmap.header.size += machine->id_hdr_size; event->mmap.start = pos->start; event->mmap.len = pos->end - pos->start; event->mmap.pid = machine->pid; memcpy(event->mmap.filename, pos->dso->long_name, pos->dso->long_name_len + 1); - process(ops, event, &synth_sample, session); + process(ops, event, &synth_sample, machine); } free(event); @@ -265,29 +263,29 @@ static int __event__synthesize_thread(union perf_event *comm_event, union perf_event *mmap_event, pid_t pid, perf_event__handler_t process, struct perf_event_ops *ops, - struct perf_session *session) + struct machine *machine) { - pid_t tgid = perf_event__synthesize_comm(ops, comm_event, pid, 1, process, - session); + pid_t tgid = perf_event__synthesize_comm(ops, comm_event, pid, 1, + process, machine); if (tgid == -1) return -1; return perf_event__synthesize_mmap_events(ops, mmap_event, pid, tgid, - process, session); + process, machine); } int perf_event__synthesize_thread_map(struct perf_event_ops *ops, struct thread_map *threads, perf_event__handler_t process, - struct perf_session *session) + struct machine *machine) { union perf_event *comm_event, *mmap_event; int err = -1, thread; - comm_event = malloc(sizeof(comm_event->comm) + session->id_hdr_size); + comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size); if (comm_event == NULL) goto out; - mmap_event = malloc(sizeof(mmap_event->mmap) + session->id_hdr_size); + mmap_event = malloc(sizeof(mmap_event->mmap) + machine->id_hdr_size); if (mmap_event == NULL) goto out_free_comm; @@ -295,7 +293,7 @@ int perf_event__synthesize_thread_map(struct perf_event_ops *ops, for (thread = 0; thread < threads->nr; ++thread) { if (__event__synthesize_thread(comm_event, mmap_event, threads->map[thread], - process, ops, session)) { + process, ops, machine)) { err = -1; break; } @@ -309,18 +307,18 @@ out: int perf_event__synthesize_threads(struct perf_event_ops *ops, perf_event__handler_t process, - struct perf_session *session) + struct machine *machine) { DIR *proc; struct dirent dirent, *next; union perf_event *comm_event, *mmap_event; int err = -1; - comm_event = malloc(sizeof(comm_event->comm) + session->id_hdr_size); + comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size); if (comm_event == NULL) goto out; - mmap_event = malloc(sizeof(mmap_event->mmap) + session->id_hdr_size); + mmap_event = malloc(sizeof(mmap_event->mmap) + machine->id_hdr_size); if (mmap_event == NULL) goto out_free_comm; @@ -336,7 +334,7 @@ int perf_event__synthesize_threads(struct perf_event_ops *ops, continue; __event__synthesize_thread(comm_event, mmap_event, pid, - process, ops, session); + process, ops, machine); } closedir(proc); @@ -373,7 +371,6 @@ static int find_symbol_cb(void *arg, const char *name, char type, int perf_event__synthesize_kernel_mmap(struct perf_event_ops *ops, perf_event__handler_t process, - struct perf_session *session, struct machine *machine, const char *symbol_name) { @@ -390,7 +387,7 @@ int perf_event__synthesize_kernel_mmap(struct perf_event_ops *ops, */ struct process_symbol_args args = { .name = symbol_name, }; union perf_event *event = zalloc((sizeof(event->mmap) + - session->id_hdr_size)); + machine->id_hdr_size)); if (event == NULL) { pr_debug("Not enough memory synthesizing mmap event " "for kernel modules\n"); @@ -424,13 +421,13 @@ int perf_event__synthesize_kernel_mmap(struct perf_event_ops *ops, size = ALIGN(size, sizeof(u64)); event->mmap.header.type = PERF_RECORD_MMAP; event->mmap.header.size = (sizeof(event->mmap) - - (sizeof(event->mmap.filename) - size) + session->id_hdr_size); + (sizeof(event->mmap.filename) - size) + machine->id_hdr_size); event->mmap.pgoff = args.start; event->mmap.start = map->start; event->mmap.len = map->end - event->mmap.start; event->mmap.pid = machine->pid; - err = process(ops, event, &synth_sample, session); + err = process(ops, event, &synth_sample, machine); free(event); return err; @@ -439,9 +436,9 @@ int perf_event__synthesize_kernel_mmap(struct perf_event_ops *ops, int perf_event__process_comm(struct perf_event_ops *ops __used, union perf_event *event, struct perf_sample *sample __used, - struct perf_session *session) + struct machine *machine) { - struct thread *thread = perf_session__findnew(session, event->comm.tid); + struct thread *thread = machine__findnew_thread(machine, event->comm.tid); dump_printf(": %s:%d\n", event->comm.comm, event->comm.tid); @@ -456,11 +453,10 @@ int perf_event__process_comm(struct perf_event_ops *ops __used, int perf_event__process_lost(struct perf_event_ops *ops __used, union perf_event *event, struct perf_sample *sample __used, - struct perf_session *session) + struct machine *machine __used) { dump_printf(": id:%" PRIu64 ": lost:%" PRIu64 "\n", event->lost.id, event->lost.lost); - session->hists.stats.total_lost += event->lost.lost; return 0; } @@ -479,20 +475,13 @@ static void perf_event__set_kernel_mmap_len(union perf_event *event, static int perf_event__process_kernel_mmap(struct perf_event_ops *ops __used, union perf_event *event, - struct perf_session *session) + struct machine *machine) { struct map *map; char kmmap_prefix[PATH_MAX]; - struct machine *machine; enum dso_kernel_type kernel_type; bool is_kernel_mmap; - machine = perf_session__findnew_machine(session, event->mmap.pid); - if (!machine) { - pr_err("Can't find id %d's machine\n", event->mmap.pid); - goto out_problem; - } - machine__mmap_name(machine, kmmap_prefix, sizeof(kmmap_prefix)); if (machine__is_host(machine)) kernel_type = DSO_TYPE_KERNEL; @@ -559,9 +548,9 @@ static int perf_event__process_kernel_mmap(struct perf_event_ops *ops __used, * time /proc/sys/kernel/kptr_restrict was non zero. */ if (event->mmap.pgoff != 0) { - perf_session__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps, - symbol_name, - event->mmap.pgoff); + maps__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps, + symbol_name, + event->mmap.pgoff); } if (machine__is_default_guest(machine)) { @@ -580,9 +569,8 @@ out_problem: int perf_event__process_mmap(struct perf_event_ops *ops, union perf_event *event, struct perf_sample *sample __used, - struct perf_session *session) + struct machine *machine) { - struct machine *machine; struct thread *thread; struct map *map; u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; @@ -594,16 +582,13 @@ int perf_event__process_mmap(struct perf_event_ops *ops, if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL || cpumode == PERF_RECORD_MISC_KERNEL) { - ret = perf_event__process_kernel_mmap(ops, event, session); + ret = perf_event__process_kernel_mmap(ops, event, machine); if (ret < 0) goto out_problem; return 0; } - machine = perf_session__find_host_machine(session); - if (machine == NULL) - goto out_problem; - thread = perf_session__findnew(session, event->mmap.pid); + thread = machine__findnew_thread(machine, event->mmap.pid); if (thread == NULL) goto out_problem; map = map__new(&machine->user_dsos, event->mmap.start, @@ -624,16 +609,16 @@ out_problem: int perf_event__process_task(struct perf_event_ops *ops __used, union perf_event *event, struct perf_sample *sample __used, - struct perf_session *session) + struct machine *machine) { - struct thread *thread = perf_session__findnew(session, event->fork.tid); - struct thread *parent = perf_session__findnew(session, event->fork.ptid); + struct thread *thread = machine__findnew_thread(machine, event->fork.tid); + struct thread *parent = machine__findnew_thread(machine, event->fork.ptid); dump_printf("(%d:%d):(%d:%d)\n", event->fork.pid, event->fork.tid, event->fork.ppid, event->fork.ptid); if (event->header.type == PERF_RECORD_EXIT) { - perf_session__remove_thread(session, thread); + machine__remove_thread(machine, thread); return 0; } @@ -647,21 +632,21 @@ int perf_event__process_task(struct perf_event_ops *ops __used, } int perf_event__process(struct perf_event_ops *ops, union perf_event *event, - struct perf_sample *sample, struct perf_session *session) + struct perf_sample *sample, struct machine *machine) { switch (event->header.type) { case PERF_RECORD_COMM: - perf_event__process_comm(ops, event, sample, session); + perf_event__process_comm(ops, event, sample, machine); break; case PERF_RECORD_MMAP: - perf_event__process_mmap(ops, event, sample, session); + perf_event__process_mmap(ops, event, sample, machine); break; case PERF_RECORD_FORK: case PERF_RECORD_EXIT: - perf_event__process_task(ops, event, sample, session); + perf_event__process_task(ops, event, sample, machine); break; case PERF_RECORD_LOST: - perf_event__process_lost(ops, event, sample, session); + perf_event__process_lost(ops, event, sample, machine); default: break; } @@ -670,36 +655,29 @@ int perf_event__process(struct perf_event_ops *ops, union perf_event *event, } void thread__find_addr_map(struct thread *self, - struct perf_session *session, u8 cpumode, - enum map_type type, pid_t pid, u64 addr, + struct machine *machine, u8 cpumode, + enum map_type type, u64 addr, struct addr_location *al) { struct map_groups *mg = &self->mg; - struct machine *machine = NULL; al->thread = self; al->addr = addr; al->cpumode = cpumode; al->filtered = false; + if (machine == NULL) { + al->map = NULL; + return; + } + if (cpumode == PERF_RECORD_MISC_KERNEL && perf_host) { al->level = 'k'; - machine = perf_session__find_host_machine(session); - if (machine == NULL) { - al->map = NULL; - return; - } mg = &machine->kmaps; } else if (cpumode == PERF_RECORD_MISC_USER && perf_host) { al->level = '.'; - machine = perf_session__find_host_machine(session); } else if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL && perf_guest) { al->level = 'g'; - machine = perf_session__find_machine(session, pid); - if (machine == NULL) { - al->map = NULL; - return; - } mg = &machine->kmaps; } else { /* @@ -745,13 +723,12 @@ try_again: al->addr = al->map->map_ip(al->map, al->addr); } -void thread__find_addr_location(struct thread *self, - struct perf_session *session, u8 cpumode, - enum map_type type, pid_t pid, u64 addr, +void thread__find_addr_location(struct thread *thread, struct machine *machine, + u8 cpumode, enum map_type type, u64 addr, struct addr_location *al, symbol_filter_t filter) { - thread__find_addr_map(self, session, cpumode, type, pid, addr, al); + thread__find_addr_map(thread, machine, cpumode, type, addr, al); if (al->map != NULL) al->sym = map__find_symbol(al->map, al->addr, filter); else @@ -759,13 +736,13 @@ void thread__find_addr_location(struct thread *self, } int perf_event__preprocess_sample(const union perf_event *event, - struct perf_session *session, + struct machine *machine, struct addr_location *al, struct perf_sample *sample, symbol_filter_t filter) { u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; - struct thread *thread = perf_session__findnew(session, event->ip.pid); + struct thread *thread = machine__findnew_thread(machine, event->ip.pid); if (thread == NULL) return -1; @@ -776,18 +753,18 @@ int perf_event__preprocess_sample(const union perf_event *event, dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); /* - * Have we already created the kernel maps for the host machine? + * Have we already created the kernel maps for this machine? * * This should have happened earlier, when we processed the kernel MMAP * events, but for older perf.data files there was no such thing, so do * it now. */ if (cpumode == PERF_RECORD_MISC_KERNEL && - session->host_machine.vmlinux_maps[MAP__FUNCTION] == NULL) - machine__create_kernel_maps(&session->host_machine); + machine->vmlinux_maps[MAP__FUNCTION] == NULL) + machine__create_kernel_maps(machine); - thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION, - event->ip.pid, event->ip.ip, al); + thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION, + event->ip.ip, al); dump_printf(" ...... dso: %s\n", al->map ? al->map->dso->long_name : al->level == 'H' ? "[hypervisor]" : ""); diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 669409d3571..1564877e870 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -142,56 +142,53 @@ union perf_event { void perf_event__print_totals(void); struct perf_event_ops; -struct perf_session; struct thread_map; typedef int (*perf_event__handler_t)(struct perf_event_ops *ops, union perf_event *event, struct perf_sample *sample, - struct perf_session *session); + struct machine *machine); int perf_event__synthesize_thread_map(struct perf_event_ops *ops, struct thread_map *threads, perf_event__handler_t process, - struct perf_session *session); + struct machine *machine); int perf_event__synthesize_threads(struct perf_event_ops *ops, perf_event__handler_t process, - struct perf_session *session); + struct machine *machine); int perf_event__synthesize_kernel_mmap(struct perf_event_ops *ops, perf_event__handler_t process, - struct perf_session *session, struct machine *machine, const char *symbol_name); int perf_event__synthesize_modules(struct perf_event_ops *ops, perf_event__handler_t process, - struct perf_session *session, struct machine *machine); int perf_event__process_comm(struct perf_event_ops *ops, union perf_event *event, struct perf_sample *sample, - struct perf_session *session); + struct machine *machine); int perf_event__process_lost(struct perf_event_ops *ops, union perf_event *event, struct perf_sample *sample, - struct perf_session *session); + struct machine *machine); int perf_event__process_mmap(struct perf_event_ops *ops, union perf_event *event, struct perf_sample *sample, - struct perf_session *session); + struct machine *machine); int perf_event__process_task(struct perf_event_ops *ops, union perf_event *event, struct perf_sample *sample, - struct perf_session *session); + struct machine *machine); int perf_event__process(struct perf_event_ops *ops, union perf_event *event, struct perf_sample *sample, - struct perf_session *session); + struct machine *machine); struct addr_location; int perf_event__preprocess_sample(const union perf_event *self, - struct perf_session *session, + struct machine *machine, struct addr_location *al, struct perf_sample *sample, symbol_filter_t filter); diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index ab3a2b0e8f0..db280d6ca89 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -2072,8 +2072,7 @@ out_delete_evlist: int perf_event__synthesize_attr(struct perf_event_ops *ops, struct perf_event_attr *attr, u16 ids, u64 *id, - perf_event__handler_t process, - struct perf_session *session) + perf_event__handler_t process) { union perf_event *ev; size_t size; @@ -2095,7 +2094,7 @@ int perf_event__synthesize_attr(struct perf_event_ops *ops, ev->attr.header.type = PERF_RECORD_HEADER_ATTR; ev->attr.header.size = size; - err = process(ops, ev, NULL, session); + err = process(ops, ev, NULL, NULL); free(ev); @@ -2111,7 +2110,7 @@ int perf_event__synthesize_attrs(struct perf_event_ops *ops, list_for_each_entry(attr, &session->evlist->entries, node) { err = perf_event__synthesize_attr(ops, &attr->attr, attr->ids, - attr->id, process, session); + attr->id, process); if (err) { pr_debug("failed to create perf header attribute\n"); return err; @@ -2161,7 +2160,7 @@ int perf_event__process_attr(union perf_event *event, int perf_event__synthesize_event_type(struct perf_event_ops *ops, u64 event_id, char *name, perf_event__handler_t process, - struct perf_session *session) + struct machine *machine) { union perf_event ev; size_t size = 0; @@ -2179,14 +2178,14 @@ int perf_event__synthesize_event_type(struct perf_event_ops *ops, ev.event_type.header.size = sizeof(ev.event_type) - (sizeof(ev.event_type.event_type.name) - size); - err = process(ops, &ev, NULL, session); + err = process(ops, &ev, NULL, machine); return err; } int perf_event__synthesize_event_types(struct perf_event_ops *ops, perf_event__handler_t process, - struct perf_session *session) + struct machine *machine) { struct perf_trace_event_type *type; int i, err = 0; @@ -2196,7 +2195,7 @@ int perf_event__synthesize_event_types(struct perf_event_ops *ops, err = perf_event__synthesize_event_type(ops, type->event_id, type->name, process, - session); + machine); if (err) { pr_debug("failed to create perf header event type\n"); return err; @@ -2207,8 +2206,7 @@ int perf_event__synthesize_event_types(struct perf_event_ops *ops, } int perf_event__process_event_type(struct perf_event_ops *ops __unused, - union perf_event *event, - struct perf_session *session __unused) + union perf_event *event) { if (perf_header__push_event(event->event_type.event_type.event_id, event->event_type.event_type.name) < 0) @@ -2219,8 +2217,7 @@ int perf_event__process_event_type(struct perf_event_ops *ops __unused, int perf_event__synthesize_tracing_data(struct perf_event_ops *ops, int fd, struct perf_evlist *evlist, - perf_event__handler_t process, - struct perf_session *session __unused) + perf_event__handler_t process) { union perf_event ev; struct tracing_data *tdata; @@ -2251,7 +2248,7 @@ int perf_event__synthesize_tracing_data(struct perf_event_ops *ops, int fd, ev.tracing_data.header.size = sizeof(ev.tracing_data); ev.tracing_data.size = aligned_size; - process(ops, &ev, NULL, session); + process(ops, &ev, NULL, NULL); /* * The put function will copy all the tracing data @@ -2296,8 +2293,7 @@ int perf_event__process_tracing_data(union perf_event *event, int perf_event__synthesize_build_id(struct perf_event_ops *ops, struct dso *pos, u16 misc, perf_event__handler_t process, - struct machine *machine, - struct perf_session *session) + struct machine *machine) { union perf_event ev; size_t len; @@ -2317,7 +2313,7 @@ int perf_event__synthesize_build_id(struct perf_event_ops *ops, ev.build_id.header.size = sizeof(ev.build_id) + len; memcpy(&ev.build_id.filename, pos->long_name, pos->long_name_len); - err = process(ops, &ev, NULL, session); + err = process(ops, &ev, NULL, machine); return err; } diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index 54dae5f0955..a604962fc43 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h @@ -99,8 +99,7 @@ int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir); int perf_event__synthesize_attr(struct perf_event_ops *ops, struct perf_event_attr *attr, u16 ids, u64 *id, - perf_event__handler_t process, - struct perf_session *session); + perf_event__handler_t process); int perf_event__synthesize_attrs(struct perf_event_ops *ops, struct perf_session *session, perf_event__handler_t process); @@ -109,26 +108,23 @@ int perf_event__process_attr(union perf_event *event, struct perf_evlist **pevli int perf_event__synthesize_event_type(struct perf_event_ops *ops, u64 event_id, char *name, perf_event__handler_t process, - struct perf_session *session); + struct machine *machine); int perf_event__synthesize_event_types(struct perf_event_ops *ops, perf_event__handler_t process, - struct perf_session *session); + struct machine *machine); int perf_event__process_event_type(struct perf_event_ops *ops, - union perf_event *event, - struct perf_session *session); + union perf_event *event); int perf_event__synthesize_tracing_data(struct perf_event_ops *ops, int fd, struct perf_evlist *evlist, - perf_event__handler_t process, - struct perf_session *session); + perf_event__handler_t process); int perf_event__process_tracing_data(union perf_event *event, struct perf_session *session); int perf_event__synthesize_build_id(struct perf_event_ops *ops, struct dso *pos, u16 misc, perf_event__handler_t process, - struct machine *machine, - struct perf_session *session); + struct machine *machine); int perf_event__process_build_id(struct perf_event_ops *ops, union perf_event *event, struct perf_session *session); diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h index bde6835ee25..2b8017f8a93 100644 --- a/tools/perf/util/map.h +++ b/tools/perf/util/map.h @@ -18,9 +18,11 @@ enum map_type { extern const char *map_type__name[MAP__NR_TYPES]; struct dso; +struct ip_callchain; struct ref_reloc_sym; struct map_groups; struct machine; +struct perf_evsel; struct map { union { @@ -61,6 +63,7 @@ struct map_groups { struct machine { struct rb_node rb_node; pid_t pid; + u16 id_hdr_size; char *root_dir; struct rb_root threads; struct list_head dead_threads; @@ -151,6 +154,13 @@ int machine__init(struct machine *self, const char *root_dir, pid_t pid); void machine__exit(struct machine *self); void machine__delete(struct machine *self); +int machine__resolve_callchain(struct machine *machine, + struct perf_evsel *evsel, struct thread *thread, + struct ip_callchain *chain, + struct symbol **parent); +int maps__set_kallsyms_ref_reloc_sym(struct map **maps, const char *symbol_name, + u64 addr); + /* * Default guest kernel is defined by parameter --guestkallsyms * and --guestmodules diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c index 74350ffb57f..a82ce4303ff 100644 --- a/tools/perf/util/scripting-engines/trace-event-perl.c +++ b/tools/perf/util/scripting-engines/trace-event-perl.c @@ -27,6 +27,8 @@ #include "../../perf.h" #include "../util.h" +#include "../thread.h" +#include "../event.h" #include "../trace-event.h" #include @@ -248,7 +250,7 @@ static inline struct event *find_cache_event(int type) static void perl_process_event(union perf_event *pevent __unused, struct perf_sample *sample, struct perf_evsel *evsel, - struct perf_session *session __unused, + struct machine *machine __unused, struct thread *thread) { struct format_field *field; diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 6ccf70e8d8f..0b2a4878317 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -29,6 +29,8 @@ #include "../../perf.h" #include "../util.h" +#include "../event.h" +#include "../thread.h" #include "../trace-event.h" PyMODINIT_FUNC initperf_trace_context(void); @@ -207,7 +209,7 @@ static inline struct event *find_cache_event(int type) static void python_process_event(union perf_event *pevent __unused, struct perf_sample *sample, struct perf_evsel *evsel __unused, - struct perf_session *session __unused, + struct machine *machine __unused, struct thread *thread) { PyObject *handler, *retval, *context, *t, *obj, *dict = NULL; diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index a36023a6677..be33606386b 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -84,6 +84,7 @@ void perf_session__update_sample_type(struct perf_session *self) self->sample_size = __perf_evsel__sample_size(self->sample_type); self->sample_id_all = perf_evlist__sample_id_all(self->evlist); self->id_hdr_size = perf_evlist__id_hdr_size(self->evlist); + self->host_machine.id_hdr_size = self->id_hdr_size; } int perf_session__create_kernel_maps(struct perf_session *self) @@ -216,10 +217,10 @@ static bool symbol__match_parent_regex(struct symbol *sym) return 0; } -int perf_session__resolve_callchain(struct perf_session *self, struct perf_evsel *evsel, - struct thread *thread, - struct ip_callchain *chain, - struct symbol **parent) +int machine__resolve_callchain(struct machine *self, struct perf_evsel *evsel, + struct thread *thread, + struct ip_callchain *chain, + struct symbol **parent) { u8 cpumode = PERF_RECORD_MISC_USER; unsigned int i; @@ -252,7 +253,7 @@ int perf_session__resolve_callchain(struct perf_session *self, struct perf_evsel al.filtered = false; thread__find_addr_location(thread, self, cpumode, - MAP__FUNCTION, thread->pid, ip, &al, NULL); + MAP__FUNCTION, ip, &al, NULL); if (al.sym != NULL) { if (sort__has_parent && !*parent && symbol__match_parent_regex(al.sym)) @@ -270,14 +271,6 @@ int perf_session__resolve_callchain(struct perf_session *self, struct perf_evsel return 0; } -static int process_event_synth_stub(struct perf_event_ops *ops __used, - union perf_event *event __used, - struct perf_session *session __used) -{ - dump_printf(": unhandled!\n"); - return 0; -} - static int process_event_synth_tracing_data_stub(union perf_event *event __used, struct perf_session *session __used) { @@ -296,7 +289,7 @@ static int process_event_sample_stub(struct perf_event_ops *ops __used, union perf_event *event __used, struct perf_sample *sample __used, struct perf_evsel *evsel __used, - struct perf_session *session __used) + struct machine *machine __used) { dump_printf(": unhandled!\n"); return 0; @@ -305,7 +298,7 @@ static int process_event_sample_stub(struct perf_event_ops *ops __used, static int process_event_stub(struct perf_event_ops *ops __used, union perf_event *event __used, struct perf_sample *sample __used, - struct perf_session *session __used) + struct machine *machine __used) { dump_printf(": unhandled!\n"); return 0; @@ -313,7 +306,14 @@ static int process_event_stub(struct perf_event_ops *ops __used, static int process_finished_round_stub(struct perf_event_ops *ops __used, union perf_event *event __used, - struct perf_session *session __used) + struct perf_session *perf_session __used) +{ + dump_printf(": unhandled!\n"); + return 0; +} + +static int process_event_type_stub(struct perf_event_ops *ops __used, + union perf_event *event __used) { dump_printf(": unhandled!\n"); return 0; @@ -338,7 +338,7 @@ static void perf_event_ops__fill_defaults(struct perf_event_ops *handler) if (handler->lost == NULL) handler->lost = perf_event__process_lost; if (handler->read == NULL) - handler->read = process_event_stub; + handler->read = process_event_sample_stub; if (handler->throttle == NULL) handler->throttle = process_event_stub; if (handler->unthrottle == NULL) @@ -346,11 +346,11 @@ static void perf_event_ops__fill_defaults(struct perf_event_ops *handler) if (handler->attr == NULL) handler->attr = process_event_synth_attr_stub; if (handler->event_type == NULL) - handler->event_type = process_event_synth_stub; + handler->event_type = process_event_type_stub; if (handler->tracing_data == NULL) handler->tracing_data = process_event_synth_tracing_data_stub; if (handler->build_id == NULL) - handler->build_id = process_event_synth_stub; + handler->build_id = process_finished_round_stub; if (handler->finished_round == NULL) { if (handler->ordered_samples) handler->finished_round = process_finished_round; @@ -734,6 +734,18 @@ static void dump_sample(struct perf_session *session, union perf_event *event, callchain__printf(sample); } +static struct machine * + perf_session__find_machine_for_cpumode(struct perf_session *session, + union perf_event *event) +{ + const u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; + + if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL && perf_guest) + return perf_session__find_machine(session, event->ip.pid); + + return perf_session__find_host_machine(session); +} + static int perf_session_deliver_event(struct perf_session *session, union perf_event *event, struct perf_sample *sample, @@ -741,6 +753,7 @@ static int perf_session_deliver_event(struct perf_session *session, u64 file_offset) { struct perf_evsel *evsel; + struct machine *machine; dump_event(session, event, file_offset, sample); @@ -762,6 +775,8 @@ static int perf_session_deliver_event(struct perf_session *session, hists__inc_nr_events(&evsel->hists, event->header.type); } + machine = perf_session__find_machine_for_cpumode(session, event); + switch (event->header.type) { case PERF_RECORD_SAMPLE: dump_sample(session, event, sample); @@ -769,23 +784,25 @@ static int perf_session_deliver_event(struct perf_session *session, ++session->hists.stats.nr_unknown_id; return -1; } - return ops->sample(ops, event, sample, evsel, session); + return ops->sample(ops, event, sample, evsel, machine); case PERF_RECORD_MMAP: - return ops->mmap(ops, event, sample, session); + return ops->mmap(ops, event, sample, machine); case PERF_RECORD_COMM: - return ops->comm(ops, event, sample, session); + return ops->comm(ops, event, sample, machine); case PERF_RECORD_FORK: - return ops->fork(ops, event, sample, session); + return ops->fork(ops, event, sample, machine); case PERF_RECORD_EXIT: - return ops->exit(ops, event, sample, session); + return ops->exit(ops, event, sample, machine); case PERF_RECORD_LOST: - return ops->lost(ops, event, sample, session); + if (ops->lost == perf_event__process_lost) + session->hists.stats.total_lost += event->lost.lost; + return ops->lost(ops, event, sample, machine); case PERF_RECORD_READ: - return ops->read(ops, event, sample, session); + return ops->read(ops, event, sample, evsel, machine); case PERF_RECORD_THROTTLE: - return ops->throttle(ops, event, sample, session); + return ops->throttle(ops, event, sample, machine); case PERF_RECORD_UNTHROTTLE: - return ops->unthrottle(ops, event, sample, session); + return ops->unthrottle(ops, event, sample, machine); default: ++session->hists.stats.nr_unknown_events; return -1; @@ -823,7 +840,7 @@ static int perf_session__process_user_event(struct perf_session *session, union perf_session__update_sample_type(session); return err; case PERF_RECORD_HEADER_EVENT_TYPE: - return ops->event_type(ops, event, session); + return ops->event_type(ops, event); case PERF_RECORD_HEADER_TRACING_DATA: /* setup for reading amidst mmap */ lseek(session->fd, file_offset, SEEK_SET); @@ -1170,9 +1187,8 @@ bool perf_session__has_traces(struct perf_session *self, const char *msg) return true; } -int perf_session__set_kallsyms_ref_reloc_sym(struct map **maps, - const char *symbol_name, - u64 addr) +int maps__set_kallsyms_ref_reloc_sym(struct map **maps, + const char *symbol_name, u64 addr) { char *bracket; enum map_type i; @@ -1264,17 +1280,16 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, return NULL; } -void perf_session__print_ip(union perf_event *event, struct perf_evsel *evsel, - struct perf_sample *sample, - struct perf_session *session, - int print_sym, int print_dso) +void perf_event__print_ip(union perf_event *event, struct perf_sample *sample, + struct machine *machine, struct perf_evsel *evsel, + int print_sym, int print_dso) { struct addr_location al; const char *symname, *dsoname; struct callchain_cursor *cursor = &evsel->hists.callchain_cursor; struct callchain_cursor_node *node; - if (perf_event__preprocess_sample(event, session, &al, sample, + if (perf_event__preprocess_sample(event, machine, &al, sample, NULL) < 0) { error("problem processing %d event, skipping it.\n", event->header.type); @@ -1283,7 +1298,7 @@ void perf_session__print_ip(union perf_event *event, struct perf_evsel *evsel, if (symbol_conf.use_callchain && sample->callchain) { - if (perf_session__resolve_callchain(session, evsel, al.thread, + if (machine__resolve_callchain(machine, evsel, al.thread, sample->callchain, NULL) != 0) { if (verbose) error("Failed to resolve callchain. Skipping\n"); diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 6de3d136890..1c5823c7d6d 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -58,32 +58,34 @@ struct perf_event_ops; typedef int (*event_sample)(struct perf_event_ops *ops, union perf_event *event, struct perf_sample *sample, - struct perf_evsel *evsel, struct perf_session *session); + struct perf_evsel *evsel, struct machine *machine); typedef int (*event_op)(struct perf_event_ops *ops, union perf_event *event, struct perf_sample *sample, - struct perf_session *session); + struct machine *machine); typedef int (*event_synth_op)(union perf_event *self, struct perf_session *session); typedef int (*event_attr_op)(union perf_event *event, struct perf_evlist **pevlist); +typedef int (*event_simple_op)(struct perf_event_ops *ops, + union perf_event *event); typedef int (*event_op2)(struct perf_event_ops *ops, union perf_event *event, struct perf_session *session); struct perf_event_ops { - event_sample sample; + event_sample sample, + read; event_op mmap, comm, fork, exit, lost, - read, throttle, unthrottle; event_attr_op attr; event_synth_op tracing_data; - event_op2 event_type, - build_id, - finished_round; + event_simple_op event_type; + event_op2 finished_round, + build_id; bool ordered_samples; bool ordering_requires_timestamps; }; @@ -108,10 +110,6 @@ int perf_session__resolve_callchain(struct perf_session *self, struct perf_evsel bool perf_session__has_traces(struct perf_session *self, const char *msg); -int perf_session__set_kallsyms_ref_reloc_sym(struct map **maps, - const char *symbol_name, - u64 addr); - void mem_bswap_64(void *src, int byte_size); void perf_event__attr_swap(struct perf_event_attr *attr); @@ -151,6 +149,9 @@ void perf_session__process_machines(struct perf_session *self, return machines__process(&self->machines, process, ops); } +struct thread *perf_session__findnew(struct perf_session *self, pid_t pid); +size_t perf_session__fprintf(struct perf_session *self, FILE *fp); + size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp); size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, @@ -171,10 +172,9 @@ static inline int perf_session__parse_sample(struct perf_session *session, struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, unsigned int type); -void perf_session__print_ip(union perf_event *event, struct perf_evsel *evsel, - struct perf_sample *sample, - struct perf_session *session, - int print_sym, int print_dso); +void perf_event__print_ip(union perf_event *event, struct perf_sample *sample, + struct machine *machine, struct perf_evsel *evsel, + int print_sym, int print_dso); int perf_session__cpu_bitmap(struct perf_session *session, const char *cpu_list, unsigned long *cpu_bitmap); diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index e5f2401c1b5..70c2c13ff67 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h @@ -18,16 +18,14 @@ struct thread { int comm_len; }; -struct perf_session; +struct machine; void thread__delete(struct thread *self); int thread__set_comm(struct thread *self, const char *comm); int thread__comm_len(struct thread *self); -struct thread *perf_session__findnew(struct perf_session *self, pid_t pid); void thread__insert_map(struct thread *self, struct map *map); int thread__fork(struct thread *self, struct thread *parent); -size_t perf_session__fprintf(struct perf_session *self, FILE *fp); static inline struct map *thread__find_map(struct thread *self, enum map_type type, u64 addr) @@ -35,14 +33,12 @@ static inline struct map *thread__find_map(struct thread *self, return self ? map_groups__find(&self->mg, type, addr) : NULL; } -void thread__find_addr_map(struct thread *self, - struct perf_session *session, u8 cpumode, - enum map_type type, pid_t pid, u64 addr, +void thread__find_addr_map(struct thread *thread, struct machine *machine, + u8 cpumode, enum map_type type, u64 addr, struct addr_location *al); -void thread__find_addr_location(struct thread *self, - struct perf_session *session, u8 cpumode, - enum map_type type, pid_t pid, u64 addr, +void thread__find_addr_location(struct thread *thread, struct machine *machine, + u8 cpumode, enum map_type type, u64 addr, struct addr_location *al, symbol_filter_t filter); #endif /* __PERF_THREAD_H */ diff --git a/tools/perf/util/trace-event-scripting.c b/tools/perf/util/trace-event-scripting.c index c9dcbec7d80..a3fdf55f317 100644 --- a/tools/perf/util/trace-event-scripting.c +++ b/tools/perf/util/trace-event-scripting.c @@ -39,7 +39,7 @@ static int stop_script_unsupported(void) static void process_event_unsupported(union perf_event *event __unused, struct perf_sample *sample __unused, struct perf_evsel *evsel __unused, - struct perf_session *session __unused, + struct machine *machine __unused, struct thread *thread __unused) { } diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h index a8410081764..58ae14c5baa 100644 --- a/tools/perf/util/trace-event.h +++ b/tools/perf/util/trace-event.h @@ -3,7 +3,11 @@ #include #include "parse-events.h" -#include "session.h" + +struct machine; +struct perf_sample; +union perf_event; +struct thread; #define __unused __attribute__((unused)) @@ -292,7 +296,7 @@ struct scripting_ops { void (*process_event) (union perf_event *event, struct perf_sample *sample, struct perf_evsel *evsel, - struct perf_session *session, + struct machine *machine, struct thread *thread); int (*generate_script) (const char *outfile); }; -- cgit v1.2.3-70-g09d2 From 45694aa7702bc44d538a3bcb51bb2bb96cf190c0 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 28 Nov 2011 08:30:20 -0200 Subject: perf tools: Rename perf_event_ops to perf_tool To better reflect that it became the base class for all tools, that must be in each tool struct and where common stuff will be put. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-qgpc4msetqlwr8y2k7537cxe@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Makefile | 1 + tools/perf/builtin-annotate.c | 13 ++-- tools/perf/builtin-diff.c | 11 +-- tools/perf/builtin-inject.c | 55 +++++++------- tools/perf/builtin-kmem.c | 9 ++- tools/perf/builtin-lock.c | 5 +- tools/perf/builtin-record.c | 35 ++++----- tools/perf/builtin-report.c | 17 +++-- tools/perf/builtin-sched.c | 9 ++- tools/perf/builtin-script.c | 9 ++- tools/perf/builtin-timechart.c | 15 ++-- tools/perf/builtin-top.c | 6 +- tools/perf/util/build-id.c | 7 +- tools/perf/util/build-id.h | 2 +- tools/perf/util/event.c | 54 +++++++------- tools/perf/util/event.h | 22 +++--- tools/perf/util/header.c | 28 +++---- tools/perf/util/header.h | 16 ++-- tools/perf/util/session.c | 163 +++++++++++++++++++++-------------------- tools/perf/util/session.h | 49 ++----------- tools/perf/util/tool.h | 45 ++++++++++++ tools/perf/util/top.h | 7 +- 22 files changed, 301 insertions(+), 277 deletions(-) create mode 100644 tools/perf/util/tool.h (limited to 'tools') diff --git a/tools/perf/Makefile b/tools/perf/Makefile index b98e3075646..ac86d67b636 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -278,6 +278,7 @@ LIB_H += util/strbuf.h LIB_H += util/strlist.h LIB_H += util/strfilter.h LIB_H += util/svghelper.h +LIB_H += util/tool.h LIB_H += util/run-command.h LIB_H += util/sigchain.h LIB_H += util/symbol.h diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index dff081a388b..c01139fa4a1 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -27,11 +27,12 @@ #include "util/sort.h" #include "util/hist.h" #include "util/session.h" +#include "util/tool.h" #include struct perf_annotate { - struct perf_event_ops ops; + struct perf_tool tool; char const *input_name; bool force, use_tui, use_stdio; bool full_paths; @@ -79,13 +80,13 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel, return ret; } -static int process_sample_event(struct perf_event_ops *ops, +static int process_sample_event(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, struct perf_evsel *evsel, struct machine *machine) { - struct perf_annotate *ann = container_of(ops, struct perf_annotate, ops); + struct perf_annotate *ann = container_of(tool, struct perf_annotate, tool); struct addr_location al; if (perf_event__preprocess_sample(event, machine, &al, sample, @@ -174,7 +175,7 @@ static int __cmd_annotate(struct perf_annotate *ann) u64 total_nr_samples; session = perf_session__new(ann->input_name, O_RDONLY, - ann->force, false, &ann->ops); + ann->force, false, &ann->tool); if (session == NULL) return -ENOMEM; @@ -185,7 +186,7 @@ static int __cmd_annotate(struct perf_annotate *ann) goto out_delete; } - ret = perf_session__process_events(session, &ann->ops); + ret = perf_session__process_events(session, &ann->tool); if (ret) goto out_delete; @@ -241,7 +242,7 @@ static const char * const annotate_usage[] = { int cmd_annotate(int argc, const char **argv, const char *prefix __used) { struct perf_annotate annotate = { - .ops = { + .tool = { .sample = process_sample_event, .mmap = perf_event__process_mmap, .comm = perf_event__process_comm, diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 478b0aeb2a6..4f19513d7dd 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -11,6 +11,7 @@ #include "util/hist.h" #include "util/evsel.h" #include "util/session.h" +#include "util/tool.h" #include "util/sort.h" #include "util/symbol.h" #include "util/util.h" @@ -31,7 +32,7 @@ static int hists__add_entry(struct hists *self, return -ENOMEM; } -static int diff__process_sample_event(struct perf_event_ops *ops __used, +static int diff__process_sample_event(struct perf_tool *tool __used, union perf_event *event, struct perf_sample *sample, struct perf_evsel *evsel __used, @@ -57,7 +58,7 @@ static int diff__process_sample_event(struct perf_event_ops *ops __used, return 0; } -static struct perf_event_ops event_ops = { +static struct perf_tool perf_diff = { .sample = diff__process_sample_event, .mmap = perf_event__process_mmap, .comm = perf_event__process_comm, @@ -147,13 +148,13 @@ static int __cmd_diff(void) int ret, i; struct perf_session *session[2]; - session[0] = perf_session__new(input_old, O_RDONLY, force, false, &event_ops); - session[1] = perf_session__new(input_new, O_RDONLY, force, false, &event_ops); + session[0] = perf_session__new(input_old, O_RDONLY, force, false, &perf_diff); + session[1] = perf_session__new(input_new, O_RDONLY, force, false, &perf_diff); if (session[0] == NULL || session[1] == NULL) return -ENOMEM; for (i = 0; i < 2; ++i) { - ret = perf_session__process_events(session[i], &event_ops); + ret = perf_session__process_events(session[i], &perf_diff); if (ret) goto out_delete; } diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index a5bcf81776f..09c106193e6 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c @@ -9,6 +9,7 @@ #include "perf.h" #include "util/session.h" +#include "util/tool.h" #include "util/debug.h" #include "util/parse-options.h" @@ -16,7 +17,7 @@ static char const *input_name = "-"; static bool inject_build_ids; -static int perf_event__repipe_synth(struct perf_event_ops *ops __used, +static int perf_event__repipe_synth(struct perf_tool *tool __used, union perf_event *event, struct machine *machine __used) { @@ -37,17 +38,17 @@ static int perf_event__repipe_synth(struct perf_event_ops *ops __used, return 0; } -static int perf_event__repipe_op2_synth(struct perf_event_ops *ops, +static int perf_event__repipe_op2_synth(struct perf_tool *tool, union perf_event *event, struct perf_session *session __used) { - return perf_event__repipe_synth(ops, event, NULL); + return perf_event__repipe_synth(tool, event, NULL); } -static int perf_event__repipe_event_type_synth(struct perf_event_ops *ops, +static int perf_event__repipe_event_type_synth(struct perf_tool *tool, union perf_event *event) { - return perf_event__repipe_synth(ops, event, NULL); + return perf_event__repipe_synth(tool, event, NULL); } static int perf_event__repipe_tracing_data_synth(union perf_event *event, @@ -62,45 +63,45 @@ static int perf_event__repipe_attr(union perf_event *event, return perf_event__repipe_synth(NULL, event, NULL); } -static int perf_event__repipe(struct perf_event_ops *ops, +static int perf_event__repipe(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample __used, struct machine *machine) { - return perf_event__repipe_synth(ops, event, machine); + return perf_event__repipe_synth(tool, event, machine); } -static int perf_event__repipe_sample(struct perf_event_ops *ops, +static int perf_event__repipe_sample(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample __used, struct perf_evsel *evsel __used, struct machine *machine) { - return perf_event__repipe_synth(ops, event, machine); + return perf_event__repipe_synth(tool, event, machine); } -static int perf_event__repipe_mmap(struct perf_event_ops *ops, +static int perf_event__repipe_mmap(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, struct machine *machine) { int err; - err = perf_event__process_mmap(ops, event, sample, machine); - perf_event__repipe(ops, event, sample, machine); + err = perf_event__process_mmap(tool, event, sample, machine); + perf_event__repipe(tool, event, sample, machine); return err; } -static int perf_event__repipe_task(struct perf_event_ops *ops, +static int perf_event__repipe_task(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, struct machine *machine) { int err; - err = perf_event__process_task(ops, event, sample, machine); - perf_event__repipe(ops, event, sample, machine); + err = perf_event__process_task(tool, event, sample, machine); + perf_event__repipe(tool, event, sample, machine); return err; } @@ -130,7 +131,7 @@ static int dso__read_build_id(struct dso *self) return -1; } -static int dso__inject_build_id(struct dso *self, struct perf_event_ops *ops, +static int dso__inject_build_id(struct dso *self, struct perf_tool *tool, struct machine *machine) { u16 misc = PERF_RECORD_MISC_USER; @@ -144,7 +145,7 @@ static int dso__inject_build_id(struct dso *self, struct perf_event_ops *ops, if (self->kernel) misc = PERF_RECORD_MISC_KERNEL; - err = perf_event__synthesize_build_id(ops, self, misc, perf_event__repipe, + err = perf_event__synthesize_build_id(tool, self, misc, perf_event__repipe, machine); if (err) { pr_err("Can't synthesize build_id event for %s\n", self->long_name); @@ -154,7 +155,7 @@ static int dso__inject_build_id(struct dso *self, struct perf_event_ops *ops, return 0; } -static int perf_event__inject_buildid(struct perf_event_ops *ops, +static int perf_event__inject_buildid(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, struct perf_evsel *evsel __used, @@ -180,7 +181,7 @@ static int perf_event__inject_buildid(struct perf_event_ops *ops, if (!al.map->dso->hit) { al.map->dso->hit = 1; if (map__load(al.map, NULL) >= 0) { - dso__inject_build_id(al.map->dso, ops, machine); + dso__inject_build_id(al.map->dso, tool, machine); /* * If this fails, too bad, let the other side * account this as unresolved. @@ -193,11 +194,11 @@ static int perf_event__inject_buildid(struct perf_event_ops *ops, } repipe: - perf_event__repipe(ops, event, sample, machine); + perf_event__repipe(tool, event, sample, machine); return 0; } -struct perf_event_ops inject_ops = { +struct perf_tool perf_inject = { .sample = perf_event__repipe_sample, .mmap = perf_event__repipe, .comm = perf_event__repipe, @@ -228,17 +229,17 @@ static int __cmd_inject(void) signal(SIGINT, sig_handler); if (inject_build_ids) { - inject_ops.sample = perf_event__inject_buildid; - inject_ops.mmap = perf_event__repipe_mmap; - inject_ops.fork = perf_event__repipe_task; - inject_ops.tracing_data = perf_event__repipe_tracing_data; + perf_inject.sample = perf_event__inject_buildid; + perf_inject.mmap = perf_event__repipe_mmap; + perf_inject.fork = perf_event__repipe_task; + perf_inject.tracing_data = perf_event__repipe_tracing_data; } - session = perf_session__new(input_name, O_RDONLY, false, true, &inject_ops); + session = perf_session__new(input_name, O_RDONLY, false, true, &perf_inject); if (session == NULL) return -ENOMEM; - ret = perf_session__process_events(session, &inject_ops); + ret = perf_session__process_events(session, &perf_inject); perf_session__delete(session); diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index 27b2a15dc7b..886174e9525 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c @@ -7,6 +7,7 @@ #include "util/thread.h" #include "util/header.h" #include "util/session.h" +#include "util/tool.h" #include "util/parse-options.h" #include "util/trace-event.h" @@ -303,7 +304,7 @@ static void process_raw_event(union perf_event *raw_event __used, void *data, } } -static int process_sample_event(struct perf_event_ops *ops __used, +static int process_sample_event(struct perf_tool *tool __used, union perf_event *event, struct perf_sample *sample, struct perf_evsel *evsel __used, @@ -325,7 +326,7 @@ static int process_sample_event(struct perf_event_ops *ops __used, return 0; } -static struct perf_event_ops event_ops = { +static struct perf_tool perf_kmem = { .sample = process_sample_event, .comm = perf_event__process_comm, .ordered_samples = true, @@ -484,7 +485,7 @@ static int __cmd_kmem(void) { int err = -EINVAL; struct perf_session *session = perf_session__new(input_name, O_RDONLY, - 0, false, &event_ops); + 0, false, &perf_kmem); if (session == NULL) return -ENOMEM; @@ -495,7 +496,7 @@ static int __cmd_kmem(void) goto out_delete; setup_pager(); - err = perf_session__process_events(session, &event_ops); + err = perf_session__process_events(session, &perf_kmem); if (err != 0) goto out_delete; sort_result(); diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c index 99b032adb83..4db5e529306 100644 --- a/tools/perf/builtin-lock.c +++ b/tools/perf/builtin-lock.c @@ -12,6 +12,7 @@ #include "util/debug.h" #include "util/session.h" +#include "util/tool.h" #include #include @@ -845,7 +846,7 @@ static void dump_info(void) die("Unknown type of information\n"); } -static int process_sample_event(struct perf_event_ops *ops __used, +static int process_sample_event(struct perf_tool *tool __used, union perf_event *event, struct perf_sample *sample, struct perf_evsel *evsel __used, @@ -864,7 +865,7 @@ static int process_sample_event(struct perf_event_ops *ops __used, return 0; } -static struct perf_event_ops eops = { +static struct perf_tool eops = { .sample = process_sample_event, .comm = perf_event__process_comm, .ordered_samples = true, diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 0af598a1059..7d4fdaacc8b 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -22,6 +22,7 @@ #include "util/evsel.h" #include "util/debug.h" #include "util/session.h" +#include "util/tool.h" #include "util/symbol.h" #include "util/cpumap.h" #include "util/thread_map.h" @@ -36,7 +37,7 @@ enum write_mode_t { }; struct perf_record { - struct perf_event_ops ops; + struct perf_tool tool; struct perf_record_opts opts; u64 bytes_written; const char *output_name; @@ -76,12 +77,12 @@ static void write_output(struct perf_record *rec, void *buf, size_t size) } } -static int process_synthesized_event(struct perf_event_ops *ops, +static int process_synthesized_event(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample __used, struct machine *machine __used) { - struct perf_record *rec = container_of(ops, struct perf_record, ops); + struct perf_record *rec = container_of(tool, struct perf_record, tool); write_output(rec, event, event->header.size); return 0; } @@ -319,7 +320,7 @@ static void perf_record__exit(int status __used, void *arg) static void perf_event__synthesize_guest_os(struct machine *machine, void *data) { int err; - struct perf_event_ops *ops = data; + struct perf_tool *tool = data; if (machine__is_host(machine)) return; @@ -332,7 +333,7 @@ static void perf_event__synthesize_guest_os(struct machine *machine, void *data) *method is used to avoid symbol missing when the first addr is *in module instead of in guest kernel. */ - err = perf_event__synthesize_modules(ops, process_synthesized_event, + err = perf_event__synthesize_modules(tool, process_synthesized_event, machine); if (err < 0) pr_err("Couldn't record guest kernel [%d]'s reference" @@ -342,10 +343,10 @@ static void perf_event__synthesize_guest_os(struct machine *machine, void *data) * We use _stext for guest kernel because guest kernel's /proc/kallsyms * have no _text sometimes. */ - err = perf_event__synthesize_kernel_mmap(ops, process_synthesized_event, + err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event, machine, "_text"); if (err < 0) - err = perf_event__synthesize_kernel_mmap(ops, process_synthesized_event, + err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event, machine, "_stext"); if (err < 0) pr_err("Couldn't record guest kernel [%d]'s reference" @@ -378,7 +379,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) unsigned long waking = 0; const bool forks = argc > 0; struct machine *machine; - struct perf_event_ops *ops = &rec->ops; + struct perf_tool *tool = &rec->tool; struct perf_record_opts *opts = &rec->opts; struct perf_evlist *evsel_list = rec->evlist; const char *output_name = rec->output_name; @@ -501,14 +502,14 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) } if (opts->pipe_output) { - err = perf_event__synthesize_attrs(ops, session, + err = perf_event__synthesize_attrs(tool, session, process_synthesized_event); if (err < 0) { pr_err("Couldn't synthesize attrs.\n"); return err; } - err = perf_event__synthesize_event_types(ops, process_synthesized_event, + err = perf_event__synthesize_event_types(tool, process_synthesized_event, machine); if (err < 0) { pr_err("Couldn't synthesize event_types.\n"); @@ -524,7 +525,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) * return this more properly and also * propagate errors that now are calling die() */ - err = perf_event__synthesize_tracing_data(ops, output, evsel_list, + err = perf_event__synthesize_tracing_data(tool, output, evsel_list, process_synthesized_event); if (err <= 0) { pr_err("Couldn't record tracing data.\n"); @@ -534,17 +535,17 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) } } - err = perf_event__synthesize_kernel_mmap(ops, process_synthesized_event, + err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event, machine, "_text"); if (err < 0) - err = perf_event__synthesize_kernel_mmap(ops, process_synthesized_event, + err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event, machine, "_stext"); if (err < 0) pr_err("Couldn't record kernel reference relocation symbol\n" "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n" "Check /proc/kallsyms permission or run as root.\n"); - err = perf_event__synthesize_modules(ops, process_synthesized_event, + err = perf_event__synthesize_modules(tool, process_synthesized_event, machine); if (err < 0) pr_err("Couldn't record kernel module information.\n" @@ -552,15 +553,15 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) "Check /proc/modules permission or run as root.\n"); if (perf_guest) - perf_session__process_machines(session, ops, + perf_session__process_machines(session, tool, perf_event__synthesize_guest_os); if (!opts->system_wide) - perf_event__synthesize_thread_map(ops, evsel_list->threads, + perf_event__synthesize_thread_map(tool, evsel_list->threads, process_synthesized_event, machine); else - perf_event__synthesize_threads(ops, process_synthesized_event, + perf_event__synthesize_threads(tool, process_synthesized_event, machine); if (rec->realtime_prio) { diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index ea64fbbdff4..eef8e423deb 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -25,6 +25,7 @@ #include "util/evsel.h" #include "util/header.h" #include "util/session.h" +#include "util/tool.h" #include "util/parse-options.h" #include "util/parse-events.h" @@ -36,7 +37,7 @@ #include struct perf_report { - struct perf_event_ops ops; + struct perf_tool tool; struct perf_session *session; char const *input_name; bool force, use_tui, use_stdio; @@ -103,13 +104,13 @@ out: } -static int process_sample_event(struct perf_event_ops *ops, +static int process_sample_event(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, struct perf_evsel *evsel, struct machine *machine) { - struct perf_report *rep = container_of(ops, struct perf_report, ops); + struct perf_report *rep = container_of(tool, struct perf_report, tool); struct addr_location al; if (perf_event__preprocess_sample(event, machine, &al, sample, @@ -136,13 +137,13 @@ static int process_sample_event(struct perf_event_ops *ops, return 0; } -static int process_read_event(struct perf_event_ops *ops, +static int process_read_event(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample __used, struct perf_evsel *evsel, struct machine *machine __used) { - struct perf_report *rep = container_of(ops, struct perf_report, ops); + struct perf_report *rep = container_of(tool, struct perf_report, tool); if (rep->show_threads) { const char *name = evsel ? event_name(evsel) : "unknown"; @@ -254,7 +255,7 @@ static int __cmd_report(struct perf_report *rep) signal(SIGINT, sig_handler); session = perf_session__new(rep->input_name, O_RDONLY, - rep->force, false, &rep->ops); + rep->force, false, &rep->tool); if (session == NULL) return -ENOMEM; @@ -277,7 +278,7 @@ static int __cmd_report(struct perf_report *rep) if (ret) goto out_delete; - ret = perf_session__process_events(session, &rep->ops); + ret = perf_session__process_events(session, &rep->tool); if (ret) goto out_delete; @@ -435,7 +436,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __used) NULL }; struct perf_report report = { - .ops = { + .tool = { .sample = process_sample_event, .mmap = perf_event__process_mmap, .comm = perf_event__process_comm, diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index 6a771f822e5..0ee868e6f63 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -8,6 +8,7 @@ #include "util/thread.h" #include "util/header.h" #include "util/session.h" +#include "util/tool.h" #include "util/parse-options.h" #include "util/trace-event.h" @@ -1602,7 +1603,7 @@ static void process_raw_event(union perf_event *raw_event __used, process_sched_migrate_task_event(data, machine, event, cpu, timestamp, thread); } -static int process_sample_event(struct perf_event_ops *ops __used, +static int process_sample_event(struct perf_tool *tool __used, union perf_event *event, struct perf_sample *sample, struct perf_evsel *evsel, @@ -1631,7 +1632,7 @@ static int process_sample_event(struct perf_event_ops *ops __used, return 0; } -static struct perf_event_ops event_ops = { +static struct perf_tool perf_sched = { .sample = process_sample_event, .comm = perf_event__process_comm, .lost = perf_event__process_lost, @@ -1643,12 +1644,12 @@ static void read_events(bool destroy, struct perf_session **psession) { int err = -EINVAL; struct perf_session *session = perf_session__new(input_name, O_RDONLY, - 0, false, &event_ops); + 0, false, &perf_sched); if (session == NULL) die("No Memory"); if (perf_session__has_traces(session, "record -R")) { - err = perf_session__process_events(session, &event_ops); + err = perf_session__process_events(session, &perf_sched); if (err) die("Failed to process events, error %d", err); diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 31a8d14e5fb..5f8afc65d5f 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -7,6 +7,7 @@ #include "util/header.h" #include "util/parse-options.h" #include "util/session.h" +#include "util/tool.h" #include "util/symbol.h" #include "util/thread.h" #include "util/trace-event.h" @@ -434,7 +435,7 @@ static int cleanup_scripting(void) static char const *input_name = "perf.data"; -static int process_sample_event(struct perf_event_ops *ops __used, +static int process_sample_event(struct perf_tool *tool __used, union perf_event *event, struct perf_sample *sample, struct perf_evsel *evsel, @@ -468,7 +469,7 @@ static int process_sample_event(struct perf_event_ops *ops __used, return 0; } -static struct perf_event_ops event_ops = { +static struct perf_tool perf_script = { .sample = process_sample_event, .mmap = perf_event__process_mmap, .comm = perf_event__process_comm, @@ -495,7 +496,7 @@ static int __cmd_script(struct perf_session *session) signal(SIGINT, sig_handler); - ret = perf_session__process_events(session, &event_ops); + ret = perf_session__process_events(session, &perf_script); if (debug_mode) pr_err("Misordered timestamps: %" PRIu64 "\n", nr_unordered); @@ -1262,7 +1263,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __used) if (!script_name) setup_pager(); - session = perf_session__new(input_name, O_RDONLY, 0, false, &event_ops); + session = perf_session__new(input_name, O_RDONLY, 0, false, &perf_script); if (session == NULL) return -ENOMEM; diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index 8e6539625bc..135376a37f9 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c @@ -32,6 +32,7 @@ #include "util/event.h" #include "util/session.h" #include "util/svghelper.h" +#include "util/tool.h" #define SUPPORT_OLD_POWER_EVENTS 1 #define PWR_EVENT_EXIT -1 @@ -274,7 +275,7 @@ static int cpus_cstate_state[MAX_CPUS]; static u64 cpus_pstate_start_times[MAX_CPUS]; static u64 cpus_pstate_state[MAX_CPUS]; -static int process_comm_event(struct perf_event_ops *ops __used, +static int process_comm_event(struct perf_tool *tool __used, union perf_event *event, struct perf_sample *sample __used, struct machine *machine __used) @@ -283,7 +284,7 @@ static int process_comm_event(struct perf_event_ops *ops __used, return 0; } -static int process_fork_event(struct perf_event_ops *ops __used, +static int process_fork_event(struct perf_tool *tool __used, union perf_event *event, struct perf_sample *sample __used, struct machine *machine __used) @@ -292,7 +293,7 @@ static int process_fork_event(struct perf_event_ops *ops __used, return 0; } -static int process_exit_event(struct perf_event_ops *ops __used, +static int process_exit_event(struct perf_tool *tool __used, union perf_event *event, struct perf_sample *sample __used, struct machine *machine __used) @@ -490,7 +491,7 @@ static void sched_switch(int cpu, u64 timestamp, struct trace_entry *te) } -static int process_sample_event(struct perf_event_ops *ops __used, +static int process_sample_event(struct perf_tool *tool __used, union perf_event *event __used, struct perf_sample *sample, struct perf_evsel *evsel, @@ -979,7 +980,7 @@ static void write_svg_file(const char *filename) svg_close(); } -static struct perf_event_ops event_ops = { +static struct perf_tool perf_timechart = { .comm = process_comm_event, .fork = process_fork_event, .exit = process_exit_event, @@ -990,7 +991,7 @@ static struct perf_event_ops event_ops = { static int __cmd_timechart(void) { struct perf_session *session = perf_session__new(input_name, O_RDONLY, - 0, false, &event_ops); + 0, false, &perf_timechart); int ret = -EINVAL; if (session == NULL) @@ -999,7 +1000,7 @@ static int __cmd_timechart(void) if (!perf_session__has_traces(session, "timechart record")) goto out_delete; - ret = perf_session__process_events(session, &event_ops); + ret = perf_session__process_events(session, &perf_timechart); if (ret) goto out_delete; diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 31d497368cc..42a7d96b4db 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -826,7 +826,7 @@ static void perf_session__mmap_read_idx(struct perf_session *self, int idx) perf_event__process_sample(event, evsel, &sample, machine); else if (event->header.type < PERF_RECORD_MAX) { hists__inc_nr_events(&evsel->hists, event->header.type); - perf_event__process(&top.ops, event, &sample, machine); + perf_event__process(&top.tool, event, &sample, machine); } else ++self->hists.stats.nr_unknown_events; } @@ -968,11 +968,11 @@ static int __cmd_top(void) goto out_delete; if (top.target_tid != -1) - perf_event__synthesize_thread_map(&top.ops, top.evlist->threads, + perf_event__synthesize_thread_map(&top.tool, top.evlist->threads, perf_event__process, &top.session->host_machine); else - perf_event__synthesize_threads(&top.ops, perf_event__process, + perf_event__synthesize_threads(&top.tool, perf_event__process, &top.session->host_machine); start_counters(top.evlist); top.session->evlist = top.evlist; diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c index 2f84c4802ac..dff9c7a725f 100644 --- a/tools/perf/util/build-id.c +++ b/tools/perf/util/build-id.c @@ -14,8 +14,9 @@ #include #include "debug.h" #include "session.h" +#include "tool.h" -static int build_id__mark_dso_hit(struct perf_event_ops *ops __used, +static int build_id__mark_dso_hit(struct perf_tool *tool __used, union perf_event *event, struct perf_sample *sample __used, struct perf_evsel *evsel __used, @@ -40,7 +41,7 @@ static int build_id__mark_dso_hit(struct perf_event_ops *ops __used, return 0; } -static int perf_event__exit_del_thread(struct perf_event_ops *ops __used, +static int perf_event__exit_del_thread(struct perf_tool *tool __used, union perf_event *event, struct perf_sample *sample __used, struct machine *machine) @@ -59,7 +60,7 @@ static int perf_event__exit_del_thread(struct perf_event_ops *ops __used, return 0; } -struct perf_event_ops build_id__mark_dso_hit_ops = { +struct perf_tool build_id__mark_dso_hit_ops = { .sample = build_id__mark_dso_hit, .mmap = perf_event__process_mmap, .fork = perf_event__process_task, diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h index 5dafb00eaa0..a993ba87d99 100644 --- a/tools/perf/util/build-id.h +++ b/tools/perf/util/build-id.h @@ -3,7 +3,7 @@ #include "session.h" -extern struct perf_event_ops build_id__mark_dso_hit_ops; +extern struct perf_tool build_id__mark_dso_hit_ops; char *dso__build_id_filename(struct dso *self, char *bf, size_t size); diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 0cdc811c48e..0ebbe764133 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -43,7 +43,7 @@ static struct perf_sample synth_sample = { .period = 1, }; -static pid_t perf_event__synthesize_comm(struct perf_event_ops *ops, +static pid_t perf_event__synthesize_comm(struct perf_tool *tool, union perf_event *event, pid_t pid, int full, perf_event__handler_t process, struct machine *machine) @@ -99,7 +99,7 @@ out_race: if (!full) { event->comm.tid = pid; - process(ops, event, &synth_sample, machine); + process(tool, event, &synth_sample, machine); goto out; } @@ -117,7 +117,7 @@ out_race: event->comm.tid = pid; - process(ops, event, &synth_sample, machine); + process(tool, event, &synth_sample, machine); } closedir(tasks); @@ -127,7 +127,7 @@ out: return tgid; } -static int perf_event__synthesize_mmap_events(struct perf_event_ops *ops, +static int perf_event__synthesize_mmap_events(struct perf_tool *tool, union perf_event *event, pid_t pid, pid_t tgid, perf_event__handler_t process, @@ -199,7 +199,7 @@ static int perf_event__synthesize_mmap_events(struct perf_event_ops *ops, event->mmap.pid = tgid; event->mmap.tid = pid; - process(ops, event, &synth_sample, machine); + process(tool, event, &synth_sample, machine); } } @@ -207,7 +207,7 @@ static int perf_event__synthesize_mmap_events(struct perf_event_ops *ops, return 0; } -int perf_event__synthesize_modules(struct perf_event_ops *ops, +int perf_event__synthesize_modules(struct perf_tool *tool, perf_event__handler_t process, struct machine *machine) { @@ -252,7 +252,7 @@ int perf_event__synthesize_modules(struct perf_event_ops *ops, memcpy(event->mmap.filename, pos->dso->long_name, pos->dso->long_name_len + 1); - process(ops, event, &synth_sample, machine); + process(tool, event, &synth_sample, machine); } free(event); @@ -262,18 +262,18 @@ int perf_event__synthesize_modules(struct perf_event_ops *ops, static int __event__synthesize_thread(union perf_event *comm_event, union perf_event *mmap_event, pid_t pid, perf_event__handler_t process, - struct perf_event_ops *ops, + struct perf_tool *tool, struct machine *machine) { - pid_t tgid = perf_event__synthesize_comm(ops, comm_event, pid, 1, + pid_t tgid = perf_event__synthesize_comm(tool, comm_event, pid, 1, process, machine); if (tgid == -1) return -1; - return perf_event__synthesize_mmap_events(ops, mmap_event, pid, tgid, + return perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid, process, machine); } -int perf_event__synthesize_thread_map(struct perf_event_ops *ops, +int perf_event__synthesize_thread_map(struct perf_tool *tool, struct thread_map *threads, perf_event__handler_t process, struct machine *machine) @@ -293,7 +293,7 @@ int perf_event__synthesize_thread_map(struct perf_event_ops *ops, for (thread = 0; thread < threads->nr; ++thread) { if (__event__synthesize_thread(comm_event, mmap_event, threads->map[thread], - process, ops, machine)) { + process, tool, machine)) { err = -1; break; } @@ -305,7 +305,7 @@ out: return err; } -int perf_event__synthesize_threads(struct perf_event_ops *ops, +int perf_event__synthesize_threads(struct perf_tool *tool, perf_event__handler_t process, struct machine *machine) { @@ -334,7 +334,7 @@ int perf_event__synthesize_threads(struct perf_event_ops *ops, continue; __event__synthesize_thread(comm_event, mmap_event, pid, - process, ops, machine); + process, tool, machine); } closedir(proc); @@ -369,7 +369,7 @@ static int find_symbol_cb(void *arg, const char *name, char type, return 1; } -int perf_event__synthesize_kernel_mmap(struct perf_event_ops *ops, +int perf_event__synthesize_kernel_mmap(struct perf_tool *tool, perf_event__handler_t process, struct machine *machine, const char *symbol_name) @@ -427,13 +427,13 @@ int perf_event__synthesize_kernel_mmap(struct perf_event_ops *ops, event->mmap.len = map->end - event->mmap.start; event->mmap.pid = machine->pid; - err = process(ops, event, &synth_sample, machine); + err = process(tool, event, &synth_sample, machine); free(event); return err; } -int perf_event__process_comm(struct perf_event_ops *ops __used, +int perf_event__process_comm(struct perf_tool *tool __used, union perf_event *event, struct perf_sample *sample __used, struct machine *machine) @@ -450,7 +450,7 @@ int perf_event__process_comm(struct perf_event_ops *ops __used, return 0; } -int perf_event__process_lost(struct perf_event_ops *ops __used, +int perf_event__process_lost(struct perf_tool *tool __used, union perf_event *event, struct perf_sample *sample __used, struct machine *machine __used) @@ -473,7 +473,7 @@ static void perf_event__set_kernel_mmap_len(union perf_event *event, maps[MAP__FUNCTION]->end = ~0ULL; } -static int perf_event__process_kernel_mmap(struct perf_event_ops *ops __used, +static int perf_event__process_kernel_mmap(struct perf_tool *tool __used, union perf_event *event, struct machine *machine) { @@ -566,7 +566,7 @@ out_problem: return -1; } -int perf_event__process_mmap(struct perf_event_ops *ops, +int perf_event__process_mmap(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample __used, struct machine *machine) @@ -582,7 +582,7 @@ int perf_event__process_mmap(struct perf_event_ops *ops, if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL || cpumode == PERF_RECORD_MISC_KERNEL) { - ret = perf_event__process_kernel_mmap(ops, event, machine); + ret = perf_event__process_kernel_mmap(tool, event, machine); if (ret < 0) goto out_problem; return 0; @@ -606,7 +606,7 @@ out_problem: return 0; } -int perf_event__process_task(struct perf_event_ops *ops __used, +int perf_event__process_task(struct perf_tool *tool __used, union perf_event *event, struct perf_sample *sample __used, struct machine *machine) @@ -631,22 +631,22 @@ int perf_event__process_task(struct perf_event_ops *ops __used, return 0; } -int perf_event__process(struct perf_event_ops *ops, union perf_event *event, +int perf_event__process(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, struct machine *machine) { switch (event->header.type) { case PERF_RECORD_COMM: - perf_event__process_comm(ops, event, sample, machine); + perf_event__process_comm(tool, event, sample, machine); break; case PERF_RECORD_MMAP: - perf_event__process_mmap(ops, event, sample, machine); + perf_event__process_mmap(tool, event, sample, machine); break; case PERF_RECORD_FORK: case PERF_RECORD_EXIT: - perf_event__process_task(ops, event, sample, machine); + perf_event__process_task(tool, event, sample, machine); break; case PERF_RECORD_LOST: - perf_event__process_lost(ops, event, sample, machine); + perf_event__process_lost(tool, event, sample, machine); default: break; } diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 1564877e870..d8499e7cf64 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -141,47 +141,47 @@ union perf_event { void perf_event__print_totals(void); -struct perf_event_ops; +struct perf_tool; struct thread_map; -typedef int (*perf_event__handler_t)(struct perf_event_ops *ops, +typedef int (*perf_event__handler_t)(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, struct machine *machine); -int perf_event__synthesize_thread_map(struct perf_event_ops *ops, +int perf_event__synthesize_thread_map(struct perf_tool *tool, struct thread_map *threads, perf_event__handler_t process, struct machine *machine); -int perf_event__synthesize_threads(struct perf_event_ops *ops, +int perf_event__synthesize_threads(struct perf_tool *tool, perf_event__handler_t process, struct machine *machine); -int perf_event__synthesize_kernel_mmap(struct perf_event_ops *ops, +int perf_event__synthesize_kernel_mmap(struct perf_tool *tool, perf_event__handler_t process, struct machine *machine, const char *symbol_name); -int perf_event__synthesize_modules(struct perf_event_ops *ops, +int perf_event__synthesize_modules(struct perf_tool *tool, perf_event__handler_t process, struct machine *machine); -int perf_event__process_comm(struct perf_event_ops *ops, +int perf_event__process_comm(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, struct machine *machine); -int perf_event__process_lost(struct perf_event_ops *ops, +int perf_event__process_lost(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, struct machine *machine); -int perf_event__process_mmap(struct perf_event_ops *ops, +int perf_event__process_mmap(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, struct machine *machine); -int perf_event__process_task(struct perf_event_ops *ops, +int perf_event__process_task(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, struct machine *machine); -int perf_event__process(struct perf_event_ops *ops, +int perf_event__process(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, struct machine *machine); diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index db280d6ca89..9272f3a20ca 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -2070,7 +2070,7 @@ out_delete_evlist: return -ENOMEM; } -int perf_event__synthesize_attr(struct perf_event_ops *ops, +int perf_event__synthesize_attr(struct perf_tool *tool, struct perf_event_attr *attr, u16 ids, u64 *id, perf_event__handler_t process) { @@ -2094,14 +2094,14 @@ int perf_event__synthesize_attr(struct perf_event_ops *ops, ev->attr.header.type = PERF_RECORD_HEADER_ATTR; ev->attr.header.size = size; - err = process(ops, ev, NULL, NULL); + err = process(tool, ev, NULL, NULL); free(ev); return err; } -int perf_event__synthesize_attrs(struct perf_event_ops *ops, +int perf_event__synthesize_attrs(struct perf_tool *tool, struct perf_session *session, perf_event__handler_t process) { @@ -2109,7 +2109,7 @@ int perf_event__synthesize_attrs(struct perf_event_ops *ops, int err = 0; list_for_each_entry(attr, &session->evlist->entries, node) { - err = perf_event__synthesize_attr(ops, &attr->attr, attr->ids, + err = perf_event__synthesize_attr(tool, &attr->attr, attr->ids, attr->id, process); if (err) { pr_debug("failed to create perf header attribute\n"); @@ -2157,7 +2157,7 @@ int perf_event__process_attr(union perf_event *event, return 0; } -int perf_event__synthesize_event_type(struct perf_event_ops *ops, +int perf_event__synthesize_event_type(struct perf_tool *tool, u64 event_id, char *name, perf_event__handler_t process, struct machine *machine) @@ -2178,12 +2178,12 @@ int perf_event__synthesize_event_type(struct perf_event_ops *ops, ev.event_type.header.size = sizeof(ev.event_type) - (sizeof(ev.event_type.event_type.name) - size); - err = process(ops, &ev, NULL, machine); + err = process(tool, &ev, NULL, machine); return err; } -int perf_event__synthesize_event_types(struct perf_event_ops *ops, +int perf_event__synthesize_event_types(struct perf_tool *tool, perf_event__handler_t process, struct machine *machine) { @@ -2193,7 +2193,7 @@ int perf_event__synthesize_event_types(struct perf_event_ops *ops, for (i = 0; i < event_count; i++) { type = &events[i]; - err = perf_event__synthesize_event_type(ops, type->event_id, + err = perf_event__synthesize_event_type(tool, type->event_id, type->name, process, machine); if (err) { @@ -2205,7 +2205,7 @@ int perf_event__synthesize_event_types(struct perf_event_ops *ops, return err; } -int perf_event__process_event_type(struct perf_event_ops *ops __unused, +int perf_event__process_event_type(struct perf_tool *tool __unused, union perf_event *event) { if (perf_header__push_event(event->event_type.event_type.event_id, @@ -2215,7 +2215,7 @@ int perf_event__process_event_type(struct perf_event_ops *ops __unused, return 0; } -int perf_event__synthesize_tracing_data(struct perf_event_ops *ops, int fd, +int perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd, struct perf_evlist *evlist, perf_event__handler_t process) { @@ -2248,7 +2248,7 @@ int perf_event__synthesize_tracing_data(struct perf_event_ops *ops, int fd, ev.tracing_data.header.size = sizeof(ev.tracing_data); ev.tracing_data.size = aligned_size; - process(ops, &ev, NULL, NULL); + process(tool, &ev, NULL, NULL); /* * The put function will copy all the tracing data @@ -2290,7 +2290,7 @@ int perf_event__process_tracing_data(union perf_event *event, return size_read + padding; } -int perf_event__synthesize_build_id(struct perf_event_ops *ops, +int perf_event__synthesize_build_id(struct perf_tool *tool, struct dso *pos, u16 misc, perf_event__handler_t process, struct machine *machine) @@ -2313,12 +2313,12 @@ int perf_event__synthesize_build_id(struct perf_event_ops *ops, ev.build_id.header.size = sizeof(ev.build_id) + len; memcpy(&ev.build_id.filename, pos->long_name, pos->long_name_len); - err = process(ops, &ev, NULL, machine); + err = process(tool, &ev, NULL, machine); return err; } -int perf_event__process_build_id(struct perf_event_ops *ops __used, +int perf_event__process_build_id(struct perf_tool *tool __used, union perf_event *event, struct perf_session *session) { diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index a604962fc43..09365b32098 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h @@ -97,35 +97,35 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir, const char *name, bool is_kallsyms); int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir); -int perf_event__synthesize_attr(struct perf_event_ops *ops, +int perf_event__synthesize_attr(struct perf_tool *tool, struct perf_event_attr *attr, u16 ids, u64 *id, perf_event__handler_t process); -int perf_event__synthesize_attrs(struct perf_event_ops *ops, +int perf_event__synthesize_attrs(struct perf_tool *tool, struct perf_session *session, perf_event__handler_t process); int perf_event__process_attr(union perf_event *event, struct perf_evlist **pevlist); -int perf_event__synthesize_event_type(struct perf_event_ops *ops, +int perf_event__synthesize_event_type(struct perf_tool *tool, u64 event_id, char *name, perf_event__handler_t process, struct machine *machine); -int perf_event__synthesize_event_types(struct perf_event_ops *ops, +int perf_event__synthesize_event_types(struct perf_tool *tool, perf_event__handler_t process, struct machine *machine); -int perf_event__process_event_type(struct perf_event_ops *ops, +int perf_event__process_event_type(struct perf_tool *tool, union perf_event *event); -int perf_event__synthesize_tracing_data(struct perf_event_ops *ops, +int perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd, struct perf_evlist *evlist, perf_event__handler_t process); int perf_event__process_tracing_data(union perf_event *event, struct perf_session *session); -int perf_event__synthesize_build_id(struct perf_event_ops *ops, +int perf_event__synthesize_build_id(struct perf_tool *tool, struct dso *pos, u16 misc, perf_event__handler_t process, struct machine *machine); -int perf_event__process_build_id(struct perf_event_ops *ops, +int perf_event__process_build_id(struct perf_tool *tool, union perf_event *event, struct perf_session *session); diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index be33606386b..7d159088c4a 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -10,6 +10,7 @@ #include "evlist.h" #include "evsel.h" #include "session.h" +#include "tool.h" #include "sort.h" #include "util.h" #include "cpumap.h" @@ -104,7 +105,7 @@ static void perf_session__destroy_kernel_maps(struct perf_session *self) struct perf_session *perf_session__new(const char *filename, int mode, bool force, bool repipe, - struct perf_event_ops *ops) + struct perf_tool *tool) { size_t len = filename ? strlen(filename) + 1 : 0; struct perf_session *self = zalloc(sizeof(*self) + len); @@ -142,10 +143,10 @@ struct perf_session *perf_session__new(const char *filename, int mode, goto out_delete; } - if (ops && ops->ordering_requires_timestamps && - ops->ordered_samples && !self->sample_id_all) { + if (tool && tool->ordering_requires_timestamps && + tool->ordered_samples && !self->sample_id_all) { dump_printf("WARNING: No sample_id_all support, falling back to unordered processing\n"); - ops->ordered_samples = false; + tool->ordered_samples = false; } out: @@ -285,7 +286,7 @@ static int process_event_synth_attr_stub(union perf_event *event __used, return 0; } -static int process_event_sample_stub(struct perf_event_ops *ops __used, +static int process_event_sample_stub(struct perf_tool *tool __used, union perf_event *event __used, struct perf_sample *sample __used, struct perf_evsel *evsel __used, @@ -295,7 +296,7 @@ static int process_event_sample_stub(struct perf_event_ops *ops __used, return 0; } -static int process_event_stub(struct perf_event_ops *ops __used, +static int process_event_stub(struct perf_tool *tool __used, union perf_event *event __used, struct perf_sample *sample __used, struct machine *machine __used) @@ -304,7 +305,7 @@ static int process_event_stub(struct perf_event_ops *ops __used, return 0; } -static int process_finished_round_stub(struct perf_event_ops *ops __used, +static int process_finished_round_stub(struct perf_tool *tool __used, union perf_event *event __used, struct perf_session *perf_session __used) { @@ -312,50 +313,50 @@ static int process_finished_round_stub(struct perf_event_ops *ops __used, return 0; } -static int process_event_type_stub(struct perf_event_ops *ops __used, +static int process_event_type_stub(struct perf_tool *tool __used, union perf_event *event __used) { dump_printf(": unhandled!\n"); return 0; } -static int process_finished_round(struct perf_event_ops *ops, +static int process_finished_round(struct perf_tool *tool, union perf_event *event, struct perf_session *session); -static void perf_event_ops__fill_defaults(struct perf_event_ops *handler) +static void perf_tool__fill_defaults(struct perf_tool *tool) { - if (handler->sample == NULL) - handler->sample = process_event_sample_stub; - if (handler->mmap == NULL) - handler->mmap = process_event_stub; - if (handler->comm == NULL) - handler->comm = process_event_stub; - if (handler->fork == NULL) - handler->fork = process_event_stub; - if (handler->exit == NULL) - handler->exit = process_event_stub; - if (handler->lost == NULL) - handler->lost = perf_event__process_lost; - if (handler->read == NULL) - handler->read = process_event_sample_stub; - if (handler->throttle == NULL) - handler->throttle = process_event_stub; - if (handler->unthrottle == NULL) - handler->unthrottle = process_event_stub; - if (handler->attr == NULL) - handler->attr = process_event_synth_attr_stub; - if (handler->event_type == NULL) - handler->event_type = process_event_type_stub; - if (handler->tracing_data == NULL) - handler->tracing_data = process_event_synth_tracing_data_stub; - if (handler->build_id == NULL) - handler->build_id = process_finished_round_stub; - if (handler->finished_round == NULL) { - if (handler->ordered_samples) - handler->finished_round = process_finished_round; + if (tool->sample == NULL) + tool->sample = process_event_sample_stub; + if (tool->mmap == NULL) + tool->mmap = process_event_stub; + if (tool->comm == NULL) + tool->comm = process_event_stub; + if (tool->fork == NULL) + tool->fork = process_event_stub; + if (tool->exit == NULL) + tool->exit = process_event_stub; + if (tool->lost == NULL) + tool->lost = perf_event__process_lost; + if (tool->read == NULL) + tool->read = process_event_sample_stub; + if (tool->throttle == NULL) + tool->throttle = process_event_stub; + if (tool->unthrottle == NULL) + tool->unthrottle = process_event_stub; + if (tool->attr == NULL) + tool->attr = process_event_synth_attr_stub; + if (tool->event_type == NULL) + tool->event_type = process_event_type_stub; + if (tool->tracing_data == NULL) + tool->tracing_data = process_event_synth_tracing_data_stub; + if (tool->build_id == NULL) + tool->build_id = process_finished_round_stub; + if (tool->finished_round == NULL) { + if (tool->ordered_samples) + tool->finished_round = process_finished_round; else - handler->finished_round = process_finished_round_stub; + tool->finished_round = process_finished_round_stub; } } @@ -487,11 +488,11 @@ static void perf_session_free_sample_buffers(struct perf_session *session) static int perf_session_deliver_event(struct perf_session *session, union perf_event *event, struct perf_sample *sample, - struct perf_event_ops *ops, + struct perf_tool *tool, u64 file_offset); static void flush_sample_queue(struct perf_session *s, - struct perf_event_ops *ops) + struct perf_tool *tool) { struct ordered_samples *os = &s->ordered_samples; struct list_head *head = &os->samples; @@ -502,7 +503,7 @@ static void flush_sample_queue(struct perf_session *s, unsigned idx = 0, progress_next = os->nr_samples / 16; int ret; - if (!ops->ordered_samples || !limit) + if (!tool->ordered_samples || !limit) return; list_for_each_entry_safe(iter, tmp, head, list) { @@ -513,7 +514,7 @@ static void flush_sample_queue(struct perf_session *s, if (ret) pr_err("Can't parse sample, err = %d\n", ret); else - perf_session_deliver_event(s, iter->event, &sample, ops, + perf_session_deliver_event(s, iter->event, &sample, tool, iter->file_offset); os->last_flush = iter->timestamp; @@ -575,11 +576,11 @@ static void flush_sample_queue(struct perf_session *s, * Flush every events below timestamp 7 * etc... */ -static int process_finished_round(struct perf_event_ops *ops, +static int process_finished_round(struct perf_tool *tool, union perf_event *event __used, struct perf_session *session) { - flush_sample_queue(session, ops); + flush_sample_queue(session, tool); session->ordered_samples.next_flush = session->ordered_samples.max_timestamp; return 0; @@ -749,7 +750,7 @@ static struct machine * static int perf_session_deliver_event(struct perf_session *session, union perf_event *event, struct perf_sample *sample, - struct perf_event_ops *ops, + struct perf_tool *tool, u64 file_offset) { struct perf_evsel *evsel; @@ -784,25 +785,25 @@ static int perf_session_deliver_event(struct perf_session *session, ++session->hists.stats.nr_unknown_id; return -1; } - return ops->sample(ops, event, sample, evsel, machine); + return tool->sample(tool, event, sample, evsel, machine); case PERF_RECORD_MMAP: - return ops->mmap(ops, event, sample, machine); + return tool->mmap(tool, event, sample, machine); case PERF_RECORD_COMM: - return ops->comm(ops, event, sample, machine); + return tool->comm(tool, event, sample, machine); case PERF_RECORD_FORK: - return ops->fork(ops, event, sample, machine); + return tool->fork(tool, event, sample, machine); case PERF_RECORD_EXIT: - return ops->exit(ops, event, sample, machine); + return tool->exit(tool, event, sample, machine); case PERF_RECORD_LOST: - if (ops->lost == perf_event__process_lost) + if (tool->lost == perf_event__process_lost) session->hists.stats.total_lost += event->lost.lost; - return ops->lost(ops, event, sample, machine); + return tool->lost(tool, event, sample, machine); case PERF_RECORD_READ: - return ops->read(ops, event, sample, evsel, machine); + return tool->read(tool, event, sample, evsel, machine); case PERF_RECORD_THROTTLE: - return ops->throttle(ops, event, sample, machine); + return tool->throttle(tool, event, sample, machine); case PERF_RECORD_UNTHROTTLE: - return ops->unthrottle(ops, event, sample, machine); + return tool->unthrottle(tool, event, sample, machine); default: ++session->hists.stats.nr_unknown_events; return -1; @@ -826,7 +827,7 @@ static int perf_session__preprocess_sample(struct perf_session *session, } static int perf_session__process_user_event(struct perf_session *session, union perf_event *event, - struct perf_event_ops *ops, u64 file_offset) + struct perf_tool *tool, u64 file_offset) { int err; @@ -835,20 +836,20 @@ static int perf_session__process_user_event(struct perf_session *session, union /* These events are processed right away */ switch (event->header.type) { case PERF_RECORD_HEADER_ATTR: - err = ops->attr(event, &session->evlist); + err = tool->attr(event, &session->evlist); if (err == 0) perf_session__update_sample_type(session); return err; case PERF_RECORD_HEADER_EVENT_TYPE: - return ops->event_type(ops, event); + return tool->event_type(tool, event); case PERF_RECORD_HEADER_TRACING_DATA: /* setup for reading amidst mmap */ lseek(session->fd, file_offset, SEEK_SET); - return ops->tracing_data(event, session); + return tool->tracing_data(event, session); case PERF_RECORD_HEADER_BUILD_ID: - return ops->build_id(ops, event, session); + return tool->build_id(tool, event, session); case PERF_RECORD_FINISHED_ROUND: - return ops->finished_round(ops, event, session); + return tool->finished_round(tool, event, session); default: return -EINVAL; } @@ -856,7 +857,7 @@ static int perf_session__process_user_event(struct perf_session *session, union static int perf_session__process_event(struct perf_session *session, union perf_event *event, - struct perf_event_ops *ops, + struct perf_tool *tool, u64 file_offset) { struct perf_sample sample; @@ -872,7 +873,7 @@ static int perf_session__process_event(struct perf_session *session, hists__inc_nr_events(&session->hists, event->header.type); if (event->header.type >= PERF_RECORD_USER_TYPE_START) - return perf_session__process_user_event(session, event, ops, file_offset); + return perf_session__process_user_event(session, event, tool, file_offset); /* * For all kernel events we get the sample data @@ -885,14 +886,14 @@ static int perf_session__process_event(struct perf_session *session, if (perf_session__preprocess_sample(session, event, &sample)) return 0; - if (ops->ordered_samples) { + if (tool->ordered_samples) { ret = perf_session_queue_event(session, event, &sample, file_offset); if (ret != -ETIME) return ret; } - return perf_session_deliver_event(session, event, &sample, ops, + return perf_session_deliver_event(session, event, &sample, tool, file_offset); } @@ -921,9 +922,9 @@ static struct thread *perf_session__register_idle_thread(struct perf_session *se } static void perf_session__warn_about_errors(const struct perf_session *session, - const struct perf_event_ops *ops) + const struct perf_tool *tool) { - if (ops->lost == perf_event__process_lost && + if (tool->lost == perf_event__process_lost && session->hists.stats.nr_events[PERF_RECORD_LOST] != 0) { ui__warning("Processed %d events and lost %d chunks!\n\n" "Check IO/CPU overload!\n\n", @@ -958,7 +959,7 @@ static void perf_session__warn_about_errors(const struct perf_session *session, volatile int session_done; static int __perf_session__process_pipe_events(struct perf_session *self, - struct perf_event_ops *ops) + struct perf_tool *tool) { union perf_event event; uint32_t size; @@ -967,7 +968,7 @@ static int __perf_session__process_pipe_events(struct perf_session *self, int err; void *p; - perf_event_ops__fill_defaults(ops); + perf_tool__fill_defaults(tool); head = 0; more: @@ -1004,7 +1005,7 @@ more: } if (size == 0 || - (skip = perf_session__process_event(self, &event, ops, head)) < 0) { + (skip = perf_session__process_event(self, &event, tool, head)) < 0) { dump_printf("%#" PRIx64 " [%#x]: skipping unknown header type: %d\n", head, event.header.size, event.header.type); /* @@ -1027,7 +1028,7 @@ more: done: err = 0; out_err: - perf_session__warn_about_errors(self, ops); + perf_session__warn_about_errors(self, tool); perf_session_free_sample_buffers(self); return err; } @@ -1058,7 +1059,7 @@ fetch_mmaped_event(struct perf_session *session, int __perf_session__process_events(struct perf_session *session, u64 data_offset, u64 data_size, - u64 file_size, struct perf_event_ops *ops) + u64 file_size, struct perf_tool *tool) { u64 head, page_offset, file_offset, file_pos, progress_next; int err, mmap_prot, mmap_flags, map_idx = 0; @@ -1067,7 +1068,7 @@ int __perf_session__process_events(struct perf_session *session, union perf_event *event; uint32_t size; - perf_event_ops__fill_defaults(ops); + perf_tool__fill_defaults(tool); page_size = sysconf(_SC_PAGESIZE); @@ -1122,7 +1123,7 @@ more: size = event->header.size; if (size == 0 || - perf_session__process_event(session, event, ops, file_pos) < 0) { + perf_session__process_event(session, event, tool, file_pos) < 0) { dump_printf("%#" PRIx64 " [%#x]: skipping unknown header type: %d\n", file_offset + head, event->header.size, event->header.type); @@ -1151,15 +1152,15 @@ more: err = 0; /* do the final flush for ordered samples */ session->ordered_samples.next_flush = ULLONG_MAX; - flush_sample_queue(session, ops); + flush_sample_queue(session, tool); out_err: - perf_session__warn_about_errors(session, ops); + perf_session__warn_about_errors(session, tool); perf_session_free_sample_buffers(session); return err; } int perf_session__process_events(struct perf_session *self, - struct perf_event_ops *ops) + struct perf_tool *tool) { int err; @@ -1170,9 +1171,9 @@ int perf_session__process_events(struct perf_session *self, err = __perf_session__process_events(self, self->header.data_offset, self->header.data_size, - self->size, ops); + self->size, tool); else - err = __perf_session__process_pipe_events(self, ops); + err = __perf_session__process_pipe_events(self, tool); return err; } diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 1c5823c7d6d..30e9c6b6fc3 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -53,55 +53,20 @@ struct perf_session { char filename[0]; }; -struct perf_evsel; -struct perf_event_ops; - -typedef int (*event_sample)(struct perf_event_ops *ops, - union perf_event *event, struct perf_sample *sample, - struct perf_evsel *evsel, struct machine *machine); -typedef int (*event_op)(struct perf_event_ops *ops, union perf_event *event, - struct perf_sample *sample, - struct machine *machine); -typedef int (*event_synth_op)(union perf_event *self, - struct perf_session *session); -typedef int (*event_attr_op)(union perf_event *event, - struct perf_evlist **pevlist); -typedef int (*event_simple_op)(struct perf_event_ops *ops, - union perf_event *event); -typedef int (*event_op2)(struct perf_event_ops *ops, union perf_event *event, - struct perf_session *session); - -struct perf_event_ops { - event_sample sample, - read; - event_op mmap, - comm, - fork, - exit, - lost, - throttle, - unthrottle; - event_attr_op attr; - event_synth_op tracing_data; - event_simple_op event_type; - event_op2 finished_round, - build_id; - bool ordered_samples; - bool ordering_requires_timestamps; -}; +struct perf_tool; struct perf_session *perf_session__new(const char *filename, int mode, bool force, bool repipe, - struct perf_event_ops *ops); + struct perf_tool *tool); void perf_session__delete(struct perf_session *self); void perf_event_header__bswap(struct perf_event_header *self); int __perf_session__process_events(struct perf_session *self, u64 data_offset, u64 data_size, u64 size, - struct perf_event_ops *ops); + struct perf_tool *tool); int perf_session__process_events(struct perf_session *self, - struct perf_event_ops *event_ops); + struct perf_tool *tool); int perf_session__resolve_callchain(struct perf_session *self, struct perf_evsel *evsel, struct thread *thread, @@ -142,11 +107,11 @@ struct machine *perf_session__findnew_machine(struct perf_session *self, pid_t p static inline void perf_session__process_machines(struct perf_session *self, - struct perf_event_ops *ops, + struct perf_tool *tool, machine__process_t process) { - process(&self->host_machine, ops); - return machines__process(&self->machines, process, ops); + process(&self->host_machine, tool); + return machines__process(&self->machines, process, tool); } struct thread *perf_session__findnew(struct perf_session *self, pid_t pid); diff --git a/tools/perf/util/tool.h b/tools/perf/util/tool.h new file mode 100644 index 00000000000..89ff1b551a7 --- /dev/null +++ b/tools/perf/util/tool.h @@ -0,0 +1,45 @@ +#ifndef __PERF_TOOL_H +#define __PERF_TOOL_H + +struct perf_session; +struct perf_evsel; +struct perf_tool; +struct machine; + +typedef int (*event_sample)(struct perf_tool *tool, union perf_event *event, + struct perf_sample *sample, + struct perf_evsel *evsel, struct machine *machine); + +typedef int (*event_op)(struct perf_tool *tool, union perf_event *event, + struct perf_sample *sample, struct machine *machine); + +typedef int (*event_attr_op)(union perf_event *event, + struct perf_evlist **pevlist); +typedef int (*event_simple_op)(struct perf_tool *tool, union perf_event *event); + +typedef int (*event_synth_op)(union perf_event *event, + struct perf_session *session); + +typedef int (*event_op2)(struct perf_tool *tool, union perf_event *event, + struct perf_session *session); + +struct perf_tool { + event_sample sample, + read; + event_op mmap, + comm, + fork, + exit, + lost, + throttle, + unthrottle; + event_attr_op attr; + event_synth_op tracing_data; + event_simple_op event_type; + event_op2 finished_round, + build_id; + bool ordered_samples; + bool ordering_requires_timestamps; +}; + +#endif /* __PERF_TOOL_H */ diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h index 44eda6fc6b3..40430ec5c26 100644 --- a/tools/perf/util/top.h +++ b/tools/perf/util/top.h @@ -1,16 +1,17 @@ #ifndef __PERF_TOP_H #define __PERF_TOP_H 1 +#include "tool.h" #include "types.h" -#include "session.h" -#include "../perf.h" #include +#include struct perf_evlist; struct perf_evsel; +struct perf_session; struct perf_top { - struct perf_event_ops ops; + struct perf_tool tool; struct perf_evlist *evlist; /* * Symbols will be added here in perf_event__process_sample and will -- cgit v1.2.3-70-g09d2 From 1758af10cf13d156014035b29ff50eab3773d849 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 28 Nov 2011 09:37:05 -0200 Subject: perf top: Stop using globals for tool state Use its 'perf_tool' base class instead. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-i33q40wwvk2zna8fd36ex6sm@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 464 +++++++++++++++++++++++------------------------ tools/perf/util/top.h | 16 ++ 2 files changed, 245 insertions(+), 235 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 42a7d96b4db..50ff362ff01 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -64,44 +64,6 @@ #include #include -static struct perf_top top = { - .count_filter = 5, - .delay_secs = 2, - .target_pid = -1, - .target_tid = -1, - .freq = 1000, /* 1 KHz */ -}; - -static bool system_wide = false; - -static bool use_tui, use_stdio; - -static bool sort_has_symbols; - -static bool dont_use_callchains; -static char callchain_default_opt[] = "fractal,0.5,callee"; - - -static int default_interval = 0; - -static bool kptr_restrict_warned; -static bool vmlinux_warned; -static bool inherit = false; -static int realtime_prio = 0; -static bool group = false; -static bool sample_id_all_avail = true; -static unsigned int mmap_pages = 128; - -static bool dump_symtab = false; - -static struct winsize winsize; - -static const char *sym_filter = NULL; -static int sym_pcnt_filter = 5; - -/* - * Source functions - */ void get_term_dimensions(struct winsize *ws) { @@ -125,21 +87,23 @@ void get_term_dimensions(struct winsize *ws) ws->ws_col = 80; } -static void update_print_entries(struct winsize *ws) +static void perf_top__update_print_entries(struct perf_top *top) { - top.print_entries = ws->ws_row; + top->print_entries = top->winsize.ws_row; - if (top.print_entries > 9) - top.print_entries -= 9; + if (top->print_entries > 9) + top->print_entries -= 9; } -static void sig_winch_handler(int sig __used) +static void perf_top__sig_winch(int sig __used, siginfo_t *info __used, void *arg) { - get_term_dimensions(&winsize); - update_print_entries(&winsize); + struct perf_top *top = arg; + + get_term_dimensions(&top->winsize); + perf_top__update_print_entries(top); } -static int parse_source(struct hist_entry *he) +static int perf_top__parse_source(struct perf_top *top, struct hist_entry *he) { struct symbol *sym; struct annotation *notes; @@ -181,7 +145,7 @@ static int parse_source(struct hist_entry *he) err = symbol__annotate(sym, map, 0); if (err == 0) { out_assign: - top.sym_filter_entry = he; + top->sym_filter_entry = he; } pthread_mutex_unlock(¬es->lock); @@ -194,14 +158,16 @@ static void __zero_source_counters(struct hist_entry *he) symbol__annotate_zero_histograms(sym); } -static void record_precise_ip(struct hist_entry *he, int counter, u64 ip) +static void perf_top__record_precise_ip(struct perf_top *top, + struct hist_entry *he, + int counter, u64 ip) { struct annotation *notes; struct symbol *sym; if (he == NULL || he->ms.sym == NULL || - ((top.sym_filter_entry == NULL || - top.sym_filter_entry->ms.sym != he->ms.sym) && use_browser != 1)) + ((top->sym_filter_entry == NULL || + top->sym_filter_entry->ms.sym != he->ms.sym) && use_browser != 1)) return; sym = he->ms.sym; @@ -224,8 +190,9 @@ static void record_precise_ip(struct hist_entry *he, int counter, u64 ip) pthread_mutex_unlock(¬es->lock); } -static void show_details(struct hist_entry *he) +static void perf_top__show_details(struct perf_top *top) { + struct hist_entry *he = top->sym_filter_entry; struct annotation *notes; struct symbol *symbol; int more; @@ -241,15 +208,15 @@ static void show_details(struct hist_entry *he) if (notes->src == NULL) goto out_unlock; - printf("Showing %s for %s\n", event_name(top.sym_evsel), symbol->name); - printf(" Events Pcnt (>=%d%%)\n", sym_pcnt_filter); + printf("Showing %s for %s\n", event_name(top->sym_evsel), symbol->name); + printf(" Events Pcnt (>=%d%%)\n", top->sym_pcnt_filter); - more = symbol__annotate_printf(symbol, he->ms.map, top.sym_evsel->idx, - 0, sym_pcnt_filter, top.print_entries, 4); - if (top.zero) - symbol__annotate_zero_histogram(symbol, top.sym_evsel->idx); + more = symbol__annotate_printf(symbol, he->ms.map, top->sym_evsel->idx, + 0, top->sym_pcnt_filter, top->print_entries, 4); + if (top->zero) + symbol__annotate_zero_histogram(symbol, top->sym_evsel->idx); else - symbol__annotate_decay_histogram(symbol, top.sym_evsel->idx); + symbol__annotate_decay_histogram(symbol, top->sym_evsel->idx); if (more != 0) printf("%d lines not displayed, maybe increase display entries [e]\n", more); out_unlock: @@ -273,45 +240,46 @@ static struct hist_entry *perf_evsel__add_hist_entry(struct perf_evsel *evsel, return he; } -static void print_sym_table(void) +static void perf_top__print_sym_table(struct perf_top *top) { char bf[160]; int printed = 0; - const int win_width = winsize.ws_col - 1; + const int win_width = top->winsize.ws_col - 1; puts(CONSOLE_CLEAR); - perf_top__header_snprintf(&top, bf, sizeof(bf)); + perf_top__header_snprintf(top, bf, sizeof(bf)); printf("%s\n", bf); - perf_top__reset_sample_counters(&top); + perf_top__reset_sample_counters(top); printf("%-*.*s\n", win_width, win_width, graph_dotted_line); - if (top.sym_evsel->hists.stats.nr_lost_warned != - top.sym_evsel->hists.stats.nr_events[PERF_RECORD_LOST]) { - top.sym_evsel->hists.stats.nr_lost_warned = - top.sym_evsel->hists.stats.nr_events[PERF_RECORD_LOST]; + if (top->sym_evsel->hists.stats.nr_lost_warned != + top->sym_evsel->hists.stats.nr_events[PERF_RECORD_LOST]) { + top->sym_evsel->hists.stats.nr_lost_warned = + top->sym_evsel->hists.stats.nr_events[PERF_RECORD_LOST]; color_fprintf(stdout, PERF_COLOR_RED, "WARNING: LOST %d chunks, Check IO/CPU overload", - top.sym_evsel->hists.stats.nr_lost_warned); + top->sym_evsel->hists.stats.nr_lost_warned); ++printed; } - if (top.sym_filter_entry) { - show_details(top.sym_filter_entry); + if (top->sym_filter_entry) { + perf_top__show_details(top); return; } - hists__collapse_resort_threaded(&top.sym_evsel->hists); - hists__output_resort_threaded(&top.sym_evsel->hists); - hists__decay_entries_threaded(&top.sym_evsel->hists, - top.hide_user_symbols, - top.hide_kernel_symbols); - hists__output_recalc_col_len(&top.sym_evsel->hists, winsize.ws_row - 3); + hists__collapse_resort_threaded(&top->sym_evsel->hists); + hists__output_resort_threaded(&top->sym_evsel->hists); + hists__decay_entries_threaded(&top->sym_evsel->hists, + top->hide_user_symbols, + top->hide_kernel_symbols); + hists__output_recalc_col_len(&top->sym_evsel->hists, + top->winsize.ws_row - 3); putchar('\n'); - hists__fprintf(&top.sym_evsel->hists, NULL, false, false, - winsize.ws_row - 4 - printed, win_width, stdout); + hists__fprintf(&top->sym_evsel->hists, NULL, false, false, + top->winsize.ws_row - 4 - printed, win_width, stdout); } static void prompt_integer(int *target, const char *msg) @@ -349,17 +317,17 @@ static void prompt_percent(int *target, const char *msg) *target = tmp; } -static void prompt_symbol(struct hist_entry **target, const char *msg) +static void perf_top__prompt_symbol(struct perf_top *top, const char *msg) { char *buf = malloc(0), *p; - struct hist_entry *syme = *target, *n, *found = NULL; + struct hist_entry *syme = top->sym_filter_entry, *n, *found = NULL; struct rb_node *next; size_t dummy = 0; /* zero counters of active symbol */ if (syme) { __zero_source_counters(syme); - *target = NULL; + top->sym_filter_entry = NULL; } fprintf(stdout, "\n%s: ", msg); @@ -370,7 +338,7 @@ static void prompt_symbol(struct hist_entry **target, const char *msg) if (p) *p = 0; - next = rb_first(&top.sym_evsel->hists.entries); + next = rb_first(&top->sym_evsel->hists.entries); while (next) { n = rb_entry(next, struct hist_entry, rb_node); if (n->ms.sym && !strcmp(buf, n->ms.sym->name)) { @@ -385,45 +353,45 @@ static void prompt_symbol(struct hist_entry **target, const char *msg) sleep(1); return; } else - parse_source(found); + perf_top__parse_source(top, found); out_free: free(buf); } -static void print_mapped_keys(void) +static void perf_top__print_mapped_keys(struct perf_top *top) { char *name = NULL; - if (top.sym_filter_entry) { - struct symbol *sym = top.sym_filter_entry->ms.sym; + if (top->sym_filter_entry) { + struct symbol *sym = top->sym_filter_entry->ms.sym; name = sym->name; } fprintf(stdout, "\nMapped keys:\n"); - fprintf(stdout, "\t[d] display refresh delay. \t(%d)\n", top.delay_secs); - fprintf(stdout, "\t[e] display entries (lines). \t(%d)\n", top.print_entries); + fprintf(stdout, "\t[d] display refresh delay. \t(%d)\n", top->delay_secs); + fprintf(stdout, "\t[e] display entries (lines). \t(%d)\n", top->print_entries); - if (top.evlist->nr_entries > 1) - fprintf(stdout, "\t[E] active event counter. \t(%s)\n", event_name(top.sym_evsel)); + if (top->evlist->nr_entries > 1) + fprintf(stdout, "\t[E] active event counter. \t(%s)\n", event_name(top->sym_evsel)); - fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", top.count_filter); + fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", top->count_filter); - fprintf(stdout, "\t[F] annotate display filter (percent). \t(%d%%)\n", sym_pcnt_filter); + fprintf(stdout, "\t[F] annotate display filter (percent). \t(%d%%)\n", top->sym_pcnt_filter); fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL"); fprintf(stdout, "\t[S] stop annotation.\n"); fprintf(stdout, "\t[K] hide kernel_symbols symbols. \t(%s)\n", - top.hide_kernel_symbols ? "yes" : "no"); + top->hide_kernel_symbols ? "yes" : "no"); fprintf(stdout, "\t[U] hide user symbols. \t(%s)\n", - top.hide_user_symbols ? "yes" : "no"); - fprintf(stdout, "\t[z] toggle sample zeroing. \t(%d)\n", top.zero ? 1 : 0); + top->hide_user_symbols ? "yes" : "no"); + fprintf(stdout, "\t[z] toggle sample zeroing. \t(%d)\n", top->zero ? 1 : 0); fprintf(stdout, "\t[qQ] quit.\n"); } -static int key_mapped(int c) +static int perf_top__key_mapped(struct perf_top *top, int c) { switch (c) { case 'd': @@ -439,7 +407,7 @@ static int key_mapped(int c) case 'S': return 1; case 'E': - return top.evlist->nr_entries > 1 ? 1 : 0; + return top->evlist->nr_entries > 1 ? 1 : 0; default: break; } @@ -447,13 +415,13 @@ static int key_mapped(int c) return 0; } -static void handle_keypress(int c) +static void perf_top__handle_keypress(struct perf_top *top, int c) { - if (!key_mapped(c)) { + if (!perf_top__key_mapped(top, c)) { struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; struct termios tc, save; - print_mapped_keys(); + perf_top__print_mapped_keys(top); fprintf(stdout, "\nEnter selection, or unmapped key to continue: "); fflush(stdout); @@ -468,81 +436,86 @@ static void handle_keypress(int c) c = getc(stdin); tcsetattr(0, TCSAFLUSH, &save); - if (!key_mapped(c)) + if (!perf_top__key_mapped(top, c)) return; } switch (c) { case 'd': - prompt_integer(&top.delay_secs, "Enter display delay"); - if (top.delay_secs < 1) - top.delay_secs = 1; + prompt_integer(&top->delay_secs, "Enter display delay"); + if (top->delay_secs < 1) + top->delay_secs = 1; break; case 'e': - prompt_integer(&top.print_entries, "Enter display entries (lines)"); - if (top.print_entries == 0) { - sig_winch_handler(SIGWINCH); - signal(SIGWINCH, sig_winch_handler); + prompt_integer(&top->print_entries, "Enter display entries (lines)"); + if (top->print_entries == 0) { + struct sigaction act = { + .sa_sigaction = perf_top__sig_winch, + .sa_flags = SA_SIGINFO, + }; + perf_top__sig_winch(SIGWINCH, NULL, top); + sigaction(SIGWINCH, &act, NULL); } else signal(SIGWINCH, SIG_DFL); break; case 'E': - if (top.evlist->nr_entries > 1) { + if (top->evlist->nr_entries > 1) { /* Select 0 as the default event: */ int counter = 0; fprintf(stderr, "\nAvailable events:"); - list_for_each_entry(top.sym_evsel, &top.evlist->entries, node) - fprintf(stderr, "\n\t%d %s", top.sym_evsel->idx, event_name(top.sym_evsel)); + list_for_each_entry(top->sym_evsel, &top->evlist->entries, node) + fprintf(stderr, "\n\t%d %s", top->sym_evsel->idx, event_name(top->sym_evsel)); prompt_integer(&counter, "Enter details event counter"); - if (counter >= top.evlist->nr_entries) { - top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node); - fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(top.sym_evsel)); + if (counter >= top->evlist->nr_entries) { + top->sym_evsel = list_entry(top->evlist->entries.next, struct perf_evsel, node); + fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(top->sym_evsel)); sleep(1); break; } - list_for_each_entry(top.sym_evsel, &top.evlist->entries, node) - if (top.sym_evsel->idx == counter) + list_for_each_entry(top->sym_evsel, &top->evlist->entries, node) + if (top->sym_evsel->idx == counter) break; } else - top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node); + top->sym_evsel = list_entry(top->evlist->entries.next, struct perf_evsel, node); break; case 'f': - prompt_integer(&top.count_filter, "Enter display event count filter"); + prompt_integer(&top->count_filter, "Enter display event count filter"); break; case 'F': - prompt_percent(&sym_pcnt_filter, "Enter details display event filter (percent)"); + prompt_percent(&top->sym_pcnt_filter, + "Enter details display event filter (percent)"); break; case 'K': - top.hide_kernel_symbols = !top.hide_kernel_symbols; + top->hide_kernel_symbols = !top->hide_kernel_symbols; break; case 'q': case 'Q': printf("exiting.\n"); - if (dump_symtab) - perf_session__fprintf_dsos(top.session, stderr); + if (top->dump_symtab) + perf_session__fprintf_dsos(top->session, stderr); exit(0); case 's': - prompt_symbol(&top.sym_filter_entry, "Enter details symbol"); + perf_top__prompt_symbol(top, "Enter details symbol"); break; case 'S': - if (!top.sym_filter_entry) + if (!top->sym_filter_entry) break; else { - struct hist_entry *syme = top.sym_filter_entry; + struct hist_entry *syme = top->sym_filter_entry; - top.sym_filter_entry = NULL; + top->sym_filter_entry = NULL; __zero_source_counters(syme); } break; case 'U': - top.hide_user_symbols = !top.hide_user_symbols; + top->hide_user_symbols = !top->hide_user_symbols; break; case 'z': - top.zero = !top.zero; + top->zero = !top->zero; break; default: break; @@ -560,28 +533,30 @@ static void perf_top__sort_new_samples(void *arg) hists__collapse_resort_threaded(&t->sym_evsel->hists); hists__output_resort_threaded(&t->sym_evsel->hists); hists__decay_entries_threaded(&t->sym_evsel->hists, - top.hide_user_symbols, - top.hide_kernel_symbols); + t->hide_user_symbols, + t->hide_kernel_symbols); } -static void *display_thread_tui(void *arg __used) +static void *display_thread_tui(void *arg) { + struct perf_top *top = arg; const char *help = "For a higher level overview, try: perf top --sort comm,dso"; - perf_top__sort_new_samples(&top); - perf_evlist__tui_browse_hists(top.evlist, help, + perf_top__sort_new_samples(top); + perf_evlist__tui_browse_hists(top->evlist, help, perf_top__sort_new_samples, - &top, top.delay_secs); + top, top->delay_secs); exit_browser(0); exit(0); return NULL; } -static void *display_thread(void *arg __used) +static void *display_thread(void *arg) { struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; struct termios tc, save; + struct perf_top *top = arg; int delay_msecs, c; tcgetattr(0, &save); @@ -592,13 +567,13 @@ static void *display_thread(void *arg __used) pthread__unblock_sigwinch(); repeat: - delay_msecs = top.delay_secs * 1000; + delay_msecs = top->delay_secs * 1000; tcsetattr(0, TCSANOW, &tc); /* trash return*/ getc(stdin); while (1) { - print_sym_table(); + perf_top__print_sym_table(top); /* * Either timeout expired or we got an EINTR due to SIGWINCH, * refresh screen in both cases. @@ -618,7 +593,7 @@ process_hotkey: c = getc(stdin); tcsetattr(0, TCSAFLUSH, &save); - handle_keypress(c); + perf_top__handle_keypress(top, c); goto repeat; return NULL; @@ -670,11 +645,13 @@ static int symbol_filter(struct map *map __used, struct symbol *sym) return 0; } -static void perf_event__process_sample(const union perf_event *event, +static void perf_event__process_sample(struct perf_tool *tool, + const union perf_event *event, struct perf_evsel *evsel, struct perf_sample *sample, struct machine *machine) { + struct perf_top *top = container_of(tool, struct perf_top, tool); struct symbol *parent = NULL; u64 ip = event->ip.ip; struct addr_location al; @@ -687,14 +664,14 @@ static void perf_event__process_sample(const union perf_event *event, } if (event->header.misc & PERF_RECORD_MISC_EXACT_IP) - top.exact_samples++; + top->exact_samples++; if (perf_event__preprocess_sample(event, machine, &al, sample, symbol_filter) < 0 || al.filtered) return; - if (!kptr_restrict_warned && + if (!top->kptr_restrict_warned && symbol_conf.kptr_restrict && al.cpumode == PERF_RECORD_MISC_KERNEL) { ui__warning( @@ -705,7 +682,7 @@ static void perf_event__process_sample(const union perf_event *event, " modules" : ""); if (use_browser <= 0) sleep(5); - kptr_restrict_warned = true; + top->kptr_restrict_warned = true; } if (al.sym == NULL) { @@ -721,7 +698,7 @@ static void perf_event__process_sample(const union perf_event *event, * --hide-kernel-symbols, even if the user specifies an * invalid --vmlinux ;-) */ - if (!kptr_restrict_warned && !vmlinux_warned && + if (!top->kptr_restrict_warned && !top->vmlinux_warned && al.map == machine->vmlinux_maps[MAP__FUNCTION] && RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION])) { if (symbol_conf.vmlinux_name) { @@ -734,7 +711,7 @@ static void perf_event__process_sample(const union perf_event *event, if (use_browser <= 0) sleep(5); - vmlinux_warned = true; + top->vmlinux_warned = true; } } @@ -762,56 +739,57 @@ static void perf_event__process_sample(const union perf_event *event, return; } - if (sort_has_symbols) - record_precise_ip(he, evsel->idx, ip); + if (top->sort_has_symbols) + perf_top__record_precise_ip(top, he, evsel->idx, ip); } return; } -static void perf_session__mmap_read_idx(struct perf_session *self, int idx) +static void perf_top__mmap_read_idx(struct perf_top *top, int idx) { struct perf_sample sample; struct perf_evsel *evsel; + struct perf_session *session = top->session; union perf_event *event; struct machine *machine; u8 origin; int ret; - while ((event = perf_evlist__mmap_read(top.evlist, idx)) != NULL) { - ret = perf_session__parse_sample(self, event, &sample); + while ((event = perf_evlist__mmap_read(top->evlist, idx)) != NULL) { + ret = perf_session__parse_sample(session, event, &sample); if (ret) { pr_err("Can't parse sample, err = %d\n", ret); continue; } - evsel = perf_evlist__id2evsel(self->evlist, sample.id); + evsel = perf_evlist__id2evsel(session->evlist, sample.id); assert(evsel != NULL); origin = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; if (event->header.type == PERF_RECORD_SAMPLE) - ++top.samples; + ++top->samples; switch (origin) { case PERF_RECORD_MISC_USER: - ++top.us_samples; - if (top.hide_user_symbols) + ++top->us_samples; + if (top->hide_user_symbols) continue; - machine = perf_session__find_host_machine(self); + machine = perf_session__find_host_machine(session); break; case PERF_RECORD_MISC_KERNEL: - ++top.kernel_samples; - if (top.hide_kernel_symbols) + ++top->kernel_samples; + if (top->hide_kernel_symbols) continue; - machine = perf_session__find_host_machine(self); + machine = perf_session__find_host_machine(session); break; case PERF_RECORD_MISC_GUEST_KERNEL: - ++top.guest_kernel_samples; - machine = perf_session__find_machine(self, event->ip.pid); + ++top->guest_kernel_samples; + machine = perf_session__find_machine(session, event->ip.pid); break; case PERF_RECORD_MISC_GUEST_USER: - ++top.guest_us_samples; + ++top->guest_us_samples; /* * TODO: we don't process guest user from host side * except simple counting. @@ -822,27 +800,29 @@ static void perf_session__mmap_read_idx(struct perf_session *self, int idx) } - if (event->header.type == PERF_RECORD_SAMPLE) - perf_event__process_sample(event, evsel, &sample, machine); - else if (event->header.type < PERF_RECORD_MAX) { + if (event->header.type == PERF_RECORD_SAMPLE) { + perf_event__process_sample(&top->tool, event, evsel, + &sample, machine); + } else if (event->header.type < PERF_RECORD_MAX) { hists__inc_nr_events(&evsel->hists, event->header.type); - perf_event__process(&top.tool, event, &sample, machine); + perf_event__process(&top->tool, event, &sample, machine); } else - ++self->hists.stats.nr_unknown_events; + ++session->hists.stats.nr_unknown_events; } } -static void perf_session__mmap_read(struct perf_session *self) +static void perf_top__mmap_read(struct perf_top *top) { int i; - for (i = 0; i < top.evlist->nr_mmaps; i++) - perf_session__mmap_read_idx(self, i); + for (i = 0; i < top->evlist->nr_mmaps; i++) + perf_top__mmap_read_idx(top, i); } -static void start_counters(struct perf_evlist *evlist) +static void perf_top__start_counters(struct perf_top *top) { struct perf_evsel *counter, *first; + struct perf_evlist *evlist = top->evlist; first = list_entry(evlist->entries.next, struct perf_evsel, node); @@ -850,15 +830,15 @@ static void start_counters(struct perf_evlist *evlist) struct perf_event_attr *attr = &counter->attr; struct xyarray *group_fd = NULL; - if (group && counter != first) + if (top->group && counter != first) group_fd = first->fd; attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; - if (top.freq) { + if (top->freq) { attr->sample_type |= PERF_SAMPLE_PERIOD; attr->freq = 1; - attr->sample_freq = top.freq; + attr->sample_freq = top->freq; } if (evlist->nr_entries > 1) { @@ -871,23 +851,23 @@ static void start_counters(struct perf_evlist *evlist) attr->mmap = 1; attr->comm = 1; - attr->inherit = inherit; + attr->inherit = top->inherit; retry_sample_id: - attr->sample_id_all = sample_id_all_avail ? 1 : 0; + attr->sample_id_all = top->sample_id_all_avail ? 1 : 0; try_again: - if (perf_evsel__open(counter, top.evlist->cpus, - top.evlist->threads, group, + if (perf_evsel__open(counter, top->evlist->cpus, + top->evlist->threads, top->group, group_fd) < 0) { int err = errno; if (err == EPERM || err == EACCES) { ui__error_paranoid(); goto out_err; - } else if (err == EINVAL && sample_id_all_avail) { + } else if (err == EINVAL && top->sample_id_all_avail) { /* * Old kernel, no attr->sample_id_type_all field */ - sample_id_all_avail = false; + top->sample_id_all_avail = false; goto retry_sample_id; } /* @@ -921,7 +901,7 @@ try_again: } } - if (perf_evlist__mmap(evlist, mmap_pages, false) < 0) { + if (perf_evlist__mmap(evlist, top->mmap_pages, false) < 0) { ui__warning("Failed to mmap with %d (%s)\n", errno, strerror(errno)); goto out_err; @@ -934,14 +914,14 @@ out_err: exit(0); } -static int setup_sample_type(void) +static int perf_top__setup_sample_type(struct perf_top *top) { - if (!sort_has_symbols) { + if (!top->sort_has_symbols) { if (symbol_conf.use_callchain) { ui__warning("Selected -g but \"sym\" not present in --sort/-s."); return -EINVAL; } - } else if (!dont_use_callchains && callchain_param.mode != CHAIN_NONE) { + } else if (!top->dont_use_callchains && callchain_param.mode != CHAIN_NONE) { if (callchain_register_param(&callchain_param) < 0) { ui__warning("Can't register callchain params.\n"); return -EINVAL; @@ -951,7 +931,7 @@ static int setup_sample_type(void) return 0; } -static int __cmd_top(void) +static int __cmd_top(struct perf_top *top) { pthread_t thread; int ret; @@ -959,40 +939,40 @@ static int __cmd_top(void) * FIXME: perf_session__new should allow passing a O_MMAP, so that all this * mmap reading, etc is encapsulated in it. Use O_WRONLY for now. */ - top.session = perf_session__new(NULL, O_WRONLY, false, false, NULL); - if (top.session == NULL) + top->session = perf_session__new(NULL, O_WRONLY, false, false, NULL); + if (top->session == NULL) return -ENOMEM; - ret = setup_sample_type(); + ret = perf_top__setup_sample_type(top); if (ret) goto out_delete; - if (top.target_tid != -1) - perf_event__synthesize_thread_map(&top.tool, top.evlist->threads, + if (top->target_tid != -1) + perf_event__synthesize_thread_map(&top->tool, top->evlist->threads, perf_event__process, - &top.session->host_machine); + &top->session->host_machine); else - perf_event__synthesize_threads(&top.tool, perf_event__process, - &top.session->host_machine); - start_counters(top.evlist); - top.session->evlist = top.evlist; - perf_session__update_sample_type(top.session); + perf_event__synthesize_threads(&top->tool, perf_event__process, + &top->session->host_machine); + perf_top__start_counters(top); + top->session->evlist = top->evlist; + perf_session__update_sample_type(top->session); /* Wait for a minimal set of events before starting the snapshot */ - poll(top.evlist->pollfd, top.evlist->nr_fds, 100); + poll(top->evlist->pollfd, top->evlist->nr_fds, 100); - perf_session__mmap_read(top.session); + perf_top__mmap_read(top); if (pthread_create(&thread, NULL, (use_browser > 0 ? display_thread_tui : - display_thread), NULL)) { + display_thread), top)) { printf("Could not create display thread.\n"); exit(-1); } - if (realtime_prio) { + if (top->realtime_prio) { struct sched_param param; - param.sched_priority = realtime_prio; + param.sched_priority = top->realtime_prio; if (sched_setscheduler(0, SCHED_FIFO, ¶m)) { printf("Could not set realtime priority.\n"); exit(-1); @@ -1000,25 +980,25 @@ static int __cmd_top(void) } while (1) { - u64 hits = top.samples; + u64 hits = top->samples; - perf_session__mmap_read(top.session); + perf_top__mmap_read(top); - if (hits == top.samples) - ret = poll(top.evlist->pollfd, top.evlist->nr_fds, 100); + if (hits == top->samples) + ret = poll(top->evlist->pollfd, top->evlist->nr_fds, 100); } out_delete: - perf_session__delete(top.session); - top.session = NULL; + perf_session__delete(top->session); + top->session = NULL; return 0; } static int -parse_callchain_opt(const struct option *opt __used, const char *arg, - int unset) +parse_callchain_opt(const struct option *opt, const char *arg, int unset) { + struct perf_top *top = (struct perf_top *)opt->value; char *tok, *tok2; char *endptr; @@ -1026,7 +1006,7 @@ parse_callchain_opt(const struct option *opt __used, const char *arg, * --no-call-graph */ if (unset) { - dont_use_callchains = true; + top->dont_use_callchains = true; return 0; } @@ -1100,17 +1080,32 @@ static const char * const top_usage[] = { NULL }; -static const struct option options[] = { +int cmd_top(int argc, const char **argv, const char *prefix __used) +{ + struct perf_evsel *pos; + int status = -ENOMEM; + struct perf_top top = { + .count_filter = 5, + .delay_secs = 2, + .target_pid = -1, + .target_tid = -1, + .freq = 1000, /* 1 KHz */ + .sample_id_all_avail = true, + .mmap_pages = 128, + .sym_pcnt_filter = 5, + }; + char callchain_default_opt[] = "fractal,0.5,callee"; + const struct option options[] = { OPT_CALLBACK('e', "event", &top.evlist, "event", "event selector. use 'perf list' to list available events", parse_events_option), - OPT_INTEGER('c', "count", &default_interval, + OPT_INTEGER('c', "count", &top.default_interval, "event period to sample"), OPT_INTEGER('p', "pid", &top.target_pid, "profile events on existing process id"), OPT_INTEGER('t', "tid", &top.target_tid, "profile events on existing thread id"), - OPT_BOOLEAN('a', "all-cpus", &system_wide, + OPT_BOOLEAN('a', "all-cpus", &top.system_wide, "system-wide collection from all CPUs"), OPT_STRING('C', "cpu", &top.cpu_list, "cpu", "list of cpus to monitor"), @@ -1118,20 +1113,20 @@ static const struct option options[] = { "file", "vmlinux pathname"), OPT_BOOLEAN('K', "hide_kernel_symbols", &top.hide_kernel_symbols, "hide kernel symbols"), - OPT_UINTEGER('m', "mmap-pages", &mmap_pages, "number of mmap data pages"), - OPT_INTEGER('r', "realtime", &realtime_prio, + OPT_UINTEGER('m', "mmap-pages", &top.mmap_pages, "number of mmap data pages"), + OPT_INTEGER('r', "realtime", &top.realtime_prio, "collect data with this RT SCHED_FIFO priority"), OPT_INTEGER('d', "delay", &top.delay_secs, "number of seconds to delay between refreshes"), - OPT_BOOLEAN('D', "dump-symtab", &dump_symtab, + OPT_BOOLEAN('D', "dump-symtab", &top.dump_symtab, "dump the symbol table used for profiling"), OPT_INTEGER('f', "count-filter", &top.count_filter, "only display functions with more events than this"), - OPT_BOOLEAN('g', "group", &group, + OPT_BOOLEAN('g', "group", &top.group, "put the counters into a counter group"), - OPT_BOOLEAN('i', "inherit", &inherit, + OPT_BOOLEAN('i', "inherit", &top.inherit, "child tasks inherit counters"), - OPT_STRING(0, "sym-annotate", &sym_filter, "symbol name", + OPT_STRING(0, "sym-annotate", &top.sym_filter, "symbol name", "symbol to annotate"), OPT_BOOLEAN('z', "zero", &top.zero, "zero history across updates"), @@ -1141,15 +1136,15 @@ static const struct option options[] = { "display this many functions"), OPT_BOOLEAN('U', "hide_user_symbols", &top.hide_user_symbols, "hide user symbols"), - OPT_BOOLEAN(0, "tui", &use_tui, "Use the TUI interface"), - OPT_BOOLEAN(0, "stdio", &use_stdio, "Use the stdio interface"), + OPT_BOOLEAN(0, "tui", &top.use_tui, "Use the TUI interface"), + OPT_BOOLEAN(0, "stdio", &top.use_stdio, "Use the stdio interface"), OPT_INCR('v', "verbose", &verbose, "be more verbose (show counter open errors, etc)"), OPT_STRING('s', "sort", &sort_order, "key[,key2...]", "sort by key(s): pid, comm, dso, symbol, parent"), OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples, "Show a column with the number of samples"), - OPT_CALLBACK_DEFAULT('G', "call-graph", NULL, "output_type,min_percent, call_order", + OPT_CALLBACK_DEFAULT('G', "call-graph", &top, "output_type,min_percent, call_order", "Display callchains using output_type (graph, flat, fractal, or none), min percent threshold and callchain order. " "Default: fractal,0.5,callee", &parse_callchain_opt, callchain_default_opt), @@ -1168,12 +1163,7 @@ static const struct option options[] = { OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", "Specify disassembler style (e.g. -M intel for intel syntax)"), OPT_END() -}; - -int cmd_top(int argc, const char **argv, const char *prefix __used) -{ - struct perf_evsel *pos; - int status = -ENOMEM; + }; top.evlist = perf_evlist__new(NULL, NULL); if (top.evlist == NULL) @@ -1190,9 +1180,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) setup_sorting(top_usage, options); - if (use_stdio) + if (top.use_stdio) use_browser = 0; - else if (use_tui) + else if (top.use_tui) use_browser = 1; setup_browser(false); @@ -1225,10 +1215,10 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) /* * User specified count overrides default frequency. */ - if (default_interval) + if (top.default_interval) top.freq = 0; else if (top.freq) { - default_interval = top.freq; + top.default_interval = top.freq; } else { fprintf(stderr, "frequency and count are zero, aborting\n"); exit(EXIT_FAILURE); @@ -1244,7 +1234,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) if (pos->attr.sample_period) continue; - pos->attr.sample_period = default_interval; + pos->attr.sample_period = top.default_interval; } if (perf_evlist__alloc_pollfd(top.evlist) < 0 || @@ -1267,15 +1257,19 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) * Avoid annotation data structures overhead when symbols aren't on the * sort list. */ - sort_has_symbols = sort_sym.list.next != NULL; + top.sort_has_symbols = sort_sym.list.next != NULL; - get_term_dimensions(&winsize); + get_term_dimensions(&top.winsize); if (top.print_entries == 0) { - update_print_entries(&winsize); - signal(SIGWINCH, sig_winch_handler); + struct sigaction act = { + .sa_sigaction = perf_top__sig_winch, + .sa_flags = SA_SIGINFO, + }; + perf_top__update_print_entries(&top); + sigaction(SIGWINCH, &act, NULL); } - status = __cmd_top(); + status = __cmd_top(&top); out_free_fd: perf_evlist__delete(top.evlist); diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h index 40430ec5c26..a248f3c2c60 100644 --- a/tools/perf/util/top.h +++ b/tools/perf/util/top.h @@ -25,10 +25,26 @@ struct perf_top { int freq; pid_t target_pid, target_tid; bool hide_kernel_symbols, hide_user_symbols, zero; + bool system_wide; + bool use_tui, use_stdio; + bool sort_has_symbols; + bool dont_use_callchains; + bool kptr_restrict_warned; + bool vmlinux_warned; + bool inherit; + bool group; + bool sample_id_all_avail; + bool dump_symtab; const char *cpu_list; struct hist_entry *sym_filter_entry; struct perf_evsel *sym_evsel; struct perf_session *session; + struct winsize winsize; + unsigned int mmap_pages; + int default_interval; + int realtime_prio; + int sym_pcnt_filter; + const char *sym_filter; }; size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size); -- cgit v1.2.3-70-g09d2 From c8e6672035e84799e6167e933fafedc8e3256973 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Sun, 13 Nov 2011 11:30:08 -0700 Subject: perf tools: make -C consistent across commands (for cpu list arg) Currently the meaning of -C varies by perf command: for perf-top, perf-stat, perf-record it means cpu list. For perf-report it means comm list. Then perf-annotate, perf-report and perf-script use -c for cpu list. Fix annotate, report and script to use -C for cpu list to be consistent with top, stat and record. This means report needs to use -c for comm list which does introduce a backward compatibility change. v1 -> v2 - update perf-script.txt too Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1321209008-7004-1-git-send-email-dsahern@gmail.com Signed-off-by: David Ahern Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-annotate.txt | 2 +- tools/perf/Documentation/perf-report.txt | 4 ++-- tools/perf/Documentation/perf-script.txt | 2 +- tools/perf/builtin-annotate.c | 2 +- tools/perf/builtin-report.c | 4 ++-- tools/perf/builtin-script.c | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) (limited to 'tools') diff --git a/tools/perf/Documentation/perf-annotate.txt b/tools/perf/Documentation/perf-annotate.txt index fe6762ed56b..476029d3062 100644 --- a/tools/perf/Documentation/perf-annotate.txt +++ b/tools/perf/Documentation/perf-annotate.txt @@ -66,7 +66,7 @@ OPTIONS used. This interfaces starts by centering on the line with more samples, TAB/UNTAB cycles through the lines with more samples. --c:: +-C:: --cpu:: Only report samples for the list of CPUs provided. Multiple CPUs can be provided as a comma-separated list with no space: 0,1. Ranges of CPUs are specified with -: 0-2. Default is to report samples on all diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt index 212f24d672e..dc85392a5ac 100644 --- a/tools/perf/Documentation/perf-report.txt +++ b/tools/perf/Documentation/perf-report.txt @@ -39,7 +39,7 @@ OPTIONS -T:: --threads:: Show per-thread event counters --C:: +-c:: --comms=:: Only consider symbols in these comms. CSV that understands file://filename entries. @@ -128,7 +128,7 @@ OPTIONS --symfs=:: Look for files with symbols relative to this directory. --c:: +-C:: --cpu:: Only report samples for the list of CPUs provided. Multiple CPUs can be provided as a comma-separated list with no space: 0,1. Ranges of CPUs are specified with -: 0-2. Default is to report samples on all diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt index dec87ecb530..3613b0a1aff 100644 --- a/tools/perf/Documentation/perf-script.txt +++ b/tools/perf/Documentation/perf-script.txt @@ -182,7 +182,7 @@ OPTIONS --hide-call-graph:: When printing symbols do not display call chain. --c:: +-C:: --cpu:: Only report samples for the list of CPUs provided. Multiple CPUs can be provided as a comma-separated list with no space: 0,1. Ranges of CPUs are specified with -: 0-2. Default is to report samples on all diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index c01139fa4a1..d449645c5ef 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -274,7 +274,7 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __used) "print matching source lines (may be slow)"), OPT_BOOLEAN('P', "full-paths", &annotate.full_paths, "Don't shorten the displayed pathnames"), - OPT_STRING('c', "cpu", &annotate.cpu_list, "cpu", "list of cpus to profile"), + OPT_STRING('C', "cpu", &annotate.cpu_list, "cpu", "list of cpus to profile"), OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", "Look for files with symbols relative to this directory"), OPT_BOOLEAN(0, "source", &symbol_conf.annotate_src, diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index eef8e423deb..ece7c5d3f50 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -492,7 +492,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __used) "alias for inverted call graph"), OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", "only consider symbols in these dsos"), - OPT_STRING('C', "comms", &symbol_conf.comm_list_str, "comm[,comm...]", + OPT_STRING('c', "comms", &symbol_conf.comm_list_str, "comm[,comm...]", "only consider symbols in these comms"), OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]", "only consider these symbols"), @@ -506,7 +506,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __used) "Only display entries resolved to a symbol"), OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", "Look for files with symbols relative to this directory"), - OPT_STRING('c', "cpu", &report.cpu_list, "cpu", + OPT_STRING('C', "cpu", &report.cpu_list, "cpu", "list of cpus to profile"), OPT_BOOLEAN('I', "show-info", &report.show_full_info, "Display extended information about perf.data file"), diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 5f8afc65d5f..7731a09e975 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -1085,7 +1085,7 @@ static const struct option options[] = { OPT_CALLBACK('f', "fields", NULL, "str", "comma separated output fields prepend with 'type:'. Valid types: hw,sw,trace,raw. Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso,addr", parse_output_fields), - OPT_STRING('c', "cpu", &cpu_list, "cpu", "list of cpus to profile"), + OPT_STRING('C', "cpu", &cpu_list, "cpu", "list of cpus to profile"), OPT_BOOLEAN('I', "show-info", &show_full_info, "display extended information from perf.data file"), OPT_END() -- cgit v1.2.3-70-g09d2 From e7984b7bee2fca8f582f5bc2bf1e6c93420a5dd5 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Mon, 21 Nov 2011 10:02:52 -0700 Subject: perf script: Add comm filtering option Allows collecting events system wide and then pulling out events for a specific task name(s). e.g, perf script -c gnome-shell,gnome-terminal Applies on top of: https://lkml.org/lkml/2011/11/13/74 v2->v3 - update Documentation v1->v2 - use comm_list from symbol_conf Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1321894972-24246-1-git-send-email-dsahern@gmail.com Signed-off-by: David Ahern Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-script.txt | 5 +++++ tools/perf/builtin-script.c | 12 ++++++++++++ 2 files changed, 17 insertions(+) (limited to 'tools') diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt index 3613b0a1aff..7f61eaaf9ab 100644 --- a/tools/perf/Documentation/perf-script.txt +++ b/tools/perf/Documentation/perf-script.txt @@ -188,6 +188,11 @@ OPTIONS CPUs are specified with -: 0-2. Default is to report samples on all CPUs. +-c:: +--comms=:: + Only display events for these comms. CSV that understands + file://filename entries. + -I:: --show-info:: Display extended information about the perf.data file. This adds diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 7731a09e975..619d6dcaa1d 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -441,6 +441,7 @@ static int process_sample_event(struct perf_tool *tool __used, struct perf_evsel *evsel, struct machine *machine) { + struct addr_location al; struct thread *thread = machine__findnew_thread(machine, event->ip.pid); if (thread == NULL) { @@ -460,6 +461,15 @@ static int process_sample_event(struct perf_tool *tool __used, return 0; } + if (perf_event__preprocess_sample(event, machine, &al, sample, 0) < 0) { + pr_err("problem processing %d event, skipping it.\n", + event->header.type); + return -1; + } + + if (al.filtered) + return 0; + if (cpu_list && !test_bit(sample->cpu, cpu_bitmap)) return 0; @@ -1086,6 +1096,8 @@ static const struct option options[] = { "comma separated output fields prepend with 'type:'. Valid types: hw,sw,trace,raw. Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso,addr", parse_output_fields), OPT_STRING('C', "cpu", &cpu_list, "cpu", "list of cpus to profile"), + OPT_STRING('c', "comms", &symbol_conf.comm_list_str, "comm[,comm...]", + "only display events for these comms"), OPT_BOOLEAN('I', "show-info", &show_full_info, "display extended information from perf.data file"), OPT_END() -- cgit v1.2.3-70-g09d2 From ee29be625bd7b115d45eba4b0526ff3e24bf3ca0 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 28 Nov 2011 17:57:40 -0200 Subject: perf tools: Save some loops using perf_evlist__id2evsel Since we already ask for PERF_SAMPLE_ID and use it to quickly find the associated evsel, add handler func + data to struct perf_evsel to avoid using chains of if(strcmp(event_name)) and also to avoid all the linear list searches via trace_event_find. To demonstrate the technique convert 'perf sched' to it: # perf sched record sleep 5m And then: Performance counter stats for '/tmp/oldperf sched lat': 646.929438 task-clock # 0.999 CPUs utilized 9 context-switches # 0.000 M/sec 0 CPU-migrations # 0.000 M/sec 20,901 page-faults # 0.032 M/sec 1,290,144,450 cycles # 1.994 GHz stalled-cycles-frontend stalled-cycles-backend 1,606,158,439 instructions # 1.24 insns per cycle 339,088,395 branches # 524.151 M/sec 4,550,735 branch-misses # 1.34% of all branches 0.647524759 seconds time elapsed Versus: Performance counter stats for 'perf sched lat': 473.564691 task-clock # 0.999 CPUs utilized 9 context-switches # 0.000 M/sec 0 CPU-migrations # 0.000 M/sec 20,903 page-faults # 0.044 M/sec 944,367,984 cycles # 1.994 GHz stalled-cycles-frontend stalled-cycles-backend 1,442,385,571 instructions # 1.53 insns per cycle 308,383,106 branches # 651.195 M/sec 4,481,784 branch-misses # 1.45% of all branches 0.474215751 seconds time elapsed [root@emilia ~]# Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-1kbzpl74lwi6lavpqke2u2p3@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-sched.c | 149 ++++++++++++++++++++++----------------------- tools/perf/util/evlist.c | 42 +++++++++++++ tools/perf/util/evlist.h | 11 ++++ tools/perf/util/evsel.h | 4 ++ tools/perf/util/tool.h | 5 ++ 5 files changed, 136 insertions(+), 75 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index 0ee868e6f63..6284ed2317f 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -2,6 +2,7 @@ #include "perf.h" #include "util/util.h" +#include "util/evlist.h" #include "util/cache.h" #include "util/evsel.h" #include "util/symbol.h" @@ -1358,12 +1359,13 @@ static void sort_lat(void) static struct trace_sched_handler *trace_handler; static void -process_sched_wakeup_event(void *data, struct machine *machine, +process_sched_wakeup_event(struct perf_tool *tool __used, struct event *event, - int cpu __used, - u64 timestamp __used, - struct thread *thread __used) + struct perf_sample *sample, + struct machine *machine, + struct thread *thread) { + void *data = sample->raw_data; struct trace_wakeup_event wakeup_event; FILL_COMMON_FIELDS(wakeup_event, event, data); @@ -1376,7 +1378,7 @@ process_sched_wakeup_event(void *data, struct machine *machine, if (trace_handler->wakeup_event) trace_handler->wakeup_event(&wakeup_event, machine, event, - cpu, timestamp, thread); + sample->cpu, sample->time, thread); } /* @@ -1471,14 +1473,15 @@ map_switch_event(struct trace_switch_event *switch_event, } } - static void -process_sched_switch_event(void *data, struct machine *machine, +process_sched_switch_event(struct perf_tool *tool __used, struct event *event, - int this_cpu, - u64 timestamp __used, - struct thread *thread __used) + struct perf_sample *sample, + struct machine *machine, + struct thread *thread) { + int this_cpu = sample->cpu; + void *data = sample->raw_data; struct trace_switch_event switch_event; FILL_COMMON_FIELDS(switch_event, event, data); @@ -1501,18 +1504,19 @@ process_sched_switch_event(void *data, struct machine *machine, } if (trace_handler->switch_event) trace_handler->switch_event(&switch_event, machine, event, - this_cpu, timestamp, thread); + this_cpu, sample->time, thread); curr_pid[this_cpu] = switch_event.next_pid; } static void -process_sched_runtime_event(void *data, struct machine *machine, - struct event *event, - int cpu __used, - u64 timestamp __used, - struct thread *thread __used) +process_sched_runtime_event(struct perf_tool *tool __used, + struct event *event, + struct perf_sample *sample, + struct machine *machine, + struct thread *thread) { + void *data = sample->raw_data; struct trace_runtime_event runtime_event; FILL_ARRAY(runtime_event, comm, event, data); @@ -1521,16 +1525,18 @@ process_sched_runtime_event(void *data, struct machine *machine, FILL_FIELD(runtime_event, vruntime, event, data); if (trace_handler->runtime_event) - trace_handler->runtime_event(&runtime_event, machine, event, cpu, timestamp, thread); + trace_handler->runtime_event(&runtime_event, machine, event, + sample->cpu, sample->time, thread); } static void -process_sched_fork_event(void *data, +process_sched_fork_event(struct perf_tool *tool __used, struct event *event, - int cpu __used, - u64 timestamp __used, - struct thread *thread __used) + struct perf_sample *sample, + struct machine *machine __used, + struct thread *thread) { + void *data = sample->raw_data; struct trace_fork_event fork_event; FILL_COMMON_FIELDS(fork_event, event, data); @@ -1542,13 +1548,14 @@ process_sched_fork_event(void *data, if (trace_handler->fork_event) trace_handler->fork_event(&fork_event, event, - cpu, timestamp, thread); + sample->cpu, sample->time, thread); } static void -process_sched_exit_event(struct event *event, - int cpu __used, - u64 timestamp __used, +process_sched_exit_event(struct perf_tool *tool __used, + struct event *event, + struct perf_sample *sample __used, + struct machine *machine __used, struct thread *thread __used) { if (verbose) @@ -1556,12 +1563,13 @@ process_sched_exit_event(struct event *event, } static void -process_sched_migrate_task_event(void *data, struct machine *machine, - struct event *event, - int cpu __used, - u64 timestamp __used, - struct thread *thread __used) +process_sched_migrate_task_event(struct perf_tool *tool __used, + struct event *event, + struct perf_sample *sample, + struct machine *machine, + struct thread *thread) { + void *data = sample->raw_data; struct trace_migrate_task_event migrate_task_event; FILL_COMMON_FIELDS(migrate_task_event, event, data); @@ -1573,67 +1581,46 @@ process_sched_migrate_task_event(void *data, struct machine *machine, if (trace_handler->migrate_task_event) trace_handler->migrate_task_event(&migrate_task_event, machine, - event, cpu, timestamp, thread); + event, sample->cpu, + sample->time, thread); } -static void process_raw_event(union perf_event *raw_event __used, - struct machine *machine, void *data, int cpu, - u64 timestamp, struct thread *thread) -{ - struct event *event; - int type; - - - type = trace_parse_common_type(data); - event = trace_find_event(type); - - if (!strcmp(event->name, "sched_switch")) - process_sched_switch_event(data, machine, event, cpu, timestamp, thread); - if (!strcmp(event->name, "sched_stat_runtime")) - process_sched_runtime_event(data, machine, event, cpu, timestamp, thread); - if (!strcmp(event->name, "sched_wakeup")) - process_sched_wakeup_event(data, machine, event, cpu, timestamp, thread); - if (!strcmp(event->name, "sched_wakeup_new")) - process_sched_wakeup_event(data, machine, event, cpu, timestamp, thread); - if (!strcmp(event->name, "sched_process_fork")) - process_sched_fork_event(data, event, cpu, timestamp, thread); - if (!strcmp(event->name, "sched_process_exit")) - process_sched_exit_event(event, cpu, timestamp, thread); - if (!strcmp(event->name, "sched_migrate_task")) - process_sched_migrate_task_event(data, machine, event, cpu, timestamp, thread); -} +typedef void (*tracepoint_handler)(struct perf_tool *tool, struct event *event, + struct perf_sample *sample, + struct machine *machine, + struct thread *thread); -static int process_sample_event(struct perf_tool *tool __used, - union perf_event *event, - struct perf_sample *sample, - struct perf_evsel *evsel, - struct machine *machine) +static int perf_sched__process_tracepoint_sample(struct perf_tool *tool, + union perf_event *event __used, + struct perf_sample *sample, + struct perf_evsel *evsel, + struct machine *machine) { - struct thread *thread; - - if (!(evsel->attr.sample_type & PERF_SAMPLE_RAW)) - return 0; + struct thread *thread = machine__findnew_thread(machine, sample->pid); - thread = machine__findnew_thread(machine, sample->pid); if (thread == NULL) { - pr_debug("problem processing %d event, skipping it.\n", - event->header.type); + pr_debug("problem processing %s event, skipping it.\n", + evsel->name); return -1; } - dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); + evsel->hists.stats.total_period += sample->period; + hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); - if (profile_cpu != -1 && profile_cpu != (int)sample->cpu) - return 0; + if (evsel->handler.func != NULL) { + tracepoint_handler f = evsel->handler.func; - process_raw_event(event, machine, sample->raw_data, sample->cpu, - sample->time, thread); + if (evsel->handler.data == NULL) + evsel->handler.data = trace_find_event(evsel->attr.config); + + f(tool, evsel->handler.data, sample, machine, thread); + } return 0; } static struct perf_tool perf_sched = { - .sample = process_sample_event, + .sample = perf_sched__process_tracepoint_sample, .comm = perf_event__process_comm, .lost = perf_event__process_lost, .fork = perf_event__process_task, @@ -1643,11 +1630,23 @@ static struct perf_tool perf_sched = { static void read_events(bool destroy, struct perf_session **psession) { int err = -EINVAL; + const struct perf_evsel_str_handler handlers[] = { + { "sched:sched_switch", process_sched_switch_event, }, + { "sched:sched_stat_runtime", process_sched_runtime_event, }, + { "sched:sched_wakeup", process_sched_wakeup_event, }, + { "sched:sched_wakeup_new", process_sched_wakeup_event, }, + { "sched:sched_process_fork", process_sched_fork_event, }, + { "sched:sched_process_exit", process_sched_exit_event, }, + { "sched:sched_migrate_task", process_sched_migrate_task_event, }, + }; struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0, false, &perf_sched); if (session == NULL) die("No Memory"); + err = perf_evlist__set_tracepoints_handlers_array(session->evlist, handlers); + assert(err == 0); + if (perf_session__has_traces(session, "record -R")) { err = perf_session__process_events(session, &perf_sched); if (err) diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index d44e3df13a8..b36f26fe767 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -207,6 +207,48 @@ out_free_attrs: return err; } +static struct perf_evsel * + perf_evlist__find_tracepoint_by_id(struct perf_evlist *evlist, int id) +{ + struct perf_evsel *evsel; + + list_for_each_entry(evsel, &evlist->entries, node) { + if (evsel->attr.type == PERF_TYPE_TRACEPOINT && + (int)evsel->attr.config == id) + return evsel; + } + + return NULL; +} + +int perf_evlist__set_tracepoints_handlers(struct perf_evlist *evlist, + const struct perf_evsel_str_handler *assocs, + size_t nr_assocs) +{ + struct perf_evsel *evsel; + int err; + size_t i; + + for (i = 0; i < nr_assocs; i++) { + err = trace_event__id(assocs[i].name); + if (err < 0) + goto out; + + evsel = perf_evlist__find_tracepoint_by_id(evlist, err); + if (evsel == NULL) + continue; + + err = -EEXIST; + if (evsel->handler.func != NULL) + goto out; + evsel->handler.func = assocs[i].handler; + } + + err = 0; +out: + return err; +} + void perf_evlist__disable(struct perf_evlist *evlist) { int cpu, thread; diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 2202e7b0410..f94ed7e0d98 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -36,6 +36,11 @@ struct perf_evlist { struct perf_evsel *selected; }; +struct perf_evsel_str_handler { + const char *name; + void *handler; +}; + struct perf_evsel; struct perf_evlist *perf_evlist__new(struct cpu_map *cpus, @@ -51,6 +56,9 @@ int perf_evlist__add_attrs(struct perf_evlist *evlist, struct perf_event_attr *attrs, size_t nr_attrs); int perf_evlist__add_tracepoints(struct perf_evlist *evlist, const char *tracepoints[], size_t nr_tracepoints); +int perf_evlist__set_tracepoints_handlers(struct perf_evlist *evlist, + const struct perf_evsel_str_handler *assocs, + size_t nr_assocs); #define perf_evlist__add_attrs_array(evlist, array) \ perf_evlist__add_attrs(evlist, array, ARRAY_SIZE(array)) @@ -58,6 +66,9 @@ int perf_evlist__add_tracepoints(struct perf_evlist *evlist, #define perf_evlist__add_tracepoints_array(evlist, array) \ perf_evlist__add_tracepoints(evlist, array, ARRAY_SIZE(array)) +#define perf_evlist__set_tracepoints_handlers_array(evlist, array) \ + perf_evlist__set_tracepoints_handlers(evlist, array, ARRAY_SIZE(array)) + void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel, int cpu, int thread, u64 id); diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 6421c07f501..326b8e4d503 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -61,6 +61,10 @@ struct perf_evsel { off_t id_offset; }; struct cgroup_sel *cgrp; + struct { + void *func; + void *data; + } handler; bool supported; }; diff --git a/tools/perf/util/tool.h b/tools/perf/util/tool.h index 89ff1b551a7..b0e1aadba8d 100644 --- a/tools/perf/util/tool.h +++ b/tools/perf/util/tool.h @@ -1,8 +1,13 @@ #ifndef __PERF_TOOL_H #define __PERF_TOOL_H +#include + struct perf_session; +union perf_event; +struct perf_evlist; struct perf_evsel; +struct perf_sample; struct perf_tool; struct machine; -- cgit v1.2.3-70-g09d2 From 806fb63007447622dd61d9767b4403919737e120 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 29 Nov 2011 08:05:52 -0200 Subject: perf evlist: Always do automatic allocation of pollfd and mmap structures At first tools were required to do that, but while writing the python bindings to simplify the API I made them auto-allocate when needed. This just makes record, stat and top use that auto allocation, simplifying them a bit. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-iokhcvkzzijr3keioubx8hlq@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 6 ------ tools/perf/builtin-stat.c | 3 +-- tools/perf/builtin-top.c | 19 ++++--------------- tools/perf/util/evlist.c | 4 ++-- tools/perf/util/evlist.h | 2 -- 5 files changed, 7 insertions(+), 27 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 7d4fdaacc8b..766fa0a91a3 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -778,16 +778,10 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) usage_with_options(record_usage, record_options); list_for_each_entry(pos, &evsel_list->entries, node) { - if (perf_evsel__alloc_fd(pos, evsel_list->cpus->nr, - evsel_list->threads->nr) < 0) - goto out_free_fd; if (perf_header__push_event(pos->attr.config, event_name(pos))) goto out_free_fd; } - if (perf_evlist__alloc_pollfd(evsel_list) < 0) - goto out_free_fd; - if (rec->opts.user_interval != ULLONG_MAX) rec->opts.default_interval = rec->opts.user_interval; if (rec->opts.user_freq != UINT_MAX) diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 227befbecec..4356144f121 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -1240,8 +1240,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used) list_for_each_entry(pos, &evsel_list->entries, node) { if (perf_evsel__alloc_stat_priv(pos) < 0 || - perf_evsel__alloc_counts(pos, evsel_list->cpus->nr) < 0 || - perf_evsel__alloc_fd(pos, evsel_list->cpus->nr, evsel_list->threads->nr) < 0) + perf_evsel__alloc_counts(pos, evsel_list->cpus->nr) < 0) goto out_free_fd; } diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 50ff362ff01..c3836b966cc 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -1034,9 +1034,7 @@ parse_callchain_opt(const struct option *opt, const char *arg, int unset) symbol_conf.use_callchain = false; return 0; - } - - else + } else return -1; /* get the min percentage */ @@ -1225,22 +1223,13 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) } list_for_each_entry(pos, &top.evlist->entries, node) { - if (perf_evsel__alloc_fd(pos, top.evlist->cpus->nr, - top.evlist->threads->nr) < 0) - goto out_free_fd; /* * Fill in the ones not specifically initialized via -c: */ - if (pos->attr.sample_period) - continue; - - pos->attr.sample_period = top.default_interval; + if (!pos->attr.sample_period) + pos->attr.sample_period = top.default_interval; } - if (perf_evlist__alloc_pollfd(top.evlist) < 0 || - perf_evlist__alloc_mmap(top.evlist) < 0) - goto out_free_fd; - top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node); symbol_conf.priv_size = sizeof(struct annotation); @@ -1270,7 +1259,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) } status = __cmd_top(&top); -out_free_fd: + perf_evlist__delete(top.evlist); return status; diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index b36f26fe767..8b19e7a1e88 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -275,7 +275,7 @@ void perf_evlist__enable(struct perf_evlist *evlist) } } -int perf_evlist__alloc_pollfd(struct perf_evlist *evlist) +static int perf_evlist__alloc_pollfd(struct perf_evlist *evlist) { int nfds = evlist->cpus->nr * evlist->threads->nr * evlist->nr_entries; evlist->pollfd = malloc(sizeof(struct pollfd) * nfds); @@ -431,7 +431,7 @@ void perf_evlist__munmap(struct perf_evlist *evlist) evlist->mmap = NULL; } -int perf_evlist__alloc_mmap(struct perf_evlist *evlist) +static int perf_evlist__alloc_mmap(struct perf_evlist *evlist) { evlist->nr_mmaps = evlist->cpus->nr; if (evlist->cpus->map[0] == -1) diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index f94ed7e0d98..8922aeed046 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -72,7 +72,6 @@ int perf_evlist__set_tracepoints_handlers(struct perf_evlist *evlist, void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel, int cpu, int thread, u64 id); -int perf_evlist__alloc_pollfd(struct perf_evlist *evlist); void perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd); struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id); @@ -89,7 +88,6 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist, const char *argv[]); int perf_evlist__start_workload(struct perf_evlist *evlist); -int perf_evlist__alloc_mmap(struct perf_evlist *evlist); int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, bool overwrite); void perf_evlist__munmap(struct perf_evlist *evlist); -- cgit v1.2.3-70-g09d2 From e60770a01bd889707faaaeb794f1e278e7160458 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 29 Nov 2011 12:52:07 -0200 Subject: perf test: Allow running just a subset of the available tests To obtain a list of available tests: [root@emilia linux]# perf test list 1: vmlinux symtab matches kallsyms 2: detect open syscall event 3: detect open syscall event on all cpus 4: read samples using the mmap interface 5: parse events tests [root@emilia linux]# To list just a subset: [root@emilia linux]# perf test list syscall 2: detect open syscall event 3: detect open syscall event on all cpus [root@emilia linux]# To run a subset: [root@emilia linux]# perf test detect 2: detect open syscall event: Ok 3: detect open syscall event on all cpus: Ok [root@emilia linux]# Specific tests can be chosen by number: [root@emilia linux]# perf test 1 3 parse 1: vmlinux symtab matches kallsyms: Ok 3: detect open syscall event on all cpus: Ok 5: parse events tests: Ok [root@emilia linux]# Now to write more tests! Suggested-by: Peter Zijlstra Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-nqec2145qfxdgimux28aw7v8@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-test.txt | 8 +++- tools/perf/builtin-test.c | 81 +++++++++++++++++++++++++--------- 2 files changed, 67 insertions(+), 22 deletions(-) (limited to 'tools') diff --git a/tools/perf/Documentation/perf-test.txt b/tools/perf/Documentation/perf-test.txt index 2c3b462f64b..b24ac40fcd5 100644 --- a/tools/perf/Documentation/perf-test.txt +++ b/tools/perf/Documentation/perf-test.txt @@ -8,13 +8,19 @@ perf-test - Runs sanity tests. SYNOPSIS -------- [verse] -'perf test ' +'perf test [] [{list |[|]}]' DESCRIPTION ----------- This command does assorted sanity tests, initially through linked routines but also will look for a directory with more tests in the form of scripts. +To get a list of available tests use 'perf test list', specifying a test name +fragment will show all tests that have it. + +To run just specific tests, inform test name fragments or the numbers obtained +from 'perf test list'. + OPTIONS ------- -v:: diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c index 77d68bfb79d..3ab27223fc6 100644 --- a/tools/perf/builtin-test.c +++ b/tools/perf/builtin-test.c @@ -15,8 +15,6 @@ #include "util/thread_map.h" #include "../../include/linux/hw_breakpoint.h" -static long page_size; - static int vmlinux_matches_kallsyms_filter(struct map *map __used, struct symbol *sym) { bool *visited = symbol__priv(sym); @@ -32,6 +30,7 @@ static int test__vmlinux_matches_kallsyms(void) struct map *kallsyms_map, *vmlinux_map; struct machine kallsyms, vmlinux; enum map_type type = MAP__FUNCTION; + long page_size = sysconf(_SC_PAGE_SIZE); struct ref_reloc_sym ref_reloc_sym = { .name = "_stext", }; /* @@ -871,41 +870,81 @@ static struct test { }, }; -static int __cmd_test(void) +static bool perf_test__matches(int curr, int argc, const char *argv[]) { - int i = 0; + int i; + + if (argc == 0) + return true; + + for (i = 0; i < argc; ++i) { + char *end; + long nr = strtoul(argv[i], &end, 10); + + if (*end == '\0') { + if (nr == curr + 1) + return true; + continue; + } - page_size = sysconf(_SC_PAGE_SIZE); + if (strstr(tests[curr].desc, argv[i])) + return true; + } + + return false; +} + +static int __cmd_test(int argc, const char *argv[]) +{ + int i = 0; while (tests[i].func) { - int err; - pr_info("%2d: %s:", i + 1, tests[i].desc); + int curr = i++, err; + + if (!perf_test__matches(curr, argc, argv)) + continue; + + pr_info("%2d: %s:", i, tests[curr].desc); pr_debug("\n--- start ---\n"); - err = tests[i].func(); - pr_debug("---- end ----\n%s:", tests[i].desc); + err = tests[curr].func(); + pr_debug("---- end ----\n%s:", tests[curr].desc); pr_info(" %s\n", err ? "FAILED!\n" : "Ok"); - ++i; } return 0; } -static const char * const test_usage[] = { - "perf test []", - NULL, -}; +static int perf_test__list(int argc, const char **argv) +{ + int i = 0; + + while (tests[i].func) { + int curr = i++; + + if (argc > 1 && !strstr(tests[curr].desc, argv[1])) + continue; + + pr_info("%2d: %s\n", i, tests[curr].desc); + } + + return 0; +} -static const struct option test_options[] = { +int cmd_test(int argc, const char **argv, const char *prefix __used) +{ + const char * const test_usage[] = { + "perf test [] [{list |[|]}]", + NULL, + }; + const struct option test_options[] = { OPT_INTEGER('v', "verbose", &verbose, "be more verbose (show symbol address, etc)"), OPT_END() -}; + }; -int cmd_test(int argc, const char **argv, const char *prefix __used) -{ argc = parse_options(argc, argv, test_options, test_usage, 0); - if (argc) - usage_with_options(test_usage, test_options); + if (argc >= 1 && !strcmp(argv[0], "list")) + return perf_test__list(argc, argv); symbol_conf.priv_size = sizeof(int); symbol_conf.sort_by_name = true; @@ -916,5 +955,5 @@ int cmd_test(int argc, const char **argv, const char *prefix __used) setup_pager(); - return __cmd_test(); + return __cmd_test(argc, argv); } -- cgit v1.2.3-70-g09d2 From 482ad89745f7121020f6cee38aa4e894a4e7d642 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 2 Dec 2011 11:06:37 -0200 Subject: perf event: Introduce perf_event__fprintf So that tools like 'perf test' can print the events when in verbose mode, for instance. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-xnovdqfi25nc48gy6604k7yp@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/event.c | 54 +++++++++++++++++++++++++++++++++++++++++++------ tools/perf/util/event.h | 6 ++++++ 2 files changed, 54 insertions(+), 6 deletions(-) (limited to 'tools') diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 0ebbe764133..97c479bcb0d 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -433,6 +433,11 @@ int perf_event__synthesize_kernel_mmap(struct perf_tool *tool, return err; } +size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp) +{ + return fprintf(fp, ": %s:%d\n", event->comm.comm, event->comm.tid); +} + int perf_event__process_comm(struct perf_tool *tool __used, union perf_event *event, struct perf_sample *sample __used, @@ -440,7 +445,8 @@ int perf_event__process_comm(struct perf_tool *tool __used, { struct thread *thread = machine__findnew_thread(machine, event->comm.tid); - dump_printf(": %s:%d\n", event->comm.comm, event->comm.tid); + if (dump_trace) + perf_event__fprintf_comm(event, stdout); if (thread == NULL || thread__set_comm(thread, event->comm.comm)) { dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n"); @@ -566,6 +572,13 @@ out_problem: return -1; } +size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp) +{ + return fprintf(fp, " %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64 "]: %s\n", + event->mmap.pid, event->mmap.tid, event->mmap.start, + event->mmap.len, event->mmap.pgoff, event->mmap.filename); +} + int perf_event__process_mmap(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample __used, @@ -576,9 +589,8 @@ int perf_event__process_mmap(struct perf_tool *tool, u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; int ret = 0; - dump_printf(" %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64 "]: %s\n", - event->mmap.pid, event->mmap.tid, event->mmap.start, - event->mmap.len, event->mmap.pgoff, event->mmap.filename); + if (dump_trace) + perf_event__fprintf_mmap(event, stdout); if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL || cpumode == PERF_RECORD_MISC_KERNEL) { @@ -606,6 +618,13 @@ out_problem: return 0; } +size_t perf_event__fprintf_task(union perf_event *event, FILE *fp) +{ + return fprintf(fp, "(%d:%d):(%d:%d)\n", + event->fork.pid, event->fork.tid, + event->fork.ppid, event->fork.ptid); +} + int perf_event__process_task(struct perf_tool *tool __used, union perf_event *event, struct perf_sample *sample __used, @@ -614,8 +633,8 @@ int perf_event__process_task(struct perf_tool *tool __used, struct thread *thread = machine__findnew_thread(machine, event->fork.tid); struct thread *parent = machine__findnew_thread(machine, event->fork.ptid); - dump_printf("(%d:%d):(%d:%d)\n", event->fork.pid, event->fork.tid, - event->fork.ppid, event->fork.ptid); + if (dump_trace) + perf_event__fprintf_task(event, stdout); if (event->header.type == PERF_RECORD_EXIT) { machine__remove_thread(machine, thread); @@ -631,6 +650,29 @@ int perf_event__process_task(struct perf_tool *tool __used, return 0; } +size_t perf_event__fprintf(union perf_event *event, FILE *fp) +{ + size_t ret = fprintf(fp, "PERF_RECORD_%s", + perf_event__name(event->header.type)); + + switch (event->header.type) { + case PERF_RECORD_COMM: + ret += perf_event__fprintf_comm(event, fp); + break; + case PERF_RECORD_FORK: + case PERF_RECORD_EXIT: + ret += perf_event__fprintf_task(event, fp); + break; + case PERF_RECORD_MMAP: + ret += perf_event__fprintf_mmap(event, fp); + break; + default: + ret += fprintf(fp, "\n"); + } + + return ret; +} + int perf_event__process(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, struct machine *machine) { diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index d8499e7cf64..0d80201ce84 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -2,6 +2,7 @@ #define __PERF_RECORD_H #include +#include #include "../perf.h" #include "map.h" @@ -199,4 +200,9 @@ int perf_event__parse_sample(const union perf_event *event, u64 type, int sample_size, bool sample_id_all, struct perf_sample *sample, bool swapped); +size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp); +size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp); +size_t perf_event__fprintf_task(union perf_event *event, FILE *fp); +size_t perf_event__fprintf(union perf_event *event, FILE *fp); + #endif /* __PERF_RECORD_H */ -- cgit v1.2.3-70-g09d2 From 3e7c439a7ce537ed662e347b9e6414d7881fb3dc Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 2 Dec 2011 11:13:50 -0200 Subject: perf test: Validate PERF_RECORD_ events and perf_sample fields This new test will validate these new routines extracted from 'perf record': - perf_evlist__config_attrs - perf_evlist__prepare_workload - perf_evlist__start_workload In addition to several other perf_evlist methods. It consists of starting a simple workload, setting up just one event to monitor ("cycles") requesting that several PERF_SAMPLE_ fields be present in all events. It then will check that the expected PERF_RECORD_ events are produced and will sanity check all its fields. Some checks performed: . PERF_SAMPLE_TIME monotonically increases. . PERF_SAMPLE_CPU is the one requested with sched_setaffinity . PERF_SAMPLE_TID and PERF_SAMPLE_PID matches the one we forked in perf_evlist__prepare_workload and that is stored in evlist->workload.pid . For the events where these fields are also present in its pre-sample_id_all fields (e.g. event->mmap.pid), that they are what is expected too. . That we get a bunch of mmaps: PATH/libcSUFFIX PATH/ldSUFFIX [vdso] PATH/sleep Example: [root@emilia ~]# taskset -c 3,4 perf test -v1 perf_sample 6: Validate PERF_RECORD_* events & perf_sample fields: --- start --- 7159480799825 3 PERF_RECORD_SAMPLE 7159480805584 3 PERF_RECORD_SAMPLE 7159480807814 3 PERF_RECORD_SAMPLE 7159480810430 3 PERF_RECORD_SAMPLE 7159480861511 3 PERF_RECORD_MMAP 8086/8086: [0x7fffffffd000(0x2000) @ 0x7fffffffd000]: //anon 7159481052516 3 PERF_RECORD_COMM: sleep:8086 7159481070188 3 PERF_RECORD_MMAP 8086/8086: [0x400000(0x6000) @ 0]: /bin/sleep 7159481077104 3 PERF_RECORD_MMAP 8086/8086: [0x3d06400000(0x221000) @ 0]: /lib64/ld-2.12.so 7159481092912 3 PERF_RECORD_MMAP 8086/8086: [0x7fff1adff000(0x1000) @ 0x7fff1adff000]: [vdso] 7159481196779 3 PERF_RECORD_MMAP 8086/8086: [0x3d06800000(0x37f000) @ 0]: /lib64/libc-2.12.so 7160481558435 3 PERF_RECORD_EXIT(8086:8086):(8086:8086) ---- end ---- Validate PERF_RECORD_* events & perf_sample fields: Ok [root@emilia ~]# Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-svag18v2z4idas0dyz3umjpq@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-test.c | 337 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 337 insertions(+) (limited to 'tools') diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c index 3ab27223fc6..f1e36110b10 100644 --- a/tools/perf/builtin-test.c +++ b/tools/perf/builtin-test.c @@ -841,6 +841,339 @@ static int test__parse_events(void) return ret; } + +static int sched__get_first_possible_cpu(pid_t pid, cpu_set_t **maskp, + size_t *sizep) +{ + cpu_set_t *mask; + size_t size; + int i, cpu = -1, nrcpus = 1024; +realloc: + mask = CPU_ALLOC(nrcpus); + size = CPU_ALLOC_SIZE(nrcpus); + CPU_ZERO_S(size, mask); + + if (sched_getaffinity(pid, size, mask) == -1) { + CPU_FREE(mask); + if (errno == EINVAL && nrcpus < (1024 << 8)) { + nrcpus = nrcpus << 2; + goto realloc; + } + perror("sched_getaffinity"); + return -1; + } + + for (i = 0; i < nrcpus; i++) { + if (CPU_ISSET_S(i, size, mask)) { + if (cpu == -1) { + cpu = i; + *maskp = mask; + *sizep = size; + } else + CPU_CLR_S(i, size, mask); + } + } + + if (cpu == -1) + CPU_FREE(mask); + + return cpu; +} + +static int test__PERF_RECORD(void) +{ + struct perf_record_opts opts = { + .target_pid = -1, + .target_tid = -1, + .no_delay = true, + .freq = 10, + .mmap_pages = 256, + .sample_id_all_avail = true, + }; + cpu_set_t *cpu_mask = NULL; + size_t cpu_mask_size = 0; + struct perf_evlist *evlist = perf_evlist__new(NULL, NULL); + struct perf_evsel *evsel; + struct perf_sample sample; + const char *cmd = "sleep"; + const char *argv[] = { cmd, "1", NULL, }; + char *bname; + u64 sample_type, prev_time = 0; + bool found_cmd_mmap = false, + found_libc_mmap = false, + found_vdso_mmap = false, + found_ld_mmap = false; + int err = -1, i, wakeups = 0, sample_size; + u32 cpu; + int total_events = 0, nr_events[PERF_RECORD_MAX] = { 0, }; + + if (evlist == NULL || argv == NULL) { + pr_debug("Not enough memory to create evlist\n"); + goto out; + } + + /* + * We need at least one evsel in the evlist, use the default + * one: "cycles". + */ + err = perf_evlist__add_default(evlist); + if (err < 0) { + pr_debug("Not enough memory to create evsel\n"); + goto out_delete_evlist; + } + + /* + * Create maps of threads and cpus to monitor. In this case + * we start with all threads and cpus (-1, -1) but then in + * perf_evlist__prepare_workload we'll fill in the only thread + * we're monitoring, the one forked there. + */ + err = perf_evlist__create_maps(evlist, opts.target_pid, + opts.target_tid, opts.cpu_list); + if (err < 0) { + pr_debug("Not enough memory to create thread/cpu maps\n"); + goto out_delete_evlist; + } + + /* + * Prepare the workload in argv[] to run, it'll fork it, and then wait + * for perf_evlist__start_workload() to exec it. This is done this way + * so that we have time to open the evlist (calling sys_perf_event_open + * on all the fds) and then mmap them. + */ + err = perf_evlist__prepare_workload(evlist, &opts, argv); + if (err < 0) { + pr_debug("Couldn't run the workload!\n"); + goto out_delete_evlist; + } + + /* + * Config the evsels, setting attr->comm on the first one, etc. + */ + evsel = list_entry(evlist->entries.next, struct perf_evsel, node); + evsel->attr.sample_type |= PERF_SAMPLE_CPU; + evsel->attr.sample_type |= PERF_SAMPLE_TID; + evsel->attr.sample_type |= PERF_SAMPLE_TIME; + perf_evlist__config_attrs(evlist, &opts); + + err = sched__get_first_possible_cpu(evlist->workload.pid, &cpu_mask, + &cpu_mask_size); + if (err < 0) { + pr_debug("sched__get_first_possible_cpu: %s\n", strerror(errno)); + goto out_delete_evlist; + } + + cpu = err; + + /* + * So that we can check perf_sample.cpu on all the samples. + */ + if (sched_setaffinity(evlist->workload.pid, cpu_mask_size, cpu_mask) < 0) { + pr_debug("sched_setaffinity: %s\n", strerror(errno)); + goto out_free_cpu_mask; + } + + /* + * Call sys_perf_event_open on all the fds on all the evsels, + * grouping them if asked to. + */ + err = perf_evlist__open(evlist, opts.group); + if (err < 0) { + pr_debug("perf_evlist__open: %s\n", strerror(errno)); + goto out_delete_evlist; + } + + /* + * mmap the first fd on a given CPU and ask for events for the other + * fds in the same CPU to be injected in the same mmap ring buffer + * (using ioctl(PERF_EVENT_IOC_SET_OUTPUT)). + */ + err = perf_evlist__mmap(evlist, opts.mmap_pages, false); + if (err < 0) { + pr_debug("perf_evlist__mmap: %s\n", strerror(errno)); + goto out_delete_evlist; + } + + /* + * We'll need these two to parse the PERF_SAMPLE_* fields in each + * event. + */ + sample_type = perf_evlist__sample_type(evlist); + sample_size = __perf_evsel__sample_size(sample_type); + + /* + * Now that all is properly set up, enable the events, they will + * count just on workload.pid, which will start... + */ + perf_evlist__enable(evlist); + + /* + * Now! + */ + perf_evlist__start_workload(evlist); + + err = -1; + + while (1) { + int before = total_events; + + for (i = 0; i < evlist->nr_mmaps; i++) { + union perf_event *event; + + while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) { + const u32 type = event->header.type; + const char *name = perf_event__name(type); + + ++total_events; + if (type < PERF_RECORD_MAX) + nr_events[type]++; + + if (perf_event__parse_sample(event, sample_type, + sample_size, true, + &sample, false) < 0) { + if (verbose) + perf_event__fprintf(event, stderr); + pr_debug("Couldn't parse sample\n"); + goto out_err; + } + + if (verbose) { + pr_info("%" PRIu64" %d ", sample.time, sample.cpu); + perf_event__fprintf(event, stderr); + } + + if (prev_time > sample.time) { + pr_debug("%s going backwards in time, prev=%" PRIu64 ", curr=%" PRIu64 "\n", + name, prev_time, sample.time); + goto out_err; + } + + prev_time = sample.time; + + if (sample.cpu != cpu) { + pr_debug("%s with unexpected cpu, expected %d, got %d\n", + name, cpu, sample.cpu); + goto out_err; + } + + if ((pid_t)sample.pid != evlist->workload.pid) { + pr_debug("%s with unexpected pid, expected %d, got %d\n", + name, evlist->workload.pid, sample.pid); + goto out_err; + } + + if ((pid_t)sample.tid != evlist->workload.pid) { + pr_debug("%s with unexpected tid, expected %d, got %d\n", + name, evlist->workload.pid, sample.tid); + goto out_err; + } + + if ((type == PERF_RECORD_COMM || + type == PERF_RECORD_MMAP || + type == PERF_RECORD_FORK || + type == PERF_RECORD_EXIT) && + (pid_t)event->comm.pid != evlist->workload.pid) { + pr_debug("%s with unexpected pid/tid\n", name); + goto out_err; + } + + if ((type == PERF_RECORD_COMM || + type == PERF_RECORD_MMAP) && + event->comm.pid != event->comm.tid) { + pr_debug("%s with different pid/tid!\n", name); + goto out_err; + } + + switch (type) { + case PERF_RECORD_COMM: + if (strcmp(event->comm.comm, cmd)) { + pr_debug("%s with unexpected comm!\n", name); + goto out_err; + } + break; + case PERF_RECORD_EXIT: + goto found_exit; + case PERF_RECORD_MMAP: + bname = strrchr(event->mmap.filename, '/'); + if (bname != NULL) { + if (!found_cmd_mmap) + found_cmd_mmap = !strcmp(bname + 1, cmd); + if (!found_libc_mmap) + found_libc_mmap = !strncmp(bname + 1, "libc", 4); + if (!found_ld_mmap) + found_ld_mmap = !strncmp(bname + 1, "ld", 2); + } else if (!found_vdso_mmap) + found_vdso_mmap = !strcmp(event->mmap.filename, "[vdso]"); + break; + + case PERF_RECORD_SAMPLE: + /* Just ignore samples for now */ + break; + default: + pr_debug("Unexpected perf_event->header.type %d!\n", + type); + goto out_err; + } + } + } + + /* + * We don't use poll here because at least at 3.1 times the + * PERF_RECORD_{!SAMPLE} events don't honour + * perf_event_attr.wakeup_events, just PERF_EVENT_SAMPLE does. + */ + if (total_events == before && false) + poll(evlist->pollfd, evlist->nr_fds, -1); + + sleep(1); + if (++wakeups > 5) { + pr_debug("No PERF_RECORD_EXIT event!\n"); + goto out_err; + } + } + +found_exit: + if (nr_events[PERF_RECORD_COMM] > 1) { + pr_debug("Excessive number of PERF_RECORD_COMM events!\n"); + goto out_err; + } + + if (nr_events[PERF_RECORD_COMM] == 0) { + pr_debug("Missing PERF_RECORD_COMM for %s!\n", cmd); + goto out_err; + } + + if (!found_cmd_mmap) { + pr_debug("PERF_RECORD_MMAP for %s missing!\n", cmd); + goto out_err; + } + + if (!found_libc_mmap) { + pr_debug("PERF_RECORD_MMAP for %s missing!\n", "libc"); + goto out_err; + } + + if (!found_ld_mmap) { + pr_debug("PERF_RECORD_MMAP for %s missing!\n", "ld"); + goto out_err; + } + + if (!found_vdso_mmap) { + pr_debug("PERF_RECORD_MMAP for %s missing!\n", "[vdso]"); + goto out_err; + } + + err = 0; +out_err: + perf_evlist__munmap(evlist); +out_free_cpu_mask: + CPU_FREE(cpu_mask); +out_delete_evlist: + perf_evlist__delete(evlist); +out: + return err; +} + static struct test { const char *desc; int (*func)(void); @@ -865,6 +1198,10 @@ static struct test { .desc = "parse events tests", .func = test__parse_events, }, + { + .desc = "Validate PERF_RECORD_* events & perf_sample fields", + .func = test__PERF_RECORD, + }, { .func = NULL, }, -- cgit v1.2.3-70-g09d2 From f71c49e5e985897850406a152ab99001cfb86f2a Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 2 Dec 2011 13:53:04 -0200 Subject: perf test: Soft errors shouldn't stop the "Validate PERF_RECORD_" test For errors that don't preclude checking for further errors, aka "soft" errors, just continue testing for other errors. Better coverage in verbose mode. Suggested-by: David Ahern Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-jafcokbj26m845dsgm2hx6az@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-test.c | 45 +++++++++++++++++++++------------------------ 1 file changed, 21 insertions(+), 24 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c index f1e36110b10..6173f780dce 100644 --- a/tools/perf/builtin-test.c +++ b/tools/perf/builtin-test.c @@ -903,7 +903,7 @@ static int test__PERF_RECORD(void) found_libc_mmap = false, found_vdso_mmap = false, found_ld_mmap = false; - int err = -1, i, wakeups = 0, sample_size; + int err = -1, errs = 0, i, wakeups = 0, sample_size; u32 cpu; int total_events = 0, nr_events[PERF_RECORD_MAX] = { 0, }; @@ -1012,8 +1012,6 @@ static int test__PERF_RECORD(void) */ perf_evlist__start_workload(evlist); - err = -1; - while (1) { int before = total_events; @@ -1028,9 +1026,10 @@ static int test__PERF_RECORD(void) if (type < PERF_RECORD_MAX) nr_events[type]++; - if (perf_event__parse_sample(event, sample_type, - sample_size, true, - &sample, false) < 0) { + err = perf_event__parse_sample(event, sample_type, + sample_size, true, + &sample, false); + if (err < 0) { if (verbose) perf_event__fprintf(event, stderr); pr_debug("Couldn't parse sample\n"); @@ -1045,7 +1044,7 @@ static int test__PERF_RECORD(void) if (prev_time > sample.time) { pr_debug("%s going backwards in time, prev=%" PRIu64 ", curr=%" PRIu64 "\n", name, prev_time, sample.time); - goto out_err; + ++errs; } prev_time = sample.time; @@ -1053,19 +1052,19 @@ static int test__PERF_RECORD(void) if (sample.cpu != cpu) { pr_debug("%s with unexpected cpu, expected %d, got %d\n", name, cpu, sample.cpu); - goto out_err; + ++errs; } if ((pid_t)sample.pid != evlist->workload.pid) { pr_debug("%s with unexpected pid, expected %d, got %d\n", name, evlist->workload.pid, sample.pid); - goto out_err; + ++errs; } if ((pid_t)sample.tid != evlist->workload.pid) { pr_debug("%s with unexpected tid, expected %d, got %d\n", name, evlist->workload.pid, sample.tid); - goto out_err; + ++errs; } if ((type == PERF_RECORD_COMM || @@ -1074,21 +1073,21 @@ static int test__PERF_RECORD(void) type == PERF_RECORD_EXIT) && (pid_t)event->comm.pid != evlist->workload.pid) { pr_debug("%s with unexpected pid/tid\n", name); - goto out_err; + ++errs; } if ((type == PERF_RECORD_COMM || type == PERF_RECORD_MMAP) && event->comm.pid != event->comm.tid) { pr_debug("%s with different pid/tid!\n", name); - goto out_err; + ++errs; } switch (type) { case PERF_RECORD_COMM: if (strcmp(event->comm.comm, cmd)) { pr_debug("%s with unexpected comm!\n", name); - goto out_err; + ++errs; } break; case PERF_RECORD_EXIT: @@ -1112,7 +1111,7 @@ static int test__PERF_RECORD(void) default: pr_debug("Unexpected perf_event->header.type %d!\n", type); - goto out_err; + ++errs; } } } @@ -1128,42 +1127,40 @@ static int test__PERF_RECORD(void) sleep(1); if (++wakeups > 5) { pr_debug("No PERF_RECORD_EXIT event!\n"); - goto out_err; + break; } } found_exit: if (nr_events[PERF_RECORD_COMM] > 1) { pr_debug("Excessive number of PERF_RECORD_COMM events!\n"); - goto out_err; + ++errs; } if (nr_events[PERF_RECORD_COMM] == 0) { pr_debug("Missing PERF_RECORD_COMM for %s!\n", cmd); - goto out_err; + ++errs; } if (!found_cmd_mmap) { pr_debug("PERF_RECORD_MMAP for %s missing!\n", cmd); - goto out_err; + ++errs; } if (!found_libc_mmap) { pr_debug("PERF_RECORD_MMAP for %s missing!\n", "libc"); - goto out_err; + ++errs; } if (!found_ld_mmap) { pr_debug("PERF_RECORD_MMAP for %s missing!\n", "ld"); - goto out_err; + ++errs; } if (!found_vdso_mmap) { pr_debug("PERF_RECORD_MMAP for %s missing!\n", "[vdso]"); - goto out_err; + ++errs; } - - err = 0; out_err: perf_evlist__munmap(evlist); out_free_cpu_mask: @@ -1171,7 +1168,7 @@ out_free_cpu_mask: out_delete_evlist: perf_evlist__delete(evlist); out: - return err; + return (err < 0 || errs > 0) ? -1 : 0; } static struct test { -- cgit v1.2.3-70-g09d2 From 38efb539c13f8f173e381435cdd40463ab5d38de Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Fri, 25 Nov 2011 11:38:40 +0100 Subject: perf script: Fix mem leaks and NULL pointer checks around strdup()s Fix mem leaks and missing NULL pointer checks after strdup(). And get_script_path() did not free __script_root in case of continue. Introduce a helper function get_script_root(). Cc: Ingo Molnar Link: http://lkml.kernel.org/r/1322217520-3287-1-git-send-email-robert.richter@amd.com Signed-off-by: Robert Richter Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-script.c | 48 +++++++++++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 19 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 619d6dcaa1d..ccbfd56d754 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -693,7 +693,8 @@ static int parse_output_fields(const struct option *opt __used, type = PERF_TYPE_RAW; else { fprintf(stderr, "Invalid event type in field string.\n"); - return -EINVAL; + rc = -EINVAL; + goto out; } if (output[type].user_set) @@ -935,6 +936,24 @@ static int read_script_info(struct script_desc *desc, const char *filename) return 0; } +static char *get_script_root(struct dirent *script_dirent, const char *suffix) +{ + char *script_root, *str; + + script_root = strdup(script_dirent->d_name); + if (!script_root) + return NULL; + + str = (char *)ends_with(script_root, suffix); + if (!str) { + free(script_root); + return NULL; + } + + *str = '\0'; + return script_root; +} + static int list_available_scripts(const struct option *opt __used, const char *s __used, int unset __used) { @@ -946,7 +965,6 @@ static int list_available_scripts(const struct option *opt __used, struct script_desc *desc; char first_half[BUFSIZ]; char *script_root; - char *str; snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path()); @@ -962,16 +980,14 @@ static int list_available_scripts(const struct option *opt __used, continue; for_each_script(lang_path, lang_dir, script_dirent, script_next) { - script_root = strdup(script_dirent.d_name); - str = (char *)ends_with(script_root, REPORT_SUFFIX); - if (str) { - *str = '\0'; + script_root = get_script_root(&script_dirent, REPORT_SUFFIX); + if (script_root) { desc = script_desc__findnew(script_root); snprintf(script_path, MAXPATHLEN, "%s/%s", lang_path, script_dirent.d_name); read_script_info(desc, script_path); + free(script_root); } - free(script_root); } } @@ -993,8 +1009,7 @@ static char *get_script_path(const char *script_root, const char *suffix) char script_path[MAXPATHLEN]; DIR *scripts_dir, *lang_dir; char lang_path[MAXPATHLEN]; - char *str, *__script_root; - char *path = NULL; + char *__script_root; snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path()); @@ -1010,23 +1025,18 @@ static char *get_script_path(const char *script_root, const char *suffix) continue; for_each_script(lang_path, lang_dir, script_dirent, script_next) { - __script_root = strdup(script_dirent.d_name); - str = (char *)ends_with(__script_root, suffix); - if (str) { - *str = '\0'; - if (strcmp(__script_root, script_root)) - continue; + __script_root = get_script_root(&script_dirent, suffix); + if (__script_root && !strcmp(script_root, __script_root)) { + free(__script_root); snprintf(script_path, MAXPATHLEN, "%s/%s", lang_path, script_dirent.d_name); - path = strdup(script_path); - free(__script_root); - break; + return strdup(script_path); } free(__script_root); } } - return path; + return NULL; } static bool is_top_script(const char *script_path) -- cgit v1.2.3-70-g09d2 From 317df650c588bb9091b1fa0b5d726fe485aad88e Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Fri, 25 Nov 2011 15:05:25 +0100 Subject: perf script: Implement option for system-wide profiling The option is documented in man perf-script but was not yet implemented: -a Force system-wide collection. Scripts run without a normally use -a by default, while scripts run with a normally don't - this option allows the latter to be run in system-wide mode. As with perf record you now can profile in system-wide mode for the runtime of a given command, e.g.: # perf script -a syscall-counts sleep 2 Cc: Ingo Molnar Link: http://lkml.kernel.org/r/1322229925-10075-1-git-send-email-robert.richter@amd.com Signed-off-by: Robert Richter Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-script.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index ccbfd56d754..ea71c5e1a94 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -24,6 +24,7 @@ static u64 nr_unordered; extern const struct option record_options[]; static bool no_callchain; static bool show_full_info; +static bool system_wide; static const char *cpu_list; static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); @@ -1105,6 +1106,8 @@ static const struct option options[] = { OPT_CALLBACK('f', "fields", NULL, "str", "comma separated output fields prepend with 'type:'. Valid types: hw,sw,trace,raw. Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso,addr", parse_output_fields), + OPT_BOOLEAN('a', "all-cpus", &system_wide, + "system-wide collection from all CPUs"), OPT_STRING('C', "cpu", &cpu_list, "cpu", "list of cpus to profile"), OPT_STRING('c', "comms", &symbol_conf.comm_list_str, "comm[,comm...]", "only display events for these comms"), @@ -1134,7 +1137,6 @@ int cmd_script(int argc, const char **argv, const char *prefix __used) struct perf_session *session; char *script_path = NULL; const char **__argv; - bool system_wide; int i, j, err; setup_scripting(); @@ -1202,15 +1204,17 @@ int cmd_script(int argc, const char **argv, const char *prefix __used) } if (!pid) { - system_wide = true; j = 0; dup2(live_pipe[1], 1); close(live_pipe[0]); - if (!is_top_script(argv[0])) + if (is_top_script(argv[0])) { + system_wide = true; + } else if (!system_wide) { system_wide = !have_cmd(argc - rep_args, &argv[rep_args]); + } __argv = malloc((argc + 6) * sizeof(const char *)); if (!__argv) @@ -1258,10 +1262,11 @@ int cmd_script(int argc, const char **argv, const char *prefix __used) script_path = rep_script_path; if (script_path) { - system_wide = false; j = 0; - if (rec_script_path) + if (!rec_script_path) + system_wide = false; + else if (!system_wide) system_wide = !have_cmd(argc - 1, &argv[1]); __argv = malloc((argc + 2) * sizeof(const char *)); -- cgit v1.2.3-70-g09d2 From 74eec26facadbe6dbc0621bc862892c915c4534f Mon Sep 17 00:00:00 2001 From: Andrew Vagin Date: Mon, 28 Nov 2011 12:03:31 +0300 Subject: perf tools: Add ability to synthesize event according to a sample It's the counterpart of perf_session__parse_sample. v2: fixed mistakes found by David Ahern. v3: s/data/sample/ s/perf_event__change_sample/perf_event__synthesize_sample Reviewed-by: David Ahern Cc: Arun Sharma Cc: David Ahern Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Cc: devel@openvz.org Link: http://lkml.kernel.org/r/1323266161-394927-3-git-send-email-avagin@openvz.org Signed-off-by: Andrew Vagin Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/event.h | 3 ++ tools/perf/util/evsel.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/session.h | 8 +++++ 3 files changed, 90 insertions(+) (limited to 'tools') diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 0d80201ce84..cbdeaad9c5e 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -199,6 +199,9 @@ 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, bool swapped); +int perf_event__synthesize_sample(union perf_event *event, u64 type, + const struct perf_sample *sample, + bool swapped); size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp); size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp); diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index ee68d6944e6..4a8c8b02e9c 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -574,3 +574,82 @@ int perf_event__parse_sample(const union perf_event *event, u64 type, return 0; } + +int perf_event__synthesize_sample(union perf_event *event, u64 type, + const struct perf_sample *sample, + bool swapped) +{ + u64 *array; + + /* + * used for cross-endian analysis. See git commit 65014ab3 + * for why this goofiness is needed. + */ + union { + u64 val64; + u32 val32[2]; + } u; + + array = event->sample.array; + + if (type & PERF_SAMPLE_IP) { + event->ip.ip = sample->ip; + array++; + } + + if (type & PERF_SAMPLE_TID) { + u.val32[0] = sample->pid; + u.val32[1] = sample->tid; + if (swapped) { + /* + * Inverse of what is done in perf_event__parse_sample + */ + u.val32[0] = bswap_32(u.val32[0]); + u.val32[1] = bswap_32(u.val32[1]); + u.val64 = bswap_64(u.val64); + } + + *array = u.val64; + array++; + } + + if (type & PERF_SAMPLE_TIME) { + *array = sample->time; + array++; + } + + if (type & PERF_SAMPLE_ADDR) { + *array = sample->addr; + array++; + } + + if (type & PERF_SAMPLE_ID) { + *array = sample->id; + array++; + } + + if (type & PERF_SAMPLE_STREAM_ID) { + *array = sample->stream_id; + array++; + } + + if (type & PERF_SAMPLE_CPU) { + u.val32[0] = sample->cpu; + if (swapped) { + /* + * Inverse of what is done in perf_event__parse_sample + */ + u.val32[0] = bswap_32(u.val32[0]); + u.val64 = bswap_64(u.val64); + } + *array = u.val64; + array++; + } + + if (type & PERF_SAMPLE_PERIOD) { + *array = sample->period; + array++; + } + + return 0; +} diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 30e9c6b6fc3..fb696124ad6 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -134,6 +134,14 @@ static inline int perf_session__parse_sample(struct perf_session *session, session->header.needs_swap); } +static inline int perf_session__synthesize_sample(struct perf_session *session, + union perf_event *event, + const struct perf_sample *sample) +{ + return perf_event__synthesize_sample(event, session->sample_type, + sample, session->header.needs_swap); +} + struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, unsigned int type); -- cgit v1.2.3-70-g09d2 From 9b6cf1a0120a80ec342f10c297efaa0ba79f7ab7 Mon Sep 17 00:00:00 2001 From: Arun Thomas Date: Wed, 17 Aug 2011 00:34:14 +0200 Subject: tools/power turbostat: update fields in manpage Field names were shortened: "pkg" is now "pk", "core" is now "cr" Signed-off-by: Arun Thomas Signed-off-by: Jiri Kosina --- tools/power/x86/turbostat/turbostat.8 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'tools') diff --git a/tools/power/x86/turbostat/turbostat.8 b/tools/power/x86/turbostat/turbostat.8 index ff75125deed..555c69a5592 100644 --- a/tools/power/x86/turbostat/turbostat.8 +++ b/tools/power/x86/turbostat/turbostat.8 @@ -38,8 +38,8 @@ displays the statistics gathered since it was forked. .PP .SH FIELD DESCRIPTIONS .nf -\fBpkg\fP processor package number. -\fBcore\fP processor core number. +\fBpk\fP processor package number. +\fBcr\fP processor core number. \fBCPU\fP Linux CPU (logical processor) number. \fB%c0\fP percent of the interval that the CPU retired instructions. \fBGHz\fP average clock rate while the CPU was in c0 state. @@ -58,7 +58,7 @@ Subsequent rows show per-CPU statistics. .nf [root@x980]# ./turbostat -core CPU %c0 GHz TSC %c1 %c3 %c6 %pc3 %pc6 +cr CPU %c0 GHz TSC %c1 %c3 %c6 %pc3 %pc6 0.04 1.62 3.38 0.11 0.00 99.85 0.00 95.07 0 0 0.04 1.62 3.38 0.06 0.00 99.90 0.00 95.07 0 6 0.02 1.62 3.38 0.08 0.00 99.90 0.00 95.07 @@ -102,7 +102,7 @@ until ^C while the other CPUs are mostly idle: .nf [root@x980 lenb]# ./turbostat cat /dev/zero > /dev/null -^Ccore CPU %c0 GHz TSC %c1 %c3 %c6 %pc3 %pc6 +^Ccr CPU %c0 GHz TSC %c1 %c3 %c6 %pc3 %pc6 8.49 3.63 3.38 16.23 0.66 74.63 0.00 0.00 0 0 1.22 3.62 3.38 32.18 0.00 66.60 0.00 0.00 0 6 0.40 3.61 3.38 33.00 0.00 66.60 0.00 0.00 -- cgit v1.2.3-70-g09d2 From 3e76ac78b08479e84a3eca3fb1b3066fb8230461 Mon Sep 17 00:00:00 2001 From: Andrew Vagin Date: Tue, 20 Dec 2011 17:32:45 +0300 Subject: perf record: Add ability to record event period The problem is that when SAMPLE_PERIOD is not set, the kernel generates a number of samples in proportion to an event's period. Number of these samples may be too big and the kernel throttles all samples above a defined limit. E.g.: I want to trace when a process sleeps. I created a process which sleeps for 1ms and for 4ms. perf got 100 events in both cases. swapper 0 [000] 1141.371830: sched_stat_sleep: comm=foo pid=1801 delay=1386750 [ns] swapper 0 [000] 1141.369444: sched_stat_sleep: comm=foo pid=1801 delay=4499585 [ns] In the first case a kernel want to send 4499585 events and in the second case it wants to send 1386750 events. perf-reports shows that process sleeps in both places equal time. Instead of this we can get only one sample with an attribute period. As result we have less data transferring between kernel and user-space and we avoid throttling of samples. The patch "events: Don't divide events if it has field period" added a kernel part of this functionality. Acked-by: Arun Sharma Cc: Arun Sharma Cc: David Ahern Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Cc: devel@openvz.org Link: http://lkml.kernel.org/r/1324391565-1369947-1-git-send-email-avagin@openvz.org Signed-off-by: Andrew Vagin Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 1 + tools/perf/perf.h | 1 + tools/perf/util/evsel.c | 3 +++ 3 files changed, 5 insertions(+) (limited to 'tools') diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 766fa0a91a3..f8fd14fb62e 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -700,6 +700,7 @@ const struct option record_options[] = { OPT_BOOLEAN('d', "data", &record.opts.sample_address, "Sample addresses"), OPT_BOOLEAN('T', "timestamp", &record.opts.sample_time, "Sample timestamps"), + OPT_BOOLEAN('P', "period", &record.opts.period, "Sample period"), OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples, "don't sample"), OPT_BOOLEAN('N', "no-buildid-cache", &record.no_buildid_cache, diff --git a/tools/perf/perf.h b/tools/perf/perf.h index ea804f5a8cc..64f8bee31ce 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h @@ -200,6 +200,7 @@ struct perf_record_opts { bool sample_time; bool sample_id_all_avail; bool system_wide; + bool period; unsigned int freq; unsigned int mmap_pages; unsigned int user_freq; diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 4a8c8b02e9c..60ad0286759 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -108,6 +108,9 @@ void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts) if (opts->system_wide) attr->sample_type |= PERF_SAMPLE_CPU; + if (opts->period) + attr->sample_type |= PERF_SAMPLE_PERIOD; + if (opts->sample_id_all_avail && (opts->sample_time || opts->system_wide || !opts->no_inherit || opts->cpu_list)) -- cgit v1.2.3-70-g09d2 From f3bda2c9a689b38c059f7cb2d761ff58a2996370 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 15 Dec 2011 17:32:39 +0100 Subject: perf evsel: Fix uninitialized memory access to struct perf_sample Memory in struct perf_sample is not fully initialized during parsing. Depending on sampling data some parts may left unchanged. Zero out struct perf_sample first to avoid access to uninitialized memory. Cc: Ingo Molnar Link: http://lkml.kernel.org/r/1323966762-8574-2-git-send-email-robert.richter@amd.com Signed-off-by: Robert Richter Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evsel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 60ad0286759..667f3b78bb2 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -460,7 +460,7 @@ int perf_event__parse_sample(const union perf_event *event, u64 type, u32 val32[2]; } u; - + memset(data, 0, sizeof(*data)); data->cpu = data->pid = data->tid = -1; data->stream_id = data->id = data->time = -1ULL; -- cgit v1.2.3-70-g09d2 From 6581f6e35f7d0338f699fce660adb48e863f2b59 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 13 Dec 2011 00:16:50 +0900 Subject: perf report: Document '--call-graph' for optional print_limit argument The '--call-graph' command line option can receive undocumented optional print_limit argument. Besides, use strtoul() to parse the option since its type is u32. Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1323703017-6060-2-git-send-email-namhyung@gmail.com Signed-off-by: Namhyung Kim Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-report.txt | 5 +++-- tools/perf/builtin-report.c | 6 +++--- 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'tools') diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt index dc85392a5ac..35af0dc8ccb 100644 --- a/tools/perf/Documentation/perf-report.txt +++ b/tools/perf/Documentation/perf-report.txt @@ -80,9 +80,10 @@ OPTIONS --dump-raw-trace:: Dump raw trace in ASCII. --g [type,min,order]:: +-g [type,min[,limit],order]:: --call-graph:: - Display call chains using type, min percent threshold and order. + Display call chains using type, min percent threshold, optional print + limit and order. type can be either: - flat: single column, linear exposure of call chains. - graph: use a graph tree, displaying absolute overhead rates. diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index ece7c5d3f50..b2654c9fb5c 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -407,7 +407,7 @@ parse_callchain_opt(const struct option *opt, const char *arg, int unset) goto setup; if (tok2[0] != 'c') { - callchain_param.print_limit = strtod(tok2, &endptr); + callchain_param.print_limit = strtoul(tok2, &endptr, 0); tok2 = strtok(NULL, ","); if (!tok2) goto setup; @@ -485,8 +485,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __used) "regex filter to identify parent, see: '--sort parent'"), OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other, "Only display entries with parent-match"), - OPT_CALLBACK_DEFAULT('g', "call-graph", &report, "output_type,min_percent, call_order", - "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold and callchain order. " + OPT_CALLBACK_DEFAULT('g', "call-graph", &report, "output_type,min_percent[,print_limit],call_order", + "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold, optional print limit and callchain order. " "Default: fractal,0.5,callee", &parse_callchain_opt, callchain_default_opt), OPT_BOOLEAN('G', "inverted", &report.inverted_callchain, "alias for inverted call graph"), -- cgit v1.2.3-70-g09d2 From 301b195db179241da8be25f345f3c4e64960f1d5 Mon Sep 17 00:00:00 2001 From: Nelson Elhage Date: Mon, 19 Dec 2011 08:39:30 -0500 Subject: perf evlist: Fix errno value reporting on failed mmap On failure, perf_evlist__mmap_per_{cpu,thread} will try to munmap() every map that doesn't have a NULL base. This will fail with EINVAL if one of them has base == MAP_FAILED, clobbering errno, so that perf_evlist__map will return EINVAL on any failure regardless of the root cause. Fix this by resetting failed maps to a NULL base. Acked-by: Namhyung Kim Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1324301972-22740-2-git-send-email-nelhage@nelhage.com Signed-off-by: Nelson Elhage Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evlist.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 8b19e7a1e88..963d63dde45 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -447,8 +447,10 @@ static int __perf_evlist__mmap(struct perf_evlist *evlist, evlist->mmap[idx].mask = mask; evlist->mmap[idx].base = mmap(NULL, evlist->mmap_len, prot, MAP_SHARED, fd, 0); - if (evlist->mmap[idx].base == MAP_FAILED) + if (evlist->mmap[idx].base == MAP_FAILED) { + evlist->mmap[idx].base = NULL; return -1; + } perf_evlist__add_pollfd(evlist, fd); return 0; -- cgit v1.2.3-70-g09d2 From 2b600f9578852d12af59420011e3dadfaa58b043 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 13 Dec 2011 00:16:51 +0900 Subject: perf symbols: Get rid of duplicated snprintf() The 'path' variable is set on a upper line, don't need to do it again. Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1323703017-6060-3-git-send-email-namhyung@gmail.com Signed-off-by: Namhyung Kim Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/symbol.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'tools') diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 632b50c7bc2..e54b13d4c35 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -1757,7 +1757,7 @@ static int map_groups__set_modules_path_dir(struct map_groups *mg, struct stat st; /*sshfs might return bad dent->d_type, so we have to stat*/ - sprintf(path, "%s/%s", dir_name, dent->d_name); + snprintf(path, sizeof(path), "%s/%s", dir_name, dent->d_name); if (stat(path, &st)) continue; @@ -1766,8 +1766,6 @@ static int map_groups__set_modules_path_dir(struct map_groups *mg, !strcmp(dent->d_name, "..")) continue; - snprintf(path, sizeof(path), "%s/%s", - dir_name, dent->d_name); ret = map_groups__set_modules_path_dir(mg, path); if (ret < 0) goto out; @@ -1788,9 +1786,6 @@ static int map_groups__set_modules_path_dir(struct map_groups *mg, if (map == NULL) continue; - snprintf(path, sizeof(path), "%s/%s", - dir_name, dent->d_name); - long_name = strdup(path); if (long_name == NULL) { ret = -1; -- cgit v1.2.3-70-g09d2 From d74c896b7e3250a07f7d0315eecdd2ae1a7bc3c3 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 13 Dec 2011 00:16:52 +0900 Subject: perf symbols: Fix error path on symbol__init() The order of freeing comm_list and dso_list should be reversed. Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1323703017-6060-4-git-send-email-namhyung@gmail.com Signed-off-by: Namhyung Kim Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/symbol.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tools') diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index e54b13d4c35..215d50f2042 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -2604,10 +2604,10 @@ int symbol__init(void) symbol_conf.initialized = true; return 0; -out_free_dso_list: - strlist__delete(symbol_conf.dso_list); out_free_comm_list: strlist__delete(symbol_conf.comm_list); +out_free_dso_list: + strlist__delete(symbol_conf.dso_list); return -1; } -- cgit v1.2.3-70-g09d2 From 0161d82e9b740caa90f508138d1ae1b9d981b6d3 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 13 Dec 2011 00:16:53 +0900 Subject: perf tools: Fix a memory leak on perf_read_values_destroy After freeing each elements of the @values->value, we should free itself too. Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1323703017-6060-5-git-send-email-namhyung@gmail.com Signed-off-by: Namhyung Kim Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/values.c | 1 + 1 file changed, 1 insertion(+) (limited to 'tools') diff --git a/tools/perf/util/values.c b/tools/perf/util/values.c index bdd33470b23..697c8b4e59c 100644 --- a/tools/perf/util/values.c +++ b/tools/perf/util/values.c @@ -32,6 +32,7 @@ void perf_read_values_destroy(struct perf_read_values *values) for (i = 0; i < values->threads; i++) free(values->value[i]); + free(values->value); free(values->pid); free(values->tid); free(values->counterrawid); -- cgit v1.2.3-70-g09d2 From 5f9273d64a5ccbd3c2b4446cc8b71123ed5d6366 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 13 Dec 2011 22:52:03 +0900 Subject: perf tools: Remove stale git headlines from top comment These files are part of PERF not GIT although they're come from there :) Cc: Ingo Molnar Cc: Johannes Schindelin Cc: Linus Torvalds Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1323784323-2150-1-git-send-email-namhyung@gmail.com Signed-off-by: Namhyung Kim Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/config.c | 5 ++++- tools/perf/util/usage.c | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'tools') diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c index 80d9598db31..0deac6a14b6 100644 --- a/tools/perf/util/config.c +++ b/tools/perf/util/config.c @@ -1,5 +1,8 @@ /* - * GIT - The information manager from hell + * config.c + * + * Helper functions for parsing config items. + * Originally copied from GIT source. * * Copyright (C) Linus Torvalds, 2005 * Copyright (C) Johannes Schindelin, 2005 diff --git a/tools/perf/util/usage.c b/tools/perf/util/usage.c index e16bf9a707e..d76d1c0ff98 100644 --- a/tools/perf/util/usage.c +++ b/tools/perf/util/usage.c @@ -1,5 +1,8 @@ /* - * GIT - The information manager from hell + * usage.c + * + * Various reporting routines. + * Originally copied from GIT source. * * Copyright (C) Linus Torvalds, 2005 */ -- cgit v1.2.3-70-g09d2 From cb8f4e9aa37c469ddd80dda51469f327606c0118 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 13 Dec 2011 00:16:55 +0900 Subject: perf events: Tidy up perf_event__preprocess_sample Use local variable 'dso' to reduce typing a bit and rearrange the if condition. Also NULL check of al->map in the condition is not necessary. Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1323703017-6060-7-git-send-email-namhyung@gmail.com Signed-off-by: Namhyung Kim Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/event.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'tools') diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 97c479bcb0d..b7c7f39a8f6 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -814,13 +814,14 @@ int perf_event__preprocess_sample(const union perf_event *event, al->cpu = sample->cpu; if (al->map) { + struct dso *dso = al->map->dso; + if (symbol_conf.dso_list && - (!al->map || !al->map->dso || - !(strlist__has_entry(symbol_conf.dso_list, - al->map->dso->short_name) || - (al->map->dso->short_name != al->map->dso->long_name && - strlist__has_entry(symbol_conf.dso_list, - al->map->dso->long_name))))) + (!dso || !(strlist__has_entry(symbol_conf.dso_list, + dso->short_name) || + (dso->short_name != dso->long_name && + strlist__has_entry(symbol_conf.dso_list, + dso->long_name))))) goto out_filtered; al->sym = map__find_symbol(al->map, al->addr, filter); -- cgit v1.2.3-70-g09d2 From 65c1e0452a3389f9b7b8c1b23305ed2922fafb2d Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Thu, 15 Dec 2011 16:30:39 +0100 Subject: perf test: Add more automated tests for event parsing Adding automated tests for event parsing to include testing for modifier and ',' operator. Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Cc: cjashfor@linux.vnet.ibm.com Link: http://lkml.kernel.org/r/1323963039-7602-4-git-send-email-jolsa@redhat.com Signed-off-by: Jiri Olsa [ committer note: Remove some tests that need group_leader & bison patchkits ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-test.c | 127 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 126 insertions(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c index 6173f780dce..2b9a7f497a2 100644 --- a/tools/perf/builtin-test.c +++ b/tools/perf/builtin-test.c @@ -603,7 +603,7 @@ out_free_threads: #define TEST_ASSERT_VAL(text, cond) \ do { \ - if (!cond) { \ + if (!(cond)) { \ pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \ return -1; \ } \ @@ -759,6 +759,103 @@ static int test__checkevent_breakpoint_w(struct perf_evlist *evlist) return 0; } +static int test__checkevent_tracepoint_modifier(struct perf_evlist *evlist) +{ + struct perf_evsel *evsel = list_entry(evlist->entries.next, + struct perf_evsel, node); + + TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); + TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); + + return test__checkevent_tracepoint(evlist); +} + +static int +test__checkevent_tracepoint_multi_modifier(struct perf_evlist *evlist) +{ + struct perf_evsel *evsel; + + TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1); + + list_for_each_entry(evsel, &evlist->entries, node) { + TEST_ASSERT_VAL("wrong exclude_user", + !evsel->attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", + evsel->attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); + TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); + } + + return test__checkevent_tracepoint_multi(evlist); +} + +static int test__checkevent_raw_modifier(struct perf_evlist *evlist) +{ + struct perf_evsel *evsel = list_entry(evlist->entries.next, + struct perf_evsel, node); + + TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); + TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); + + return test__checkevent_raw(evlist); +} + +static int test__checkevent_numeric_modifier(struct perf_evlist *evlist) +{ + struct perf_evsel *evsel = list_entry(evlist->entries.next, + struct perf_evsel, node); + + TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); + TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); + + return test__checkevent_numeric(evlist); +} + +static int test__checkevent_symbolic_name_modifier(struct perf_evlist *evlist) +{ + struct perf_evsel *evsel = list_entry(evlist->entries.next, + struct perf_evsel, node); + + TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); + TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); + + return test__checkevent_symbolic_name(evlist); +} + +static int test__checkevent_symbolic_alias_modifier(struct perf_evlist *evlist) +{ + struct perf_evsel *evsel = list_entry(evlist->entries.next, + struct perf_evsel, node); + + TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); + TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); + + return test__checkevent_symbolic_alias(evlist); +} + +static int test__checkevent_genhw_modifier(struct perf_evlist *evlist) +{ + struct perf_evsel *evsel = list_entry(evlist->entries.next, + struct perf_evsel, node); + + TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); + TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); + + return test__checkevent_genhw(evlist); +} + static struct test__event_st { const char *name; __u32 type; @@ -808,6 +905,34 @@ static struct test__event_st { .name = "mem:0:w", .check = test__checkevent_breakpoint_w, }, + { + .name = "syscalls:sys_enter_open:k", + .check = test__checkevent_tracepoint_modifier, + }, + { + .name = "syscalls:*:u", + .check = test__checkevent_tracepoint_multi_modifier, + }, + { + .name = "r1:kp", + .check = test__checkevent_raw_modifier, + }, + { + .name = "1:1:hp", + .check = test__checkevent_numeric_modifier, + }, + { + .name = "instructions:h", + .check = test__checkevent_symbolic_name_modifier, + }, + { + .name = "faults:u", + .check = test__checkevent_symbolic_alias_modifier, + }, + { + .name = "L1-dcache-load-miss:kp", + .check = test__checkevent_genhw_modifier, + }, }; #define TEST__EVENTS_CNT (sizeof(test__events) / sizeof(struct test__event_st)) -- cgit v1.2.3-70-g09d2 From f1ac18af219835fd5b8e19c14d2dd75c55f78737 Mon Sep 17 00:00:00 2001 From: Stephane Eranian Date: Sun, 11 Dec 2011 00:28:54 +0100 Subject: perf: Add support for PERF_HW_COUNT_REF_CPU_CYCLES Add new generic hw event: ref-cycles, which maps to PERF_HW_COUNT_REF_CPUCYCLES: $ perf stat -e ref-cycles ls Signed-off-by: Stephane Eranian Signed-off-by: Peter Zijlstra Link: http://lkml.kernel.org/r/1323559734-3488-5-git-send-email-eranian@google.com Signed-off-by: Ingo Molnar --- tools/perf/util/parse-events.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'tools') diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 586ab3fe60f..531c283fc0c 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -38,6 +38,7 @@ static struct event_symbol event_symbols[] = { { CHW(BRANCH_INSTRUCTIONS), "branch-instructions", "branches" }, { CHW(BRANCH_MISSES), "branch-misses", "" }, { CHW(BUS_CYCLES), "bus-cycles", "" }, + { CHW(REF_CPU_CYCLES), "ref-cycles", "" }, { CSW(CPU_CLOCK), "cpu-clock", "" }, { CSW(TASK_CLOCK), "task-clock", "" }, @@ -68,6 +69,7 @@ static const char *hw_event_names[PERF_COUNT_HW_MAX] = { "bus-cycles", "stalled-cycles-frontend", "stalled-cycles-backend", + "ref-cycles", }; static const char *sw_event_names[PERF_COUNT_SW_MAX] = { -- cgit v1.2.3-70-g09d2 From fb2baceb5a64990163e93b77ee205d0173202ee6 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 13 Dec 2011 00:16:56 +0900 Subject: perf report: Fix usage string perf report does not take a command from command line. Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1323703017-6060-8-git-send-email-namhyung@gmail.com Signed-off-by: Namhyung Kim Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-report.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index b2654c9fb5c..9051f6bfaa7 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -432,7 +432,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __used) { char callchain_default_opt[] = "fractal,0.5,callee"; const char * const report_usage[] = { - "perf report [] ", + "perf report []", NULL }; struct perf_report report = { -- cgit v1.2.3-70-g09d2 From dad98754924735d4dfcbd49b68c00957e999c0ef Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Tue, 22 Nov 2011 20:48:57 -0500 Subject: ktest: Allow bisect test to restart where it left off If a bisect is killed for some reason, have ktest detect that a bisect is in progress and if so, allow the user to start the bisect where it left off. Signed-off-by: Steven Rostedt --- tools/testing/ktest/ktest.pl | 70 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 64 insertions(+), 6 deletions(-) (limited to 'tools') diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl index 77b464980de..2ffb67c3c49 100755 --- a/tools/testing/ktest/ktest.pl +++ b/tools/testing/ktest/ktest.pl @@ -239,20 +239,36 @@ $config_help{"REBOOT_SCRIPT"} = << "EOF" EOF ; -sub read_yn { - my ($prompt) = @_; +sub read_prompt { + my ($cancel, $prompt) = @_; my $ans; for (;;) { - print "$prompt [Y/n] "; + if ($cancel) { + print "$prompt [y/n/C] "; + } else { + print "$prompt [Y/n] "; + } $ans = ; chomp $ans; if ($ans =~ /^\s*$/) { - $ans = "y"; + if ($cancel) { + $ans = "c"; + } else { + $ans = "y"; + } } last if ($ans =~ /^y$/i || $ans =~ /^n$/i); - print "Please answer either 'y' or 'n'.\n"; + if ($cancel) { + last if ($ans =~ /^c$/i); + print "Please answer either 'y', 'n' or 'c'.\n"; + } else { + print "Please answer either 'y' or 'n'.\n"; + } + } + if ($ans =~ /^c/i) { + exit; } if ($ans !~ /^y$/i) { return 0; @@ -260,6 +276,18 @@ sub read_yn { return 1; } +sub read_yn { + my ($prompt) = @_; + + return read_prompt 0, $prompt; +} + +sub read_ync { + my ($prompt) = @_; + + return read_prompt 1, $prompt; +} + sub get_ktest_config { my ($config) = @_; my $ans; @@ -1895,6 +1923,13 @@ sub run_bisect { } } +sub update_bisect_replay { + my $tmp_log = "$tmpdir/ktest_bisect_log"; + run_command "git bisect log > $tmp_log" or + die "can't create bisect log"; + return $tmp_log; +} + sub bisect { my ($i) = @_; @@ -1934,8 +1969,31 @@ sub bisect { $type = "boot"; } + # Check if a bisect was running + my $bisect_start_file = "$builddir/.git/BISECT_START"; + my $check = $opt{"BISECT_CHECK[$i]"}; - if (defined($check) && $check ne "0") { + my $do_check = defined($check) && $check ne "0"; + + if ( -f $bisect_start_file ) { + print "Bisect in progress found\n"; + if ($do_check) { + print " If you say yes, then no checks of good or bad will be done\n"; + } + if (defined($replay)) { + print "** BISECT_REPLAY is defined in config file **"; + print " Ignore config option and perform new git bisect log?\n"; + if (read_ync " (yes, no, or cancel) ") { + $replay = update_bisect_replay; + $do_check = 0; + } + } elsif (read_yn "read git log and continue?") { + $replay = update_bisect_replay; + $do_check = 0; + } + } + + if ($do_check) { # get current HEAD my $head = get_sha1("HEAD"); -- cgit v1.2.3-70-g09d2 From c4261d0f62ccbb42184d13b43807b36b100e8fb5 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 23 Nov 2011 13:41:18 -0500 Subject: ktest: Ask for type of test when creating a new config When no argument is supplied to ktest, or the config applied does not exist and a new config is being created, instead of just using the default test type, give the user an option to pick the test type of either 'build, install, or boot'. Other options may be added later but then those would require more questions as they require more fields. But that's for another release of ktest to add that feature. Signed-off-by: Steven Rostedt --- tools/testing/ktest/ktest.pl | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'tools') diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl index 2ffb67c3c49..f50b44fa8a0 100755 --- a/tools/testing/ktest/ktest.pl +++ b/tools/testing/ktest/ktest.pl @@ -752,6 +752,15 @@ sub __read_config { return $test_case; } +sub get_test_case { + print "What test case would you like to run?\n"; + print " (build, install or boot)\n"; + print " Other tests are available but require editing the config file\n"; + my $ans = ; + chomp $ans; + $default{"TEST_TYPE"} = $ans; +} + sub read_config { my ($config) = @_; @@ -766,10 +775,7 @@ sub read_config { # was a test specified? if (!$test_case) { print "No test case specified.\n"; - print "What test case would you like to run?\n"; - my $ans = ; - chomp $ans; - $default{"TEST_TYPE"} = $ans; + get_test_case; } # set any defaults @@ -3070,6 +3076,7 @@ if ($#ARGV == 0) { } if (! -f $ktest_config) { + get_test_case; open(OUT, ">$ktest_config") or die "Can not create $ktest_config"; print OUT << "EOF" # Generated by ktest.pl @@ -3088,6 +3095,7 @@ THIS_DIR := $variable{"PWD"} # Define each test with TEST_START # The config options below it will override the defaults TEST_START +TEST_TYPE = $default{"TEST_TYPE"} DEFAULTS EOF -- cgit v1.2.3-70-g09d2 From bb8474b181a715182a110c8ed2b3786ea7487f2b Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 23 Nov 2011 15:58:00 -0500 Subject: ktest: Do not ask for some options if the only test is build When creating a ktest config or if te config only has build only tests, some of the manditory config options are not needed. Do not ask for them if all tests in the config file are just build tests. Suggested-by: Darren Hart Signed-off-by: Steven Rostedt --- tools/testing/ktest/ktest.pl | 43 +++++++++++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 12 deletions(-) (limited to 'tools') diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl index f50b44fa8a0..7159e10ab8a 100755 --- a/tools/testing/ktest/ktest.pl +++ b/tools/testing/ktest/ktest.pl @@ -22,7 +22,7 @@ my %default; #default opts $default{"NUM_TESTS"} = 1; -$default{"TEST_TYPE"} = "test"; +$default{"TEST_TYPE"} = "build"; $default{"BUILD_TYPE"} = "randconfig"; $default{"MAKE_CMD"} = "make"; $default{"TIMEOUT"} = 120; @@ -136,6 +136,10 @@ my $localversion; my $iteration = 0; my $successes = 0; +# set when a test is something other that just building +# which would require more options. +my $buildonly = 1; + my %entered_configs; my %config_help; my %variable; @@ -149,6 +153,7 @@ chomp ($variable{"PWD"} = `pwd`); $config_help{"MACHINE"} = << "EOF" The machine hostname that you will test. + For build only tests, it is still needed to differentiate log files. EOF ; $config_help{"SSH_USER"} = << "EOF" @@ -321,15 +326,22 @@ sub get_ktest_config { sub get_ktest_configs { get_ktest_config("MACHINE"); - get_ktest_config("SSH_USER"); get_ktest_config("BUILD_DIR"); get_ktest_config("OUTPUT_DIR"); - get_ktest_config("BUILD_TARGET"); - get_ktest_config("TARGET_IMAGE"); - get_ktest_config("POWER_CYCLE"); - get_ktest_config("CONSOLE"); + + # options required for other than just building a kernel + if (!$buildonly) { + get_ktest_config("SSH_USER"); + get_ktest_config("BUILD_TARGET"); + get_ktest_config("TARGET_IMAGE"); + get_ktest_config("POWER_CYCLE"); + get_ktest_config("CONSOLE"); + } + get_ktest_config("LOCALVERSION"); + return if ($buildonly); + my $rtype = $opt{"REBOOT_TYPE"}; if (!defined($rtype)) { @@ -388,6 +400,12 @@ sub process_variables { sub set_value { my ($lvalue, $rvalue, $override, $overrides, $name) = @_; + if ($lvalue =~ /^TEST_TYPE(\[.*\])?$/ && $rvalue ne "build") { + # Note if a test is something other than build, then we + # will need other manditory options. + $buildonly = 0; + } + if (defined($opt{$lvalue})) { if (!$override || defined(${$overrides}{$lvalue})) { my $extra = ""; @@ -3271,18 +3289,19 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { $ENV{"SSH_USER"} = $ssh_user; $ENV{"MACHINE"} = $machine; - $target = "$ssh_user\@$machine"; - $buildlog = "$tmpdir/buildlog-$machine"; $testlog = "$tmpdir/testlog-$machine"; $dmesg = "$tmpdir/dmesg-$machine"; $make = "$makecmd O=$outputdir"; $output_config = "$outputdir/.config"; - if ($reboot_type eq "grub") { - dodie "GRUB_MENU not defined" if (!defined($grub_menu)); - } elsif (!defined($reboot_script)) { - dodie "REBOOT_SCRIPT not defined" + if (!$buildonly) { + $target = "$ssh_user\@$machine"; + if ($reboot_type eq "grub") { + dodie "GRUB_MENU not defined" if (!defined($grub_menu)); + } elsif (!defined($reboot_script)) { + dodie "REBOOT_SCRIPT not defined" + } } my $run_type = $build_type; -- cgit v1.2.3-70-g09d2 From dbd3783b4dd33dd7ce5c378bf5b1da27a1298735 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 23 Nov 2011 16:00:48 -0500 Subject: ktest: When creating a new config, ask for BUILD_OPTIONS When creating a new config, ask for the BUILD_OPTIONS variable that lets users add things like -j20 to the make. Signed-off-by: Steven Rostedt --- tools/testing/ktest/ktest.pl | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl index 7159e10ab8a..2b547d6683c 100755 --- a/tools/testing/ktest/ktest.pl +++ b/tools/testing/ktest/ktest.pl @@ -140,6 +140,9 @@ my $successes = 0; # which would require more options. my $buildonly = 1; +# set when creating a new config +my $newconfig = 0; + my %entered_configs; my %config_help; my %variable; @@ -179,6 +182,11 @@ $config_help{"BUILD_TARGET"} = << "EOF" (relative to OUTPUT_DIR) EOF ; +$config_help{"BUILD_OPTIONS"} = << "EOF" + Options to add to \"make\" when building. + i.e. -j20 +EOF + ; $config_help{"TARGET_IMAGE"} = << "EOF" The place to put your image on the test machine. EOF @@ -306,7 +314,7 @@ sub get_ktest_config { for (;;) { print "$config = "; - if (defined($default{$config})) { + if (defined($default{$config}) && length($default{$config})) { print "\[$default{$config}\] "; } $ans = ; @@ -329,6 +337,10 @@ sub get_ktest_configs { get_ktest_config("BUILD_DIR"); get_ktest_config("OUTPUT_DIR"); + if ($newconfig) { + get_ktest_config("BUILD_OPTIONS"); + } + # options required for other than just building a kernel if (!$buildonly) { get_ktest_config("SSH_USER"); @@ -3094,6 +3106,7 @@ if ($#ARGV == 0) { } if (! -f $ktest_config) { + $newconfig = 1; get_test_case; open(OUT, ">$ktest_config") or die "Can not create $ktest_config"; print OUT << "EOF" -- cgit v1.2.3-70-g09d2 From 165708b273f87ac52a4564b114a6c046e6b3a02d Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Sat, 26 Nov 2011 20:56:52 -0500 Subject: ktest: Only ask options needed for install If all the tests are only for build or install, do not ask for options not needed to do the install, if the options do not exist. Signed-off-by: Steven Rostedt --- tools/testing/ktest/ktest.pl | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) (limited to 'tools') diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl index 2b547d6683c..5d82c275e9e 100755 --- a/tools/testing/ktest/ktest.pl +++ b/tools/testing/ktest/ktest.pl @@ -136,7 +136,7 @@ my $localversion; my $iteration = 0; my $successes = 0; -# set when a test is something other that just building +# set when a test is something other that just building or install # which would require more options. my $buildonly = 1; @@ -343,11 +343,15 @@ sub get_ktest_configs { # options required for other than just building a kernel if (!$buildonly) { + get_ktest_config("POWER_CYCLE"); + get_ktest_config("CONSOLE"); + } + + # options required for install and more + if ($buildonly != 1) { get_ktest_config("SSH_USER"); get_ktest_config("BUILD_TARGET"); get_ktest_config("TARGET_IMAGE"); - get_ktest_config("POWER_CYCLE"); - get_ktest_config("CONSOLE"); } get_ktest_config("LOCALVERSION"); @@ -412,10 +416,15 @@ sub process_variables { sub set_value { my ($lvalue, $rvalue, $override, $overrides, $name) = @_; - if ($lvalue =~ /^TEST_TYPE(\[.*\])?$/ && $rvalue ne "build") { + if ($buildonly && $lvalue =~ /^TEST_TYPE(\[.*\])?$/ && $rvalue ne "build") { # Note if a test is something other than build, then we # will need other manditory options. - $buildonly = 0; + if ($rvalue ne "install") { + $buildonly = 0; + } else { + # install still limits some manditory options. + $buildonly = 2; + } } if (defined($opt{$lvalue})) { -- cgit v1.2.3-70-g09d2 From 2b29b2f8f869847d437b525d4cf027c09dc38286 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Thu, 22 Dec 2011 11:25:46 -0500 Subject: ktest: Evaluate $KERNEL_VERSION in both install and post install The install process may also need to know what the kernel version is, to add it to the name. Evaluate it for both install and post install. Signed-off-by: Steven Rostedt --- tools/testing/ktest/ktest.pl | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'tools') diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl index 5d82c275e9e..59738aa6ca7 100755 --- a/tools/testing/ktest/ktest.pl +++ b/tools/testing/ktest/ktest.pl @@ -1434,12 +1434,19 @@ sub monitor { return 1; } +sub eval_kernel_version { + my ($option) = @_; + + $option =~ s/\$KERNEL_VERSION/$version/g; + + return $option; +} + sub do_post_install { return if (!defined($post_install)); - my $cp_post_install = $post_install; - $cp_post_install =~ s/\$KERNEL_VERSION/$version/g; + my $cp_post_install = eval_kernel_version $post_install; run_command "$cp_post_install" or dodie "Failed to run post install"; } @@ -1448,7 +1455,9 @@ sub install { return if ($no_install); - run_scp "$outputdir/$build_target", "$target_image" or + my $cp_target = eval_kernel_version $target_image; + + run_scp "$outputdir/$build_target", "$cp_target" or dodie "failed to copy image"; my $install_mods = 0; -- cgit v1.2.3-70-g09d2 From cad9666980c1c1a76345f36a68e96fda3d78d857 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Thu, 22 Dec 2011 11:32:52 -0500 Subject: ktest: Evaluate options before processing them All options can take variables "${var}". Before doing any processing or decision making on the content of an option, evaluate it incase there are variables that may change the outcome. Signed-off-by: Steven Rostedt --- tools/testing/ktest/ktest.pl | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'tools') diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl index 59738aa6ca7..04a7bb573da 100755 --- a/tools/testing/ktest/ktest.pl +++ b/tools/testing/ktest/ktest.pl @@ -416,10 +416,12 @@ sub process_variables { sub set_value { my ($lvalue, $rvalue, $override, $overrides, $name) = @_; - if ($buildonly && $lvalue =~ /^TEST_TYPE(\[.*\])?$/ && $rvalue ne "build") { + my $prvalue = process_variables($rvalue); + + if ($buildonly && $lvalue =~ /^TEST_TYPE(\[.*\])?$/ && $prvalue ne "build") { # Note if a test is something other than build, then we # will need other manditory options. - if ($rvalue ne "install") { + if ($prvalue ne "install") { $buildonly = 0; } else { # install still limits some manditory options. @@ -435,13 +437,12 @@ sub set_value { } die "$name: $.: Option $lvalue defined more than once!\n$extra"; } - ${$overrides}{$lvalue} = $rvalue; + ${$overrides}{$lvalue} = $prvalue; } if ($rvalue =~ /^\s*$/) { delete $opt{$lvalue}; } else { - $rvalue = process_variables($rvalue); - $opt{$lvalue} = $rvalue; + $opt{$lvalue} = $prvalue; } } -- cgit v1.2.3-70-g09d2 From c5dacb88f0a6410b3270f77e3d1e1b159afc4adc Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Thu, 22 Dec 2011 12:43:57 -0500 Subject: ktest: Allow overriding bisect test results When running the ktest git bisect test, if the BISECT_TYPE is "test", the bisect is determined to be good or bad based off of the error code of the test that is run. Currently, if the test returns 0, it is considered a pass (good), a non-zero is considered a fail (bad). But it has been requested to add more options, and also change the meanings of the error codes of the test. For example, one may want the test to detect if the commit is not good or bad, (maybe the bisect came to a point where the code in question does not exist). The test could report an error code that should tell ktest to skip the commit. Also, a test could detect that something is horribly wrong and the biscet should just be aborted. The new options: BISECT_RET_GOOD BISECT_RET_BAD BISECT_RET_SKIP BISECT_RET_ABORT BISECT_RET_DEFAULT have been added. The first 4 take an integer value that will represent if the test should be considered a pass, fail, neither good nor bad, or abort respectively. The BISECT_RET_DEFAULT will bo whatever is not defined by the above codes. If only BISECT_RET_DEFAULT is defined, then all tests will do the default. Signed-off-by: Steven Rostedt --- tools/testing/ktest/ktest.pl | 47 +++++++++++++++++++++++++++++++++++++++++ tools/testing/ktest/sample.conf | 36 +++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) (limited to 'tools') diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl index 04a7bb573da..47c28146dfc 100755 --- a/tools/testing/ktest/ktest.pl +++ b/tools/testing/ktest/ktest.pl @@ -105,6 +105,11 @@ my $reverse_bisect; my $bisect_manual; my $bisect_skip; my $config_bisect_good; +my $bisect_ret_good; +my $bisect_ret_bad; +my $bisect_ret_skip; +my $bisect_ret_abort; +my $bisect_ret_default; my $in_patchcheck = 0; my $run_test; my $redirect; @@ -1854,6 +1859,43 @@ sub do_run_test { waitpid $child_pid, 0; $child_exit = $?; + if (!$bug && $in_bisect) { + if (defined($bisect_ret_good)) { + if ($child_exit == $bisect_ret_good) { + return 1; + } + } + if (defined($bisect_ret_skip)) { + if ($child_exit == $bisect_ret_skip) { + return -1; + } + } + if (defined($bisect_ret_abort)) { + if ($child_exit == $bisect_ret_abort) { + fail "test abort" and return -2; + } + } + if (defined($bisect_ret_bad)) { + if ($child_exit == $bisect_ret_skip) { + return 0; + } + } + if (defined($bisect_ret_default)) { + if ($bisect_ret_default eq "good") { + return 1; + } elsif ($bisect_ret_default eq "bad") { + return 0; + } elsif ($bisect_ret_default eq "skip") { + return -1; + } elsif ($bisect_ret_default eq "abort") { + return -2; + } else { + fail "unknown default action: $bisect_ret_default" + and return -2; + } + } + } + if ($bug || $child_exit) { return 0 if $in_bisect; fail "test failed" and return 0; @@ -3284,6 +3326,11 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { $bisect_manual = set_test_option("BISECT_MANUAL", $i); $bisect_skip = set_test_option("BISECT_SKIP", $i); $config_bisect_good = set_test_option("CONFIG_BISECT_GOOD", $i); + $bisect_ret_good = set_test_option("BISECT_RET_GOOD", $i); + $bisect_ret_bad = set_test_option("BISECT_RET_BAD", $i); + $bisect_ret_skip = set_test_option("BISECT_RET_SKIP", $i); + $bisect_ret_abort = set_test_option("BISECT_RET_ABORT", $i); + $bisect_ret_default = set_test_option("BISECT_RET_DEFAULT", $i); $store_failures = set_test_option("STORE_FAILURES", $i); $store_successes = set_test_option("STORE_SUCCESSES", $i); $test_name = set_test_option("TEST_NAME", $i); diff --git a/tools/testing/ktest/sample.conf b/tools/testing/ktest/sample.conf index 42e0eb9442e..2ff0f8c483e 100644 --- a/tools/testing/ktest/sample.conf +++ b/tools/testing/ktest/sample.conf @@ -868,6 +868,42 @@ # BISECT_BAD with BISECT_CHECK = good or # BISECT_CHECK = bad, respectively. # +# BISECT_RET_GOOD = 0 (optional, default undefined) +# +# In case the specificed test returns something other than just +# 0 for good, and non-zero for bad, you can override 0 being +# good by defining BISECT_RET_GOOD. +# +# BISECT_RET_BAD = 1 (optional, default undefined) +# +# In case the specificed test returns something other than just +# 0 for good, and non-zero for bad, you can override non-zero being +# bad by defining BISECT_RET_BAD. +# +# BISECT_RET_ABORT = 255 (optional, default undefined) +# +# If you need to abort the bisect if the test discovers something +# that was wrong, you can define BISECT_RET_ABORT to be the error +# code returned by the test in order to abort the bisect. +# +# BISECT_RET_SKIP = 2 (optional, default undefined) +# +# If the test detects that the current commit is neither good +# nor bad, but something else happened (another bug detected) +# you can specify BISECT_RET_SKIP to an error code that the +# test returns when it should skip the current commit. +# +# BISECT_RET_DEFAULT = good (optional, default undefined) +# +# You can override the default of what to do when the above +# options are not hit. This may be one of, "good", "bad", +# "abort" or "skip" (without the quotes). +# +# Note, if you do not define any of the previous BISECT_RET_* +# and define BISECT_RET_DEFAULT, all bisects results will do +# what the BISECT_RET_DEFAULT has. +# +# # Example: # TEST_START # TEST_TYPE = bisect -- cgit v1.2.3-70-g09d2 From bc7c580377195f9f4da31b63fbbf52293cb4c861 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Thu, 22 Dec 2011 16:29:10 -0500 Subject: ktest: Add options SWITCH_TO_GOOD and SWITCH_TO_TEST For machines that do no use grub, it may be needed to update an external image (tftp) before doing a reboot into either the test image or the known good image. The option SWITCH_TO_GOOD is added, where if it is defined, the command that is specified as its value will be executed before doing a reboot into a known good image. The option SWITCH_TO_TEST is added, where if it is defined, the command that is specified as its value will be executed before doing a reboot into the test image. Signed-off-by: Steven Rostedt --- tools/testing/ktest/ktest.pl | 33 ++++++++++++++++++++++++++------- tools/testing/ktest/sample.conf | 21 +++++++++++++++++++++ 2 files changed, 47 insertions(+), 7 deletions(-) (limited to 'tools') diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl index 47c28146dfc..ff21e921be2 100755 --- a/tools/testing/ktest/ktest.pl +++ b/tools/testing/ktest/ktest.pl @@ -79,6 +79,8 @@ my $reboot_script; my $power_cycle; my $reboot; my $reboot_on_error; +my $switch_to_good; +my $switch_to_test; my $poweroff_on_error; my $die_on_failure; my $powercycle_after_reboot; @@ -964,6 +966,17 @@ sub reboot { } } +sub reboot_to_good { + my ($time) = @_; + + if (defined($switch_to_good)) { + run_command $switch_to_good; + return; + } + + reboot $time; +} + sub do_not_reboot { my $i = $iteration; @@ -980,7 +993,7 @@ sub dodie { if ($reboot_on_error && !do_not_reboot) { doprint "REBOOTING\n"; - reboot; + reboot_to_good; } elsif ($poweroff_on_error && defined($power_off)) { doprint "POWERING OFF\n"; @@ -1116,7 +1129,7 @@ sub fail { # no need to reboot for just building. if (!do_not_reboot) { doprint "REBOOTING\n"; - reboot $sleep_time; + reboot_to_good $sleep_time; } my $name = ""; @@ -1269,6 +1282,10 @@ sub wait_for_input } sub reboot_to { + if (defined($switch_to_test)) { + run_command $switch_to_test; + } + if ($reboot_type eq "grub") { run_ssh "'(echo \"savedefault --default=$grub_number --once\" | grub --batch)'"; reboot; @@ -1754,7 +1771,7 @@ sub success { if ($i != $opt{"NUM_TESTS"} && !do_not_reboot) { doprint "Reboot and wait $sleep_time seconds\n"; - reboot $sleep_time; + reboot_to_good $sleep_time; } } @@ -1935,7 +1952,7 @@ sub run_git_bisect { sub bisect_reboot { doprint "Reboot and sleep $bisect_sleep_time seconds\n"; - reboot $bisect_sleep_time; + reboot_to_good $bisect_sleep_time; } # returns 1 on success, 0 on failure, -1 on skip @@ -2528,7 +2545,7 @@ sub config_bisect { sub patchcheck_reboot { doprint "Reboot and sleep $patchcheck_sleep_time seconds\n"; - reboot $patchcheck_sleep_time; + reboot_to_good $patchcheck_sleep_time; } sub patchcheck { @@ -3145,7 +3162,7 @@ sub make_min_config { } doprint "Reboot and wait $sleep_time seconds\n"; - reboot $sleep_time; + reboot_to_good $sleep_time; } success $i; @@ -3314,6 +3331,8 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { $no_install = set_test_option("NO_INSTALL", $i); $reboot_script = set_test_option("REBOOT_SCRIPT", $i); $reboot_on_error = set_test_option("REBOOT_ON_ERROR", $i); + $switch_to_good = set_test_option("SWITCH_TO_GOOD", $i); + $switch_to_test = set_test_option("SWITCH_TO_TEST", $i); $poweroff_on_error = set_test_option("POWEROFF_ON_ERROR", $i); $die_on_failure = set_test_option("DIE_ON_FAILURE", $i); $power_off = set_test_option("POWER_OFF", $i); @@ -3472,7 +3491,7 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { if ($opt{"POWEROFF_ON_SUCCESS"}) { halt; } elsif ($opt{"REBOOT_ON_SUCCESS"} && !do_not_reboot) { - reboot; + reboot_to_good; } doprint "\n $successes of $opt{NUM_TESTS} tests were successful\n\n"; diff --git a/tools/testing/ktest/sample.conf b/tools/testing/ktest/sample.conf index 2ff0f8c483e..c8dc7575c2f 100644 --- a/tools/testing/ktest/sample.conf +++ b/tools/testing/ktest/sample.conf @@ -468,6 +468,27 @@ # The test will not modify that file. #REBOOT_TYPE = grub +# If you are using a machine that doesn't boot with grub, and +# perhaps gets its kernel from a remote server (tftp), then +# you can use this option to update the target image with the +# test image. +# +# You could also do the same with POST_INSTALL, but the difference +# between that option and this option is that POST_INSTALL runs +# after the install, where this one runs just before a reboot. +# (default undefined) +#SWITCH_TO_TEST = cp ${OUTPUT_DIR}/${BUILD_TARGET} ${TARGET_IMAGE} + +# If you are using a machine that doesn't boot with grub, and +# perhaps gets its kernel from a remote server (tftp), then +# you can use this option to update the target image with the +# the known good image to reboot safely back into. +# +# This option holds a command that will execute before needing +# to reboot to a good known image. +# (default undefined) +#SWITCH_TO_GOOD = ssh ${SSH_USER}/${MACHINE} cp good_image ${TARGET_IMAGE} + # The min config that is needed to build for the machine # A nice way to create this is with the following: # -- cgit v1.2.3-70-g09d2 From 4f43e0dcafe89205d3c266fed196fd417a9fe3de Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Thu, 22 Dec 2011 21:32:05 -0500 Subject: ktest: Change initialization of defaults hash to perl format Initializing each default value by specifying the hash name is ugly. This is one of the rare cases that the "perl way" is actually much cleaner and easier to read. Signed-off-by: Steven Rostedt --- tools/testing/ktest/ktest.pl | 71 ++++++++++++++++++++++---------------------- 1 file changed, 36 insertions(+), 35 deletions(-) (limited to 'tools') diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl index ff21e921be2..85c5d943c6d 100755 --- a/tools/testing/ktest/ktest.pl +++ b/tools/testing/ktest/ktest.pl @@ -18,46 +18,47 @@ $| = 1; my %opt; my %repeat_tests; my %repeats; -my %default; #default opts -$default{"NUM_TESTS"} = 1; -$default{"TEST_TYPE"} = "build"; -$default{"BUILD_TYPE"} = "randconfig"; -$default{"MAKE_CMD"} = "make"; -$default{"TIMEOUT"} = 120; -$default{"TMP_DIR"} = "/tmp/ktest/\${MACHINE}"; -$default{"SLEEP_TIME"} = 60; # sleep time between tests -$default{"BUILD_NOCLEAN"} = 0; -$default{"REBOOT_ON_ERROR"} = 0; -$default{"POWEROFF_ON_ERROR"} = 0; -$default{"REBOOT_ON_SUCCESS"} = 1; -$default{"POWEROFF_ON_SUCCESS"} = 0; -$default{"BUILD_OPTIONS"} = ""; -$default{"BISECT_SLEEP_TIME"} = 60; # sleep time between bisects -$default{"PATCHCHECK_SLEEP_TIME"} = 60; # sleep time between patch checks -$default{"CLEAR_LOG"} = 0; -$default{"BISECT_MANUAL"} = 0; -$default{"BISECT_SKIP"} = 1; -$default{"SUCCESS_LINE"} = "login:"; -$default{"DETECT_TRIPLE_FAULT"} = 1; -$default{"NO_INSTALL"} = 0; -$default{"BOOTED_TIMEOUT"} = 1; -$default{"DIE_ON_FAILURE"} = 1; -$default{"SSH_EXEC"} = "ssh \$SSH_USER\@\$MACHINE \$SSH_COMMAND"; -$default{"SCP_TO_TARGET"} = "scp \$SRC_FILE \$SSH_USER\@\$MACHINE:\$DST_FILE"; -$default{"REBOOT"} = "ssh \$SSH_USER\@\$MACHINE reboot"; -$default{"STOP_AFTER_SUCCESS"} = 10; -$default{"STOP_AFTER_FAILURE"} = 60; -$default{"STOP_TEST_AFTER"} = 600; +my %default = ( + "NUM_TESTS" => 1, + "TEST_TYPE" => "build", + "BUILD_TYPE" => "randconfig", + "MAKE_CMD" => "make", + "TIMEOUT" => 120, + "TMP_DIR" => "/tmp/ktest/\${MACHINE}", + "SLEEP_TIME" => 60, # sleep time between tests + "BUILD_NOCLEAN" => 0, + "REBOOT_ON_ERROR" => 0, + "POWEROFF_ON_ERROR" => 0, + "REBOOT_ON_SUCCESS" => 1, + "POWEROFF_ON_SUCCESS" => 0, + "BUILD_OPTIONS" => "", + "BISECT_SLEEP_TIME" => 60, # sleep time between bisects + "PATCHCHECK_SLEEP_TIME" => 60, # sleep time between patch checks + "CLEAR_LOG" => 0, + "BISECT_MANUAL" => 0, + "BISECT_SKIP" => 1, + "SUCCESS_LINE" => "login:", + "DETECT_TRIPLE_FAULT" => 1, + "NO_INSTALL" => 0, + "BOOTED_TIMEOUT" => 1, + "DIE_ON_FAILURE" => 1, + "SSH_EXEC" => "ssh \$SSH_USER\@\$MACHINE \$SSH_COMMAND", + "SCP_TO_TARGET" => "scp \$SRC_FILE \$SSH_USER\@\$MACHINE:\$DST_FILE", + "REBOOT" => "ssh \$SSH_USER\@\$MACHINE reboot", + "STOP_AFTER_SUCCESS" => 10, + "STOP_AFTER_FAILURE" => 60, + "STOP_TEST_AFTER" => 600, # required, and we will ask users if they don't have them but we keep the default # value something that is common. -$default{"REBOOT_TYPE"} = "grub"; -$default{"LOCALVERSION"} = "-test"; -$default{"SSH_USER"} = "root"; -$default{"BUILD_TARGET"} = "arch/x86/boot/bzImage"; -$default{"TARGET_IMAGE"} = "/boot/vmlinuz-test"; + "REBOOT_TYPE" => "grub", + "LOCALVERSION" => "-test", + "SSH_USER" => "root", + "BUILD_TARGET" => "arch/x86/boot/bzImage", + "TARGET_IMAGE" => "/boot/vmlinuz-test", +); my $ktest_config; my $version; -- cgit v1.2.3-70-g09d2 From b5f4aea687797bf9ab24f59643f88f82443b01fa Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Thu, 22 Dec 2011 21:33:55 -0500 Subject: ktest: Have all values be set by defaults Currently the patchcheck, bisect, and config_bisect variables are only able to be set per test. You can not set a default value for them. By letting default values be set, it makes some config files a bit easier, and also makes it easier to find typos in the option names. Signed-off-by: Steven Rostedt --- tools/testing/ktest/ktest.pl | 86 ++++++++++++++++++++++++++++++-------------- 1 file changed, 59 insertions(+), 27 deletions(-) (limited to 'tools') diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl index 85c5d943c6d..5ba9ad4248d 100755 --- a/tools/testing/ktest/ktest.pl +++ b/tools/testing/ktest/ktest.pl @@ -103,7 +103,7 @@ my $output_minconfig; my $ignore_config; my $addconfig; my $in_bisect = 0; -my $bisect_bad = ""; +my $bisect_bad_commit = ""; my $reverse_bisect; my $bisect_manual; my $bisect_skip; @@ -140,10 +140,27 @@ my $stop_after_failure; my $stop_test_after; my $build_target; my $target_image; +my $checkout; my $localversion; my $iteration = 0; my $successes = 0; +my $bisect_good; +my $bisect_bad; +my $bisect_type; +my $bisect_start; +my $bisect_replay; +my $bisect_files; +my $bisect_reverse; +my $bisect_check; + +my $config_bisect; +my $config_bisect_type; + +my $patchcheck_type; +my $patchcheck_start; +my $patchcheck_end; + # set when a test is something other that just building or install # which would require more options. my $buildonly = 1; @@ -1940,7 +1957,7 @@ sub run_git_bisect { if ($output =~ m/^(Bisecting: .*\(roughly \d+ steps?\))\s+\[([[:xdigit:]]+)\]/) { doprint "$1 [$2]\n"; } elsif ($output =~ m/^([[:xdigit:]]+) is the first bad commit/) { - $bisect_bad = $1; + $bisect_bad_commit = $1; doprint "Found bad commit... $1\n"; return 0; } else { @@ -2050,16 +2067,16 @@ sub bisect { my $result; - die "BISECT_GOOD[$i] not defined\n" if (!defined($opt{"BISECT_GOOD[$i]"})); - die "BISECT_BAD[$i] not defined\n" if (!defined($opt{"BISECT_BAD[$i]"})); - die "BISECT_TYPE[$i] not defined\n" if (!defined($opt{"BISECT_TYPE[$i]"})); + die "BISECT_GOOD[$i] not defined\n" if (!defined($bisect_good)); + die "BISECT_BAD[$i] not defined\n" if (!defined($bisect_bad)); + die "BISECT_TYPE[$i] not defined\n" if (!defined($bisect_type)); - my $good = $opt{"BISECT_GOOD[$i]"}; - my $bad = $opt{"BISECT_BAD[$i]"}; - my $type = $opt{"BISECT_TYPE[$i]"}; - my $start = $opt{"BISECT_START[$i]"}; - my $replay = $opt{"BISECT_REPLAY[$i]"}; - my $start_files = $opt{"BISECT_FILES[$i]"}; + my $good = $bisect_good; + my $bad = $bisect_bad; + my $type = $bisect_type; + my $start = $bisect_start; + my $replay = $bisect_replay; + my $start_files = $bisect_files; if (defined($start_files)) { $start_files = " -- " . $start_files; @@ -2071,8 +2088,7 @@ sub bisect { $good = get_sha1($good); $bad = get_sha1($bad); - if (defined($opt{"BISECT_REVERSE[$i]"}) && - $opt{"BISECT_REVERSE[$i]"} == 1) { + if (defined($bisect_reverse) && $bisect_reverse == 1) { doprint "Performing a reverse bisect (bad is good, good is bad!)\n"; $reverse_bisect = 1; } else { @@ -2087,7 +2103,7 @@ sub bisect { # Check if a bisect was running my $bisect_start_file = "$builddir/.git/BISECT_START"; - my $check = $opt{"BISECT_CHECK[$i]"}; + my $check = $bisect_check; my $do_check = defined($check) && $check ne "0"; if ( -f $bisect_start_file ) { @@ -2173,7 +2189,7 @@ sub bisect { run_command "git bisect reset" or dodie "could not reset git bisect"; - doprint "Bad commit was [$bisect_bad]\n"; + doprint "Bad commit was [$bisect_bad_commit]\n"; success $i; } @@ -2329,7 +2345,7 @@ sub run_config_bisect { } doprint "***** RUN TEST ***\n"; - my $type = $opt{"CONFIG_BISECT_TYPE[$iteration]"}; + my $type = $config_bisect_type; my $ret; my %current_config; @@ -2433,7 +2449,7 @@ sub run_config_bisect { sub config_bisect { my ($i) = @_; - my $start_config = $opt{"CONFIG_BISECT[$i]"}; + my $start_config = $config_bisect; my $tmpconfig = "$tmpdir/use_config"; @@ -2553,22 +2569,22 @@ sub patchcheck { my ($i) = @_; die "PATCHCHECK_START[$i] not defined\n" - if (!defined($opt{"PATCHCHECK_START[$i]"})); + if (!defined($patchcheck_start)); die "PATCHCHECK_TYPE[$i] not defined\n" - if (!defined($opt{"PATCHCHECK_TYPE[$i]"})); + if (!defined($patchcheck_type)); - my $start = $opt{"PATCHCHECK_START[$i]"}; + my $start = $patchcheck_start; my $end = "HEAD"; - if (defined($opt{"PATCHCHECK_END[$i]"})) { - $end = $opt{"PATCHCHECK_END[$i]"}; + if (defined($patchcheck_end)) { + $end = $patchcheck_end; } # Get the true sha1's since we can use things like HEAD~3 $start = get_sha1($start); $end = get_sha1($end); - my $type = $opt{"PATCHCHECK_TYPE[$i]"}; + my $type = $patchcheck_type; # Can't have a test without having a test to run if ($type eq "test" && !defined($run_test)) { @@ -3366,9 +3382,26 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { $build_target = set_test_option("BUILD_TARGET", $i); $ssh_exec = set_test_option("SSH_EXEC", $i); $scp_to_target = set_test_option("SCP_TO_TARGET", $i); + $checkout = set_test_option("CHECKOUT", $i); $target_image = set_test_option("TARGET_IMAGE", $i); $localversion = set_test_option("LOCALVERSION", $i); + $bisect_good = set_test_option("BISECT_GOOD", $i); + $bisect_bad = set_test_option("BISECT_BAD", $i); + $bisect_type = set_test_option("BISECT_TYPE", $i); + $bisect_start = set_test_option("BISECT_START", $i); + $bisect_replay = set_test_option("BISECT_REPLAY", $i); + $bisect_files = set_test_option("BISECT_FILES", $i); + $bisect_reverse = set_test_option("BISECT_REVERSE", $i); + $bisect_check = set_test_option("BISECT_CHECK", $i); + + $config_bisect = set_test_option("CONFIG_BISECT", $i); + $config_bisect_type = set_test_option("CONFIG_BISECT_TYPE", $i); + + $patchcheck_type = set_test_option("PATCHCHECK_TYPE", $i); + $patchcheck_start = set_test_option("PATCHCHECK_START", $i); + $patchcheck_end = set_test_option("PATCHCHECK_END", $i); + $start_minconfig_defined = 1; if (!defined($start_minconfig)) { @@ -3405,11 +3438,11 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { my $run_type = $build_type; if ($test_type eq "patchcheck") { - $run_type = $opt{"PATCHCHECK_TYPE[$i]"}; + $run_type = $patchcheck_type; } elsif ($test_type eq "bisect") { - $run_type = $opt{"BISECT_TYPE[$i]"}; + $run_type = $bisect_type; } elsif ($test_type eq "config_bisect") { - $run_type = $opt{"CONFIG_BISECT_TYPE[$i]"}; + $run_type = $config_bisect_type; } if ($test_type eq "make_min_config") { @@ -3441,7 +3474,6 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { $minconfig = "$tmpdir/add_config"; } - my $checkout = $opt{"CHECKOUT[$i]"}; if (defined($checkout)) { run_command "git checkout $checkout" or die "failed to checkout $checkout"; -- cgit v1.2.3-70-g09d2 From 9cc9e091ed4c70535309dd9336a5ea5c2c5920aa Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Thu, 22 Dec 2011 21:37:22 -0500 Subject: ktest: Detect typos in option names It becomes quite annoying when you go to run a test and then realize that you typed an option name wrong, and the test starts doing the default action and not what you expected it to do. It is even more annoying when you wake up the next day after running the test over night when you discover this. By testing if all options specified in a config file are used by either ktest or were used in one of the option's values we can see if there are any dangling options that were not used. In such a case, show the user the options that were not used and ask them if they want to continue or not. The option IGNORE_UNUSED was also added to allow the user to override this feature. Signed-off-by: Steven Rostedt --- tools/testing/ktest/ktest.pl | 208 ++++++++++++++++++++++++---------------- tools/testing/ktest/sample.conf | 11 +++ 2 files changed, 139 insertions(+), 80 deletions(-) (limited to 'tools') diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl index 5ba9ad4248d..f360cbdbf00 100755 --- a/tools/testing/ktest/ktest.pl +++ b/tools/testing/ktest/ktest.pl @@ -58,6 +58,9 @@ my %default = ( "SSH_USER" => "root", "BUILD_TARGET" => "arch/x86/boot/bzImage", "TARGET_IMAGE" => "/boot/vmlinuz-test", + + "LOG_FILE" => undef, + "IGNORE_UNUSED" => 0, ); my $ktest_config; @@ -176,6 +179,92 @@ my %force_config; # do not force reboots on config problems my $no_reboot = 1; +my %option_map = ( + "MACHINE" => \$machine, + "SSH_USER" => \$ssh_user, + "TMP_DIR" => \$tmpdir, + "OUTPUT_DIR" => \$outputdir, + "BUILD_DIR" => \$builddir, + "TEST_TYPE" => \$test_type, + "BUILD_TYPE" => \$build_type, + "BUILD_OPTIONS" => \$build_options, + "PRE_BUILD" => \$pre_build, + "POST_BUILD" => \$post_build, + "PRE_BUILD_DIE" => \$pre_build_die, + "POST_BUILD_DIE" => \$post_build_die, + "POWER_CYCLE" => \$power_cycle, + "REBOOT" => \$reboot, + "BUILD_NOCLEAN" => \$noclean, + "MIN_CONFIG" => \$minconfig, + "OUTPUT_MIN_CONFIG" => \$output_minconfig, + "START_MIN_CONFIG" => \$start_minconfig, + "IGNORE_CONFIG" => \$ignore_config, + "TEST" => \$run_test, + "ADD_CONFIG" => \$addconfig, + "REBOOT_TYPE" => \$reboot_type, + "GRUB_MENU" => \$grub_menu, + "POST_INSTALL" => \$post_install, + "NO_INSTALL" => \$no_install, + "REBOOT_SCRIPT" => \$reboot_script, + "REBOOT_ON_ERROR" => \$reboot_on_error, + "SWITCH_TO_GOOD" => \$switch_to_good, + "SWITCH_TO_TEST" => \$switch_to_test, + "POWEROFF_ON_ERROR" => \$poweroff_on_error, + "DIE_ON_FAILURE" => \$die_on_failure, + "POWER_OFF" => \$power_off, + "POWERCYCLE_AFTER_REBOOT" => \$powercycle_after_reboot, + "POWEROFF_AFTER_HALT" => \$poweroff_after_halt, + "SLEEP_TIME" => \$sleep_time, + "BISECT_SLEEP_TIME" => \$bisect_sleep_time, + "PATCHCHECK_SLEEP_TIME" => \$patchcheck_sleep_time, + "IGNORE_WARNINGS" => \$ignore_warnings, + "BISECT_MANUAL" => \$bisect_manual, + "BISECT_SKIP" => \$bisect_skip, + "CONFIG_BISECT_GOOD" => \$config_bisect_good, + "BISECT_RET_GOOD" => \$bisect_ret_good, + "BISECT_RET_BAD" => \$bisect_ret_bad, + "BISECT_RET_SKIP" => \$bisect_ret_skip, + "BISECT_RET_ABORT" => \$bisect_ret_abort, + "BISECT_RET_DEFAULT" => \$bisect_ret_default, + "STORE_FAILURES" => \$store_failures, + "STORE_SUCCESSES" => \$store_successes, + "TEST_NAME" => \$test_name, + "TIMEOUT" => \$timeout, + "BOOTED_TIMEOUT" => \$booted_timeout, + "CONSOLE" => \$console, + "DETECT_TRIPLE_FAULT" => \$detect_triplefault, + "SUCCESS_LINE" => \$success_line, + "REBOOT_SUCCESS_LINE" => \$reboot_success_line, + "STOP_AFTER_SUCCESS" => \$stop_after_success, + "STOP_AFTER_FAILURE" => \$stop_after_failure, + "STOP_TEST_AFTER" => \$stop_test_after, + "BUILD_TARGET" => \$build_target, + "SSH_EXEC" => \$ssh_exec, + "SCP_TO_TARGET" => \$scp_to_target, + "CHECKOUT" => \$checkout, + "TARGET_IMAGE" => \$target_image, + "LOCALVERSION" => \$localversion, + + "BISECT_GOOD" => \$bisect_good, + "BISECT_BAD" => \$bisect_bad, + "BISECT_TYPE" => \$bisect_type, + "BISECT_START" => \$bisect_start, + "BISECT_REPLAY" => \$bisect_replay, + "BISECT_FILES" => \$bisect_files, + "BISECT_REVERSE" => \$bisect_reverse, + "BISECT_CHECK" => \$bisect_check, + + "CONFIG_BISECT" => \$config_bisect, + "CONFIG_BISECT_TYPE" => \$config_bisect_type, + + "PATCHCHECK_TYPE" => \$patchcheck_type, + "PATCHCHECK_START" => \$patchcheck_start, + "PATCHCHECK_END" => \$patchcheck_end, +); + +# Options may be used by other options, record them. +my %used_options; + # default variables that can be used chomp ($variable{"PWD"} = `pwd`); @@ -427,6 +516,10 @@ sub process_variables { } else { # put back the origin piece. $retval = "$retval\$\{$var\}"; + # This could be an option that is used later, save + # it so we don't warn if this option is not one of + # ktests options. + $used_options{$var} = 1; } $value = $end; } @@ -850,6 +943,37 @@ sub read_config { $opt{$default} = $default{$default}; } } + + if ($opt{"IGNORE_UNUSED"} == 1) { + return; + } + + my %not_used; + + # check if there are any stragglers (typos?) + foreach my $option (keys %opt) { + my $op = $option; + # remove per test labels. + $op =~ s/\[.*\]//; + if (!exists($option_map{$op}) && + !exists($default{$op}) && + !exists($used_options{$op})) { + $not_used{$op} = 1; + } + } + + if (%not_used) { + my $s = "s are"; + $s = " is" if (keys %not_used == 1); + print "The following option$s not used; could be a typo:\n"; + foreach my $option (keys %not_used) { + print "$option\n"; + } + print "Set IGRNORE_UNUSED = 1 to have ktest ignore unused variables\n"; + if (!read_yn "Do you want to continue?") { + exit -1; + } + } } sub __eval_option { @@ -3321,86 +3445,10 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { my $makecmd = set_test_option("MAKE_CMD", $i); - $machine = set_test_option("MACHINE", $i); - $ssh_user = set_test_option("SSH_USER", $i); - $tmpdir = set_test_option("TMP_DIR", $i); - $outputdir = set_test_option("OUTPUT_DIR", $i); - $builddir = set_test_option("BUILD_DIR", $i); - $test_type = set_test_option("TEST_TYPE", $i); - $build_type = set_test_option("BUILD_TYPE", $i); - $build_options = set_test_option("BUILD_OPTIONS", $i); - $pre_build = set_test_option("PRE_BUILD", $i); - $post_build = set_test_option("POST_BUILD", $i); - $pre_build_die = set_test_option("PRE_BUILD_DIE", $i); - $post_build_die = set_test_option("POST_BUILD_DIE", $i); - $power_cycle = set_test_option("POWER_CYCLE", $i); - $reboot = set_test_option("REBOOT", $i); - $noclean = set_test_option("BUILD_NOCLEAN", $i); - $minconfig = set_test_option("MIN_CONFIG", $i); - $output_minconfig = set_test_option("OUTPUT_MIN_CONFIG", $i); - $start_minconfig = set_test_option("START_MIN_CONFIG", $i); - $ignore_config = set_test_option("IGNORE_CONFIG", $i); - $run_test = set_test_option("TEST", $i); - $addconfig = set_test_option("ADD_CONFIG", $i); - $reboot_type = set_test_option("REBOOT_TYPE", $i); - $grub_menu = set_test_option("GRUB_MENU", $i); - $post_install = set_test_option("POST_INSTALL", $i); - $no_install = set_test_option("NO_INSTALL", $i); - $reboot_script = set_test_option("REBOOT_SCRIPT", $i); - $reboot_on_error = set_test_option("REBOOT_ON_ERROR", $i); - $switch_to_good = set_test_option("SWITCH_TO_GOOD", $i); - $switch_to_test = set_test_option("SWITCH_TO_TEST", $i); - $poweroff_on_error = set_test_option("POWEROFF_ON_ERROR", $i); - $die_on_failure = set_test_option("DIE_ON_FAILURE", $i); - $power_off = set_test_option("POWER_OFF", $i); - $powercycle_after_reboot = set_test_option("POWERCYCLE_AFTER_REBOOT", $i); - $poweroff_after_halt = set_test_option("POWEROFF_AFTER_HALT", $i); - $sleep_time = set_test_option("SLEEP_TIME", $i); - $bisect_sleep_time = set_test_option("BISECT_SLEEP_TIME", $i); - $patchcheck_sleep_time = set_test_option("PATCHCHECK_SLEEP_TIME", $i); - $ignore_warnings = set_test_option("IGNORE_WARNINGS", $i); - $bisect_manual = set_test_option("BISECT_MANUAL", $i); - $bisect_skip = set_test_option("BISECT_SKIP", $i); - $config_bisect_good = set_test_option("CONFIG_BISECT_GOOD", $i); - $bisect_ret_good = set_test_option("BISECT_RET_GOOD", $i); - $bisect_ret_bad = set_test_option("BISECT_RET_BAD", $i); - $bisect_ret_skip = set_test_option("BISECT_RET_SKIP", $i); - $bisect_ret_abort = set_test_option("BISECT_RET_ABORT", $i); - $bisect_ret_default = set_test_option("BISECT_RET_DEFAULT", $i); - $store_failures = set_test_option("STORE_FAILURES", $i); - $store_successes = set_test_option("STORE_SUCCESSES", $i); - $test_name = set_test_option("TEST_NAME", $i); - $timeout = set_test_option("TIMEOUT", $i); - $booted_timeout = set_test_option("BOOTED_TIMEOUT", $i); - $console = set_test_option("CONSOLE", $i); - $detect_triplefault = set_test_option("DETECT_TRIPLE_FAULT", $i); - $success_line = set_test_option("SUCCESS_LINE", $i); - $reboot_success_line = set_test_option("REBOOT_SUCCESS_LINE", $i); - $stop_after_success = set_test_option("STOP_AFTER_SUCCESS", $i); - $stop_after_failure = set_test_option("STOP_AFTER_FAILURE", $i); - $stop_test_after = set_test_option("STOP_TEST_AFTER", $i); - $build_target = set_test_option("BUILD_TARGET", $i); - $ssh_exec = set_test_option("SSH_EXEC", $i); - $scp_to_target = set_test_option("SCP_TO_TARGET", $i); - $checkout = set_test_option("CHECKOUT", $i); - $target_image = set_test_option("TARGET_IMAGE", $i); - $localversion = set_test_option("LOCALVERSION", $i); - - $bisect_good = set_test_option("BISECT_GOOD", $i); - $bisect_bad = set_test_option("BISECT_BAD", $i); - $bisect_type = set_test_option("BISECT_TYPE", $i); - $bisect_start = set_test_option("BISECT_START", $i); - $bisect_replay = set_test_option("BISECT_REPLAY", $i); - $bisect_files = set_test_option("BISECT_FILES", $i); - $bisect_reverse = set_test_option("BISECT_REVERSE", $i); - $bisect_check = set_test_option("BISECT_CHECK", $i); - - $config_bisect = set_test_option("CONFIG_BISECT", $i); - $config_bisect_type = set_test_option("CONFIG_BISECT_TYPE", $i); - - $patchcheck_type = set_test_option("PATCHCHECK_TYPE", $i); - $patchcheck_start = set_test_option("PATCHCHECK_START", $i); - $patchcheck_end = set_test_option("PATCHCHECK_END", $i); + # Load all the options into their mapped variable names + foreach my $opt (keys %option_map) { + ${$option_map{$opt}} = set_test_option($opt, $i); + } $start_minconfig_defined = 1; diff --git a/tools/testing/ktest/sample.conf b/tools/testing/ktest/sample.conf index c8dc7575c2f..86ce62c3fdc 100644 --- a/tools/testing/ktest/sample.conf +++ b/tools/testing/ktest/sample.conf @@ -727,6 +727,17 @@ # (default 1) #DETECT_TRIPLE_FAULT = 0 +# All options in the config file should be either used by ktest +# or could be used within a value of another option. If an option +# in the config file is not used, ktest will warn about it and ask +# if you want to continue. +# +# If you don't care if there are non-used options, enable this +# option. Be careful though, a non-used option is usually a sign +# of an option name being typed incorrectly. +# (default 0) +#IGNORE_UNUSED = 1 + #### Per test run options #### # The following options are only allowed in TEST_START sections. # They are ignored in the DEFAULTS sections. -- cgit v1.2.3-70-g09d2 From c2857cb4a855aba0c3f826bcd0dfef72abb0995b Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Thu, 22 Dec 2011 22:06:59 -0500 Subject: ktest: Fix compare script to test if options are not documented The compare script compare-ktest-sample.pl checks for options that are defined in ktest.pl and not documented in samples.conf, as well as samples in samples.conf that are not used in ktest.pl. With the switch to the hash format to initialize the ktest variables the compare script needs to be updated to handle the change. Signed-off-by: Steven Rostedt --- tools/testing/ktest/compare-ktest-sample.pl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/testing/ktest/compare-ktest-sample.pl b/tools/testing/ktest/compare-ktest-sample.pl index 9a571e71683..a373a5bfff6 100755 --- a/tools/testing/ktest/compare-ktest-sample.pl +++ b/tools/testing/ktest/compare-ktest-sample.pl @@ -2,7 +2,9 @@ open (IN,"ktest.pl"); while () { + # hashes are now used if (/\$opt\{"?([A-Z].*?)(\[.*\])?"?\}/ || + /^\s*"?([A-Z].*?)"?\s*=>\s*/ || /set_test_option\("(.*?)"/) { $opt{$1} = 1; } @@ -11,7 +13,7 @@ close IN; open (IN, "sample.conf"); while () { - if (/^\s*#?\s*(\S+)\s*=/) { + if (/^\s*#?\s*([A-Z]\S*)\s*=/) { $samp{$1} = 1; } } -- cgit v1.2.3-70-g09d2 From defd8d38773cf9e01c69a903d04d5895b78ee74f Mon Sep 17 00:00:00 2001 From: David Ahern Date: Thu, 22 Dec 2011 11:30:01 -0700 Subject: perf tools: Fix comm for processes with named threads perf does not properly handle monitoring of processes with named threads. For example: $ ps -C myapp -L PID LWP TTY TIME CMD 25118 25118 ? 00:00:00 myapp 25118 25119 ? 00:00:00 myapp:worker perf record -e cs -c 1 -fo /tmp/perf.data -p 25118 -- sleep 10 perf report --stdio -i /tmp/perf.data 100.00% myapp:worker [kernel.kallsyms] [k] perf_event_task_sched_out The process name is set to the name of the last thread it finds for the process. The Problem: perf-top and perf-record both create a thread_map of threads to be monitored. That map is used in perf_event__synthesize_thread_map which loops over the entries in thread_map and calls __event__synthesize_thread to generate COMM and MMAP events. __event__synthesize_thread calls perf_event__synthesize_comm which opens /proc/pid/status, reads the name of the task and its thread group id. That's all fine. The problem is that it then reads /proc/pid/task and generates COMM events for each task it finds - but using the name found in /proc/pid/status where pid is the thread of interest. The end result (looping over thread_map + synthesizing comm events for each thread each time) means the name of the last thread processed sets the name for all threads in the process - which is not good for multithreaded processes with named threads. The Fix: perf_event__synthesize_comm has an input argument (full) that decides whether to process task entries for each pid it is passed. It currently never set to 0 (perf_event__synthesize_comm has a single caller and it always passes the value 1). Let's fix that. Add the full input argument to __event__synthesize_thread which passes it to perf_event__synthesize_comm. For thread/process monitoring set full to 0 which means COMM and MMAP events are only generated for the pid passed to it. For system wide monitoring set full to 1 so that COMM events are generated for all threads in a process. Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1324578603-12762-2-git-send-email-dsahern@gmail.com Signed-off-by: David Ahern Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/event.c | 37 ++++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) (limited to 'tools') diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index b7c7f39a8f6..a5787260181 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -261,11 +261,12 @@ int perf_event__synthesize_modules(struct perf_tool *tool, static int __event__synthesize_thread(union perf_event *comm_event, union perf_event *mmap_event, - pid_t pid, perf_event__handler_t process, + pid_t pid, int full, + perf_event__handler_t process, struct perf_tool *tool, struct machine *machine) { - pid_t tgid = perf_event__synthesize_comm(tool, comm_event, pid, 1, + pid_t tgid = perf_event__synthesize_comm(tool, comm_event, pid, full, process, machine); if (tgid == -1) return -1; @@ -279,7 +280,7 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool, struct machine *machine) { union perf_event *comm_event, *mmap_event; - int err = -1, thread; + int err = -1, thread, j; comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size); if (comm_event == NULL) @@ -292,11 +293,37 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool, err = 0; for (thread = 0; thread < threads->nr; ++thread) { if (__event__synthesize_thread(comm_event, mmap_event, - threads->map[thread], + threads->map[thread], 0, process, tool, machine)) { err = -1; break; } + + /* + * comm.pid is set to thread group id by + * perf_event__synthesize_comm + */ + if ((int) comm_event->comm.pid != threads->map[thread]) { + bool need_leader = true; + + /* is thread group leader in thread_map? */ + for (j = 0; j < threads->nr; ++j) { + if ((int) comm_event->comm.pid == threads->map[j]) { + need_leader = false; + break; + } + } + + /* if not, generate events for it */ + if (need_leader && + __event__synthesize_thread(comm_event, + mmap_event, + comm_event->comm.pid, 0, + process, tool, machine)) { + err = -1; + break; + } + } } free(mmap_event); out_free_comm: @@ -333,7 +360,7 @@ int perf_event__synthesize_threads(struct perf_tool *tool, if (*end) /* only interested in proper numerical dirents */ continue; - __event__synthesize_thread(comm_event, mmap_event, pid, + __event__synthesize_thread(comm_event, mmap_event, pid, 1, process, tool, machine); } -- cgit v1.2.3-70-g09d2 From f5faf726184a6a5ca1735f610cb97e509fce33e2 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Thu, 22 Dec 2011 11:30:02 -0700 Subject: perf tools: Look up thread names for system wide profiling This handles multithreaded processes with named threads when doing system wide profiling: the comm for each thread is looked up allowing them to be different from the thread group leader. v2: - fixed sizeof arg to perf_event__get_comm_tgid Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1324578603-12762-3-git-send-email-dsahern@gmail.com Signed-off-by: David Ahern Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/event.c | 75 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 53 insertions(+), 22 deletions(-) (limited to 'tools') diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index a5787260181..73ddaf06b8e 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -43,37 +43,27 @@ static struct perf_sample synth_sample = { .period = 1, }; -static pid_t perf_event__synthesize_comm(struct perf_tool *tool, - union perf_event *event, pid_t pid, - int full, perf_event__handler_t process, - struct machine *machine) +static pid_t perf_event__get_comm_tgid(pid_t pid, char *comm, size_t len) { char filename[PATH_MAX]; char bf[BUFSIZ]; FILE *fp; size_t size = 0; - DIR *tasks; - struct dirent dirent, *next; - pid_t tgid = 0; + pid_t tgid = -1; snprintf(filename, sizeof(filename), "/proc/%d/status", pid); fp = fopen(filename, "r"); if (fp == NULL) { -out_race: - /* - * We raced with a task exiting - just return: - */ pr_debug("couldn't open %s\n", filename); return 0; } - memset(&event->comm, 0, sizeof(event->comm)); - - while (!event->comm.comm[0] || !event->comm.pid) { + while (!comm[0] || (tgid < 0)) { if (fgets(bf, sizeof(bf), fp) == NULL) { - pr_warning("couldn't get COMM and pgid, malformed %s\n", filename); - goto out; + pr_warning("couldn't get COMM and pgid, malformed %s\n", + filename); + break; } if (memcmp(bf, "Name:", 5) == 0) { @@ -81,16 +71,46 @@ out_race: while (*name && isspace(*name)) ++name; size = strlen(name) - 1; - memcpy(event->comm.comm, name, size++); + if (size >= len) + size = len - 1; + memcpy(comm, name, size); + } else if (memcmp(bf, "Tgid:", 5) == 0) { char *tgids = bf + 5; while (*tgids && isspace(*tgids)) ++tgids; - tgid = event->comm.pid = atoi(tgids); + tgid = atoi(tgids); } } + fclose(fp); + + return tgid; +} + +static pid_t perf_event__synthesize_comm(struct perf_tool *tool, + union perf_event *event, pid_t pid, + int full, + perf_event__handler_t process, + struct machine *machine) +{ + char filename[PATH_MAX]; + size_t size; + DIR *tasks; + struct dirent dirent, *next; + pid_t tgid; + + memset(&event->comm, 0, sizeof(event->comm)); + + tgid = perf_event__get_comm_tgid(pid, event->comm.comm, + sizeof(event->comm.comm)); + if (tgid < 0) + goto out; + + event->comm.pid = tgid; event->comm.header.type = PERF_RECORD_COMM; + + size = strlen(event->comm.comm) + 1; size = ALIGN(size, sizeof(u64)); memset(event->comm.comm + size, 0, machine->id_hdr_size); event->comm.header.size = (sizeof(event->comm) - @@ -106,8 +126,10 @@ out_race: snprintf(filename, sizeof(filename), "/proc/%d/task", pid); tasks = opendir(filename); - if (tasks == NULL) - goto out_race; + if (tasks == NULL) { + pr_debug("couldn't open %s\n", filename); + return 0; + } while (!readdir_r(tasks, &dirent, &next) && next) { char *end; @@ -115,6 +137,17 @@ out_race: if (*end) continue; + /* already have tgid; jut want to update the comm */ + (void) perf_event__get_comm_tgid(pid, event->comm.comm, + sizeof(event->comm.comm)); + + size = strlen(event->comm.comm) + 1; + size = ALIGN(size, sizeof(u64)); + memset(event->comm.comm + size, 0, machine->id_hdr_size); + event->comm.header.size = (sizeof(event->comm) - + (sizeof(event->comm.comm) - size) + + machine->id_hdr_size); + event->comm.tid = pid; process(tool, event, &synth_sample, machine); @@ -122,8 +155,6 @@ out_race: closedir(tasks); out: - fclose(fp); - return tgid; } -- cgit v1.2.3-70-g09d2 From 64aab93cdffb3967642ffab954395ae2400c0b06 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Thu, 22 Dec 2011 11:30:03 -0700 Subject: perf script: look up thread using tid instead of pid This allows the thread name to be dispalyed when dumping events: myapp 25118 [000] 450385.538815: context-switches ... myapp:worker 25119 [000] 450385.538894: context-switches ... Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1324578603-12762-4-git-send-email-dsahern@gmail.com Signed-off-by: David Ahern Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-script.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index ea71c5e1a94..d71b745da06 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -443,7 +443,7 @@ static int process_sample_event(struct perf_tool *tool __used, struct machine *machine) { struct addr_location al; - struct thread *thread = machine__findnew_thread(machine, event->ip.pid); + struct thread *thread = machine__findnew_thread(machine, event->ip.tid); if (thread == NULL) { pr_debug("problem processing %d event, skipping it.\n", -- cgit v1.2.3-70-g09d2 From f41612f43be9575e1160460b08c3a760e6e27e1b Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Fri, 23 Dec 2011 14:08:04 +0100 Subject: perf tools: Fix truncated annotation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I get such truncated annotation results in 'perf top': : Disassembly of section .text: â–’ : â–’ : ffffffff810966a8 : â–’ 4.94 : ffffffff810966a8: movslq %edi,%rdi â–’ 3.70 : ffffffff810966ab: mov $0x13700,%rax â–’ 0.00 : ffffffff810966b2: add -0x7e32cb00(,%rdi,8),%rax â–’ 8.64 : ffffffff810966ba: mov 0x7e0(%rax),%eax â–’ 82.72 : ffffffff810966c0: cltq â–’ Note the missing 'retq' which is there in the original function: ffffffff810966a8 : ffffffff810966a8: 48 63 ff movslq %edi,%rdi ffffffff810966ab: 48 c7 c0 00 37 01 00 mov $0x13700,%rax ffffffff810966b2: 48 03 04 fd 00 35 cd add -0x7e32cb00(,%rdi,8),%rax ffffffff810966b9: 81 ffffffff810966ba: 8b 80 e0 07 00 00 mov 0x7e0(%rax),%eax ffffffff810966c0: 48 98 cltq ffffffff810966c2: c3 retq ffffffff810966c3 : I'm using a fairly recent binutils: GNU objdump version 2.21.51.0.6-2.fc16 20110118 AFAICS the bug is simply that sym->end points to the last byte of the symbol in question - while objdump's --stop-address expects the last byte plus 1 to disassemble the full range. Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20111223130804.GA24305@elte.hu Signed-off-by: Ingo Molnar Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 376e643f706..011ed267660 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -334,7 +334,7 @@ fallback: disassembler_style ? "-M " : "", disassembler_style ? disassembler_style : "", map__rip_2objdump(map, sym->start), - map__rip_2objdump(map, sym->end), + map__rip_2objdump(map, sym->end+1), symbol_conf.annotate_asm_raw ? "" : "--no-show-raw", symbol_conf.annotate_src ? "-S" : "", symfs_filename, filename); -- cgit v1.2.3-70-g09d2 From 18e6093904abfd51671ff5846c2fdaba9ebbf21b Mon Sep 17 00:00:00 2001 From: Nelson Elhage Date: Mon, 19 Dec 2011 08:39:31 -0500 Subject: perf: builtin-record: Provide advice if mmap'ing fails with EPERM. This failure is most likely due to running up against the kernel.perf_event_mlock_kb sysctl, so we can tell the user what to do to fix the issue. Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1324301972-22740-3-git-send-email-nelhage@nelhage.com Signed-off-by: Nelson Elhage Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index f8fd14fb62e..56bb4476e3b 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -272,8 +272,15 @@ try_again: exit(-1); } - if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) + if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) { + if (errno == EPERM) + die("Permission error mapping pages.\n" + "Consider increasing " + "/proc/sys/kernel/perf_event_mlock_kb,\n" + "or try again with a smaller value of -m/--mmap_pages.\n" + "(current value: %d)\n", opts->mmap_pages); die("failed to mmap with %d (%s)\n", errno, strerror(errno)); + } if (rec->file_new) session->evlist = evlist; -- cgit v1.2.3-70-g09d2 From 41d0d933494ce10eb77758a1168b08e317c42e8e Mon Sep 17 00:00:00 2001 From: Nelson Elhage Date: Mon, 19 Dec 2011 08:39:32 -0500 Subject: perf: builtin-record: Document and check that mmap_pages must be a power of two. Now that we automatically point users at it, let's provide them some guidance so that they hopefully don't just get mysterious EINVAL's from the kernel. Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1324301972-22740-4-git-send-email-nelhage@nelhage.com Signed-off-by: Nelson Elhage [ committer note: Made it work after 50a682c ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-record.txt | 2 +- tools/perf/builtin-record.c | 3 +++ tools/perf/util/evlist.c | 2 ++ tools/perf/util/util.h | 11 +++++++++++ 4 files changed, 17 insertions(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index 5a520f82529..2937f7e14bb 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt @@ -89,7 +89,7 @@ OPTIONS -m:: --mmap-pages=:: - Number of mmap data pages. + Number of mmap data pages. Must be a power of two. -g:: --call-graph:: diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 56bb4476e3b..e873ae2dd54 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -279,6 +279,9 @@ try_again: "/proc/sys/kernel/perf_event_mlock_kb,\n" "or try again with a smaller value of -m/--mmap_pages.\n" "(current value: %d)\n", opts->mmap_pages); + else if (!is_power_of_2(opts->mmap_pages)) + die("--mmap_pages/-m value must be a power of two."); + die("failed to mmap with %d (%s)\n", errno, strerror(errno)); } diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 963d63dde45..fa1837088ca 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -563,6 +563,8 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, /* 512 kiB: default amount of unprivileged mlocked memory */ if (pages == UINT_MAX) pages = (512 * 1024) / page_size; + else if (!is_power_of_2(pages)) + return -EINVAL; mask = pages * page_size - 1; diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 0128906bac8..37be34dff79 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -245,4 +245,15 @@ int readn(int fd, void *buf, size_t size); #define _STR(x) #x #define STR(x) _STR(x) +/* + * Determine whether some value is a power of two, where zero is + * *not* considered a power of two. + */ + +static inline __attribute__((const)) +bool is_power_of_2(unsigned long n) +{ + return (n != 0 && ((n & (n - 1)) == 0)); +} + #endif -- cgit v1.2.3-70-g09d2 From 8cdfa78a885d94a79205d183a611ebc4876d6f33 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Wed, 7 Dec 2011 10:02:56 +0100 Subject: perf tools: Improve macros for struct feature_ops Reducing duplication and line size by extending function names for print and write from a single name. Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1323248577-11268-7-git-send-email-robert.richter@amd.com Signed-off-by: Robert Richter Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/header.c | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) (limited to 'tools') diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 5b01449152e..4c48be80dcd 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -1065,26 +1065,30 @@ struct feature_ops { bool full_only; }; -#define FEAT_OPA(n, w, p) \ - [n] = { .name = #n, .write = w, .print = p } -#define FEAT_OPF(n, w, p) \ - [n] = { .name = #n, .write = w, .print = p, .full_only = true } +#define FEAT_OPA(n, func) \ + [n] = { .name = #n, .write = write_##func, .print = print_##func } +#define FEAT_OPF(n, func) \ + [n] = { .name = #n, .write = write_##func, .print = print_##func, .full_only = true } + +/* feature_ops not implemented: */ +#define print_trace_info NULL +#define print_build_id NULL static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = { - FEAT_OPA(HEADER_TRACE_INFO, write_trace_info, NULL), - FEAT_OPA(HEADER_BUILD_ID, write_build_id, NULL), - FEAT_OPA(HEADER_HOSTNAME, write_hostname, print_hostname), - FEAT_OPA(HEADER_OSRELEASE, write_osrelease, print_osrelease), - FEAT_OPA(HEADER_VERSION, write_version, print_version), - FEAT_OPA(HEADER_ARCH, write_arch, print_arch), - FEAT_OPA(HEADER_NRCPUS, write_nrcpus, print_nrcpus), - FEAT_OPA(HEADER_CPUDESC, write_cpudesc, print_cpudesc), - FEAT_OPA(HEADER_CPUID, write_cpuid, print_cpuid), - FEAT_OPA(HEADER_TOTAL_MEM, write_total_mem, print_total_mem), - FEAT_OPA(HEADER_EVENT_DESC, write_event_desc, print_event_desc), - FEAT_OPA(HEADER_CMDLINE, write_cmdline, print_cmdline), - FEAT_OPF(HEADER_CPU_TOPOLOGY, write_cpu_topology, print_cpu_topology), - FEAT_OPF(HEADER_NUMA_TOPOLOGY, write_numa_topology, print_numa_topology), + FEAT_OPA(HEADER_TRACE_INFO, trace_info), + FEAT_OPA(HEADER_BUILD_ID, build_id), + FEAT_OPA(HEADER_HOSTNAME, hostname), + FEAT_OPA(HEADER_OSRELEASE, osrelease), + FEAT_OPA(HEADER_VERSION, version), + FEAT_OPA(HEADER_ARCH, arch), + FEAT_OPA(HEADER_NRCPUS, nrcpus), + FEAT_OPA(HEADER_CPUDESC, cpudesc), + FEAT_OPA(HEADER_CPUID, cpuid), + FEAT_OPA(HEADER_TOTAL_MEM, total_mem), + FEAT_OPA(HEADER_EVENT_DESC, event_desc), + FEAT_OPA(HEADER_CMDLINE, cmdline), + FEAT_OPF(HEADER_CPU_TOPOLOGY, cpu_topology), + FEAT_OPF(HEADER_NUMA_TOPOLOGY, numa_topology), }; struct header_print_data { -- cgit v1.2.3-70-g09d2 From f7a8a1336416883dc0ccd96c17c604e34de61c25 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Wed, 7 Dec 2011 10:02:51 +0100 Subject: perf tools: Continue processing header on unknown features A feature may be unknown if perf.data is created and parsed on different perf tool versions. This should not stop the header to be processed, instead continue processing it. Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1323248577-11268-2-git-send-email-robert.richter@amd.com Signed-off-by: Robert Richter Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/header.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 4c48be80dcd..428a4a2ce35 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -1109,7 +1109,7 @@ static int perf_file_section__fprintf_info(struct perf_file_section *section, } if (feat < HEADER_TRACE_INFO || feat >= HEADER_LAST_FEATURE) { pr_warning("unknown feature %d\n", feat); - return -1; + return 0; } if (!feat_ops[feat].print) return 0; -- cgit v1.2.3-70-g09d2 From 002c4fd92d772becf8745b9cbcebe5c95fe6dad0 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Wed, 7 Dec 2011 10:02:52 +0100 Subject: perf tools: Fix out-of-bound access to struct perf_session If filename is NULL there is an out-of-bound access to struct perf_session if it would be used with perf_session__open(). Shouldn't actually happen in current implementation as filename is always !NULL. Fixing this by always null-terminating filename. Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1323248577-11268-3-git-send-email-robert.richter@amd.com Signed-off-by: Robert Richter Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/session.c | 2 +- tools/perf/util/session.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'tools') diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index d9318d8a9ba..ea17dfb85ba 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -107,7 +107,7 @@ struct perf_session *perf_session__new(const char *filename, int mode, bool force, bool repipe, struct perf_tool *tool) { - size_t len = filename ? strlen(filename) + 1 : 0; + size_t len = filename ? strlen(filename) : 0; struct perf_session *self = zalloc(sizeof(*self) + len); if (self == NULL) diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index fb696124ad6..37bc38381fb 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -50,7 +50,7 @@ struct perf_session { int cwdlen; char *cwd; struct ordered_samples ordered_samples; - char filename[0]; + char filename[1]; }; struct perf_tool; -- cgit v1.2.3-70-g09d2 From 1b5495043d5bc058def21f9b66fd8feaa794eb44 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Wed, 7 Dec 2011 10:02:53 +0100 Subject: perf tools: Moving code in some files Needed for later changes. No modified functionality. Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1323248577-11268-4-git-send-email-robert.richter@amd.com Signed-off-by: Robert Richter Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-buildid-list.c | 36 +-- tools/perf/util/header.c | 495 +++++++++++++++++++------------------- 2 files changed, 264 insertions(+), 267 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c index cb690a65bf0..4895668577b 100644 --- a/tools/perf/builtin-buildid-list.c +++ b/tools/perf/builtin-buildid-list.c @@ -39,24 +39,6 @@ static const struct option options[] = { OPT_END() }; -static int perf_session__list_build_ids(void) -{ - struct perf_session *session; - - session = perf_session__new(input_name, O_RDONLY, force, false, - &build_id__mark_dso_hit_ops); - if (session == NULL) - return -1; - - if (with_hits) - perf_session__process_events(session, &build_id__mark_dso_hit_ops); - - perf_session__fprintf_dsos_buildid(session, stdout, with_hits); - - perf_session__delete(session); - return 0; -} - static int sysfs__fprintf_build_id(FILE *fp) { u8 kallsyms_build_id[BUILD_ID_SIZE]; @@ -85,6 +67,24 @@ static int filename__fprintf_build_id(const char *name, FILE *fp) return fprintf(fp, "%s\n", sbuild_id); } +static int perf_session__list_build_ids(void) +{ + struct perf_session *session; + + session = perf_session__new(input_name, O_RDONLY, force, false, + &build_id__mark_dso_hit_ops); + if (session == NULL) + return -1; + + if (with_hits) + perf_session__process_events(session, &build_id__mark_dso_hit_ops); + + perf_session__fprintf_dsos_buildid(session, stdout, with_hits); + + perf_session__delete(session); + return 0; +} + static int __cmd_buildid_list(void) { if (show_kernel) diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 428a4a2ce35..609d79b5fb5 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -28,9 +28,6 @@ static struct perf_trace_event_type *events; static u32 header_argc; static const char **header_argv; -static int dsos__write_buildid_table(struct perf_header *header, int fd); -static int perf_session__cache_build_ids(struct perf_session *session); - int perf_header__push_event(u64 id, const char *name) { if (strlen(name) > MAX_EVENT_NAME) @@ -187,6 +184,252 @@ perf_header__set_cmdline(int argc, const char **argv) return 0; } +#define dsos__for_each_with_build_id(pos, head) \ + list_for_each_entry(pos, head, node) \ + if (!pos->has_build_id) \ + continue; \ + else + +static int __dsos__write_buildid_table(struct list_head *head, pid_t pid, + u16 misc, int fd) +{ + struct dso *pos; + + dsos__for_each_with_build_id(pos, head) { + int err; + struct build_id_event b; + size_t len; + + if (!pos->hit) + continue; + len = pos->long_name_len + 1; + len = ALIGN(len, NAME_ALIGN); + memset(&b, 0, sizeof(b)); + memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id)); + b.pid = pid; + b.header.misc = misc; + b.header.size = sizeof(b) + len; + err = do_write(fd, &b, sizeof(b)); + if (err < 0) + return err; + err = write_padded(fd, pos->long_name, + pos->long_name_len + 1, len); + if (err < 0) + return err; + } + + return 0; +} + +static int machine__write_buildid_table(struct machine *machine, int fd) +{ + int err; + u16 kmisc = PERF_RECORD_MISC_KERNEL, + umisc = PERF_RECORD_MISC_USER; + + if (!machine__is_host(machine)) { + kmisc = PERF_RECORD_MISC_GUEST_KERNEL; + umisc = PERF_RECORD_MISC_GUEST_USER; + } + + err = __dsos__write_buildid_table(&machine->kernel_dsos, machine->pid, + kmisc, fd); + if (err == 0) + err = __dsos__write_buildid_table(&machine->user_dsos, + machine->pid, umisc, fd); + return err; +} + +static int dsos__write_buildid_table(struct perf_header *header, int fd) +{ + struct perf_session *session = container_of(header, + struct perf_session, header); + struct rb_node *nd; + int err = machine__write_buildid_table(&session->host_machine, fd); + + if (err) + return err; + + for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) { + struct machine *pos = rb_entry(nd, struct machine, rb_node); + err = machine__write_buildid_table(pos, fd); + if (err) + break; + } + return err; +} + +int build_id_cache__add_s(const char *sbuild_id, const char *debugdir, + const char *name, bool is_kallsyms) +{ + const size_t size = PATH_MAX; + char *realname, *filename = zalloc(size), + *linkname = zalloc(size), *targetname; + int len, err = -1; + + if (is_kallsyms) { + if (symbol_conf.kptr_restrict) { + pr_debug("Not caching a kptr_restrict'ed /proc/kallsyms\n"); + return 0; + } + realname = (char *)name; + } else + realname = realpath(name, NULL); + + if (realname == NULL || filename == NULL || linkname == NULL) + goto out_free; + + len = snprintf(filename, size, "%s%s%s", + debugdir, is_kallsyms ? "/" : "", realname); + if (mkdir_p(filename, 0755)) + goto out_free; + + snprintf(filename + len, sizeof(filename) - len, "/%s", sbuild_id); + + if (access(filename, F_OK)) { + if (is_kallsyms) { + if (copyfile("/proc/kallsyms", filename)) + goto out_free; + } else if (link(realname, filename) && copyfile(name, filename)) + goto out_free; + } + + len = snprintf(linkname, size, "%s/.build-id/%.2s", + debugdir, sbuild_id); + + if (access(linkname, X_OK) && mkdir_p(linkname, 0755)) + goto out_free; + + snprintf(linkname + len, size - len, "/%s", sbuild_id + 2); + targetname = filename + strlen(debugdir) - 5; + memcpy(targetname, "../..", 5); + + if (symlink(targetname, linkname) == 0) + err = 0; +out_free: + if (!is_kallsyms) + free(realname); + free(filename); + free(linkname); + return err; +} + +static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size, + const char *name, const char *debugdir, + bool is_kallsyms) +{ + char sbuild_id[BUILD_ID_SIZE * 2 + 1]; + + build_id__sprintf(build_id, build_id_size, sbuild_id); + + return build_id_cache__add_s(sbuild_id, debugdir, name, is_kallsyms); +} + +int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir) +{ + const size_t size = PATH_MAX; + char *filename = zalloc(size), + *linkname = zalloc(size); + int err = -1; + + if (filename == NULL || linkname == NULL) + goto out_free; + + snprintf(linkname, size, "%s/.build-id/%.2s/%s", + debugdir, sbuild_id, sbuild_id + 2); + + if (access(linkname, F_OK)) + goto out_free; + + if (readlink(linkname, filename, size - 1) < 0) + goto out_free; + + if (unlink(linkname)) + goto out_free; + + /* + * Since the link is relative, we must make it absolute: + */ + snprintf(linkname, size, "%s/.build-id/%.2s/%s", + debugdir, sbuild_id, filename); + + if (unlink(linkname)) + goto out_free; + + err = 0; +out_free: + free(filename); + free(linkname); + return err; +} + +static int dso__cache_build_id(struct dso *dso, const char *debugdir) +{ + bool is_kallsyms = dso->kernel && dso->long_name[0] != '/'; + + return build_id_cache__add_b(dso->build_id, sizeof(dso->build_id), + dso->long_name, debugdir, is_kallsyms); +} + +static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir) +{ + struct dso *pos; + int err = 0; + + dsos__for_each_with_build_id(pos, head) + if (dso__cache_build_id(pos, debugdir)) + err = -1; + + return err; +} + +static int machine__cache_build_ids(struct machine *machine, const char *debugdir) +{ + int ret = __dsos__cache_build_ids(&machine->kernel_dsos, debugdir); + ret |= __dsos__cache_build_ids(&machine->user_dsos, debugdir); + return ret; +} + +static int perf_session__cache_build_ids(struct perf_session *session) +{ + struct rb_node *nd; + int ret; + char debugdir[PATH_MAX]; + + snprintf(debugdir, sizeof(debugdir), "%s", buildid_dir); + + if (mkdir(debugdir, 0755) != 0 && errno != EEXIST) + return -1; + + ret = machine__cache_build_ids(&session->host_machine, debugdir); + + for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) { + struct machine *pos = rb_entry(nd, struct machine, rb_node); + ret |= machine__cache_build_ids(pos, debugdir); + } + return ret ? -1 : 0; +} + +static bool machine__read_build_ids(struct machine *machine, bool with_hits) +{ + bool ret = __dsos__read_build_ids(&machine->kernel_dsos, with_hits); + ret |= __dsos__read_build_ids(&machine->user_dsos, with_hits); + return ret; +} + +static bool perf_session__read_build_ids(struct perf_session *session, bool with_hits) +{ + struct rb_node *nd; + bool ret = machine__read_build_ids(&session->host_machine, with_hits); + + for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) { + struct machine *pos = rb_entry(nd, struct machine, rb_node); + ret |= machine__read_build_ids(pos, with_hits); + } + + return ret; +} + static int write_trace_info(int fd, struct perf_header *h __used, struct perf_evlist *evlist) { @@ -1136,252 +1379,6 @@ int perf_header__fprintf_info(struct perf_session *session, FILE *fp, bool full) return 0; } -#define dsos__for_each_with_build_id(pos, head) \ - list_for_each_entry(pos, head, node) \ - if (!pos->has_build_id) \ - continue; \ - else - -static int __dsos__write_buildid_table(struct list_head *head, pid_t pid, - u16 misc, int fd) -{ - struct dso *pos; - - dsos__for_each_with_build_id(pos, head) { - int err; - struct build_id_event b; - size_t len; - - if (!pos->hit) - continue; - len = pos->long_name_len + 1; - len = ALIGN(len, NAME_ALIGN); - memset(&b, 0, sizeof(b)); - memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id)); - b.pid = pid; - b.header.misc = misc; - b.header.size = sizeof(b) + len; - err = do_write(fd, &b, sizeof(b)); - if (err < 0) - return err; - err = write_padded(fd, pos->long_name, - pos->long_name_len + 1, len); - if (err < 0) - return err; - } - - return 0; -} - -static int machine__write_buildid_table(struct machine *machine, int fd) -{ - int err; - u16 kmisc = PERF_RECORD_MISC_KERNEL, - umisc = PERF_RECORD_MISC_USER; - - if (!machine__is_host(machine)) { - kmisc = PERF_RECORD_MISC_GUEST_KERNEL; - umisc = PERF_RECORD_MISC_GUEST_USER; - } - - err = __dsos__write_buildid_table(&machine->kernel_dsos, machine->pid, - kmisc, fd); - if (err == 0) - err = __dsos__write_buildid_table(&machine->user_dsos, - machine->pid, umisc, fd); - return err; -} - -static int dsos__write_buildid_table(struct perf_header *header, int fd) -{ - struct perf_session *session = container_of(header, - struct perf_session, header); - struct rb_node *nd; - int err = machine__write_buildid_table(&session->host_machine, fd); - - if (err) - return err; - - for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) { - struct machine *pos = rb_entry(nd, struct machine, rb_node); - err = machine__write_buildid_table(pos, fd); - if (err) - break; - } - return err; -} - -int build_id_cache__add_s(const char *sbuild_id, const char *debugdir, - const char *name, bool is_kallsyms) -{ - const size_t size = PATH_MAX; - char *realname, *filename = zalloc(size), - *linkname = zalloc(size), *targetname; - int len, err = -1; - - if (is_kallsyms) { - if (symbol_conf.kptr_restrict) { - pr_debug("Not caching a kptr_restrict'ed /proc/kallsyms\n"); - return 0; - } - realname = (char *)name; - } else - realname = realpath(name, NULL); - - if (realname == NULL || filename == NULL || linkname == NULL) - goto out_free; - - len = snprintf(filename, size, "%s%s%s", - debugdir, is_kallsyms ? "/" : "", realname); - if (mkdir_p(filename, 0755)) - goto out_free; - - snprintf(filename + len, sizeof(filename) - len, "/%s", sbuild_id); - - if (access(filename, F_OK)) { - if (is_kallsyms) { - if (copyfile("/proc/kallsyms", filename)) - goto out_free; - } else if (link(realname, filename) && copyfile(name, filename)) - goto out_free; - } - - len = snprintf(linkname, size, "%s/.build-id/%.2s", - debugdir, sbuild_id); - - if (access(linkname, X_OK) && mkdir_p(linkname, 0755)) - goto out_free; - - snprintf(linkname + len, size - len, "/%s", sbuild_id + 2); - targetname = filename + strlen(debugdir) - 5; - memcpy(targetname, "../..", 5); - - if (symlink(targetname, linkname) == 0) - err = 0; -out_free: - if (!is_kallsyms) - free(realname); - free(filename); - free(linkname); - return err; -} - -static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size, - const char *name, const char *debugdir, - bool is_kallsyms) -{ - char sbuild_id[BUILD_ID_SIZE * 2 + 1]; - - build_id__sprintf(build_id, build_id_size, sbuild_id); - - return build_id_cache__add_s(sbuild_id, debugdir, name, is_kallsyms); -} - -int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir) -{ - const size_t size = PATH_MAX; - char *filename = zalloc(size), - *linkname = zalloc(size); - int err = -1; - - if (filename == NULL || linkname == NULL) - goto out_free; - - snprintf(linkname, size, "%s/.build-id/%.2s/%s", - debugdir, sbuild_id, sbuild_id + 2); - - if (access(linkname, F_OK)) - goto out_free; - - if (readlink(linkname, filename, size - 1) < 0) - goto out_free; - - if (unlink(linkname)) - goto out_free; - - /* - * Since the link is relative, we must make it absolute: - */ - snprintf(linkname, size, "%s/.build-id/%.2s/%s", - debugdir, sbuild_id, filename); - - if (unlink(linkname)) - goto out_free; - - err = 0; -out_free: - free(filename); - free(linkname); - return err; -} - -static int dso__cache_build_id(struct dso *dso, const char *debugdir) -{ - bool is_kallsyms = dso->kernel && dso->long_name[0] != '/'; - - return build_id_cache__add_b(dso->build_id, sizeof(dso->build_id), - dso->long_name, debugdir, is_kallsyms); -} - -static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir) -{ - struct dso *pos; - int err = 0; - - dsos__for_each_with_build_id(pos, head) - if (dso__cache_build_id(pos, debugdir)) - err = -1; - - return err; -} - -static int machine__cache_build_ids(struct machine *machine, const char *debugdir) -{ - int ret = __dsos__cache_build_ids(&machine->kernel_dsos, debugdir); - ret |= __dsos__cache_build_ids(&machine->user_dsos, debugdir); - return ret; -} - -static int perf_session__cache_build_ids(struct perf_session *session) -{ - struct rb_node *nd; - int ret; - char debugdir[PATH_MAX]; - - snprintf(debugdir, sizeof(debugdir), "%s", buildid_dir); - - if (mkdir(debugdir, 0755) != 0 && errno != EEXIST) - return -1; - - ret = machine__cache_build_ids(&session->host_machine, debugdir); - - for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) { - struct machine *pos = rb_entry(nd, struct machine, rb_node); - ret |= machine__cache_build_ids(pos, debugdir); - } - return ret ? -1 : 0; -} - -static bool machine__read_build_ids(struct machine *machine, bool with_hits) -{ - bool ret = __dsos__read_build_ids(&machine->kernel_dsos, with_hits); - ret |= __dsos__read_build_ids(&machine->user_dsos, with_hits); - return ret; -} - -static bool perf_session__read_build_ids(struct perf_session *session, bool with_hits) -{ - struct rb_node *nd; - bool ret = machine__read_build_ids(&session->host_machine, with_hits); - - for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) { - struct machine *pos = rb_entry(nd, struct machine, rb_node); - ret |= machine__read_build_ids(pos, with_hits); - } - - return ret; -} - static int do_write_feat(int fd, struct perf_header *h, int type, struct perf_file_section **p, struct perf_evlist *evlist) -- cgit v1.2.3-70-g09d2 From efad14150a0b4429f37da7245001a8096ef7ee38 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Wed, 7 Dec 2011 10:02:54 +0100 Subject: perf report: Accept fifos as input file The default input file for perf report is not handled the same way as perf record does it for its output file. This leads to unexpected behavior of perf report, etc. E.g.: # perf record -a -e cpu-cycles sleep 2 | perf report | cat failed to open perf.data: No such file or directory (try 'perf record' first) While perf record writes to a fifo, perf report expects perf.data to be read. This patch changes this to accept fifos as input file. Applies to the following commands: perf annotate perf buildid-list perf evlist perf kmem perf lock perf report perf sched perf script perf timechart Also fixes char const* -> const char* type declaration for filename strings. v2: * Prevent potential null pointer access to input_name in builtin-report.c. Needed due to removal of patch "perf report: Setup browser if stdout is a pipe" Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1323248577-11268-5-git-send-email-robert.richter@amd.com Signed-off-by: Robert Richter Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-annotate.txt | 2 +- tools/perf/Documentation/perf-buildid-list.txt | 2 +- tools/perf/Documentation/perf-evlist.txt | 2 +- tools/perf/Documentation/perf-kmem.txt | 2 +- tools/perf/Documentation/perf-lock.txt | 2 +- tools/perf/Documentation/perf-report.txt | 2 +- tools/perf/Documentation/perf-sched.txt | 2 +- tools/perf/Documentation/perf-script.txt | 2 +- tools/perf/Documentation/perf-timechart.txt | 2 +- tools/perf/builtin-annotate.c | 3 +-- tools/perf/builtin-buildid-list.c | 19 ++++++++++--------- tools/perf/builtin-evlist.c | 2 +- tools/perf/builtin-kmem.c | 2 +- tools/perf/builtin-lock.c | 2 +- tools/perf/builtin-report.c | 13 ++++++++++--- tools/perf/builtin-sched.c | 2 +- tools/perf/builtin-script.c | 4 ++-- tools/perf/builtin-timechart.c | 4 ++-- tools/perf/util/session.c | 15 +++++++++++++-- 19 files changed, 51 insertions(+), 33 deletions(-) (limited to 'tools') diff --git a/tools/perf/Documentation/perf-annotate.txt b/tools/perf/Documentation/perf-annotate.txt index 476029d3062..c89f9e1453f 100644 --- a/tools/perf/Documentation/perf-annotate.txt +++ b/tools/perf/Documentation/perf-annotate.txt @@ -22,7 +22,7 @@ OPTIONS ------- -i:: --input=:: - Input file name. (default: perf.data) + Input file name. (default: perf.data unless stdin is a fifo) -d:: --dsos=:: diff --git a/tools/perf/Documentation/perf-buildid-list.txt b/tools/perf/Documentation/perf-buildid-list.txt index cc22325ffd1..25c52efcc7f 100644 --- a/tools/perf/Documentation/perf-buildid-list.txt +++ b/tools/perf/Documentation/perf-buildid-list.txt @@ -26,7 +26,7 @@ OPTIONS Show only DSOs with hits. -i:: --input=:: - Input file name. (default: perf.data) + Input file name. (default: perf.data unless stdin is a fifo) -f:: --force:: Don't do ownership validation. diff --git a/tools/perf/Documentation/perf-evlist.txt b/tools/perf/Documentation/perf-evlist.txt index 0cada9e053d..0507ec7bad7 100644 --- a/tools/perf/Documentation/perf-evlist.txt +++ b/tools/perf/Documentation/perf-evlist.txt @@ -18,7 +18,7 @@ OPTIONS ------- -i:: --input=:: - Input file name. (default: perf.data) + Input file name. (default: perf.data unless stdin is a fifo) SEE ALSO -------- diff --git a/tools/perf/Documentation/perf-kmem.txt b/tools/perf/Documentation/perf-kmem.txt index a52fcde894c..7c8fbbf3f61 100644 --- a/tools/perf/Documentation/perf-kmem.txt +++ b/tools/perf/Documentation/perf-kmem.txt @@ -23,7 +23,7 @@ OPTIONS ------- -i :: --input=:: - Select the input file (default: perf.data) + Select the input file (default: perf.data unless stdin is a fifo) --caller:: Show per-callsite statistics diff --git a/tools/perf/Documentation/perf-lock.txt b/tools/perf/Documentation/perf-lock.txt index 4a26a2f3a6a..d6b2a4f2108 100644 --- a/tools/perf/Documentation/perf-lock.txt +++ b/tools/perf/Documentation/perf-lock.txt @@ -29,7 +29,7 @@ COMMON OPTIONS -i:: --input=:: - Input file name. + Input file name. (default: perf.data unless stdin is a fifo) -v:: --verbose:: diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt index 35af0dc8ccb..9b430e98712 100644 --- a/tools/perf/Documentation/perf-report.txt +++ b/tools/perf/Documentation/perf-report.txt @@ -19,7 +19,7 @@ OPTIONS ------- -i:: --input=:: - Input file name. (default: perf.data) + Input file name. (default: perf.data unless stdin is a fifo) -v:: --verbose:: diff --git a/tools/perf/Documentation/perf-sched.txt b/tools/perf/Documentation/perf-sched.txt index 5b212b57f70..8ff4df95695 100644 --- a/tools/perf/Documentation/perf-sched.txt +++ b/tools/perf/Documentation/perf-sched.txt @@ -40,7 +40,7 @@ OPTIONS ------- -i:: --input=:: - Input file name. (default: perf.data) + Input file name. (default: perf.data unless stdin is a fifo) -v:: --verbose:: diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt index 7f61eaaf9ab..2f6cef43da2 100644 --- a/tools/perf/Documentation/perf-script.txt +++ b/tools/perf/Documentation/perf-script.txt @@ -106,7 +106,7 @@ OPTIONS -i:: --input=:: - Input file name. + Input file name. (default: perf.data unless stdin is a fifo) -d:: --debug-mode:: diff --git a/tools/perf/Documentation/perf-timechart.txt b/tools/perf/Documentation/perf-timechart.txt index d7b79e2ba2a..1632b0efc75 100644 --- a/tools/perf/Documentation/perf-timechart.txt +++ b/tools/perf/Documentation/perf-timechart.txt @@ -27,7 +27,7 @@ OPTIONS Select the output file (default: output.svg) -i:: --input=:: - Select the input file (default: perf.data) + Select the input file (default: perf.data unless stdin is a fifo) -w:: --width=:: Select the width of the SVG file (default: 1000) diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index d449645c5ef..214ba7f9f57 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -215,7 +215,7 @@ static int __cmd_annotate(struct perf_annotate *ann) } if (total_nr_samples == 0) { - ui__warning("The %s file has no samples!\n", ann->input_name); + ui__warning("The %s file has no samples!\n", session->filename); goto out_delete; } out_delete: @@ -250,7 +250,6 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __used) .ordered_samples = true, .ordering_requires_timestamps = true, }, - .input_name = "perf.data", }; const struct option options[] = { OPT_STRING('i', "input", &annotate.input_name, "file", diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c index 4895668577b..52480467e9f 100644 --- a/tools/perf/builtin-buildid-list.c +++ b/tools/perf/builtin-buildid-list.c @@ -18,7 +18,7 @@ #include -static char const *input_name = "perf.data"; +static const char *input_name; static bool force; static bool show_kernel; static bool with_hits; @@ -71,16 +71,24 @@ static int perf_session__list_build_ids(void) { struct perf_session *session; + elf_version(EV_CURRENT); + session = perf_session__new(input_name, O_RDONLY, force, false, &build_id__mark_dso_hit_ops); if (session == NULL) return -1; + /* + * See if this is an ELF file first: + */ + if (filename__fprintf_build_id(session->filename, stdout)) + goto out; + if (with_hits) perf_session__process_events(session, &build_id__mark_dso_hit_ops); perf_session__fprintf_dsos_buildid(session, stdout, with_hits); - +out: perf_session__delete(session); return 0; } @@ -90,13 +98,6 @@ static int __cmd_buildid_list(void) if (show_kernel) return sysfs__fprintf_build_id(stdout); - elf_version(EV_CURRENT); - /* - * See if this is an ELF file first: - */ - if (filename__fprintf_build_id(input_name, stdout)) - return 0; - return perf_session__list_build_ids(); } diff --git a/tools/perf/builtin-evlist.c b/tools/perf/builtin-evlist.c index 4c5e9e04a41..26760322c4f 100644 --- a/tools/perf/builtin-evlist.c +++ b/tools/perf/builtin-evlist.c @@ -15,7 +15,7 @@ #include "util/parse-options.h" #include "util/session.h" -static char const *input_name = "perf.data"; +static const char *input_name; static int __cmd_evlist(void) { diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index 886174e9525..fe1ad8f2196 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c @@ -19,7 +19,7 @@ struct alloc_stat; typedef int (*sort_fn_t)(struct alloc_stat *, struct alloc_stat *); -static char const *input_name = "perf.data"; +static const char *input_name; static int alloc_flag; static int caller_flag; diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c index 4db5e529306..2296c391d0f 100644 --- a/tools/perf/builtin-lock.c +++ b/tools/perf/builtin-lock.c @@ -326,7 +326,7 @@ alloc_failed: die("memory allocation failed\n"); } -static char const *input_name = "perf.data"; +static const char *input_name; struct raw_event_sample { u32 size; diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 9051f6bfaa7..25d34d483e4 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -321,8 +321,7 @@ static int __cmd_report(struct perf_report *rep) } if (nr_samples == 0) { - ui__warning("The %s file has no samples!\n", - rep->input_name); + ui__warning("The %s file has no samples!\n", session->filename); goto out_delete; } @@ -430,6 +429,7 @@ setup: int cmd_report(int argc, const char **argv, const char *prefix __used) { + struct stat st; char callchain_default_opt[] = "fractal,0.5,callee"; const char * const report_usage[] = { "perf report []", @@ -451,7 +451,6 @@ int cmd_report(int argc, const char **argv, const char *prefix __used) .ordered_samples = true, .ordering_requires_timestamps = true, }, - .input_name = "perf.data", .pretty_printing_style = "normal", }; const struct option options[] = { @@ -531,10 +530,18 @@ int cmd_report(int argc, const char **argv, const char *prefix __used) if (report.inverted_callchain) callchain_param.order = ORDER_CALLER; + if (!report.input_name || !strlen(report.input_name)) { + if (!fstat(STDIN_FILENO, &st) && S_ISFIFO(st.st_mode)) + report.input_name = "-"; + else + report.input_name = "perf.data"; + } + if (strcmp(report.input_name, "-") != 0) setup_browser(true); else use_browser = 0; + /* * Only in the newt browser we are doing integrated annotation, * so don't allocate extra space that won't be used in the stdio diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index 6284ed2317f..fb8b5f83b4a 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -22,7 +22,7 @@ #include #include -static char const *input_name = "perf.data"; +static const char *input_name; static char default_sort_order[] = "avg, max, switch, runtime"; static const char *sort_order = default_sort_order; diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index d71b745da06..3d4c0c7b576 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -434,7 +434,7 @@ static int cleanup_scripting(void) return scripting_ops->stop_script(); } -static char const *input_name = "perf.data"; +static const char *input_name; static int process_sample_event(struct perf_tool *tool __used, union perf_event *event, @@ -1316,7 +1316,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __used) return -1; } - input = open(input_name, O_RDONLY); + input = open(session->filename, O_RDONLY); /* input_name */ if (input < 0) { perror("failed to open file"); exit(-1); diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index 135376a37f9..3b75b2e21ea 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c @@ -38,8 +38,8 @@ #define PWR_EVENT_EXIT -1 -static char const *input_name = "perf.data"; -static char const *output_name = "output.svg"; +static const char *input_name; +static const char *output_name = "output.svg"; static unsigned int numcpus; static u64 min_freq; /* Lowest CPU frequency seen */ diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index ea17dfb85ba..cc5e6be46d8 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -107,8 +107,19 @@ struct perf_session *perf_session__new(const char *filename, int mode, bool force, bool repipe, struct perf_tool *tool) { - size_t len = filename ? strlen(filename) : 0; - struct perf_session *self = zalloc(sizeof(*self) + len); + struct perf_session *self; + struct stat st; + size_t len; + + if (!filename || !strlen(filename)) { + if (!fstat(STDIN_FILENO, &st) && S_ISFIFO(st.st_mode)) + filename = "-"; + else + filename = "perf.data"; + } + + len = strlen(filename); + self = zalloc(sizeof(*self) + len); if (self == NULL) goto out; -- cgit v1.2.3-70-g09d2 From e20960c0271f91aead94746872fd976326a703b3 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Wed, 7 Dec 2011 10:02:55 +0100 Subject: perf tools: Unify handling of features when writing feature section The features HEADER_TRACE_INFO and HEADER_BUILD_ID are handled different when writing the feature section. All other features are simply disabled on failure and writing the section goes on without returning an error. There is no reason for these special cases. This patch unifies handling of the features. This should be ok since all features can be parsed independently. Offset and size of a feature's block is stored in struct perf_file_ section right after the data block of perf.data (see perf_session__ write_header()). Thus, if a feature does not exist then other features can be processed anyway. Also moving special code for HEADER_BUILD_ID out to write_build_id(). v2: * perf record throws an error now if buildids may not be generated, which can be disabled with the --no-buildid option. Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1323248577-11268-6-git-send-email-robert.richter@amd.com Signed-off-by: Robert Richter Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 7 +++++++ tools/perf/util/header.c | 14 +++++--------- 2 files changed, 12 insertions(+), 9 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index e873ae2dd54..0abfb18b911 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -503,6 +503,13 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) return err; } + if (!!rec->no_buildid + && !perf_header__has_feat(&session->header, HEADER_BUILD_ID)) { + pr_err("Couldn't generating buildids. " + "Use --no-buildid to profile anyway.\n"); + return -1; + } + rec->post_processing_offset = lseek(output, 0, SEEK_CUR); machine = perf_session__find_host_machine(session); diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 609d79b5fb5..71326836921 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -445,6 +445,9 @@ static int write_build_id(int fd, struct perf_header *h, session = container_of(h, struct perf_session, header); + if (!perf_session__read_build_ids(session, true)) + return -1; + err = dsos__write_buildid_table(h, fd); if (err < 0) { pr_debug("failed to write buildid table\n"); @@ -1417,10 +1420,6 @@ static int perf_header__adds_write(struct perf_header *header, session = container_of(header, struct perf_session, header); - if (perf_header__has_feat(header, HEADER_BUILD_ID && - !perf_session__read_build_ids(session, true))) - perf_header__clear_feat(header, HEADER_BUILD_ID); - nr_sections = bitmap_weight(header->adds_features, HEADER_FEAT_BITS); if (!nr_sections) return 0; @@ -1436,13 +1435,11 @@ static int perf_header__adds_write(struct perf_header *header, err = do_write_feat(fd, header, HEADER_TRACE_INFO, &p, evlist); if (err) - goto out_free; + perf_header__clear_feat(header, HEADER_TRACE_INFO); err = do_write_feat(fd, header, HEADER_BUILD_ID, &p, evlist); - if (err) { + if (err) perf_header__clear_feat(header, HEADER_BUILD_ID); - goto out_free; - } err = do_write_feat(fd, header, HEADER_HOSTNAME, &p, evlist); if (err) @@ -1500,7 +1497,6 @@ static int perf_header__adds_write(struct perf_header *header, err = do_write(fd, feat_sec, sec_size); if (err < 0) pr_debug("failed to write feature section\n"); -out_free: free(feat_sec); return err; } -- cgit v1.2.3-70-g09d2 From b1e5a9bee3c342dd3281aef76d1be1044dd8addf Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Wed, 7 Dec 2011 10:02:57 +0100 Subject: perf tools: Use for_each_set_bit() to iterate over feature flags This patch introduces the for_each_set_bit() macro and modifies feature implementation to use it. Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1323248577-11268-8-git-send-email-robert.richter@amd.com Signed-off-by: Robert Richter Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/header.c | 118 ++++++++------------------------- tools/perf/util/header.h | 6 +- tools/perf/util/include/linux/bitops.h | 118 +++++++++++++++++++++++++++++++++ 3 files changed, 149 insertions(+), 93 deletions(-) (limited to 'tools') diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 71326836921..e509a9dea00 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include "evlist.h" @@ -1353,7 +1354,7 @@ static int perf_file_section__fprintf_info(struct perf_file_section *section, "%d, continuing...\n", section->offset, feat); return 0; } - if (feat < HEADER_TRACE_INFO || feat >= HEADER_LAST_FEATURE) { + if (feat >= HEADER_LAST_FEATURE) { pr_warning("unknown feature %d\n", feat); return 0; } @@ -1390,6 +1391,8 @@ static int do_write_feat(int fd, struct perf_header *h, int type, int ret = 0; if (perf_header__has_feat(h, type)) { + if (!feat_ops[type].write) + return -1; (*p)->offset = lseek(fd, 0, SEEK_CUR); @@ -1416,6 +1419,7 @@ static int perf_header__adds_write(struct perf_header *header, struct perf_file_section *feat_sec, *p; int sec_size; u64 sec_start; + int feat; int err; session = container_of(header, struct perf_session, header); @@ -1433,61 +1437,10 @@ static int perf_header__adds_write(struct perf_header *header, sec_start = header->data_offset + header->data_size; lseek(fd, sec_start + sec_size, SEEK_SET); - err = do_write_feat(fd, header, HEADER_TRACE_INFO, &p, evlist); - if (err) - perf_header__clear_feat(header, HEADER_TRACE_INFO); - - err = do_write_feat(fd, header, HEADER_BUILD_ID, &p, evlist); - if (err) - perf_header__clear_feat(header, HEADER_BUILD_ID); - - err = do_write_feat(fd, header, HEADER_HOSTNAME, &p, evlist); - if (err) - perf_header__clear_feat(header, HEADER_HOSTNAME); - - err = do_write_feat(fd, header, HEADER_OSRELEASE, &p, evlist); - if (err) - perf_header__clear_feat(header, HEADER_OSRELEASE); - - err = do_write_feat(fd, header, HEADER_VERSION, &p, evlist); - if (err) - perf_header__clear_feat(header, HEADER_VERSION); - - err = do_write_feat(fd, header, HEADER_ARCH, &p, evlist); - if (err) - perf_header__clear_feat(header, HEADER_ARCH); - - err = do_write_feat(fd, header, HEADER_NRCPUS, &p, evlist); - if (err) - perf_header__clear_feat(header, HEADER_NRCPUS); - - err = do_write_feat(fd, header, HEADER_CPUDESC, &p, evlist); - if (err) - perf_header__clear_feat(header, HEADER_CPUDESC); - - err = do_write_feat(fd, header, HEADER_CPUID, &p, evlist); - if (err) - perf_header__clear_feat(header, HEADER_CPUID); - - err = do_write_feat(fd, header, HEADER_TOTAL_MEM, &p, evlist); - if (err) - perf_header__clear_feat(header, HEADER_TOTAL_MEM); - - err = do_write_feat(fd, header, HEADER_CMDLINE, &p, evlist); - if (err) - perf_header__clear_feat(header, HEADER_CMDLINE); - - err = do_write_feat(fd, header, HEADER_EVENT_DESC, &p, evlist); - if (err) - perf_header__clear_feat(header, HEADER_EVENT_DESC); - - err = do_write_feat(fd, header, HEADER_CPU_TOPOLOGY, &p, evlist); - if (err) - perf_header__clear_feat(header, HEADER_CPU_TOPOLOGY); - - err = do_write_feat(fd, header, HEADER_NUMA_TOPOLOGY, &p, evlist); - if (err) - perf_header__clear_feat(header, HEADER_NUMA_TOPOLOGY); + for_each_set_bit(feat, header->adds_features, HEADER_FEAT_BITS) { + if (do_write_feat(fd, header, feat, &p, evlist)) + perf_header__clear_feat(header, feat); + } lseek(fd, sec_start, SEEK_SET); /* @@ -1634,20 +1587,20 @@ static int perf_header__getbuffer64(struct perf_header *header, int perf_header__process_sections(struct perf_header *header, int fd, void *data, int (*process)(struct perf_file_section *section, - struct perf_header *ph, - int feat, int fd, void *data)) + struct perf_header *ph, + int feat, int fd, void *data)) { - struct perf_file_section *feat_sec; + struct perf_file_section *feat_sec, *sec; int nr_sections; int sec_size; - int idx = 0; - int err = -1, feat = 1; + int feat; + int err; nr_sections = bitmap_weight(header->adds_features, HEADER_FEAT_BITS); if (!nr_sections) return 0; - feat_sec = calloc(sizeof(*feat_sec), nr_sections); + feat_sec = sec = calloc(sizeof(*feat_sec), nr_sections); if (!feat_sec) return -1; @@ -1655,20 +1608,16 @@ int perf_header__process_sections(struct perf_header *header, int fd, lseek(fd, header->data_offset + header->data_size, SEEK_SET); - if (perf_header__getbuffer64(header, fd, feat_sec, sec_size)) + err = perf_header__getbuffer64(header, fd, feat_sec, sec_size); + if (err < 0) goto out_free; - err = 0; - while (idx < nr_sections && feat < HEADER_LAST_FEATURE) { - if (perf_header__has_feat(header, feat)) { - struct perf_file_section *sec = &feat_sec[idx++]; - - err = process(sec, header, feat, fd, data); - if (err < 0) - break; - } - ++feat; + for_each_set_bit(feat, header->adds_features, HEADER_LAST_FEATURE) { + err = process(sec++, header, feat, fd, data); + if (err < 0) + goto out_free; } + err = 0; out_free: free(feat_sec); return err; @@ -1903,32 +1852,21 @@ static int perf_file_section__process(struct perf_file_section *section, return 0; } + if (feat >= HEADER_LAST_FEATURE) { + pr_debug("unknown feature %d, continuing...\n", feat); + return 0; + } + switch (feat) { case HEADER_TRACE_INFO: trace_report(fd, false); break; - case HEADER_BUILD_ID: if (perf_header__read_build_ids(ph, fd, section->offset, section->size)) pr_debug("Failed to read buildids, continuing...\n"); break; - - case HEADER_HOSTNAME: - case HEADER_OSRELEASE: - case HEADER_VERSION: - case HEADER_ARCH: - case HEADER_NRCPUS: - case HEADER_CPUDESC: - case HEADER_CPUID: - case HEADER_TOTAL_MEM: - case HEADER_CMDLINE: - case HEADER_EVENT_DESC: - case HEADER_CPU_TOPOLOGY: - case HEADER_NUMA_TOPOLOGY: - break; - default: - pr_debug("unknown feature %d, continuing...\n", feat); + break; } return 0; diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index 09365b32098..ac4ec956024 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h @@ -10,7 +10,8 @@ #include enum { - HEADER_TRACE_INFO = 1, + HEADER_RESERVED = 0, /* always cleared */ + HEADER_TRACE_INFO = 1, HEADER_BUILD_ID, HEADER_HOSTNAME, @@ -27,10 +28,9 @@ enum { HEADER_NUMA_TOPOLOGY, HEADER_LAST_FEATURE, + HEADER_FEAT_BITS = 256, }; -#define HEADER_FEAT_BITS 256 - struct perf_file_section { u64 offset; u64 size; diff --git a/tools/perf/util/include/linux/bitops.h b/tools/perf/util/include/linux/bitops.h index 305c8484f20..62cdee78db7 100644 --- a/tools/perf/util/include/linux/bitops.h +++ b/tools/perf/util/include/linux/bitops.h @@ -9,6 +9,17 @@ #define BITS_PER_BYTE 8 #define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) +#define for_each_set_bit(bit, addr, size) \ + for ((bit) = find_first_bit((addr), (size)); \ + (bit) < (size); \ + (bit) = find_next_bit((addr), (size), (bit) + 1)) + +/* same as for_each_set_bit() but use bit as value to start with */ +#define for_each_set_bit_cont(bit, addr, size) \ + for ((bit) = find_next_bit((addr), (size), (bit)); \ + (bit) < (size); \ + (bit) = find_next_bit((addr), (size), (bit) + 1)) + static inline void set_bit(int nr, unsigned long *addr) { addr[nr / BITS_PER_LONG] |= 1UL << (nr % BITS_PER_LONG); @@ -30,4 +41,111 @@ static inline unsigned long hweight_long(unsigned long w) return sizeof(w) == 4 ? hweight32(w) : hweight64(w); } +#define BITOP_WORD(nr) ((nr) / BITS_PER_LONG) + +/** + * __ffs - find first bit in word. + * @word: The word to search + * + * Undefined if no bit exists, so code should check against 0 first. + */ +static __always_inline unsigned long __ffs(unsigned long word) +{ + int num = 0; + +#if BITS_PER_LONG == 64 + if ((word & 0xffffffff) == 0) { + num += 32; + word >>= 32; + } +#endif + if ((word & 0xffff) == 0) { + num += 16; + word >>= 16; + } + if ((word & 0xff) == 0) { + num += 8; + word >>= 8; + } + if ((word & 0xf) == 0) { + num += 4; + word >>= 4; + } + if ((word & 0x3) == 0) { + num += 2; + word >>= 2; + } + if ((word & 0x1) == 0) + num += 1; + return num; +} + +/* + * Find the first set bit in a memory region. + */ +static inline unsigned long +find_first_bit(const unsigned long *addr, unsigned long size) +{ + const unsigned long *p = addr; + unsigned long result = 0; + unsigned long tmp; + + while (size & ~(BITS_PER_LONG-1)) { + if ((tmp = *(p++))) + goto found; + result += BITS_PER_LONG; + size -= BITS_PER_LONG; + } + if (!size) + return result; + + tmp = (*p) & (~0UL >> (BITS_PER_LONG - size)); + if (tmp == 0UL) /* Are any bits set? */ + return result + size; /* Nope. */ +found: + return result + __ffs(tmp); +} + +/* + * Find the next set bit in a memory region. + */ +static inline unsigned long +find_next_bit(const unsigned long *addr, unsigned long size, unsigned long offset) +{ + const unsigned long *p = addr + BITOP_WORD(offset); + unsigned long result = offset & ~(BITS_PER_LONG-1); + unsigned long tmp; + + if (offset >= size) + return size; + size -= result; + offset %= BITS_PER_LONG; + if (offset) { + tmp = *(p++); + tmp &= (~0UL << offset); + if (size < BITS_PER_LONG) + goto found_first; + if (tmp) + goto found_middle; + size -= BITS_PER_LONG; + result += BITS_PER_LONG; + } + while (size & ~(BITS_PER_LONG-1)) { + if ((tmp = *(p++))) + goto found_middle; + result += BITS_PER_LONG; + size -= BITS_PER_LONG; + } + if (!size) + return result; + tmp = *p; + +found_first: + tmp &= (~0UL >> (BITS_PER_LONG - size)); + if (tmp == 0UL) /* Are any bits set? */ + return result + size; /* Nope. */ +found_middle: + return result + __ffs(tmp); +} + #endif -- cgit v1.2.3-70-g09d2 From 37a058ea006de0cc24553637afa788594a975176 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 15 Dec 2011 18:23:43 +0100 Subject: perf script: Add generic perl handler to process events The current perf scripting facility only supports tracepoints. This patch implements a generic perl handler to support other events than tracepoints too. This patch introduces a function process_event() that is called by perf for each sample. The function is called with byte streams as arguments containing information about the event, its attributes, the sample and raw data. Perl's unpack() function can easily be used for byte decoding. The following is the default implementation for process_event() that can also be generated with perf script: # Packed byte string args of process_event(): # # $event: union perf_event util/event.h # $attr: struct perf_event_attr linux/perf_event.h # $sample: struct perf_sample util/event.h # $raw_data: perf_sample->raw_data util/event.h sub process_event { my ($event, $attr, $sample, $raw_data) = @_; my @event = unpack("LSS", $event); my @attr = unpack("LLQQQQQLLQQ", $attr); my @sample = unpack("QLLQQQQQLL", $sample); my @raw_data = unpack("C*", $raw_data); use Data::Dumper; print Dumper \@event, \@attr, \@sample, \@raw_data; } Cc: Ingo Molnar Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1323969824-9711-4-git-send-email-robert.richter@amd.com Signed-off-by: Robert Richter Signed-off-by: Arnaldo Carvalho de Melo --- .../perf/util/scripting-engines/trace-event-perl.c | 73 ++++++++++++++++++++-- 1 file changed, 67 insertions(+), 6 deletions(-) (limited to 'tools') diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c index a82ce4303ff..e30749e38a9 100644 --- a/tools/perf/util/scripting-engines/trace-event-perl.c +++ b/tools/perf/util/scripting-engines/trace-event-perl.c @@ -30,6 +30,7 @@ #include "../thread.h" #include "../event.h" #include "../trace-event.h" +#include "../evsel.h" #include #include @@ -247,11 +248,11 @@ static inline struct event *find_cache_event(int type) return event; } -static void perl_process_event(union perf_event *pevent __unused, - struct perf_sample *sample, - struct perf_evsel *evsel, - struct machine *machine __unused, - struct thread *thread) +static void perl_process_tracepoint(union perf_event *pevent __unused, + struct perf_sample *sample, + struct perf_evsel *evsel, + struct machine *machine __unused, + struct thread *thread) { struct format_field *field; static char handler[256]; @@ -267,6 +268,9 @@ static void perl_process_event(union perf_event *pevent __unused, dSP; + if (evsel->attr.type != PERF_TYPE_TRACEPOINT) + return; + type = trace_parse_common_type(data); event = find_cache_event(type); @@ -334,6 +338,42 @@ static void perl_process_event(union perf_event *pevent __unused, LEAVE; } +static void perl_process_event_generic(union perf_event *pevent __unused, + struct perf_sample *sample, + struct perf_evsel *evsel __unused, + struct machine *machine __unused, + struct thread *thread __unused) +{ + dSP; + + if (!get_cv("process_event", 0)) + return; + + ENTER; + SAVETMPS; + PUSHMARK(SP); + XPUSHs(sv_2mortal(newSVpvn((const char *)pevent, pevent->header.size))); + XPUSHs(sv_2mortal(newSVpvn((const char *)&evsel->attr, sizeof(evsel->attr)))); + XPUSHs(sv_2mortal(newSVpvn((const char *)sample, sizeof(*sample)))); + XPUSHs(sv_2mortal(newSVpvn((const char *)sample->raw_data, sample->raw_size))); + PUTBACK; + call_pv("process_event", G_SCALAR); + SPAGAIN; + PUTBACK; + FREETMPS; + LEAVE; +} + +static void perl_process_event(union perf_event *pevent, + struct perf_sample *sample, + struct perf_evsel *evsel, + struct machine *machine, + struct thread *thread) +{ + perl_process_tracepoint(pevent, sample, evsel, machine, thread); + perl_process_event_generic(pevent, sample, evsel, machine, thread); +} + static void run_start_sub(void) { dSP; /* access to Perl stack */ @@ -555,7 +595,28 @@ static int perl_generate_script(const char *outfile) fprintf(ofp, "sub print_header\n{\n" "\tmy ($event_name, $cpu, $secs, $nsecs, $pid, $comm) = @_;\n\n" "\tprintf(\"%%-20s %%5u %%05u.%%09u %%8u %%-20s \",\n\t " - "$event_name, $cpu, $secs, $nsecs, $pid, $comm);\n}"); + "$event_name, $cpu, $secs, $nsecs, $pid, $comm);\n}\n"); + + fprintf(ofp, + "\n# Packed byte string args of process_event():\n" + "#\n" + "# $event:\tunion perf_event\tutil/event.h\n" + "# $attr:\tstruct perf_event_attr\tlinux/perf_event.h\n" + "# $sample:\tstruct perf_sample\tutil/event.h\n" + "# $raw_data:\tperf_sample->raw_data\tutil/event.h\n" + "\n" + "sub process_event\n" + "{\n" + "\tmy ($event, $attr, $sample, $raw_data) = @_;\n" + "\n" + "\tmy @event\t= unpack(\"LSS\", $event);\n" + "\tmy @attr\t= unpack(\"LLQQQQQLLQQ\", $attr);\n" + "\tmy @sample\t= unpack(\"QLLQQQQQLL\", $sample);\n" + "\tmy @raw_data\t= unpack(\"C*\", $raw_data);\n" + "\n" + "\tuse Data::Dumper;\n" + "\tprint Dumper \\@event, \\@attr, \\@sample, \\@raw_data;\n" + "}\n"); fclose(ofp); -- cgit v1.2.3-70-g09d2 From f2328062726d36e562f1458d6346b77aa048acad Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Thu, 29 Dec 2011 21:26:17 +0100 Subject: perf tools: Fix feature-bits rework fallout, remove unused variable Cc: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Robert Richter Link: http://lkml.kernel.org/n/tip-lfckuwbl8m1ykb7t9ydsxe4r@git.kernel.org Signed-off-by: Ingo Molnar --- tools/perf/util/header.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'tools') diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index e509a9dea00..3e7e0b09c12 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -1415,15 +1415,12 @@ static int perf_header__adds_write(struct perf_header *header, struct perf_evlist *evlist, int fd) { int nr_sections; - struct perf_session *session; struct perf_file_section *feat_sec, *p; int sec_size; u64 sec_start; int feat; int err; - session = container_of(header, struct perf_session, header); - nr_sections = bitmap_weight(header->adds_features, HEADER_FEAT_BITS); if (!nr_sections) return 0; -- cgit v1.2.3-70-g09d2 From d36b691077dc59c74efec0d54ed21b86f7a2a21a Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 29 Dec 2011 17:09:01 -0500 Subject: misc latin1 to utf8 conversions Signed-off-by: Al Viro Signed-off-by: Jiri Kosina --- Documentation/ABI/testing/sysfs-driver-hid-logitech-lg4ff | 2 +- Documentation/vgaarbiter.txt | 2 +- drivers/gpu/drm/i915/intel_sdvo_regs.h | 2 +- drivers/hid/hid-pl.c | 4 ++-- drivers/hid/hid-twinhan.c | 2 +- drivers/i2c/busses/i2c-xiic.c | 2 +- drivers/isdn/hisax/enternow_pci.c | 2 +- drivers/media/rc/winbond-cir.c | 2 +- drivers/misc/ibmasm/command.c | 2 +- drivers/misc/ibmasm/dot_command.c | 2 +- drivers/misc/ibmasm/dot_command.h | 2 +- drivers/misc/ibmasm/event.c | 2 +- drivers/misc/ibmasm/heartbeat.c | 2 +- drivers/misc/ibmasm/i2o.h | 2 +- drivers/misc/ibmasm/ibmasm.h | 2 +- drivers/misc/ibmasm/ibmasmfs.c | 2 +- drivers/misc/ibmasm/lowlevel.c | 2 +- drivers/misc/ibmasm/lowlevel.h | 2 +- drivers/misc/ibmasm/module.c | 2 +- drivers/misc/ibmasm/r_heartbeat.c | 2 +- drivers/misc/ibmasm/remote.h | 2 +- drivers/misc/ibmasm/uart.c | 2 +- drivers/mmc/host/omap.c | 4 ++-- drivers/scsi/jazz_esp.c | 2 +- drivers/scsi/sni_53c710.c | 2 +- drivers/staging/bcm/target_params.h | 4 ++-- drivers/staging/keucr/smilmain.c | 4 ++-- drivers/staging/wlags49_h2/debug.h | 2 +- drivers/staging/wlags49_h2/dhfcfg.h | 2 +- drivers/staging/wlags49_h2/hcf.c | 6 +++--- drivers/staging/wlags49_h2/hcf.h | 6 +++--- drivers/staging/wlags49_h2/hcfcfg.h | 6 +++--- drivers/staging/wlags49_h2/hcfdef.h | 6 +++--- drivers/staging/wlags49_h2/mdd.h | 6 +++--- drivers/staging/wlags49_h2/mmd.c | 2 +- drivers/staging/wlags49_h2/mmd.h | 2 +- drivers/staging/wlags49_h2/wl_cs.h | 4 ++-- drivers/staging/wlags49_h2/wl_enc.c | 4 ++-- drivers/staging/wlags49_h2/wl_enc.h | 4 ++-- drivers/staging/wlags49_h2/wl_if.h | 4 ++-- drivers/staging/wlags49_h2/wl_internal.h | 4 ++-- drivers/staging/wlags49_h2/wl_main.c | 4 ++-- drivers/staging/wlags49_h2/wl_main.h | 4 ++-- drivers/staging/wlags49_h2/wl_netdev.c | 4 ++-- drivers/staging/wlags49_h2/wl_netdev.h | 4 ++-- drivers/staging/wlags49_h2/wl_pci.c | 4 ++-- drivers/staging/wlags49_h2/wl_pci.h | 4 ++-- drivers/staging/wlags49_h2/wl_priv.c | 4 ++-- drivers/staging/wlags49_h2/wl_priv.h | 4 ++-- drivers/staging/wlags49_h2/wl_profile.c | 4 ++-- drivers/staging/wlags49_h2/wl_profile.h | 4 ++-- drivers/staging/wlags49_h2/wl_util.c | 4 ++-- drivers/staging/wlags49_h2/wl_util.h | 4 ++-- drivers/staging/wlags49_h2/wl_version.h | 4 ++-- drivers/staging/wlags49_h2/wl_wext.c | 4 ++-- drivers/staging/wlags49_h2/wl_wext.h | 4 ++-- drivers/usb/gadget/s3c2410_udc.c | 4 ++-- drivers/usb/gadget/s3c2410_udc.h | 2 +- drivers/usb/serial/ftdi_sio_ids.h | 6 +++--- drivers/usb/storage/isd200.c | 2 +- drivers/usb/storage/unusual_devs.h | 2 +- drivers/video/omap/rfbi.c | 2 +- drivers/video/omap/sossi.c | 2 +- drivers/watchdog/w83627hf_wdt.c | 4 ++-- drivers/zorro/zorro.ids | 2 +- kernel/events/core.c | 2 +- kernel/events/ring_buffer.c | 2 +- tools/testing/ktest/sample.conf | 2 +- 68 files changed, 106 insertions(+), 106 deletions(-) (limited to 'tools') diff --git a/Documentation/ABI/testing/sysfs-driver-hid-logitech-lg4ff b/Documentation/ABI/testing/sysfs-driver-hid-logitech-lg4ff index 9aec8ef228b..167d9032b97 100644 --- a/Documentation/ABI/testing/sysfs-driver-hid-logitech-lg4ff +++ b/Documentation/ABI/testing/sysfs-driver-hid-logitech-lg4ff @@ -1,7 +1,7 @@ What: /sys/module/hid_logitech/drivers/hid:logitech//range. Date: July 2011 KernelVersion: 3.2 -Contact: Michal Malý +Contact: Michal Malý Description: Display minimum, maximum and current range of the steering wheel. Writing a value within min and max boundaries sets the range of the wheel. diff --git a/Documentation/vgaarbiter.txt b/Documentation/vgaarbiter.txt index b7d401e0eae..014423e2824 100644 --- a/Documentation/vgaarbiter.txt +++ b/Documentation/vgaarbiter.txt @@ -177,7 +177,7 @@ II. Credits Benjamin Herrenschmidt (IBM?) started this work when he discussed such design with the Xorg community in 2005 [1, 2]. In the end of 2007, Paulo Zanoni and -Tiago Vignatti (both of C3SL/Federal University of Paraná) proceeded his work +Tiago Vignatti (both of C3SL/Federal University of Paraná) proceeded his work enhancing the kernel code to adapt as a kernel module and also did the implementation of the user space side [3]. Now (2009) Tiago Vignatti and Dave Airlie finally put this work in shape and queued to Jesse Barnes' PCI tree. diff --git a/drivers/gpu/drm/i915/intel_sdvo_regs.h b/drivers/gpu/drm/i915/intel_sdvo_regs.h index 4aa6f343e49..6b7b22f4d63 100644 --- a/drivers/gpu/drm/i915/intel_sdvo_regs.h +++ b/drivers/gpu/drm/i915/intel_sdvo_regs.h @@ -1,5 +1,5 @@ /* - * Copyright © 2006-2007 Intel Corporation + * Copyright © 2006-2007 Intel Corporation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), diff --git a/drivers/hid/hid-pl.c b/drivers/hid/hid-pl.c index 070f93a5c11..47ed74c46b6 100644 --- a/drivers/hid/hid-pl.c +++ b/drivers/hid/hid-pl.c @@ -9,10 +9,10 @@ * - contains two reports, one for each port (HID_QUIRK_MULTI_INPUT) * * 0e8f:0003 "GreenAsia Inc. USB Joystick " - * - tested with König Gaming gamepad + * - tested with König Gaming gamepad * * 0e8f:0003 "GASIA USB Gamepad" - * - another version of the König gamepad + * - another version of the König gamepad * * Copyright (c) 2007, 2009 Anssi Hannula */ diff --git a/drivers/hid/hid-twinhan.c b/drivers/hid/hid-twinhan.c index c40afc57fc8..f23456b1fd4 100644 --- a/drivers/hid/hid-twinhan.c +++ b/drivers/hid/hid-twinhan.c @@ -3,7 +3,7 @@ * * Based on hid-gyration.c * - * Copyright (c) 2009 Bruno Prémont + * Copyright (c) 2009 Bruno Prémont */ /* diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c index 4bb68f35caf..ac083a28ae0 100644 --- a/drivers/i2c/busses/i2c-xiic.c +++ b/drivers/i2c/busses/i2c-xiic.c @@ -426,7 +426,7 @@ static void xiic_process(struct xiic_i2c *i2c) xiic_wakeup(i2c, STATE_ERROR); } else if (pend & (XIIC_INTR_TX_EMPTY_MASK | XIIC_INTR_TX_HALF_MASK)) { - /* Transmit register/FIFO is empty or ½ empty */ + /* Transmit register/FIFO is empty or ½ empty */ clr = pend & (XIIC_INTR_TX_EMPTY_MASK | XIIC_INTR_TX_HALF_MASK); diff --git a/drivers/isdn/hisax/enternow_pci.c b/drivers/isdn/hisax/enternow_pci.c index 26264abf1f5..f55d29d6082 100644 --- a/drivers/isdn/hisax/enternow_pci.c +++ b/drivers/isdn/hisax/enternow_pci.c @@ -333,7 +333,7 @@ static void __devinit en_cs_init(struct IsdnCard *card, cs->hw.njet.isac = cs->hw.njet.base + 0xC0; // Fenster zum AMD /* Reset an */ - cs->hw.njet.ctrl_reg = 0x07; // geändert von 0xff + cs->hw.njet.ctrl_reg = 0x07; // geändert von 0xff outb(cs->hw.njet.ctrl_reg, cs->hw.njet.base + NETJET_CTRL); /* 20 ms Pause */ mdelay(20); diff --git a/drivers/media/rc/winbond-cir.c b/drivers/media/rc/winbond-cir.c index 13f54b51194..e7f7a57bf68 100644 --- a/drivers/media/rc/winbond-cir.c +++ b/drivers/media/rc/winbond-cir.c @@ -1176,6 +1176,6 @@ wbcir_exit(void) module_init(wbcir_init); module_exit(wbcir_exit); -MODULE_AUTHOR("David Härdeman "); +MODULE_AUTHOR("David Härdeman "); MODULE_DESCRIPTION("Winbond SuperI/O Consumer IR Driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/misc/ibmasm/command.c b/drivers/misc/ibmasm/command.c index 5c766b4fb23..7d56f45dee1 100644 --- a/drivers/misc/ibmasm/command.c +++ b/drivers/misc/ibmasm/command.c @@ -18,7 +18,7 @@ * * Copyright (C) IBM Corporation, 2004 * - * Author: Max Asböck + * Author: Max Asböck * */ diff --git a/drivers/misc/ibmasm/dot_command.c b/drivers/misc/ibmasm/dot_command.c index 3dd2dfb8da1..d7b2ca358b2 100644 --- a/drivers/misc/ibmasm/dot_command.c +++ b/drivers/misc/ibmasm/dot_command.c @@ -17,7 +17,7 @@ * * Copyright (C) IBM Corporation, 2004 * - * Author: Max Asböck + * Author: Max Asböck * */ diff --git a/drivers/misc/ibmasm/dot_command.h b/drivers/misc/ibmasm/dot_command.h index 6cbba1afef3..fc9fc9d4e08 100644 --- a/drivers/misc/ibmasm/dot_command.h +++ b/drivers/misc/ibmasm/dot_command.h @@ -17,7 +17,7 @@ * * Copyright (C) IBM Corporation, 2004 * - * Author: Max Asböck + * Author: Max Asböck * */ diff --git a/drivers/misc/ibmasm/event.c b/drivers/misc/ibmasm/event.c index 76bfda1ffaa..8e540f4e9d5 100644 --- a/drivers/misc/ibmasm/event.c +++ b/drivers/misc/ibmasm/event.c @@ -18,7 +18,7 @@ * * Copyright (C) IBM Corporation, 2004 * - * Author: Max Asböck + * Author: Max Asböck * */ diff --git a/drivers/misc/ibmasm/heartbeat.c b/drivers/misc/ibmasm/heartbeat.c index 1bc4306572a..90746378f9b 100644 --- a/drivers/misc/ibmasm/heartbeat.c +++ b/drivers/misc/ibmasm/heartbeat.c @@ -18,7 +18,7 @@ * * Copyright (C) IBM Corporation, 2004 * - * Author: Max Asböck + * Author: Max Asböck * */ diff --git a/drivers/misc/ibmasm/i2o.h b/drivers/misc/ibmasm/i2o.h index bf2c738d2b7..2e9566dab2b 100644 --- a/drivers/misc/ibmasm/i2o.h +++ b/drivers/misc/ibmasm/i2o.h @@ -17,7 +17,7 @@ * * Copyright (C) IBM Corporation, 2004 * - * Author: Max Asböck + * Author: Max Asböck * */ diff --git a/drivers/misc/ibmasm/ibmasm.h b/drivers/misc/ibmasm/ibmasm.h index 4d8a4e248b3..9b083448814 100644 --- a/drivers/misc/ibmasm/ibmasm.h +++ b/drivers/misc/ibmasm/ibmasm.h @@ -18,7 +18,7 @@ * * Copyright (C) IBM Corporation, 2004 * - * Author: Max Asböck + * Author: Max Asböck * */ diff --git a/drivers/misc/ibmasm/ibmasmfs.c b/drivers/misc/ibmasm/ibmasmfs.c index 89947723a27..35361753b48 100644 --- a/drivers/misc/ibmasm/ibmasmfs.c +++ b/drivers/misc/ibmasm/ibmasmfs.c @@ -17,7 +17,7 @@ * * Copyright (C) IBM Corporation, 2004 * - * Author: Max Asböck + * Author: Max Asböck * */ diff --git a/drivers/misc/ibmasm/lowlevel.c b/drivers/misc/ibmasm/lowlevel.c index 4b2398e27fd..5319ea261c0 100644 --- a/drivers/misc/ibmasm/lowlevel.c +++ b/drivers/misc/ibmasm/lowlevel.c @@ -17,7 +17,7 @@ * * Copyright (C) IBM Corporation, 2004 * - * Author: Max Asböck + * Author: Max Asböck * */ diff --git a/drivers/misc/ibmasm/lowlevel.h b/drivers/misc/ibmasm/lowlevel.h index 766766523a6..e97848f51b3 100644 --- a/drivers/misc/ibmasm/lowlevel.h +++ b/drivers/misc/ibmasm/lowlevel.h @@ -17,7 +17,7 @@ * * Copyright (C) IBM Corporation, 2004 * - * Author: Max Asböck + * Author: Max Asböck * */ diff --git a/drivers/misc/ibmasm/module.c b/drivers/misc/ibmasm/module.c index a234d965243..1ccedb71e72 100644 --- a/drivers/misc/ibmasm/module.c +++ b/drivers/misc/ibmasm/module.c @@ -18,7 +18,7 @@ * * Copyright (C) IBM Corporation, 2004 * - * Author: Max Asböck + * Author: Max Asböck * * This driver is based on code originally written by Pete Reynolds * and others. diff --git a/drivers/misc/ibmasm/r_heartbeat.c b/drivers/misc/ibmasm/r_heartbeat.c index 2de487ac788..232034f5da4 100644 --- a/drivers/misc/ibmasm/r_heartbeat.c +++ b/drivers/misc/ibmasm/r_heartbeat.c @@ -16,7 +16,7 @@ * * Copyright (C) IBM Corporation, 2004 * - * Author: Max Asböck + * Author: Max Asböck * */ diff --git a/drivers/misc/ibmasm/remote.h b/drivers/misc/ibmasm/remote.h index 00dbf1d4373..a7729ef76ac 100644 --- a/drivers/misc/ibmasm/remote.h +++ b/drivers/misc/ibmasm/remote.h @@ -18,7 +18,7 @@ * * Copyright (C) IBM Corporation, 2004 * - * Author: Max Asböck + * Author: Max Asböck * * Originally written by Pete Reynolds */ diff --git a/drivers/misc/ibmasm/uart.c b/drivers/misc/ibmasm/uart.c index 93baa350d69..1dcb9ae1905 100644 --- a/drivers/misc/ibmasm/uart.c +++ b/drivers/misc/ibmasm/uart.c @@ -18,7 +18,7 @@ * * Copyright (C) IBM Corporation, 2004 * - * Author: Max Asböck + * Author: Max Asböck * */ diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c index 2dba999caf2..887c0e598cf 100644 --- a/drivers/mmc/host/omap.c +++ b/drivers/mmc/host/omap.c @@ -2,7 +2,7 @@ * linux/drivers/mmc/host/omap.c * * Copyright (C) 2004 Nokia Corporation - * Written by Tuukka Tikkanen and Juha Yrjölä + * Written by Tuukka Tikkanen and Juha Yrjölä * Misc hacks here and there by Tony Lindgren * Other hacks (DMA, SD, etc) by David Brownell * @@ -1634,4 +1634,4 @@ module_exit(mmc_omap_exit); MODULE_DESCRIPTION("OMAP Multimedia Card driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:" DRIVER_NAME); -MODULE_AUTHOR("Juha Yrjölä"); +MODULE_AUTHOR("Juha Yrjölä"); diff --git a/drivers/scsi/jazz_esp.c b/drivers/scsi/jazz_esp.c index 08e26d4e373..27cfb0cb186 100644 --- a/drivers/scsi/jazz_esp.c +++ b/drivers/scsi/jazz_esp.c @@ -1,6 +1,6 @@ /* jazz_esp.c: ESP front-end for MIPS JAZZ systems. * - * Copyright (C) 2007 Thomas Bogendörfer (tsbogend@alpha.frankende) + * Copyright (C) 2007 Thomas Bogendörfer (tsbogend@alpha.frankende) */ #include diff --git a/drivers/scsi/sni_53c710.c b/drivers/scsi/sni_53c710.c index 9acc2b2a360..cf51432f8e7 100644 --- a/drivers/scsi/sni_53c710.c +++ b/drivers/scsi/sni_53c710.c @@ -51,7 +51,7 @@ #include "53c700.h" -MODULE_AUTHOR("Thomas Bogendörfer"); +MODULE_AUTHOR("Thomas Bogendörfer"); MODULE_DESCRIPTION("SNI RM 53c710 SCSI Driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:snirm_53c710"); diff --git a/drivers/staging/bcm/target_params.h b/drivers/staging/bcm/target_params.h index 2d8b8a367b3..14876388b87 100644 --- a/drivers/staging/bcm/target_params.h +++ b/drivers/staging/bcm/target_params.h @@ -72,8 +72,8 @@ typedef struct _TARGET_PARAMS // removed SHUT down related 'unused' params from here to sync 4.x and 5.x CFG files.. //BAMC Related Parameters - //Bit 0-15 Band AMC signaling configuration: Bit 1 = 1 – Enable Band AMC signaling. - //bit 16-31 Band AMC Data configuration: Bit 16 = 1 – Band AMC 2x3 support. + //Bit 0-15 Band AMC signaling configuration: Bit 1 = 1 – Enable Band AMC signaling. + //bit 16-31 Band AMC Data configuration: Bit 16 = 1 – Band AMC 2x3 support. B_UINT32 m_u32BandAMCEnable; } stTargetParams,TARGET_PARAMS,*PTARGET_PARAMS, STARGETPARAMS, *PSTARGETPARAMS; diff --git a/drivers/staging/keucr/smilmain.c b/drivers/staging/keucr/smilmain.c index 31f7813cab0..cc49038e55d 100644 --- a/drivers/staging/keucr/smilmain.c +++ b/drivers/staging/keucr/smilmain.c @@ -148,7 +148,7 @@ int Media_D_ReadSector(struct us_data *us, DWORD start,WORD count,BYTE *buf) { WORD len, bn; - //if (Check_D_MediaPower()) ; ¦b 6250 don't care + //if (Check_D_MediaPower()) ; ¦b 6250 don't care // return(ErrCode); //if (Check_D_MediaFmt(fdoExt)) ; // return(ErrCode); @@ -594,7 +594,7 @@ int Media_D_OneSectWriteFlush(PFDO_DEVICE_EXTENSION fdoExt) // if (Check_D_CardStsChg()) // MediaChange = ERROR; // //usleep(56*1024); -// if ((!Check_D_CntPower())&&(!MediaChange)) // ¦³ power & Media ¨S³Q change, «h return success +// if ((!Check_D_CntPower())&&(!MediaChange)) // ¦³ power & Media ¨S³Q change, «h return success // return(SMSUCCESS); // //usleep(56*1024); // diff --git a/drivers/staging/wlags49_h2/debug.h b/drivers/staging/wlags49_h2/debug.h index 8d5dddf0805..811698f1070 100644 --- a/drivers/staging/wlags49_h2/debug.h +++ b/drivers/staging/wlags49_h2/debug.h @@ -43,7 +43,7 @@ * * Disclaimer * - * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, + * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN diff --git a/drivers/staging/wlags49_h2/dhfcfg.h b/drivers/staging/wlags49_h2/dhfcfg.h index 75c279f268a..147f4c83c00 100644 --- a/drivers/staging/wlags49_h2/dhfcfg.h +++ b/drivers/staging/wlags49_h2/dhfcfg.h @@ -43,7 +43,7 @@ * * Disclaimer * - * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, + * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN diff --git a/drivers/staging/wlags49_h2/hcf.c b/drivers/staging/wlags49_h2/hcf.c index 7dc176a95aa..b008773323b 100644 --- a/drivers/staging/wlags49_h2/hcf.c +++ b/drivers/staging/wlags49_h2/hcf.c @@ -32,9 +32,9 @@ * software indicates your acceptance of these terms and conditions. If you do * not agree with these terms and conditions, do not use the software. * - * COPYRIGHT © 1994 - 1995 by AT&T. All Rights Reserved - * COPYRIGHT © 1996 - 2000 by Lucent Technologies. All Rights Reserved - * COPYRIGHT © 2001 - 2004 by Agere Systems Inc. All Rights Reserved + * COPYRIGHT © 1994 - 1995 by AT&T. All Rights Reserved + * COPYRIGHT © 1996 - 2000 by Lucent Technologies. All Rights Reserved + * COPYRIGHT © 2001 - 2004 by Agere Systems Inc. All Rights Reserved * All rights reserved. * * Redistribution and use in source or binary forms, with or without diff --git a/drivers/staging/wlags49_h2/hcf.h b/drivers/staging/wlags49_h2/hcf.h index 00099473116..95527b5cf86 100644 --- a/drivers/staging/wlags49_h2/hcf.h +++ b/drivers/staging/wlags49_h2/hcf.h @@ -40,9 +40,9 @@ * software indicates your acceptance of these terms and conditions. If you do * not agree with these terms and conditions, do not use the software. * -* COPYRIGHT © 1994 - 1995 by AT&T. All Rights Reserved -* COPYRIGHT © 1996 - 2000 by Lucent Technologies. All Rights Reserved -* COPYRIGHT © 2001 - 2004 by Agere Systems Inc. All Rights Reserved +* COPYRIGHT © 1994 - 1995 by AT&T. All Rights Reserved +* COPYRIGHT © 1996 - 2000 by Lucent Technologies. All Rights Reserved +* COPYRIGHT © 2001 - 2004 by Agere Systems Inc. All Rights Reserved * All rights reserved. * * Redistribution and use in source or binary forms, with or without diff --git a/drivers/staging/wlags49_h2/hcfcfg.h b/drivers/staging/wlags49_h2/hcfcfg.h index 7545bc55411..ef60da8c3eb 100644 --- a/drivers/staging/wlags49_h2/hcfcfg.h +++ b/drivers/staging/wlags49_h2/hcfcfg.h @@ -64,9 +64,9 @@ * software indicates your acceptance of these terms and conditions. If you do * not agree with these terms and conditions, do not use the software. * -* COPYRIGHT © 1994 - 1995 by AT&T. All Rights Reserved -* COPYRIGHT © 1996 - 2000 by Lucent Technologies. All Rights Reserved -* COPYRIGHT © 2001 - 2004 by Agere Systems Inc. All Rights Reserved +* COPYRIGHT © 1994 - 1995 by AT&T. All Rights Reserved +* COPYRIGHT © 1996 - 2000 by Lucent Technologies. All Rights Reserved +* COPYRIGHT © 2001 - 2004 by Agere Systems Inc. All Rights Reserved * All rights reserved. * * Redistribution and use in source or binary forms, with or without diff --git a/drivers/staging/wlags49_h2/hcfdef.h b/drivers/staging/wlags49_h2/hcfdef.h index a62b53a2289..30744e194a2 100644 --- a/drivers/staging/wlags49_h2/hcfdef.h +++ b/drivers/staging/wlags49_h2/hcfdef.h @@ -33,9 +33,9 @@ * software indicates your acceptance of these terms and conditions. If you do * not agree with these terms and conditions, do not use the software. * - * COPYRIGHT © 1994 - 1995 by AT&T. All Rights Reserved - * COPYRIGHT © 1996 - 2000 by Lucent Technologies. All Rights Reserved - * COPYRIGHT © 2001 - 2004 by Agere Systems Inc. All Rights Reserved + * COPYRIGHT © 1994 - 1995 by AT&T. All Rights Reserved + * COPYRIGHT © 1996 - 2000 by Lucent Technologies. All Rights Reserved + * COPYRIGHT © 2001 - 2004 by Agere Systems Inc. All Rights Reserved * All rights reserved. * * Redistribution and use in source or binary forms, with or without diff --git a/drivers/staging/wlags49_h2/mdd.h b/drivers/staging/wlags49_h2/mdd.h index b02e3ea9e47..5f951efb9c0 100644 --- a/drivers/staging/wlags49_h2/mdd.h +++ b/drivers/staging/wlags49_h2/mdd.h @@ -33,9 +33,9 @@ * software indicates your acceptance of these terms and conditions. If you do * not agree with these terms and conditions, do not use the software. * -* COPYRIGHT © 1994 - 1995 by AT&T. All Rights Reserved -* COPYRIGHT © 1996 - 2000 by Lucent Technologies. All Rights Reserved -* COPYRIGHT © 2001 - 2004 by Agere Systems Inc. All Rights Reserved +* COPYRIGHT © 1994 - 1995 by AT&T. All Rights Reserved +* COPYRIGHT © 1996 - 2000 by Lucent Technologies. All Rights Reserved +* COPYRIGHT © 2001 - 2004 by Agere Systems Inc. All Rights Reserved * All rights reserved. * * Redistribution and use in source or binary forms, with or without diff --git a/drivers/staging/wlags49_h2/mmd.c b/drivers/staging/wlags49_h2/mmd.c index de138c481a9..c8f52107e6c 100644 --- a/drivers/staging/wlags49_h2/mmd.c +++ b/drivers/staging/wlags49_h2/mmd.c @@ -35,7 +35,7 @@ * software indicates your acceptance of these terms and conditions. If you do * not agree with these terms and conditions, do not use the software. * -* COPYRIGHT © 2001 - 2004 by Agere Systems Inc. All Rights Reserved +* COPYRIGHT © 2001 - 2004 by Agere Systems Inc. All Rights Reserved * All rights reserved. * * Redistribution and use in source or binary forms, with or without diff --git a/drivers/staging/wlags49_h2/mmd.h b/drivers/staging/wlags49_h2/mmd.h index 06890c1b30a..91495251300 100644 --- a/drivers/staging/wlags49_h2/mmd.h +++ b/drivers/staging/wlags49_h2/mmd.h @@ -33,7 +33,7 @@ * software indicates your acceptance of these terms and conditions. If you do * not agree with these terms and conditions, do not use the software. * -* COPYRIGHT © 2001 - 2004 by Agere Systems Inc. All Rights Reserved +* COPYRIGHT © 2001 - 2004 by Agere Systems Inc. All Rights Reserved * All rights reserved. * * Redistribution and use in source or binary forms, with or without diff --git a/drivers/staging/wlags49_h2/wl_cs.h b/drivers/staging/wlags49_h2/wl_cs.h index 21f17be4f02..a7ab579759d 100644 --- a/drivers/staging/wlags49_h2/wl_cs.h +++ b/drivers/staging/wlags49_h2/wl_cs.h @@ -22,7 +22,7 @@ * software indicates your acceptance of these terms and conditions. If you do * not agree with these terms and conditions, do not use the software. * - * Copyright © 2003 Agere Systems Inc. + * Copyright © 2003 Agere Systems Inc. * All rights reserved. * * Redistribution and use in source or binary forms, with or without @@ -43,7 +43,7 @@ * * Disclaimer * - * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, + * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN diff --git a/drivers/staging/wlags49_h2/wl_enc.c b/drivers/staging/wlags49_h2/wl_enc.c index 26cf5486edd..4c6f776cc4d 100644 --- a/drivers/staging/wlags49_h2/wl_enc.c +++ b/drivers/staging/wlags49_h2/wl_enc.c @@ -23,7 +23,7 @@ * software indicates your acceptance of these terms and conditions. If you do * not agree with these terms and conditions, do not use the software. * - * Copyright © 2003 Agere Systems Inc. + * Copyright © 2003 Agere Systems Inc. * All rights reserved. * * Redistribution and use in source or binary forms, with or without @@ -44,7 +44,7 @@ * * Disclaimer * - * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, + * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN diff --git a/drivers/staging/wlags49_h2/wl_enc.h b/drivers/staging/wlags49_h2/wl_enc.h index b4f54d81f31..46629f3b112 100644 --- a/drivers/staging/wlags49_h2/wl_enc.h +++ b/drivers/staging/wlags49_h2/wl_enc.h @@ -22,7 +22,7 @@ * software indicates your acceptance of these terms and conditions. If you do * not agree with these terms and conditions, do not use the software. * - * Copyright © 2003 Agere Systems Inc. + * Copyright © 2003 Agere Systems Inc. * All rights reserved. * * Redistribution and use in source or binary forms, with or without @@ -43,7 +43,7 @@ * * Disclaimer * - * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, + * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN diff --git a/drivers/staging/wlags49_h2/wl_if.h b/drivers/staging/wlags49_h2/wl_if.h index ed2b4135a10..6a26130f5a3 100644 --- a/drivers/staging/wlags49_h2/wl_if.h +++ b/drivers/staging/wlags49_h2/wl_if.h @@ -23,7 +23,7 @@ * software indicates your acceptance of these terms and conditions. If you do * not agree with these terms and conditions, do not use the software. * - * Copyright © 2003 Agere Systems Inc. + * Copyright © 2003 Agere Systems Inc. * All rights reserved. * * Redistribution and use in source or binary forms, with or without @@ -44,7 +44,7 @@ * * Disclaimer * - * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, + * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN diff --git a/drivers/staging/wlags49_h2/wl_internal.h b/drivers/staging/wlags49_h2/wl_internal.h index 57534083405..553601f4887 100644 --- a/drivers/staging/wlags49_h2/wl_internal.h +++ b/drivers/staging/wlags49_h2/wl_internal.h @@ -22,7 +22,7 @@ * software indicates your acceptance of these terms and conditions. If you do * not agree with these terms and conditions, do not use the software. * - * Copyright © 2003 Agere Systems Inc. + * Copyright © 2003 Agere Systems Inc. * All rights reserved. * * Redistribution and use in source or binary forms, with or without @@ -43,7 +43,7 @@ * * Disclaimer * - * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, + * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN diff --git a/drivers/staging/wlags49_h2/wl_main.c b/drivers/staging/wlags49_h2/wl_main.c index 483eee1bf63..dab603e0f45 100644 --- a/drivers/staging/wlags49_h2/wl_main.c +++ b/drivers/staging/wlags49_h2/wl_main.c @@ -23,7 +23,7 @@ * software indicates your acceptance of these terms and conditions. If you do * not agree with these terms and conditions, do not use the software. * - * Copyright © 2003 Agere Systems Inc. + * Copyright © 2003 Agere Systems Inc. * All rights reserved. * * Redistribution and use in source or binary forms, with or without @@ -44,7 +44,7 @@ * * Disclaimer * - * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, + * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN diff --git a/drivers/staging/wlags49_h2/wl_main.h b/drivers/staging/wlags49_h2/wl_main.h index d593ae535fb..3b5acdf4e32 100644 --- a/drivers/staging/wlags49_h2/wl_main.h +++ b/drivers/staging/wlags49_h2/wl_main.h @@ -22,7 +22,7 @@ * software indicates your acceptance of these terms and conditions. If you do * not agree with these terms and conditions, do not use the software. * - * Copyright © 2003 Agere Systems Inc. + * Copyright © 2003 Agere Systems Inc. * All rights reserved. * * Redistribution and use in source or binary forms, with or without @@ -43,7 +43,7 @@ * * Disclaimer * - * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, + * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN diff --git a/drivers/staging/wlags49_h2/wl_netdev.c b/drivers/staging/wlags49_h2/wl_netdev.c index 5a2b334f206..9c16f5478a7 100644 --- a/drivers/staging/wlags49_h2/wl_netdev.c +++ b/drivers/staging/wlags49_h2/wl_netdev.c @@ -23,7 +23,7 @@ * software indicates your acceptance of these terms and conditions. If you do * not agree with these terms and conditions, do not use the software. * - * Copyright © 2003 Agere Systems Inc. + * Copyright © 2003 Agere Systems Inc. * All rights reserved. * * Redistribution and use in source or binary forms, with or without @@ -44,7 +44,7 @@ * * Disclaimer * - * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, + * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN diff --git a/drivers/staging/wlags49_h2/wl_netdev.h b/drivers/staging/wlags49_h2/wl_netdev.h index 632ab2e6302..61f040f26d9 100644 --- a/drivers/staging/wlags49_h2/wl_netdev.h +++ b/drivers/staging/wlags49_h2/wl_netdev.h @@ -23,7 +23,7 @@ * software indicates your acceptance of these terms and conditions. If you do * not agree with these terms and conditions, do not use the software. * - * Copyright © 2003 Agere Systems Inc. + * Copyright © 2003 Agere Systems Inc. * All rights reserved. * * Redistribution and use in source or binary forms, with or without @@ -44,7 +44,7 @@ * * Disclaimer * - * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, + * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN diff --git a/drivers/staging/wlags49_h2/wl_pci.c b/drivers/staging/wlags49_h2/wl_pci.c index 28ae9dd1b44..1f1d9867917 100644 --- a/drivers/staging/wlags49_h2/wl_pci.c +++ b/drivers/staging/wlags49_h2/wl_pci.c @@ -23,7 +23,7 @@ * software indicates your acceptance of these terms and conditions. If you do * not agree with these terms and conditions, do not use the software. * - * Copyright © 2003 Agere Systems Inc. + * Copyright © 2003 Agere Systems Inc. * All rights reserved. * * Redistribution and use in source or binary forms, with or without @@ -44,7 +44,7 @@ * * Disclaimer * - * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, + * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN diff --git a/drivers/staging/wlags49_h2/wl_pci.h b/drivers/staging/wlags49_h2/wl_pci.h index cea04c44ec4..86831f1b4de 100644 --- a/drivers/staging/wlags49_h2/wl_pci.h +++ b/drivers/staging/wlags49_h2/wl_pci.h @@ -22,7 +22,7 @@ * software indicates your acceptance of these terms and conditions. If you do * not agree with these terms and conditions, do not use the software. * - * Copyright © 2003 Agere Systems Inc. + * Copyright © 2003 Agere Systems Inc. * All rights reserved. * * Redistribution and use in source or binary forms, with or without @@ -43,7 +43,7 @@ * * Disclaimer * - * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, + * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN diff --git a/drivers/staging/wlags49_h2/wl_priv.c b/drivers/staging/wlags49_h2/wl_priv.c index 260d4f0d47b..f30e5ee4bca 100644 --- a/drivers/staging/wlags49_h2/wl_priv.c +++ b/drivers/staging/wlags49_h2/wl_priv.c @@ -22,7 +22,7 @@ * software indicates your acceptance of these terms and conditions. If you do * not agree with these terms and conditions, do not use the software. * - * Copyright © 2003 Agere Systems Inc. + * Copyright © 2003 Agere Systems Inc. * All rights reserved. * * Redistribution and use in source or binary forms, with or without @@ -43,7 +43,7 @@ * * Disclaimer * - * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, + * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN diff --git a/drivers/staging/wlags49_h2/wl_priv.h b/drivers/staging/wlags49_h2/wl_priv.h index 9b0254497aa..b647bfd9009 100644 --- a/drivers/staging/wlags49_h2/wl_priv.h +++ b/drivers/staging/wlags49_h2/wl_priv.h @@ -22,7 +22,7 @@ * software indicates your acceptance of these terms and conditions. If you do * not agree with these terms and conditions, do not use the software. * - * Copyright © 2003 Agere Systems Inc. + * Copyright © 2003 Agere Systems Inc. * All rights reserved. * * Redistribution and use in source or binary forms, with or without @@ -43,7 +43,7 @@ * * Disclaimer * - * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, + * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN diff --git a/drivers/staging/wlags49_h2/wl_profile.c b/drivers/staging/wlags49_h2/wl_profile.c index a459e48c7bf..b8c96cf18de 100644 --- a/drivers/staging/wlags49_h2/wl_profile.c +++ b/drivers/staging/wlags49_h2/wl_profile.c @@ -23,7 +23,7 @@ * software indicates your acceptance of these terms and conditions. If you do * not agree with these terms and conditions, do not use the software. * - * Copyright © 2003 Agere Systems Inc. + * Copyright © 2003 Agere Systems Inc. * All rights reserved. * * Redistribution and use in source or binary forms, with or without @@ -44,7 +44,7 @@ * * Disclaimer * - * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, + * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN diff --git a/drivers/staging/wlags49_h2/wl_profile.h b/drivers/staging/wlags49_h2/wl_profile.h index 81db8e8c6ba..f81df51d221 100644 --- a/drivers/staging/wlags49_h2/wl_profile.h +++ b/drivers/staging/wlags49_h2/wl_profile.h @@ -22,7 +22,7 @@ * software indicates your acceptance of these terms and conditions. If you do * not agree with these terms and conditions, do not use the software. * - * Copyright © 2003 Agere Systems Inc. + * Copyright © 2003 Agere Systems Inc. * All rights reserved. * * Redistribution and use in source or binary forms, with or without @@ -43,7 +43,7 @@ * * Disclaimer * - * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, + * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN diff --git a/drivers/staging/wlags49_h2/wl_util.c b/drivers/staging/wlags49_h2/wl_util.c index 3b6f5a59b2b..b748a3ff795 100644 --- a/drivers/staging/wlags49_h2/wl_util.c +++ b/drivers/staging/wlags49_h2/wl_util.c @@ -22,7 +22,7 @@ * software indicates your acceptance of these terms and conditions. If you do * not agree with these terms and conditions, do not use the software. * - * Copyright © 2003 Agere Systems Inc. + * Copyright © 2003 Agere Systems Inc. * All rights reserved. * * Redistribution and use in source or binary forms, with or without @@ -43,7 +43,7 @@ * * Disclaimer * - * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, + * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN diff --git a/drivers/staging/wlags49_h2/wl_util.h b/drivers/staging/wlags49_h2/wl_util.h index 2661bcd6b0e..946b1b64c46 100644 --- a/drivers/staging/wlags49_h2/wl_util.h +++ b/drivers/staging/wlags49_h2/wl_util.h @@ -23,7 +23,7 @@ * software indicates your acceptance of these terms and conditions. If you do * not agree with these terms and conditions, do not use the software. * - * Copyright © 2003 Agere Systems Inc. + * Copyright © 2003 Agere Systems Inc. * All rights reserved. * * Redistribution and use in source or binary forms, with or without @@ -44,7 +44,7 @@ * * Disclaimer * - * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, + * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN diff --git a/drivers/staging/wlags49_h2/wl_version.h b/drivers/staging/wlags49_h2/wl_version.h index fd37040afd0..3deacfac9d2 100644 --- a/drivers/staging/wlags49_h2/wl_version.h +++ b/drivers/staging/wlags49_h2/wl_version.h @@ -23,7 +23,7 @@ * software indicates your acceptance of these terms and conditions. If you do * not agree with these terms and conditions, do not use the software. * - * Copyright © 2003 Agere Systems Inc. + * Copyright © 2003 Agere Systems Inc. * All rights reserved. * * Redistribution and use in source or binary forms, with or without @@ -44,7 +44,7 @@ * * Disclaimer * - * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, + * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN diff --git a/drivers/staging/wlags49_h2/wl_wext.c b/drivers/staging/wlags49_h2/wl_wext.c index 8ac5e1081aa..7ff0a108da1 100644 --- a/drivers/staging/wlags49_h2/wl_wext.c +++ b/drivers/staging/wlags49_h2/wl_wext.c @@ -18,7 +18,7 @@ * software indicates your acceptance of these terms and conditions. If you do * not agree with these terms and conditions, do not use the software. * - * Copyright © 2003 Agere Systems Inc. + * Copyright © 2003 Agere Systems Inc. * All rights reserved. * * Redistribution and use in source or binary forms, with or without @@ -39,7 +39,7 @@ * * Disclaimer * - * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, + * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN diff --git a/drivers/staging/wlags49_h2/wl_wext.h b/drivers/staging/wlags49_h2/wl_wext.h index a713058c802..029da52c4c4 100644 --- a/drivers/staging/wlags49_h2/wl_wext.h +++ b/drivers/staging/wlags49_h2/wl_wext.h @@ -22,7 +22,7 @@ * software indicates your acceptance of these terms and conditions. If you do * not agree with these terms and conditions, do not use the software. * - * Copyright © 2003 Agere Systems Inc. + * Copyright © 2003 Agere Systems Inc. * All rights reserved. * * Redistribution and use in source or binary forms, with or without @@ -43,7 +43,7 @@ * * Disclaimer * - * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, + * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c index b8643771fa8..fac4c650d4b 100644 --- a/drivers/usb/gadget/s3c2410_udc.c +++ b/drivers/usb/gadget/s3c2410_udc.c @@ -3,7 +3,7 @@ * * Samsung S3C24xx series on-chip full speed USB device controllers * - * Copyright (C) 2004-2007 Herbert Pötzl - Arnaud Patard + * Copyright (C) 2004-2007 Herbert Pötzl - Arnaud Patard * Additional cleanups by Ben Dooks * * This program is free software; you can redistribute it and/or modify @@ -51,7 +51,7 @@ #define DRIVER_DESC "S3C2410 USB Device Controller Gadget" #define DRIVER_VERSION "29 Apr 2007" -#define DRIVER_AUTHOR "Herbert Pötzl , " \ +#define DRIVER_AUTHOR "Herbert Pötzl , " \ "Arnaud Patard " static const char gadget_name[] = "s3c2410_udc"; diff --git a/drivers/usb/gadget/s3c2410_udc.h b/drivers/usb/gadget/s3c2410_udc.h index a48f619cb1c..1653bae08b8 100644 --- a/drivers/usb/gadget/s3c2410_udc.h +++ b/drivers/usb/gadget/s3c2410_udc.h @@ -2,7 +2,7 @@ * linux/drivers/usb/gadget/s3c2410_udc.h * Samsung on-chip full speed USB device controllers * - * Copyright (C) 2004-2007 Herbert Pötzl - Arnaud Patard + * Copyright (C) 2004-2007 Herbert Pötzl - Arnaud Patard * Additional cleanups by Ben Dooks * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 571fa96b49c..e38fe48cce1 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -2,7 +2,7 @@ * vendor/product IDs (VID/PID) of devices using FTDI USB serial converters. * Please keep numerically sorted within individual areas, thanks! * - * Philipp Gühring - pg@futureware.at - added the Device ID of the USB relais + * Philipp Gühring - pg@futureware.at - added the Device ID of the USB relais * from Rudolf Gugler * */ @@ -78,7 +78,7 @@ */ #define FTDI_ASK_RDR400_PID 0xC991 /* ASK RDR 400 series card reader */ -/* www.starting-point-systems.com µChameleon device */ +/* www.starting-point-systems.com µChameleon device */ #define FTDI_MICRO_CHAMELEON_PID 0xCAA0 /* Product Id */ /* @@ -290,7 +290,7 @@ /* * Teratronik product ids. - * Submitted by O. Wölfelschneider. + * Submitted by O. Wölfelschneider. */ #define FTDI_TERATRONIK_VCP_PID 0xEC88 /* Teratronik device (preferring VCP driver on windows) */ #define FTDI_TERATRONIK_D2XX_PID 0xEC89 /* Teratronik device (preferring D2XX driver on windows) */ diff --git a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c index ffc4193e950..7019273929a 100644 --- a/drivers/usb/storage/isd200.c +++ b/drivers/usb/storage/isd200.c @@ -61,7 +61,7 @@ #include "scsiglue.h" MODULE_DESCRIPTION("Driver for In-System Design, Inc. ISD200 ASIC"); -MODULE_AUTHOR("Björn Stenberg "); +MODULE_AUTHOR("Björn Stenberg "); MODULE_LICENSE("GPL"); static int isd200_Initialization(struct us_data *us); diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 3041a974faf..50302b997bd 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -1907,7 +1907,7 @@ UNUSUAL_DEV( 0x1b1c, 0x1ab5, 0x0200, 0x0200, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_INITIAL_READ10 ), -/* Patch by Richard Schütz +/* Patch by Richard Schütz * This external hard drive enclosure uses a JMicron chip which * needs the US_FL_IGNORE_RESIDUE flag to work properly. */ UNUSUAL_DEV( 0x1e68, 0x001b, 0x0000, 0x0000, diff --git a/drivers/video/omap/rfbi.c b/drivers/video/omap/rfbi.c index 0c6981f1a4a..2c1a3402bef 100644 --- a/drivers/video/omap/rfbi.c +++ b/drivers/video/omap/rfbi.c @@ -2,7 +2,7 @@ * OMAP2 Remote Frame Buffer Interface support * * Copyright (C) 2005 Nokia Corporation - * Author: Juha Yrjölä + * Author: Juha Yrjölä * Imre Deak * * This program is free software; you can redistribute it and/or modify it diff --git a/drivers/video/omap/sossi.c b/drivers/video/omap/sossi.c index 8fb7c708f56..f79c137753d 100644 --- a/drivers/video/omap/sossi.c +++ b/drivers/video/omap/sossi.c @@ -2,7 +2,7 @@ * OMAP1 Special OptimiSed Screen Interface support * * Copyright (C) 2004-2005 Nokia Corporation - * Author: Juha Yrjölä + * Author: Juha Yrjölä * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the diff --git a/drivers/watchdog/w83627hf_wdt.c b/drivers/watchdog/w83627hf_wdt.c index dd5d6754875..576a388a116 100644 --- a/drivers/watchdog/w83627hf_wdt.c +++ b/drivers/watchdog/w83627hf_wdt.c @@ -4,7 +4,7 @@ * (c) Copyright 2007 Vlad Drukker * added support for W83627THF. * - * (c) Copyright 2003,2007 Pádraig Brady + * (c) Copyright 2003,2007 Pádraig Brady * * Based on advantechwdt.c which is based on wdt.c. * Original copyright messages: @@ -401,6 +401,6 @@ module_init(wdt_init); module_exit(wdt_exit); MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Pádraig Brady "); +MODULE_AUTHOR("Pádraig Brady "); MODULE_DESCRIPTION("w83627hf/thf WDT driver"); MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); diff --git a/drivers/zorro/zorro.ids b/drivers/zorro/zorro.ids index de24e3deced..119abea8c6c 100644 --- a/drivers/zorro/zorro.ids +++ b/drivers/zorro/zorro.ids @@ -351,7 +351,7 @@ 0200 EGS 28/24 Spectrum [Graphics Card] 0892 Apollo 0100 A1200 [FPU and RAM Expansion] -0893 Ingenieurbüro Helfrich +0893 Ingenieurbüro Helfrich 0500 Piccolo RAM [Graphics Card] 0600 Piccolo [Graphics Card] 0700 PeggyPlus MPEG [Video Card] diff --git a/kernel/events/core.c b/kernel/events/core.c index 0e8457da6f9..f641547beb7 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -4,7 +4,7 @@ * Copyright (C) 2008 Thomas Gleixner * Copyright (C) 2008-2011 Red Hat, Inc., Ingo Molnar * Copyright (C) 2008-2011 Red Hat, Inc., Peter Zijlstra - * Copyright © 2009 Paul Mackerras, IBM Corp. + * Copyright © 2009 Paul Mackerras, IBM Corp. * * For licensing details see kernel-base/COPYING */ diff --git a/kernel/events/ring_buffer.c b/kernel/events/ring_buffer.c index a2a29205cc0..809c8ec5d42 100644 --- a/kernel/events/ring_buffer.c +++ b/kernel/events/ring_buffer.c @@ -4,7 +4,7 @@ * Copyright (C) 2008 Thomas Gleixner * Copyright (C) 2008-2011 Red Hat, Inc., Ingo Molnar * Copyright (C) 2008-2011 Red Hat, Inc., Peter Zijlstra - * Copyright © 2009 Paul Mackerras, IBM Corp. + * Copyright © 2009 Paul Mackerras, IBM Corp. * * For licensing details see kernel-base/COPYING */ diff --git a/tools/testing/ktest/sample.conf b/tools/testing/ktest/sample.conf index dbedfa19672..553c06b7d6f 100644 --- a/tools/testing/ktest/sample.conf +++ b/tools/testing/ktest/sample.conf @@ -950,7 +950,7 @@ # TEST_START # TEST_TYPE = config_bisect # CONFIG_BISECT_TYPE = build -# CONFIG_BISECT = /home/test/¢onfig-bad +# CONFIG_BISECT = /home/test/config-bad # MIN_CONFIG = /home/test/config-min # BISECT_MANUAL = 1 # -- cgit v1.2.3-70-g09d2 From 29c9862f1b818bf4caa4c48a30dbe5f25c84ee08 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 28 Dec 2011 00:35:48 +0900 Subject: perf session: Remove impossible condition check The 'size' cannot be 0 because it was set to 8 on the above line in case it was 0 and never changed. Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1325000151-4463-1-git-send-email-namhyung@gmail.com Signed-off-by: Namhyung Kim Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/session.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'tools') diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index cc5e6be46d8..b5ca2558c7b 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -1015,8 +1015,7 @@ more: } } - if (size == 0 || - (skip = perf_session__process_event(self, &event, tool, head)) < 0) { + if ((skip = perf_session__process_event(self, &event, tool, head)) < 0) { dump_printf("%#" PRIx64 " [%#x]: skipping unknown header type: %d\n", head, event.header.size, event.header.type); /* -- cgit v1.2.3-70-g09d2 From 15e6392feec311f1e409d77e1ccfe51c1d940365 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 28 Dec 2011 00:35:49 +0900 Subject: perf stat: Introduce get_ratio_color() helper The get_ratio_color() returns appropriate color string based on @ratio. It helps reducing code duplication. Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1325000151-4463-2-git-send-email-namhyung@gmail.com Signed-off-by: Namhyung Kim Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-stat.c | 91 ++++++++++++++++++----------------------------- 1 file changed, 35 insertions(+), 56 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index cc53de335ce..f5d2a63eba6 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -578,6 +578,33 @@ static void nsec_printout(int cpu, struct perf_evsel *evsel, double avg) avg / avg_stats(&walltime_nsecs_stats)); } +/* used for get_ratio_color() */ +enum grc_type { + GRC_STALLED_CYCLES_FE, + GRC_STALLED_CYCLES_BE, + GRC_CACHE_MISSES, + GRC_MAX_NR +}; + +static const char *get_ratio_color(enum grc_type type, double ratio) +{ + static const double grc_table[GRC_MAX_NR][3] = { + [GRC_STALLED_CYCLES_FE] = { 50.0, 30.0, 10.0 }, + [GRC_STALLED_CYCLES_BE] = { 75.0, 50.0, 20.0 }, + [GRC_CACHE_MISSES] = { 20.0, 10.0, 5.0 }, + }; + const char *color = PERF_COLOR_NORMAL; + + if (ratio > grc_table[type][0]) + color = PERF_COLOR_RED; + else if (ratio > grc_table[type][1]) + color = PERF_COLOR_MAGENTA; + else if (ratio > grc_table[type][2]) + color = PERF_COLOR_YELLOW; + + return color; +} + static void print_stalled_cycles_frontend(int cpu, struct perf_evsel *evsel __used, double avg) { double total, ratio = 0.0; @@ -588,13 +615,7 @@ static void print_stalled_cycles_frontend(int cpu, struct perf_evsel *evsel __us if (total) ratio = avg / total * 100.0; - color = PERF_COLOR_NORMAL; - if (ratio > 50.0) - color = PERF_COLOR_RED; - else if (ratio > 30.0) - color = PERF_COLOR_MAGENTA; - else if (ratio > 10.0) - color = PERF_COLOR_YELLOW; + color = get_ratio_color(GRC_STALLED_CYCLES_FE, ratio); fprintf(output, " # "); color_fprintf(output, color, "%6.2f%%", ratio); @@ -611,13 +632,7 @@ static void print_stalled_cycles_backend(int cpu, struct perf_evsel *evsel __use if (total) ratio = avg / total * 100.0; - color = PERF_COLOR_NORMAL; - if (ratio > 75.0) - color = PERF_COLOR_RED; - else if (ratio > 50.0) - color = PERF_COLOR_MAGENTA; - else if (ratio > 20.0) - color = PERF_COLOR_YELLOW; + color = get_ratio_color(GRC_STALLED_CYCLES_BE, ratio); fprintf(output, " # "); color_fprintf(output, color, "%6.2f%%", ratio); @@ -634,13 +649,7 @@ static void print_branch_misses(int cpu, struct perf_evsel *evsel __used, double if (total) ratio = avg / total * 100.0; - color = PERF_COLOR_NORMAL; - if (ratio > 20.0) - color = PERF_COLOR_RED; - else if (ratio > 10.0) - color = PERF_COLOR_MAGENTA; - else if (ratio > 5.0) - color = PERF_COLOR_YELLOW; + color = get_ratio_color(GRC_CACHE_MISSES, ratio); fprintf(output, " # "); color_fprintf(output, color, "%6.2f%%", ratio); @@ -657,13 +666,7 @@ static void print_l1_dcache_misses(int cpu, struct perf_evsel *evsel __used, dou if (total) ratio = avg / total * 100.0; - color = PERF_COLOR_NORMAL; - if (ratio > 20.0) - color = PERF_COLOR_RED; - else if (ratio > 10.0) - color = PERF_COLOR_MAGENTA; - else if (ratio > 5.0) - color = PERF_COLOR_YELLOW; + color = get_ratio_color(GRC_CACHE_MISSES, ratio); fprintf(output, " # "); color_fprintf(output, color, "%6.2f%%", ratio); @@ -680,13 +683,7 @@ static void print_l1_icache_misses(int cpu, struct perf_evsel *evsel __used, dou if (total) ratio = avg / total * 100.0; - color = PERF_COLOR_NORMAL; - if (ratio > 20.0) - color = PERF_COLOR_RED; - else if (ratio > 10.0) - color = PERF_COLOR_MAGENTA; - else if (ratio > 5.0) - color = PERF_COLOR_YELLOW; + color = get_ratio_color(GRC_CACHE_MISSES, ratio); fprintf(output, " # "); color_fprintf(output, color, "%6.2f%%", ratio); @@ -703,13 +700,7 @@ static void print_dtlb_cache_misses(int cpu, struct perf_evsel *evsel __used, do if (total) ratio = avg / total * 100.0; - color = PERF_COLOR_NORMAL; - if (ratio > 20.0) - color = PERF_COLOR_RED; - else if (ratio > 10.0) - color = PERF_COLOR_MAGENTA; - else if (ratio > 5.0) - color = PERF_COLOR_YELLOW; + color = get_ratio_color(GRC_CACHE_MISSES, ratio); fprintf(output, " # "); color_fprintf(output, color, "%6.2f%%", ratio); @@ -726,13 +717,7 @@ static void print_itlb_cache_misses(int cpu, struct perf_evsel *evsel __used, do if (total) ratio = avg / total * 100.0; - color = PERF_COLOR_NORMAL; - if (ratio > 20.0) - color = PERF_COLOR_RED; - else if (ratio > 10.0) - color = PERF_COLOR_MAGENTA; - else if (ratio > 5.0) - color = PERF_COLOR_YELLOW; + color = get_ratio_color(GRC_CACHE_MISSES, ratio); fprintf(output, " # "); color_fprintf(output, color, "%6.2f%%", ratio); @@ -749,13 +734,7 @@ static void print_ll_cache_misses(int cpu, struct perf_evsel *evsel __used, doub if (total) ratio = avg / total * 100.0; - color = PERF_COLOR_NORMAL; - if (ratio > 20.0) - color = PERF_COLOR_RED; - else if (ratio > 10.0) - color = PERF_COLOR_MAGENTA; - else if (ratio > 5.0) - color = PERF_COLOR_YELLOW; + color = get_ratio_color(GRC_CACHE_MISSES, ratio); fprintf(output, " # "); color_fprintf(output, color, "%6.2f%%", ratio); -- cgit v1.2.3-70-g09d2 From 057a174a064f68bac042d618ce3c6ea3ccd9a8aa Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 28 Dec 2011 00:35:50 +0900 Subject: perf top: Fix a memory leak The 'buf' should be freed when symbol wasn't found too. Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1325000151-4463-3-git-send-email-namhyung@gmail.com Signed-off-by: Namhyung Kim Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 1 - 1 file changed, 1 deletion(-) (limited to 'tools') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index c3836b966cc..4f81eeb9987 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -351,7 +351,6 @@ static void perf_top__prompt_symbol(struct perf_top *top, const char *msg) if (!found) { fprintf(stderr, "Sorry, %s is not active.\n", buf); sleep(1); - return; } else perf_top__parse_source(top, found); -- cgit v1.2.3-70-g09d2 From 466e2876bcb9ddc9b92502c46689679bee7d72a0 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 28 Dec 2011 00:35:51 +0900 Subject: perf script: Kill script_spec__delete As script_spec__delete() frees given struct script_spec it should not be called if we failed to allocate the struct. Also it's the only caller of the function, we can get rid of the function itself. Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1325000151-4463-4-git-send-email-namhyung@gmail.com Signed-off-by: Namhyung Kim Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-script.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 3d4c0c7b576..fd1909afcfd 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -536,12 +536,6 @@ static struct script_spec *script_spec__new(const char *spec, return s; } -static void script_spec__delete(struct script_spec *s) -{ - free(s->spec); - free(s); -} - static void script_spec__add(struct script_spec *s) { list_add_tail(&s->node, &script_specs); @@ -567,16 +561,11 @@ static struct script_spec *script_spec__findnew(const char *spec, s = script_spec__new(spec, ops); if (!s) - goto out_delete_spec; + return NULL; script_spec__add(s); return s; - -out_delete_spec: - script_spec__delete(s); - - return NULL; } int script_spec_register(const char *spec, struct scripting_ops *ops) -- cgit v1.2.3-70-g09d2 From 9e183426bfb52bb44bf3c443d6587e4d02478603 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Wed, 5 Oct 2011 14:01:19 +0200 Subject: perf kvm: Fix copy & paste error in description The --host option certainly enables host-data collection. Cc: Avi Kivity Cc: Ingo Molnar Cc: Peter Zijlstra Cc: Joerg Roedel Cc: kvm@vger.kernel.org Link: http://lkml.kernel.org/r/1317816084-18026-5-git-send-email-gleb@redhat.com Signed-off-by: Gleb Natapov Signed-off-by: Joerg Roedel Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-kvm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index 34d1e853829..032324a76b8 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c @@ -38,7 +38,7 @@ static const struct option kvm_options[] = { OPT_BOOLEAN(0, "guest", &perf_guest, "Collect guest os data"), OPT_BOOLEAN(0, "host", &perf_host, - "Collect guest os data"), + "Collect host os data"), OPT_STRING(0, "guestmount", &symbol_conf.guestmount, "directory", "guest mount directory under which every guest os" " instance has a subdir"), -- cgit v1.2.3-70-g09d2 From 96f6a0df19238fceed77ddfc33bb2d6a4e1b9be6 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Fri, 23 Dec 2011 00:24:51 -0500 Subject: ktest: Still do reboot even for REBOOT_TYPE = script The REBOOT_TYPE may be either grub or script, if it is script it is expected that a REBOOT_SCRIPT is defined. With the SWITCH_TO_TEST which is the complement of SWITCH_TO_GOOD, which does basically the same thing as REBOOT_SCRIPT and but for both grub and script, the REBOOT_SCRIPT does not need to be mandatory anymore. Do not require the REBOOT_SCRIPT and always run the reboot code for both grub and script. Signed-off-by: Steven Rostedt --- tools/testing/ktest/ktest.pl | 11 +++-------- tools/testing/ktest/sample.conf | 5 ++++- 2 files changed, 7 insertions(+), 9 deletions(-) (limited to 'tools') diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl index f360cbdbf00..f81c8b3a39a 100755 --- a/tools/testing/ktest/ktest.pl +++ b/tools/testing/ktest/ktest.pl @@ -485,8 +485,6 @@ sub get_ktest_configs { if ($rtype eq "grub") { get_ktest_config("GRUB_MENU"); - } else { - get_ktest_config("REBOOT_SCRIPT"); } } @@ -1430,11 +1428,10 @@ sub reboot_to { if ($reboot_type eq "grub") { run_ssh "'(echo \"savedefault --default=$grub_number --once\" | grub --batch)'"; - reboot; - return; + } elsif (defined $reboot_script) { + run_command "$reboot_script"; } - - run_command "$reboot_script"; + reboot; } sub get_sha1 { @@ -3479,8 +3476,6 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { $target = "$ssh_user\@$machine"; if ($reboot_type eq "grub") { dodie "GRUB_MENU not defined" if (!defined($grub_menu)); - } elsif (!defined($reboot_script)) { - dodie "REBOOT_SCRIPT not defined" } } diff --git a/tools/testing/ktest/sample.conf b/tools/testing/ktest/sample.conf index 86ce62c3fdc..d7148f7c7c0 100644 --- a/tools/testing/ktest/sample.conf +++ b/tools/testing/ktest/sample.conf @@ -346,7 +346,10 @@ #GRUB_MENU = Test Kernel # A script to reboot the target into the test kernel -# (Only mandatory if REBOOT_TYPE = script) +# This and SWITCH_TO_TEST are about the same, except +# SWITCH_TO_TEST is run even for REBOOT_TYPE = grub. +# This may be left undefined. +# (default undefined) #REBOOT_SCRIPT = #### Optional Config Options (all have defaults) #### -- cgit v1.2.3-70-g09d2 From be405f95f0a090d1dfc26a5bb4d781c00f34479c Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 4 Jan 2012 21:51:59 -0500 Subject: ktest: Add INGORE_ERRORS to ignore warnings in boot up When testing a kernel that has warnings, ktest.pl will fail the test when it sees the warning. If you need to test the the kernel and want to ignore the errors that are produced, the option IGNORE_ERRORS has been added. When IGNORE_ERRORS is set to something other than 0, it will ignore call traces due to WARN_ON(). Signed-off-by: Steven Rostedt --- tools/testing/ktest/ktest.pl | 4 +++- tools/testing/ktest/sample.conf | 8 ++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl index f81c8b3a39a..62a134dc421 100755 --- a/tools/testing/ktest/ktest.pl +++ b/tools/testing/ktest/ktest.pl @@ -104,6 +104,7 @@ my $start_minconfig; my $start_minconfig_defined; my $output_minconfig; my $ignore_config; +my $ignore_errors; my $addconfig; my $in_bisect = 0; my $bisect_bad_commit = ""; @@ -218,6 +219,7 @@ my %option_map = ( "BISECT_SLEEP_TIME" => \$bisect_sleep_time, "PATCHCHECK_SLEEP_TIME" => \$patchcheck_sleep_time, "IGNORE_WARNINGS" => \$ignore_warnings, + "IGNORE_ERRORS" => \$ignore_errors, "BISECT_MANUAL" => \$bisect_manual, "BISECT_SKIP" => \$bisect_skip, "CONFIG_BISECT_GOOD" => \$config_bisect_good, @@ -1529,7 +1531,7 @@ sub monitor { } if ($full_line =~ /call trace:/i) { - if (!$bug && !$skip_call_trace) { + if (!$ignore_errors && !$bug && !$skip_call_trace) { $bug = 1; $failure_start = time; } diff --git a/tools/testing/ktest/sample.conf b/tools/testing/ktest/sample.conf index d7148f7c7c0..e7119024b87 100644 --- a/tools/testing/ktest/sample.conf +++ b/tools/testing/ktest/sample.conf @@ -741,6 +741,14 @@ # (default 0) #IGNORE_UNUSED = 1 +# When testing a kernel that happens to have WARNINGs, and call +# traces, ktest.pl will detect these and fail a boot or test run +# due to warnings. By setting this option, ktest will ignore +# call traces, and will not fail a test if the kernel produces +# an oops. Use this option with care. +# (default 0) +#IGNORE_ERRORS = 1 + #### Per test run options #### # The following options are only allowed in TEST_START sections. # They are ignored in the DEFAULTS sections. -- cgit v1.2.3-70-g09d2 From 13d3ee5402970216291d2c514c2ba33ef8a0e8c1 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 4 Jan 2012 11:37:15 -0200 Subject: perf hists: Rename total_session to total_period Nowadays we do it per evsel, not per session (that may have multiple evsels), so rename it to avoid confusion. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-azsgomr5h4dmaudoogw48w49@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/hist.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'tools') diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index abef2703cd2..20059d1c559 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -733,7 +733,7 @@ void hists__output_recalc_col_len(struct hists *hists, int max_rows) static int hist_entry__pcnt_snprintf(struct hist_entry *self, char *s, size_t size, struct hists *pair_hists, bool show_displacement, long displacement, - bool color, u64 session_total) + bool color, u64 total_period) { u64 period, total, period_sys, period_us, period_guest_sys, period_guest_us; u64 nr_events; @@ -754,7 +754,7 @@ static int hist_entry__pcnt_snprintf(struct hist_entry *self, char *s, } else { period = self->period; nr_events = self->nr_events; - total = session_total; + total = total_period; period_sys = self->period_sys; period_us = self->period_us; period_guest_sys = self->period_guest_sys; @@ -812,8 +812,8 @@ static int hist_entry__pcnt_snprintf(struct hist_entry *self, char *s, if (total > 0) old_percent = (period * 100.0) / total; - if (session_total > 0) - new_percent = (self->period * 100.0) / session_total; + if (total_period > 0) + new_percent = (self->period * 100.0) / total_period; diff = new_percent - old_percent; @@ -864,7 +864,7 @@ int hist_entry__snprintf(struct hist_entry *he, char *s, size_t size, int hist_entry__fprintf(struct hist_entry *he, size_t size, struct hists *hists, struct hists *pair_hists, bool show_displacement, - long displacement, FILE *fp, u64 session_total) + long displacement, FILE *fp, u64 total_period) { char bf[512]; int ret; @@ -874,14 +874,14 @@ int hist_entry__fprintf(struct hist_entry *he, size_t size, struct hists *hists, ret = hist_entry__pcnt_snprintf(he, bf, size, pair_hists, show_displacement, displacement, - true, session_total); + true, total_period); hist_entry__snprintf(he, bf + ret, size - ret, hists); return fprintf(fp, "%s\n", bf); } static size_t hist_entry__fprintf_callchain(struct hist_entry *self, struct hists *hists, FILE *fp, - u64 session_total) + u64 total_period) { int left_margin = 0; @@ -892,7 +892,7 @@ static size_t hist_entry__fprintf_callchain(struct hist_entry *self, left_margin -= thread__comm_len(self->thread); } - return hist_entry_callchain__fprintf(fp, self, session_total, + return hist_entry_callchain__fprintf(fp, self, total_period, left_margin); } -- cgit v1.2.3-70-g09d2 From 12c142781ec076fad617e7cd9f83c8618d909619 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 4 Jan 2012 12:27:03 -0200 Subject: perf hists: Stop using 'self' for struct hist_entry Stop using this python/OOP convention, doesn't really helps. Will do more from time to time till we get it cleaned up in all of /perf. Suggested-by: Thomas Gleixner Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-me4dyj6s5snh7jr8wb9gzt82@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/hist.c | 89 ++++++++++++++++++++++++++------------------------ tools/perf/util/hist.h | 7 ++-- 2 files changed, 48 insertions(+), 48 deletions(-) (limited to 'tools') diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 20059d1c559..4df449549b0 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -76,21 +76,21 @@ static void hists__calc_col_len(struct hists *hists, struct hist_entry *h) } } -static void hist_entry__add_cpumode_period(struct hist_entry *self, +static void hist_entry__add_cpumode_period(struct hist_entry *he, unsigned int cpumode, u64 period) { switch (cpumode) { case PERF_RECORD_MISC_KERNEL: - self->period_sys += period; + he->period_sys += period; break; case PERF_RECORD_MISC_USER: - self->period_us += period; + he->period_us += period; break; case PERF_RECORD_MISC_GUEST_KERNEL: - self->period_guest_sys += period; + he->period_guest_sys += period; break; case PERF_RECORD_MISC_GUEST_USER: - self->period_guest_us += period; + he->period_guest_us += period; break; default: break; @@ -165,18 +165,18 @@ void hists__decay_entries_threaded(struct hists *hists, static struct hist_entry *hist_entry__new(struct hist_entry *template) { size_t callchain_size = symbol_conf.use_callchain ? sizeof(struct callchain_root) : 0; - struct hist_entry *self = malloc(sizeof(*self) + callchain_size); + struct hist_entry *he = malloc(sizeof(*he) + callchain_size); - if (self != NULL) { - *self = *template; - self->nr_events = 1; - if (self->ms.map) - self->ms.map->referenced = true; + if (he != NULL) { + *he = *template; + he->nr_events = 1; + if (he->ms.map) + he->ms.map->referenced = true; if (symbol_conf.use_callchain) - callchain_init(self->callchain); + callchain_init(he->callchain); } - return self; + return he; } static void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h) @@ -677,15 +677,16 @@ static size_t callchain__fprintf_flat(FILE *fp, struct callchain_node *self, return ret; } -static size_t hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self, - u64 total_samples, int left_margin) +static size_t hist_entry_callchain__fprintf(struct hist_entry *he, + u64 total_samples, int left_margin, + FILE *fp) { struct rb_node *rb_node; struct callchain_node *chain; size_t ret = 0; u32 entries_printed = 0; - rb_node = rb_first(&self->sorted_chain); + rb_node = rb_first(&he->sorted_chain); while (rb_node) { double percent; @@ -730,7 +731,7 @@ void hists__output_recalc_col_len(struct hists *hists, int max_rows) } } -static int hist_entry__pcnt_snprintf(struct hist_entry *self, char *s, +static int hist_entry__pcnt_snprintf(struct hist_entry *he, char *s, size_t size, struct hists *pair_hists, bool show_displacement, long displacement, bool color, u64 total_period) @@ -740,25 +741,25 @@ static int hist_entry__pcnt_snprintf(struct hist_entry *self, char *s, const char *sep = symbol_conf.field_sep; int ret; - if (symbol_conf.exclude_other && !self->parent) + if (symbol_conf.exclude_other && !he->parent) return 0; if (pair_hists) { - period = self->pair ? self->pair->period : 0; - nr_events = self->pair ? self->pair->nr_events : 0; + period = he->pair ? he->pair->period : 0; + nr_events = he->pair ? he->pair->nr_events : 0; total = pair_hists->stats.total_period; - period_sys = self->pair ? self->pair->period_sys : 0; - period_us = self->pair ? self->pair->period_us : 0; - period_guest_sys = self->pair ? self->pair->period_guest_sys : 0; - period_guest_us = self->pair ? self->pair->period_guest_us : 0; + period_sys = he->pair ? he->pair->period_sys : 0; + period_us = he->pair ? he->pair->period_us : 0; + period_guest_sys = he->pair ? he->pair->period_guest_sys : 0; + period_guest_us = he->pair ? he->pair->period_guest_us : 0; } else { - period = self->period; - nr_events = self->nr_events; + period = he->period; + nr_events = he->nr_events; total = total_period; - period_sys = self->period_sys; - period_us = self->period_us; - period_guest_sys = self->period_guest_sys; - period_guest_us = self->period_guest_us; + period_sys = he->period_sys; + period_us = he->period_us; + period_guest_sys = he->period_guest_sys; + period_guest_us = he->period_guest_us; } if (total) { @@ -813,7 +814,7 @@ static int hist_entry__pcnt_snprintf(struct hist_entry *self, char *s, if (total > 0) old_percent = (period * 100.0) / total; if (total_period > 0) - new_percent = (self->period * 100.0) / total_period; + new_percent = (he->period * 100.0) / total_period; diff = new_percent - old_percent; @@ -862,9 +863,10 @@ int hist_entry__snprintf(struct hist_entry *he, char *s, size_t size, return ret; } -int hist_entry__fprintf(struct hist_entry *he, size_t size, struct hists *hists, - struct hists *pair_hists, bool show_displacement, - long displacement, FILE *fp, u64 total_period) +static int hist_entry__fprintf(struct hist_entry *he, size_t size, + struct hists *hists, struct hists *pair_hists, + bool show_displacement, long displacement, + u64 total_period, FILE *fp) { char bf[512]; int ret; @@ -879,9 +881,9 @@ int hist_entry__fprintf(struct hist_entry *he, size_t size, struct hists *hists, return fprintf(fp, "%s\n", bf); } -static size_t hist_entry__fprintf_callchain(struct hist_entry *self, - struct hists *hists, FILE *fp, - u64 total_period) +static size_t hist_entry__fprintf_callchain(struct hist_entry *he, + struct hists *hists, + u64 total_period, FILE *fp) { int left_margin = 0; @@ -889,11 +891,10 @@ static size_t hist_entry__fprintf_callchain(struct hist_entry *self, struct sort_entry *se = list_first_entry(&hist_entry__sort_list, typeof(*se), list); left_margin = hists__col_len(hists, se->se_width_idx); - left_margin -= thread__comm_len(self->thread); + left_margin -= thread__comm_len(he->thread); } - return hist_entry_callchain__fprintf(fp, self, total_period, - left_margin); + return hist_entry_callchain__fprintf(he, total_period, left_margin, fp); } size_t hists__fprintf(struct hists *hists, struct hists *pair, @@ -903,6 +904,7 @@ size_t hists__fprintf(struct hists *hists, struct hists *pair, struct sort_entry *se; struct rb_node *nd; size_t ret = 0; + u64 total_period; unsigned long position = 1; long displacement = 0; unsigned int width; @@ -1025,6 +1027,8 @@ size_t hists__fprintf(struct hists *hists, struct hists *pair, goto out; print_entries: + total_period = hists->stats.total_period; + for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); @@ -1040,11 +1044,10 @@ print_entries: ++position; } ret += hist_entry__fprintf(h, max_cols, hists, pair, show_displacement, - displacement, fp, hists->stats.total_period); + displacement, total_period, fp); if (symbol_conf.use_callchain) - ret += hist_entry__fprintf_callchain(h, hists, fp, - hists->stats.total_period); + ret += hist_entry__fprintf_callchain(h, hists, total_period, fp); if (max_rows && ++nr_rows >= max_rows) goto out; diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index ff6f9d56ea4..f55f0a8d1f8 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -66,11 +66,8 @@ struct hists { struct hist_entry *__hists__add_entry(struct hists *self, struct addr_location *al, struct symbol *parent, u64 period); -extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *); -extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *); -int hist_entry__fprintf(struct hist_entry *he, size_t size, struct hists *hists, - struct hists *pair_hists, bool show_displacement, - long displacement, FILE *fp, u64 session_total); +int64_t hist_entry__cmp(struct hist_entry *left, struct hist_entry *right); +int64_t hist_entry__collapse(struct hist_entry *left, struct hist_entry *right); int hist_entry__snprintf(struct hist_entry *self, char *bf, size_t size, struct hists *hists); void hist_entry__free(struct hist_entry *); -- cgit v1.2.3-70-g09d2 From df25f989a4390ca0dbc9cb24516d4b10c01ceda8 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 5 Jan 2012 12:21:08 -0200 Subject: perf top: Don't update total_period on process_sample It will be recalculated at __hists__output_resort, to take into account filters possibly applied by the TUI, etc. Since we do the percent math only for those entries that will appear on the TUI instead of for _all_ the entries at decay time, updating it for each sample makes the entries seem to decay faster when using the navigation keys (since the screen will be refreshed), as we're not coalescing the entries that are being batched to be merged at next resort/decay time, but considering their periods. Bug introduced in 743eb86. Reported-by: Ingo Molnar Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-k0d0rq9a8nqtkqohov8cir72@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 1 - 1 file changed, 1 deletion(-) (limited to 'tools') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 4f81eeb9987..d89dec90103 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -235,7 +235,6 @@ static struct hist_entry *perf_evsel__add_hist_entry(struct perf_evsel *evsel, if (he == NULL) return NULL; - evsel->hists.stats.total_period += sample->period; hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); return he; } -- cgit v1.2.3-70-g09d2 From 1aed2671738785e8f5aea663a6fda91aa7ef59b5 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Wed, 4 Jan 2012 17:54:20 +0100 Subject: perf kvm: Do guest-only counting by default Make use of exclude_guest and exlude_host in perf-kvm to do only guest-only counting by default. Cc: Gleb Natapov Cc: Ingo Molnar Cc: Joerg Roedel Cc: Peter Zijlstra Signed-off-by: Gleb Natapov Signed-off-by: Joerg Roedel [ committer note: Moved perf_{guest,host} & event_attr_init to util.c ] [ so as not to drag more stuff to the python binding] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-kvm.c | 6 ++---- tools/perf/util/evlist.c | 5 ++++- tools/perf/util/parse-events.c | 1 + tools/perf/util/util.c | 15 +++++++++++++++ tools/perf/util/util.h | 4 ++++ 5 files changed, 26 insertions(+), 5 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index 032324a76b8..9fc6e0fa3dc 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c @@ -22,9 +22,6 @@ static const char *file_name; static char name_buffer[256]; -bool perf_host = 1; -bool perf_guest; - static const char * const kvm_usage[] = { "perf kvm [] {top|record|report|diff|buildid-list}", NULL @@ -107,7 +104,8 @@ static int __cmd_buildid_list(int argc, const char **argv) int cmd_kvm(int argc, const char **argv, const char *prefix __used) { - perf_host = perf_guest = 0; + perf_host = 0; + perf_guest = 1; argc = parse_options(argc, argv, kvm_options, kvm_usage, PARSE_OPT_STOP_AT_NON_OPTION); diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index fa1837088ca..3f16e08a5c8 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -111,8 +111,11 @@ int perf_evlist__add_default(struct perf_evlist *evlist) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CPU_CYCLES, }; - struct perf_evsel *evsel = perf_evsel__new(&attr, 0); + struct perf_evsel *evsel; + + event_attr_init(&attr); + evsel = perf_evsel__new(&attr, 0); if (evsel == NULL) goto error; diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 531c283fc0c..dcf999c766b 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -838,6 +838,7 @@ int parse_events(struct perf_evlist *evlist , const char *str, int unset __used) for (;;) { ostr = str; memset(&attr, 0, sizeof(attr)); + event_attr_init(&attr); ret = parse_event_symbols(evlist, &str, &attr); if (ret == EVT_FAILED) return -1; diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index 5b3ea49aa63..813141047fc 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c @@ -1,6 +1,21 @@ +#include "../perf.h" #include "util.h" #include +/* + * XXX We need to find a better place for these things... + */ +bool perf_host = true; +bool perf_guest = true; + +void event_attr_init(struct perf_event_attr *attr) +{ + if (!perf_host) + attr->exclude_host = 1; + if (!perf_guest) + attr->exclude_guest = 1; +} + int mkdir_p(char *path, mode_t mode) { struct stat st; diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 37be34dff79..b9c530cce79 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -242,6 +242,10 @@ int strtailcmp(const char *s1, const char *s2); unsigned long convert_unit(unsigned long value, char *unit); int readn(int fd, void *buf, size_t size); +struct perf_event_attr; + +void event_attr_init(struct perf_event_attr *attr); + #define _STR(x) #x #define STR(x) _STR(x) -- cgit v1.2.3-70-g09d2 From 99320cc8240affcf33c04d28f47259de3b1a75d1 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Wed, 4 Jan 2012 17:54:19 +0100 Subject: perf tools: Add support for guest/host-only profiling To restrict a counter to either host or guest mode this patch introduces two new event modifiers: G and H. With G the counter is configured in guest-only mode and with H in host-only mode. Cc: Gleb Natapov Cc: Ingo Molnar Cc: Joerg Roedel Cc: Peter Zijlstra Signed-off-by: Gleb Natapov Signed-off-by: Joerg Roedel Link: http://lkml.kernel.org/n/tip-or5aj3rghy9ngyg882z6kln9@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-list.txt | 2 ++ tools/perf/util/parse-events.c | 14 ++++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) (limited to 'tools') diff --git a/tools/perf/Documentation/perf-list.txt b/tools/perf/Documentation/perf-list.txt index 7a527f7e9da..ddc22525228 100644 --- a/tools/perf/Documentation/perf-list.txt +++ b/tools/perf/Documentation/perf-list.txt @@ -21,6 +21,8 @@ EVENT MODIFIERS Events can optionally have a modifer by appending a colon and one or more modifiers. Modifiers allow the user to restrict when events are counted with 'u' for user-space, 'k' for kernel, 'h' for hypervisor. +Additional modifiers are 'G' for guest counting (in KVM guests) and 'H' +for host counting (not in KVM guests). The 'p' modifier can be used for specifying how precise the instruction address should be. The 'p' modifier is currently only implemented for diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index dcf999c766b..b029296d20d 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -735,8 +735,8 @@ static int parse_event_modifier(const char **strp, struct perf_event_attr *attr) { const char *str = *strp; - int exclude = 0; - int eu = 0, ek = 0, eh = 0, precise = 0; + int exclude = 0, exclude_GH = 0; + int eu = 0, ek = 0, eh = 0, eH = 0, eG = 0, precise = 0; if (!*str) return 0; @@ -760,6 +760,14 @@ parse_event_modifier(const char **strp, struct perf_event_attr *attr) if (!exclude) exclude = eu = ek = eh = 1; eh = 0; + } else if (*str == 'G') { + if (!exclude_GH) + exclude_GH = eG = eH = 1; + eG = 0; + } else if (*str == 'H') { + if (!exclude_GH) + exclude_GH = eG = eH = 1; + eH = 0; } else if (*str == 'p') { precise++; } else @@ -776,6 +784,8 @@ parse_event_modifier(const char **strp, struct perf_event_attr *attr) attr->exclude_kernel = ek; attr->exclude_hv = eh; attr->precise_ip = precise; + attr->exclude_host = eH; + attr->exclude_guest = eG; return 0; } -- cgit v1.2.3-70-g09d2 From cc5a91e972212aea022ff86b2c11d3e84d552bf5 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Sat, 17 Dec 2011 14:35:37 +0100 Subject: perf tools: Add const.h to MANIFEST to make perf-tar-src-pkg work again Fixes: |make: *** No rule to make target `../../include/linux/const.h', needed by `builtin-annotate.o'. Stop. Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1324128938-17553-1-git-send-email-sebastian@breakpoint.cc Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/MANIFEST | 1 + 1 file changed, 1 insertion(+) (limited to 'tools') diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST index c12659d8cb2..1078c5fadd5 100644 --- a/tools/perf/MANIFEST +++ b/tools/perf/MANIFEST @@ -1,4 +1,5 @@ tools/perf +include/linux/const.h include/linux/perf_event.h include/linux/rbtree.h include/linux/list.h -- cgit v1.2.3-70-g09d2 From 946ef2a24523e59e5cf931068ab7e9443c63c9df Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Sun, 8 Jan 2012 02:25:25 +0900 Subject: perf script: Add missing closedir() calls The get_script_path() calls opendir() but misses corresponding closedir()'s. Add them. Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1325957132-10600-1-git-send-email-namhyung@gmail.com Signed-off-by: Namhyung Kim Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-script.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'tools') diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index fd1909afcfd..bb68ddf257b 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -1018,13 +1018,17 @@ static char *get_script_path(const char *script_root, const char *suffix) __script_root = get_script_root(&script_dirent, suffix); if (__script_root && !strcmp(script_root, __script_root)) { free(__script_root); + closedir(lang_dir); + closedir(scripts_dir); snprintf(script_path, MAXPATHLEN, "%s/%s", lang_path, script_dirent.d_name); return strdup(script_path); } free(__script_root); } + closedir(lang_dir); } + closedir(scripts_dir); return NULL; } -- cgit v1.2.3-70-g09d2 From c30ab8aa084843159b4679e9a3d7f63187d5906a Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Sun, 8 Jan 2012 02:25:26 +0900 Subject: perf test: Change type of '-v' option to INCR The '-v' option is usually defined via OPT_INCR not _INTEGER. Follow the trend :). Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1325957132-10600-2-git-send-email-namhyung@gmail.com Signed-off-by: Namhyung Kim Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c index 2b9a7f497a2..3854e869dce 100644 --- a/tools/perf/builtin-test.c +++ b/tools/perf/builtin-test.c @@ -1396,7 +1396,7 @@ int cmd_test(int argc, const char **argv, const char *prefix __used) NULL, }; const struct option test_options[] = { - OPT_INTEGER('v', "verbose", &verbose, + OPT_INCR('v', "verbose", &verbose, "be more verbose (show symbol address, etc)"), OPT_END() }; -- cgit v1.2.3-70-g09d2 From cdce445906852d90efdc773ca7ba460e6e41664d Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Sun, 8 Jan 2012 02:25:27 +0900 Subject: perf top: Add error message for EMFILE When a user tries to open so many events, perf_event_open syscall may fail with EMFILE. Provide advise for that case. Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1325957132-10600-3-git-send-email-namhyung@gmail.com Signed-off-by: Namhyung Kim Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'tools') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index d89dec90103..8f80df89603 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -888,6 +888,10 @@ try_again: ui__warning("The %s event is not supported.\n", event_name(counter)); goto out_err; + } else if (err == EMFILE) { + ui__warning("Too many events are opened.\n" + "Try again after reducing the number of events\n"); + goto out_err; } ui__warning("The sys_perf_event_open() syscall " -- cgit v1.2.3-70-g09d2 From 8442da1d9f445b454accdb148355ee990ebf3b32 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Sun, 8 Jan 2012 02:25:28 +0900 Subject: perf kmem: Add missing closedir() calls The setup_cpunode_map() calls opendir() but misses corresponding closedir(). Add them. Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1325957132-10600-4-git-send-email-namhyung@gmail.com Signed-off-by: Namhyung Kim Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-kmem.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'tools') diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index fe1ad8f2196..7a9b5c55ad5 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c @@ -108,7 +108,9 @@ static void setup_cpunode_map(void) continue; cpunode_map[cpu] = mem; } + closedir(dir2); } + closedir(dir1); } static void insert_alloc_stat(unsigned long call_site, unsigned long ptr, -- cgit v1.2.3-70-g09d2 From 1b22859d4320d472a7a51ff4a43f62b0578469de Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Sun, 8 Jan 2012 02:25:29 +0900 Subject: perf kmem: Fix a memory leak The 'str' should be freed when sort_dimension__add() failed too. Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1325957132-10600-5-git-send-email-namhyung@gmail.com Signed-off-by: Namhyung Kim Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-kmem.c | 1 + 1 file changed, 1 insertion(+) (limited to 'tools') diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index 7a9b5c55ad5..39104c0beea 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c @@ -647,6 +647,7 @@ static int setup_sorting(struct list_head *sort_list, const char *arg) break; if (sort_dimension__add(tok, sort_list) < 0) { error("Unknown --sort key: '%s'", tok); + free(str); return -1; } } -- cgit v1.2.3-70-g09d2 From 993452541796f3637da9f2e537b9333494b3b2a1 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Sun, 8 Jan 2012 02:25:30 +0900 Subject: perf annotate: Fix usage string The annotate command doesn't take non-option arguments. In fact, it can take last argument as a symbol filter though, but that's a special case and, IMHO, it should be discouraged in favor of the -s option. Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1325957132-10600-6-git-send-email-namhyung@gmail.com Signed-off-by: Namhyung Kim Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-annotate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 214ba7f9f57..3ec2496f1e3 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -235,7 +235,7 @@ out_delete: } static const char * const annotate_usage[] = { - "perf annotate [] ", + "perf annotate []", NULL }; -- cgit v1.2.3-70-g09d2 From 6714a04114639350a7fed93edf8e1b995c5e8059 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Sun, 8 Jan 2012 02:25:31 +0900 Subject: perf annotate: Get rid of field_sep check The 'field_sep' variable is not set anywhere. Just remove the conditional. Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1325957132-10600-7-git-send-email-namhyung@gmail.com Signed-off-by: Namhyung Kim Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-annotate.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 3ec2496f1e3..806e0a28663 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -313,10 +313,5 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __used) annotate.sym_hist_filter = argv[0]; } - if (field_sep && *field_sep == '.') { - pr_err("'.' is the only non valid --field-separator argument\n"); - return -1; - } - return __cmd_annotate(&annotate); } -- cgit v1.2.3-70-g09d2 From 0ed35abc2b569e94498705d250c4767c5284f643 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Sun, 8 Jan 2012 02:25:32 +0900 Subject: perf report: Fix --stdio output alignment when --showcpuutilization used Current perf report output is broken if --showcpuutilization is used. Combination with -n and/or --show-total-period make things worse. This patch fixes it as follows: before: 48.25% 48.25% 0.00% sleep [kernel.kallsyms] [k] trace_hardirqs_off 34.99% 34.99% 0.00% sleep [kernel.kallsyms] [k] __find_get_block_slow 15.99% 15.99% 0.00% sleep [kernel.kallsyms] [k] lock_release_holdtime 0.77% 0.77% 0.00% sleep [kernel.kallsyms] [k] native_write_msr_safe after: 48.25% 48.25% 0.00% sleep [kernel.kallsyms] [k] trace_hardirqs_off 34.99% 34.99% 0.00% sleep [kernel.kallsyms] [k] __find_get_block_slow 15.99% 15.99% 0.00% sleep [kernel.kallsyms] [k] lock_release_holdtime 0.77% 0.77% 0.00% sleep [kernel.kallsyms] [k] native_write_msr_safe Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1325957132-10600-8-git-send-email-namhyung@gmail.com Signed-off-by: Namhyung Kim Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/hist.c | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) (limited to 'tools') diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 4df449549b0..6f505d1abac 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -919,20 +919,6 @@ size_t hists__fprintf(struct hists *hists, struct hists *pair, fprintf(fp, "# %s", pair ? "Baseline" : "Overhead"); - if (symbol_conf.show_nr_samples) { - if (sep) - fprintf(fp, "%cSamples", *sep); - else - fputs(" Samples ", fp); - } - - if (symbol_conf.show_total_period) { - if (sep) - ret += fprintf(fp, "%cPeriod", *sep); - else - ret += fprintf(fp, " Period "); - } - if (symbol_conf.show_cpu_utilization) { if (sep) { ret += fprintf(fp, "%csys", *sep); @@ -942,8 +928,8 @@ size_t hists__fprintf(struct hists *hists, struct hists *pair, ret += fprintf(fp, "%cguest us", *sep); } } else { - ret += fprintf(fp, " sys "); - ret += fprintf(fp, " us "); + ret += fprintf(fp, " sys "); + ret += fprintf(fp, " us "); if (perf_guest) { ret += fprintf(fp, " guest sys "); ret += fprintf(fp, " guest us "); @@ -951,6 +937,20 @@ size_t hists__fprintf(struct hists *hists, struct hists *pair, } } + if (symbol_conf.show_nr_samples) { + if (sep) + fprintf(fp, "%cSamples", *sep); + else + fputs(" Samples ", fp); + } + + if (symbol_conf.show_total_period) { + if (sep) + ret += fprintf(fp, "%cPeriod", *sep); + else + ret += fprintf(fp, " Period "); + } + if (pair) { if (sep) ret += fprintf(fp, "%cDelta", *sep); @@ -995,6 +995,8 @@ size_t hists__fprintf(struct hists *hists, struct hists *pair, goto print_entries; fprintf(fp, "# ........"); + if (symbol_conf.show_cpu_utilization) + fprintf(fp, " ....... ......."); if (symbol_conf.show_nr_samples) fprintf(fp, " .........."); if (symbol_conf.show_total_period) -- cgit v1.2.3-70-g09d2 From 172d1b0b73256551f100fc00c69e356d047103f5 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Mon, 9 Jan 2012 00:10:30 +0900 Subject: perf tools: Fix compile error on x86_64 Ubuntu MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ctype.h include is not needed here and it breaks build on some systems (at least 64bit Ubuntu 10.04) like below. Just get rid of it. CC util/trace-event-info.o cc1: warnings being treated as errors util/trace-event-info.c: In function ‘record_file’: util/trace-event-info.c:192: error: implicit declaration of function ‘pwrite’ util/trace-event-info.c:192: error: nested extern declaration of ‘pwrite’ make: *** [util/trace-event-info.o] Error 1 Cc: Ingo Molnar Cc: Joerg Roedel Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1326035430-7621-1-git-send-email-namhyung@gmail.com Signed-off-by: Namhyung Kim Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/trace-event-info.c | 1 - 1 file changed, 1 deletion(-) (limited to 'tools') diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c index ac6830d8292..fc22cf5c605 100644 --- a/tools/perf/util/trace-event-info.c +++ b/tools/perf/util/trace-event-info.c @@ -18,7 +18,6 @@ * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -#include #include "util.h" #include #include -- cgit v1.2.3-70-g09d2 From 90a5d5af74f6570af063fb6bff33c6b2f8361bbc Mon Sep 17 00:00:00 2001 From: Konstantin Khlebnikov Date: Tue, 10 Jan 2012 15:07:10 -0800 Subject: mm-tracepoint: fix documentation and examples We renamed the page-free mm tracepoints. Signed-off-by: Konstantin Khlebnikov Cc: Mel Gorman Cc: KOSAKI Motohiro Reviewed-by: Minchan Kim Cc: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/trace/tracepoint-analysis.txt | 40 ++++++++++++++--------------- tools/perf/Documentation/examples.txt | 34 ++++++++++++------------ 2 files changed, 37 insertions(+), 37 deletions(-) (limited to 'tools') diff --git a/Documentation/trace/tracepoint-analysis.txt b/Documentation/trace/tracepoint-analysis.txt index 87bee3c129b..058cc6c9dc5 100644 --- a/Documentation/trace/tracepoint-analysis.txt +++ b/Documentation/trace/tracepoint-analysis.txt @@ -93,14 +93,14 @@ By specifying the -a switch and analysing sleep, the system-wide events for a duration of time can be examined. $ perf stat -a \ - -e kmem:mm_page_alloc -e kmem:mm_page_free_direct \ - -e kmem:mm_pagevec_free \ + -e kmem:mm_page_alloc -e kmem:mm_page_free \ + -e kmem:mm_page_free_batched \ sleep 10 Performance counter stats for 'sleep 10': 9630 kmem:mm_page_alloc - 2143 kmem:mm_page_free_direct - 7424 kmem:mm_pagevec_free + 2143 kmem:mm_page_free + 7424 kmem:mm_page_free_batched 10.002577764 seconds time elapsed @@ -119,15 +119,15 @@ basis using set_ftrace_pid. Events can be activated and tracked for the duration of a process on a local basis using PCL such as follows. - $ perf stat -e kmem:mm_page_alloc -e kmem:mm_page_free_direct \ - -e kmem:mm_pagevec_free ./hackbench 10 + $ perf stat -e kmem:mm_page_alloc -e kmem:mm_page_free \ + -e kmem:mm_page_free_batched ./hackbench 10 Time: 0.909 Performance counter stats for './hackbench 10': 17803 kmem:mm_page_alloc - 12398 kmem:mm_page_free_direct - 4827 kmem:mm_pagevec_free + 12398 kmem:mm_page_free + 4827 kmem:mm_page_free_batched 0.973913387 seconds time elapsed @@ -146,8 +146,8 @@ to know what the standard deviation is. By and large, this is left to the performance analyst to do it by hand. In the event that the discrete event occurrences are useful to the performance analyst, then perf can be used. - $ perf stat --repeat 5 -e kmem:mm_page_alloc -e kmem:mm_page_free_direct - -e kmem:mm_pagevec_free ./hackbench 10 + $ perf stat --repeat 5 -e kmem:mm_page_alloc -e kmem:mm_page_free + -e kmem:mm_page_free_batched ./hackbench 10 Time: 0.890 Time: 0.895 Time: 0.915 @@ -157,8 +157,8 @@ occurrences are useful to the performance analyst, then perf can be used. Performance counter stats for './hackbench 10' (5 runs): 16630 kmem:mm_page_alloc ( +- 3.542% ) - 11486 kmem:mm_page_free_direct ( +- 4.771% ) - 4730 kmem:mm_pagevec_free ( +- 2.325% ) + 11486 kmem:mm_page_free ( +- 4.771% ) + 4730 kmem:mm_page_free_batched ( +- 2.325% ) 0.982653002 seconds time elapsed ( +- 1.448% ) @@ -168,15 +168,15 @@ aggregation of discrete events, then a script would need to be developed. Using --repeat, it is also possible to view how events are fluctuating over time on a system-wide basis using -a and sleep. - $ perf stat -e kmem:mm_page_alloc -e kmem:mm_page_free_direct \ - -e kmem:mm_pagevec_free \ + $ perf stat -e kmem:mm_page_alloc -e kmem:mm_page_free \ + -e kmem:mm_page_free_batched \ -a --repeat 10 \ sleep 1 Performance counter stats for 'sleep 1' (10 runs): 1066 kmem:mm_page_alloc ( +- 26.148% ) - 182 kmem:mm_page_free_direct ( +- 5.464% ) - 890 kmem:mm_pagevec_free ( +- 30.079% ) + 182 kmem:mm_page_free ( +- 5.464% ) + 890 kmem:mm_page_free_batched ( +- 30.079% ) 1.002251757 seconds time elapsed ( +- 0.005% ) @@ -220,8 +220,8 @@ were generating events within the kernel. To begin this sort of analysis, the data must be recorded. At the time of writing, this required root: $ perf record -c 1 \ - -e kmem:mm_page_alloc -e kmem:mm_page_free_direct \ - -e kmem:mm_pagevec_free \ + -e kmem:mm_page_alloc -e kmem:mm_page_free \ + -e kmem:mm_page_free_batched \ ./hackbench 10 Time: 0.894 [ perf record: Captured and wrote 0.733 MB perf.data (~32010 samples) ] @@ -260,8 +260,8 @@ noticed that X was generating an insane amount of page allocations so let's look at it: $ perf record -c 1 -f \ - -e kmem:mm_page_alloc -e kmem:mm_page_free_direct \ - -e kmem:mm_pagevec_free \ + -e kmem:mm_page_alloc -e kmem:mm_page_free \ + -e kmem:mm_page_free_batched \ -p `pidof X` This was interrupted after a few seconds and diff --git a/tools/perf/Documentation/examples.txt b/tools/perf/Documentation/examples.txt index 8eb6c489fb1..77f95276242 100644 --- a/tools/perf/Documentation/examples.txt +++ b/tools/perf/Documentation/examples.txt @@ -17,8 +17,8 @@ titan:~> perf list kmem:kmem_cache_alloc_node [Tracepoint event] kmem:kfree [Tracepoint event] kmem:kmem_cache_free [Tracepoint event] - kmem:mm_page_free_direct [Tracepoint event] - kmem:mm_pagevec_free [Tracepoint event] + kmem:mm_page_free [Tracepoint event] + kmem:mm_page_free_batched [Tracepoint event] kmem:mm_page_alloc [Tracepoint event] kmem:mm_page_alloc_zone_locked [Tracepoint event] kmem:mm_page_pcpu_drain [Tracepoint event] @@ -29,15 +29,15 @@ measured. For example the page alloc/free properties of a 'hackbench run' are: titan:~> perf stat -e kmem:mm_page_pcpu_drain -e kmem:mm_page_alloc - -e kmem:mm_pagevec_free -e kmem:mm_page_free_direct ./hackbench 10 + -e kmem:mm_page_free_batched -e kmem:mm_page_free ./hackbench 10 Time: 0.575 Performance counter stats for './hackbench 10': 13857 kmem:mm_page_pcpu_drain 27576 kmem:mm_page_alloc - 6025 kmem:mm_pagevec_free - 20934 kmem:mm_page_free_direct + 6025 kmem:mm_page_free_batched + 20934 kmem:mm_page_free 0.613972165 seconds time elapsed @@ -45,8 +45,8 @@ You can observe the statistical properties as well, by using the 'repeat the workload N times' feature of perf stat: titan:~> perf stat --repeat 5 -e kmem:mm_page_pcpu_drain -e - kmem:mm_page_alloc -e kmem:mm_pagevec_free -e - kmem:mm_page_free_direct ./hackbench 10 + kmem:mm_page_alloc -e kmem:mm_page_free_batched -e + kmem:mm_page_free ./hackbench 10 Time: 0.627 Time: 0.644 Time: 0.564 @@ -57,8 +57,8 @@ You can observe the statistical properties as well, by using the 12920 kmem:mm_page_pcpu_drain ( +- 3.359% ) 25035 kmem:mm_page_alloc ( +- 3.783% ) - 6104 kmem:mm_pagevec_free ( +- 0.934% ) - 18376 kmem:mm_page_free_direct ( +- 4.941% ) + 6104 kmem:mm_page_free_batched ( +- 0.934% ) + 18376 kmem:mm_page_free ( +- 4.941% ) 0.643954516 seconds time elapsed ( +- 2.363% ) @@ -158,15 +158,15 @@ Or you can observe the whole system's page allocations for 10 seconds: titan:~/git> perf stat -a -e kmem:mm_page_pcpu_drain -e -kmem:mm_page_alloc -e kmem:mm_pagevec_free -e -kmem:mm_page_free_direct sleep 10 +kmem:mm_page_alloc -e kmem:mm_page_free_batched -e +kmem:mm_page_free sleep 10 Performance counter stats for 'sleep 10': 171585 kmem:mm_page_pcpu_drain 322114 kmem:mm_page_alloc - 73623 kmem:mm_pagevec_free - 254115 kmem:mm_page_free_direct + 73623 kmem:mm_page_free_batched + 254115 kmem:mm_page_free 10.000591410 seconds time elapsed @@ -174,15 +174,15 @@ Or observe how fluctuating the page allocations are, via statistical analysis done over ten 1-second intervals: titan:~/git> perf stat --repeat 10 -a -e kmem:mm_page_pcpu_drain -e - kmem:mm_page_alloc -e kmem:mm_pagevec_free -e - kmem:mm_page_free_direct sleep 1 + kmem:mm_page_alloc -e kmem:mm_page_free_batched -e + kmem:mm_page_free sleep 1 Performance counter stats for 'sleep 1' (10 runs): 17254 kmem:mm_page_pcpu_drain ( +- 3.709% ) 34394 kmem:mm_page_alloc ( +- 4.617% ) - 7509 kmem:mm_pagevec_free ( +- 4.820% ) - 25653 kmem:mm_page_free_direct ( +- 3.672% ) + 7509 kmem:mm_page_free_batched ( +- 4.820% ) + 25653 kmem:mm_page_free ( +- 3.672% ) 1.058135029 seconds time elapsed ( +- 3.089% ) -- cgit v1.2.3-70-g09d2 From 7b21e34fd1c272e3a8c3846168f2f6287a4cd72b Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 12 Jan 2012 15:44:42 +1030 Subject: virtio: harsher barriers for rpmsg. We were cheating with our barriers; using the smp ones rather than the real device ones. That was fine, until rpmsg came along, which is used to talk to a real device (a non-SMP CPU). Unfortunately, just putting back the real barriers (reverting d57ed95d) causes a performance regression on virtio-pci. In particular, Amos reports netbench's TCP_RR over virtio_net CPU utilization increased up to 35% while throughput went down by up to 14%. By comparison, this branch is in the noise. Reference: https://lkml.org/lkml/2011/12/11/22 Signed-off-by: Rusty Russell --- drivers/lguest/lguest_device.c | 8 +++++--- drivers/s390/kvm/kvm_virtio.c | 2 +- drivers/virtio/virtio_mmio.c | 4 ++-- drivers/virtio/virtio_pci.c | 4 ++-- drivers/virtio/virtio_ring.c | 34 +++++++++++++++++++++------------- include/linux/virtio_ring.h | 1 + tools/virtio/linux/virtio.h | 1 + tools/virtio/virtio_test.c | 3 ++- 8 files changed, 35 insertions(+), 22 deletions(-) (limited to 'tools') diff --git a/drivers/lguest/lguest_device.c b/drivers/lguest/lguest_device.c index 595d7319701..6a1d6447b86 100644 --- a/drivers/lguest/lguest_device.c +++ b/drivers/lguest/lguest_device.c @@ -292,10 +292,12 @@ static struct virtqueue *lg_find_vq(struct virtio_device *vdev, /* * OK, tell virtio_ring.c to set up a virtqueue now we know its size - * and we've got a pointer to its pages. + * and we've got a pointer to its pages. Note that we set weak_barriers + * to 'true': the host just a(nother) SMP CPU, so we only need inter-cpu + * barriers. */ - vq = vring_new_virtqueue(lvq->config.num, LGUEST_VRING_ALIGN, - vdev, lvq->pages, lg_notify, callback, name); + vq = vring_new_virtqueue(lvq->config.num, LGUEST_VRING_ALIGN, vdev, + true, lvq->pages, lg_notify, callback, name); if (!vq) { err = -ENOMEM; goto unmap; diff --git a/drivers/s390/kvm/kvm_virtio.c b/drivers/s390/kvm/kvm_virtio.c index 8af868bab20..7bc1955337e 100644 --- a/drivers/s390/kvm/kvm_virtio.c +++ b/drivers/s390/kvm/kvm_virtio.c @@ -198,7 +198,7 @@ static struct virtqueue *kvm_find_vq(struct virtio_device *vdev, goto out; vq = vring_new_virtqueue(config->num, KVM_S390_VIRTIO_RING_ALIGN, - vdev, (void *) config->address, + vdev, true, (void *) config->address, kvm_notify, callback, name); if (!vq) { err = -ENOMEM; diff --git a/drivers/virtio/virtio_mmio.c b/drivers/virtio/virtio_mmio.c index 0269717436a..01d6dc250d5 100644 --- a/drivers/virtio/virtio_mmio.c +++ b/drivers/virtio/virtio_mmio.c @@ -310,8 +310,8 @@ static struct virtqueue *vm_setup_vq(struct virtio_device *vdev, unsigned index, vm_dev->base + VIRTIO_MMIO_QUEUE_PFN); /* Create the vring */ - vq = vring_new_virtqueue(info->num, VIRTIO_MMIO_VRING_ALIGN, - vdev, info->queue, vm_notify, callback, name); + vq = vring_new_virtqueue(info->num, VIRTIO_MMIO_VRING_ALIGN, vdev, + true, info->queue, vm_notify, callback, name); if (!vq) { err = -ENOMEM; goto error_new_virtqueue; diff --git a/drivers/virtio/virtio_pci.c b/drivers/virtio/virtio_pci.c index baabb7937ec..688b42d28da 100644 --- a/drivers/virtio/virtio_pci.c +++ b/drivers/virtio/virtio_pci.c @@ -414,8 +414,8 @@ static struct virtqueue *setup_vq(struct virtio_device *vdev, unsigned index, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_PFN); /* create the vring */ - vq = vring_new_virtqueue(info->num, VIRTIO_PCI_VRING_ALIGN, - vdev, info->queue, vp_notify, callback, name); + vq = vring_new_virtqueue(info->num, VIRTIO_PCI_VRING_ALIGN, vdev, + true, info->queue, vp_notify, callback, name); if (!vq) { err = -ENOMEM; goto out_activate_queue; diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c index c7a2c208f6e..50da9204609 100644 --- a/drivers/virtio/virtio_ring.c +++ b/drivers/virtio/virtio_ring.c @@ -28,17 +28,20 @@ #ifdef CONFIG_SMP /* Where possible, use SMP barriers which are more lightweight than mandatory * barriers, because mandatory barriers control MMIO effects on accesses - * through relaxed memory I/O windows (which virtio does not use). */ -#define virtio_mb() smp_mb() -#define virtio_rmb() smp_rmb() -#define virtio_wmb() smp_wmb() + * through relaxed memory I/O windows (which virtio-pci does not use). */ +#define virtio_mb(vq) \ + do { if ((vq)->weak_barriers) smp_mb(); else mb(); } while(0) +#define virtio_rmb(vq) \ + do { if ((vq)->weak_barriers) smp_rmb(); else rmb(); } while(0) +#define virtio_wmb(vq) \ + do { if ((vq)->weak_barriers) smp_rmb(); else rmb(); } while(0) #else /* We must force memory ordering even if guest is UP since host could be * running on another CPU, but SMP barriers are defined to barrier() in that * configuration. So fall back to mandatory barriers instead. */ -#define virtio_mb() mb() -#define virtio_rmb() rmb() -#define virtio_wmb() wmb() +#define virtio_mb(vq) mb() +#define virtio_rmb(vq) rmb() +#define virtio_wmb(vq) wmb() #endif #ifdef DEBUG @@ -77,6 +80,9 @@ struct vring_virtqueue /* Actual memory layout for this queue */ struct vring vring; + /* Can we use weak barriers? */ + bool weak_barriers; + /* Other side has made a mess, don't try any more. */ bool broken; @@ -245,14 +251,14 @@ void virtqueue_kick(struct virtqueue *_vq) START_USE(vq); /* Descriptors and available array need to be set before we expose the * new available array entries. */ - virtio_wmb(); + virtio_wmb(vq); old = vq->vring.avail->idx; new = vq->vring.avail->idx = old + vq->num_added; vq->num_added = 0; /* Need to update avail index before checking if we should notify */ - virtio_mb(); + virtio_mb(vq); if (vq->event ? vring_need_event(vring_avail_event(&vq->vring), new, old) : @@ -314,7 +320,7 @@ void *virtqueue_get_buf(struct virtqueue *_vq, unsigned int *len) } /* Only get used array entries after they have been exposed by host. */ - virtio_rmb(); + virtio_rmb(vq); i = vq->vring.used->ring[vq->last_used_idx%vq->vring.num].id; *len = vq->vring.used->ring[vq->last_used_idx%vq->vring.num].len; @@ -337,7 +343,7 @@ void *virtqueue_get_buf(struct virtqueue *_vq, unsigned int *len) * the read in the next get_buf call. */ if (!(vq->vring.avail->flags & VRING_AVAIL_F_NO_INTERRUPT)) { vring_used_event(&vq->vring) = vq->last_used_idx; - virtio_mb(); + virtio_mb(vq); } END_USE(vq); @@ -366,7 +372,7 @@ bool virtqueue_enable_cb(struct virtqueue *_vq) * entry. Always do both to keep code simple. */ vq->vring.avail->flags &= ~VRING_AVAIL_F_NO_INTERRUPT; vring_used_event(&vq->vring) = vq->last_used_idx; - virtio_mb(); + virtio_mb(vq); if (unlikely(more_used(vq))) { END_USE(vq); return false; @@ -393,7 +399,7 @@ bool virtqueue_enable_cb_delayed(struct virtqueue *_vq) /* TODO: tune this threshold */ bufs = (u16)(vq->vring.avail->idx - vq->last_used_idx) * 3 / 4; vring_used_event(&vq->vring) = vq->last_used_idx + bufs; - virtio_mb(); + virtio_mb(vq); if (unlikely((u16)(vq->vring.used->idx - vq->last_used_idx) > bufs)) { END_USE(vq); return false; @@ -453,6 +459,7 @@ EXPORT_SYMBOL_GPL(vring_interrupt); struct virtqueue *vring_new_virtqueue(unsigned int num, unsigned int vring_align, struct virtio_device *vdev, + bool weak_barriers, void *pages, void (*notify)(struct virtqueue *), void (*callback)(struct virtqueue *), @@ -476,6 +483,7 @@ struct virtqueue *vring_new_virtqueue(unsigned int num, vq->vq.vdev = vdev; vq->vq.name = name; vq->notify = notify; + vq->weak_barriers = weak_barriers; vq->broken = false; vq->last_used_idx = 0; vq->num_added = 0; diff --git a/include/linux/virtio_ring.h b/include/linux/virtio_ring.h index 36be0f6e18a..e338730c266 100644 --- a/include/linux/virtio_ring.h +++ b/include/linux/virtio_ring.h @@ -168,6 +168,7 @@ struct virtqueue; struct virtqueue *vring_new_virtqueue(unsigned int num, unsigned int vring_align, struct virtio_device *vdev, + bool weak_barriers, void *pages, void (*notify)(struct virtqueue *vq), void (*callback)(struct virtqueue *vq), diff --git a/tools/virtio/linux/virtio.h b/tools/virtio/linux/virtio.h index 669bcdd4580..953db2abf6b 100644 --- a/tools/virtio/linux/virtio.h +++ b/tools/virtio/linux/virtio.h @@ -214,6 +214,7 @@ void *virtqueue_detach_unused_buf(struct virtqueue *vq); struct virtqueue *vring_new_virtqueue(unsigned int num, unsigned int vring_align, struct virtio_device *vdev, + bool weak_barriers, void *pages, void (*notify)(struct virtqueue *vq), void (*callback)(struct virtqueue *vq), diff --git a/tools/virtio/virtio_test.c b/tools/virtio/virtio_test.c index 74d3331bdaf..0740284396c 100644 --- a/tools/virtio/virtio_test.c +++ b/tools/virtio/virtio_test.c @@ -92,7 +92,8 @@ static void vq_info_add(struct vdev_info *dev, int num) assert(r >= 0); memset(info->ring, 0, vring_size(num, 4096)); vring_init(&info->vring, num, info->ring, 4096); - info->vq = vring_new_virtqueue(info->vring.num, 4096, &dev->vdev, info->ring, + info->vq = vring_new_virtqueue(info->vring.num, 4096, &dev->vdev, + true, info->ring, vq_notify, vq_callback, "test"); assert(info->vq); info->vq->priv = info; -- cgit v1.2.3-70-g09d2 From f96fde41f7f9af6cf20f6a1919f5d9670f84d574 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 12 Jan 2012 15:44:42 +1030 Subject: virtio: rename virtqueue_add_buf_gfp to virtqueue_add_buf Remove wrapper functions. This makes the allocation type explicit in all callers; I used GPF_KERNEL where it seemed obvious, left it at GFP_ATOMIC otherwise. Signed-off-by: Rusty Russell Reviewed-by: Christoph Hellwig --- drivers/block/virtio_blk.c | 2 +- drivers/char/hw_random/virtio-rng.c | 2 +- drivers/char/virtio_console.c | 6 +++--- drivers/net/virtio_net.c | 12 ++++++------ drivers/virtio/virtio_balloon.c | 7 ++++--- drivers/virtio/virtio_ring.c | 22 +++++++++++----------- include/linux/virtio.h | 21 ++++++--------------- net/9p/trans_virtio.c | 6 ++++-- tools/virtio/linux/virtio.h | 21 ++++++--------------- tools/virtio/virtio_test.c | 3 ++- 10 files changed, 44 insertions(+), 58 deletions(-) (limited to 'tools') diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index 4d0b70adf5f..a345e40e1bc 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c @@ -172,7 +172,7 @@ static bool do_req(struct request_queue *q, struct virtio_blk *vblk, } } - if (virtqueue_add_buf(vblk->vq, vblk->sg, out, in, vbr) < 0) { + if (virtqueue_add_buf(vblk->vq, vblk->sg, out, in, vbr, GFP_ATOMIC)<0) { mempool_free(vbr, vblk->pool); return false; } diff --git a/drivers/char/hw_random/virtio-rng.c b/drivers/char/hw_random/virtio-rng.c index fd699ccecf5..723725bbb96 100644 --- a/drivers/char/hw_random/virtio-rng.c +++ b/drivers/char/hw_random/virtio-rng.c @@ -47,7 +47,7 @@ static void register_buffer(u8 *buf, size_t size) sg_init_one(&sg, buf, size); /* There should always be room for one buffer. */ - if (virtqueue_add_buf(vq, &sg, 0, 1, buf) < 0) + if (virtqueue_add_buf(vq, &sg, 0, 1, buf, GFP_KERNEL) < 0) BUG(); virtqueue_kick(vq); diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 8e3c46d67cb..d1ae1492ee7 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -392,7 +392,7 @@ static int add_inbuf(struct virtqueue *vq, struct port_buffer *buf) sg_init_one(sg, buf->buf, buf->size); - ret = virtqueue_add_buf(vq, sg, 0, 1, buf); + ret = virtqueue_add_buf(vq, sg, 0, 1, buf, GFP_ATOMIC); virtqueue_kick(vq); return ret; } @@ -457,7 +457,7 @@ static ssize_t __send_control_msg(struct ports_device *portdev, u32 port_id, vq = portdev->c_ovq; sg_init_one(sg, &cpkt, sizeof(cpkt)); - if (virtqueue_add_buf(vq, sg, 1, 0, &cpkt) >= 0) { + if (virtqueue_add_buf(vq, sg, 1, 0, &cpkt, GFP_ATOMIC) >= 0) { virtqueue_kick(vq); while (!virtqueue_get_buf(vq, &len)) cpu_relax(); @@ -506,7 +506,7 @@ static ssize_t send_buf(struct port *port, void *in_buf, size_t in_count, reclaim_consumed_buffers(port); sg_init_one(sg, in_buf, in_count); - ret = virtqueue_add_buf(out_vq, sg, 1, 0, in_buf); + ret = virtqueue_add_buf(out_vq, sg, 1, 0, in_buf, GFP_ATOMIC); /* Tell Host to go! */ virtqueue_kick(out_vq); diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 76fe14efb2b..6345a52194f 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -370,7 +370,7 @@ static int add_recvbuf_small(struct virtnet_info *vi, gfp_t gfp) skb_to_sgvec(skb, vi->rx_sg + 1, 0, skb->len); - err = virtqueue_add_buf_gfp(vi->rvq, vi->rx_sg, 0, 2, skb, gfp); + err = virtqueue_add_buf(vi->rvq, vi->rx_sg, 0, 2, skb, gfp); if (err < 0) dev_kfree_skb(skb); @@ -415,8 +415,8 @@ static int add_recvbuf_big(struct virtnet_info *vi, gfp_t gfp) /* chain first in list head */ first->private = (unsigned long)list; - err = virtqueue_add_buf_gfp(vi->rvq, vi->rx_sg, 0, MAX_SKB_FRAGS + 2, - first, gfp); + err = virtqueue_add_buf(vi->rvq, vi->rx_sg, 0, MAX_SKB_FRAGS + 2, + first, gfp); if (err < 0) give_pages(vi, first); @@ -434,7 +434,7 @@ static int add_recvbuf_mergeable(struct virtnet_info *vi, gfp_t gfp) sg_init_one(vi->rx_sg, page_address(page), PAGE_SIZE); - err = virtqueue_add_buf_gfp(vi->rvq, vi->rx_sg, 0, 1, page, gfp); + err = virtqueue_add_buf(vi->rvq, vi->rx_sg, 0, 1, page, gfp); if (err < 0) give_pages(vi, page); @@ -609,7 +609,7 @@ static int xmit_skb(struct virtnet_info *vi, struct sk_buff *skb) hdr->num_sg = skb_to_sgvec(skb, vi->tx_sg + 1, 0, skb->len) + 1; return virtqueue_add_buf(vi->svq, vi->tx_sg, hdr->num_sg, - 0, skb); + 0, skb, GFP_ATOMIC); } static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev) @@ -767,7 +767,7 @@ static bool virtnet_send_command(struct virtnet_info *vi, u8 class, u8 cmd, sg_set_buf(&sg[i + 1], sg_virt(s), s->length); sg_set_buf(&sg[out + in - 1], &status, sizeof(status)); - BUG_ON(virtqueue_add_buf(vi->cvq, sg, out, in, vi) < 0); + BUG_ON(virtqueue_add_buf(vi->cvq, sg, out, in, vi, GFP_ATOMIC) < 0); virtqueue_kick(vi->cvq); diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c index f64ff185b8b..0a6425aadf9 100644 --- a/drivers/virtio/virtio_balloon.c +++ b/drivers/virtio/virtio_balloon.c @@ -88,7 +88,7 @@ static void tell_host(struct virtio_balloon *vb, struct virtqueue *vq) init_completion(&vb->acked); /* We should always be able to add one buffer to an empty queue. */ - if (virtqueue_add_buf(vq, &sg, 1, 0, vb) < 0) + if (virtqueue_add_buf(vq, &sg, 1, 0, vb, GFP_KERNEL) < 0) BUG(); virtqueue_kick(vq); @@ -220,7 +220,7 @@ static void stats_handle_request(struct virtio_balloon *vb) vq = vb->stats_vq; sg_init_one(&sg, vb->stats, sizeof(vb->stats)); - if (virtqueue_add_buf(vq, &sg, 1, 0, vb) < 0) + if (virtqueue_add_buf(vq, &sg, 1, 0, vb, GFP_KERNEL) < 0) BUG(); virtqueue_kick(vq); } @@ -313,7 +313,8 @@ static int virtballoon_probe(struct virtio_device *vdev) * use it to signal us later. */ sg_init_one(&sg, vb->stats, sizeof vb->stats); - if (virtqueue_add_buf(vb->stats_vq, &sg, 1, 0, vb) < 0) + if (virtqueue_add_buf(vb->stats_vq, &sg, 1, 0, vb, GFP_KERNEL) + < 0) BUG(); virtqueue_kick(vb->stats_vq); } diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c index fe50486341a..6ea92a6d113 100644 --- a/drivers/virtio/virtio_ring.c +++ b/drivers/virtio/virtio_ring.c @@ -167,7 +167,7 @@ static int vring_add_indirect(struct vring_virtqueue *vq, } /** - * virtqueue_add_buf_gfp - expose buffer to other end + * virtqueue_add_buf - expose buffer to other end * @vq: the struct virtqueue we're talking about. * @sg: the description of the buffer(s). * @out_num: the number of sg readable by other side @@ -183,12 +183,12 @@ static int vring_add_indirect(struct vring_virtqueue *vq, * positive return values as "available": indirect buffers mean that * we can put an entire sg[] array inside a single queue entry. */ -int virtqueue_add_buf_gfp(struct virtqueue *_vq, - struct scatterlist sg[], - unsigned int out, - unsigned int in, - void *data, - gfp_t gfp) +int virtqueue_add_buf(struct virtqueue *_vq, + struct scatterlist sg[], + unsigned int out, + unsigned int in, + void *data, + gfp_t gfp) { struct vring_virtqueue *vq = to_vvq(_vq); unsigned int i, avail, uninitialized_var(prev); @@ -259,13 +259,13 @@ add_head: return vq->num_free; } -EXPORT_SYMBOL_GPL(virtqueue_add_buf_gfp); +EXPORT_SYMBOL_GPL(virtqueue_add_buf); /** * virtqueue_kick - update after add_buf * @vq: the struct virtqueue * - * After one or more virtqueue_add_buf_gfp calls, invoke this to kick + * After one or more virtqueue_add_buf calls, invoke this to kick * the other side. * * Caller must ensure we don't call this with other virtqueue @@ -341,7 +341,7 @@ static inline bool more_used(const struct vring_virtqueue *vq) * operations at the same time (except where noted). * * Returns NULL if there are no used buffers, or the "data" token - * handed to virtqueue_add_buf_gfp(). + * handed to virtqueue_add_buf(). */ void *virtqueue_get_buf(struct virtqueue *_vq, unsigned int *len) { @@ -490,7 +490,7 @@ EXPORT_SYMBOL_GPL(virtqueue_enable_cb_delayed); * virtqueue_detach_unused_buf - detach first unused buffer * @vq: the struct virtqueue we're talking about. * - * Returns NULL or the "data" token handed to virtqueue_add_buf_gfp(). + * Returns NULL or the "data" token handed to virtqueue_add_buf(). * This is not valid on an active queue; it is useful only for device * shutdown. */ diff --git a/include/linux/virtio.h b/include/linux/virtio.h index 73ad7243128..ec1706e7df5 100644 --- a/include/linux/virtio.h +++ b/include/linux/virtio.h @@ -25,21 +25,12 @@ struct virtqueue { void *priv; }; -int virtqueue_add_buf_gfp(struct virtqueue *vq, - struct scatterlist sg[], - unsigned int out_num, - unsigned int in_num, - void *data, - gfp_t gfp); - -static inline int virtqueue_add_buf(struct virtqueue *vq, - struct scatterlist sg[], - unsigned int out_num, - unsigned int in_num, - void *data) -{ - return virtqueue_add_buf_gfp(vq, sg, out_num, in_num, data, GFP_ATOMIC); -} +int virtqueue_add_buf(struct virtqueue *vq, + struct scatterlist sg[], + unsigned int out_num, + unsigned int in_num, + void *data, + gfp_t gfp); void virtqueue_kick(struct virtqueue *vq); diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c index 330421e5471..3d432068f62 100644 --- a/net/9p/trans_virtio.c +++ b/net/9p/trans_virtio.c @@ -272,7 +272,8 @@ req_retry: in = pack_sg_list(chan->sg, out, VIRTQUEUE_NUM, req->rc->sdata, req->rc->capacity); - err = virtqueue_add_buf(chan->vq, chan->sg, out, in, req->tc); + err = virtqueue_add_buf(chan->vq, chan->sg, out, in, req->tc, + GFP_ATOMIC); if (err < 0) { if (err == -ENOSPC) { chan->ring_bufs_avail = 0; @@ -414,7 +415,8 @@ req_retry_pinned: in += pack_sg_list_p(chan->sg, out + in, VIRTQUEUE_NUM, in_pages, in_nr_pages, uidata, inlen); - err = virtqueue_add_buf(chan->vq, chan->sg, out, in, req->tc); + err = virtqueue_add_buf(chan->vq, chan->sg, out, in, req->tc, + GFP_ATOMIC); if (err < 0) { if (err == -ENOSPC) { chan->ring_bufs_avail = 0; diff --git a/tools/virtio/linux/virtio.h b/tools/virtio/linux/virtio.h index 953db2abf6b..b4fbc91c41b 100644 --- a/tools/virtio/linux/virtio.h +++ b/tools/virtio/linux/virtio.h @@ -186,21 +186,12 @@ struct virtqueue { #endif /* Interfaces exported by virtio_ring. */ -int virtqueue_add_buf_gfp(struct virtqueue *vq, - struct scatterlist sg[], - unsigned int out_num, - unsigned int in_num, - void *data, - gfp_t gfp); - -static inline int virtqueue_add_buf(struct virtqueue *vq, - struct scatterlist sg[], - unsigned int out_num, - unsigned int in_num, - void *data) -{ - return virtqueue_add_buf_gfp(vq, sg, out_num, in_num, data, GFP_ATOMIC); -} +int virtqueue_add_buf(struct virtqueue *vq, + struct scatterlist sg[], + unsigned int out_num, + unsigned int in_num, + void *data, + gfp_t gfp); void virtqueue_kick(struct virtqueue *vq); diff --git a/tools/virtio/virtio_test.c b/tools/virtio/virtio_test.c index 0740284396c..6bf95f99536 100644 --- a/tools/virtio/virtio_test.c +++ b/tools/virtio/virtio_test.c @@ -161,7 +161,8 @@ static void run_test(struct vdev_info *dev, struct vq_info *vq, int bufs) if (started < bufs) { sg_init_one(&sl, dev->buf, dev->buf_size); r = virtqueue_add_buf(vq->vq, &sl, 1, 0, - dev->buf + started); + dev->buf + started, + GFP_ATOMIC); if (likely(r >= 0)) { ++started; virtqueue_kick(vq->vq); -- cgit v1.2.3-70-g09d2 From 07fe9977b6234ede1bd29e10e0323e478860c871 Mon Sep 17 00:00:00 2001 From: Davidlohr Bueso Date: Thu, 12 Jan 2012 15:44:47 +1030 Subject: lguest: move the lguest tool to the tools directory This is a better location instead of having it in Documentation. Signed-off-by: Davidlohr Bueso Signed-off-by: Rusty Russell (fixed compile) --- Documentation/virtual/lguest/.gitignore | 1 - Documentation/virtual/lguest/Makefile | 8 - Documentation/virtual/lguest/extract | 58 - Documentation/virtual/lguest/lguest.c | 2065 ------------------------------- Documentation/virtual/lguest/lguest.txt | 129 -- drivers/lguest/Makefile | 2 +- tools/lguest/.gitignore | 1 + tools/lguest/Makefile | 8 + tools/lguest/extract | 58 + tools/lguest/lguest.c | 2065 +++++++++++++++++++++++++++++++ tools/lguest/lguest.txt | 129 ++ 11 files changed, 2262 insertions(+), 2262 deletions(-) delete mode 100644 Documentation/virtual/lguest/.gitignore delete mode 100644 Documentation/virtual/lguest/Makefile delete mode 100644 Documentation/virtual/lguest/extract delete mode 100644 Documentation/virtual/lguest/lguest.c delete mode 100644 Documentation/virtual/lguest/lguest.txt create mode 100644 tools/lguest/.gitignore create mode 100644 tools/lguest/Makefile create mode 100644 tools/lguest/extract create mode 100644 tools/lguest/lguest.c create mode 100644 tools/lguest/lguest.txt (limited to 'tools') diff --git a/Documentation/virtual/lguest/.gitignore b/Documentation/virtual/lguest/.gitignore deleted file mode 100644 index 115587fd5f6..00000000000 --- a/Documentation/virtual/lguest/.gitignore +++ /dev/null @@ -1 +0,0 @@ -lguest diff --git a/Documentation/virtual/lguest/Makefile b/Documentation/virtual/lguest/Makefile deleted file mode 100644 index 0ac34206f7a..00000000000 --- a/Documentation/virtual/lguest/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# This creates the demonstration utility "lguest" which runs a Linux guest. -# Missing headers? Add "-I../../../include -I../../../arch/x86/include" -CFLAGS:=-m32 -Wall -Wmissing-declarations -Wmissing-prototypes -O3 -U_FORTIFY_SOURCE - -all: lguest - -clean: - rm -f lguest diff --git a/Documentation/virtual/lguest/extract b/Documentation/virtual/lguest/extract deleted file mode 100644 index 7730bb6e4b9..00000000000 --- a/Documentation/virtual/lguest/extract +++ /dev/null @@ -1,58 +0,0 @@ -#! /bin/sh - -set -e - -PREFIX=$1 -shift - -trap 'rm -r $TMPDIR' 0 -TMPDIR=`mktemp -d` - -exec 3>/dev/null -for f; do - while IFS=" -" read -r LINE; do - case "$LINE" in - *$PREFIX:[0-9]*:\**) - NUM=`echo "$LINE" | sed "s/.*$PREFIX:\([0-9]*\).*/\1/"` - if [ -f $TMPDIR/$NUM ]; then - echo "$TMPDIR/$NUM already exits prior to $f" - exit 1 - fi - exec 3>>$TMPDIR/$NUM - echo $f | sed 's,\.\./,,g' > $TMPDIR/.$NUM - /bin/echo "$LINE" | sed -e "s/$PREFIX:[0-9]*//" -e "s/:\*/*/" >&3 - ;; - *$PREFIX:[0-9]*) - NUM=`echo "$LINE" | sed "s/.*$PREFIX:\([0-9]*\).*/\1/"` - if [ -f $TMPDIR/$NUM ]; then - echo "$TMPDIR/$NUM already exits prior to $f" - exit 1 - fi - exec 3>>$TMPDIR/$NUM - echo $f | sed 's,\.\./,,g' > $TMPDIR/.$NUM - /bin/echo "$LINE" | sed "s/$PREFIX:[0-9]*//" >&3 - ;; - *:\**) - /bin/echo "$LINE" | sed -e "s/:\*/*/" -e "s,/\*\*/,," >&3 - echo >&3 - exec 3>/dev/null - ;; - *) - /bin/echo "$LINE" >&3 - ;; - esac - done < $f - echo >&3 - exec 3>/dev/null -done - -LASTFILE="" -for f in $TMPDIR/*; do - if [ "$LASTFILE" != $(cat $TMPDIR/.$(basename $f) ) ]; then - LASTFILE=$(cat $TMPDIR/.$(basename $f) ) - echo "[ $LASTFILE ]" - fi - cat $f -done - diff --git a/Documentation/virtual/lguest/lguest.c b/Documentation/virtual/lguest/lguest.c deleted file mode 100644 index c095d79cae7..00000000000 --- a/Documentation/virtual/lguest/lguest.c +++ /dev/null @@ -1,2065 +0,0 @@ -/*P:100 - * This is the Launcher code, a simple program which lays out the "physical" - * memory for the new Guest by mapping the kernel image and the virtual - * devices, then opens /dev/lguest to tell the kernel about the Guest and - * control it. -:*/ -#define _LARGEFILE64_SOURCE -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include "../../../include/linux/lguest_launcher.h" -/*L:110 - * We can ignore the 43 include files we need for this program, but I do want - * to draw attention to the use of kernel-style types. - * - * As Linus said, "C is a Spartan language, and so should your naming be." I - * like these abbreviations, so we define them here. Note that u64 is always - * unsigned long long, which works on all Linux systems: this means that we can - * use %llu in printf for any u64. - */ -typedef unsigned long long u64; -typedef uint32_t u32; -typedef uint16_t u16; -typedef uint8_t u8; -/*:*/ - -#define BRIDGE_PFX "bridge:" -#ifndef SIOCBRADDIF -#define SIOCBRADDIF 0x89a2 /* add interface to bridge */ -#endif -/* We can have up to 256 pages for devices. */ -#define DEVICE_PAGES 256 -/* This will occupy 3 pages: it must be a power of 2. */ -#define VIRTQUEUE_NUM 256 - -/*L:120 - * verbose is both a global flag and a macro. The C preprocessor allows - * this, and although I wouldn't recommend it, it works quite nicely here. - */ -static bool verbose; -#define verbose(args...) \ - do { if (verbose) printf(args); } while(0) -/*:*/ - -/* The pointer to the start of guest memory. */ -static void *guest_base; -/* The maximum guest physical address allowed, and maximum possible. */ -static unsigned long guest_limit, guest_max; -/* The /dev/lguest file descriptor. */ -static int lguest_fd; - -/* a per-cpu variable indicating whose vcpu is currently running */ -static unsigned int __thread cpu_id; - -/* This is our list of devices. */ -struct device_list { - /* Counter to assign interrupt numbers. */ - unsigned int next_irq; - - /* Counter to print out convenient device numbers. */ - unsigned int device_num; - - /* The descriptor page for the devices. */ - u8 *descpage; - - /* A single linked list of devices. */ - struct device *dev; - /* And a pointer to the last device for easy append. */ - struct device *lastdev; -}; - -/* The list of Guest devices, based on command line arguments. */ -static struct device_list devices; - -/* The device structure describes a single device. */ -struct device { - /* The linked-list pointer. */ - struct device *next; - - /* The device's descriptor, as mapped into the Guest. */ - struct lguest_device_desc *desc; - - /* We can't trust desc values once Guest has booted: we use these. */ - unsigned int feature_len; - unsigned int num_vq; - - /* The name of this device, for --verbose. */ - const char *name; - - /* Any queues attached to this device */ - struct virtqueue *vq; - - /* Is it operational */ - bool running; - - /* Device-specific data. */ - void *priv; -}; - -/* The virtqueue structure describes a queue attached to a device. */ -struct virtqueue { - struct virtqueue *next; - - /* Which device owns me. */ - struct device *dev; - - /* The configuration for this queue. */ - struct lguest_vqconfig config; - - /* The actual ring of buffers. */ - struct vring vring; - - /* Last available index we saw. */ - u16 last_avail_idx; - - /* How many are used since we sent last irq? */ - unsigned int pending_used; - - /* Eventfd where Guest notifications arrive. */ - int eventfd; - - /* Function for the thread which is servicing this virtqueue. */ - void (*service)(struct virtqueue *vq); - pid_t thread; -}; - -/* Remember the arguments to the program so we can "reboot" */ -static char **main_args; - -/* The original tty settings to restore on exit. */ -static struct termios orig_term; - -/* - * We have to be careful with barriers: our devices are all run in separate - * threads and so we need to make sure that changes visible to the Guest happen - * in precise order. - */ -#define wmb() __asm__ __volatile__("" : : : "memory") -#define mb() __asm__ __volatile__("" : : : "memory") - -/* - * Convert an iovec element to the given type. - * - * This is a fairly ugly trick: we need to know the size of the type and - * alignment requirement to check the pointer is kosher. It's also nice to - * have the name of the type in case we report failure. - * - * Typing those three things all the time is cumbersome and error prone, so we - * have a macro which sets them all up and passes to the real function. - */ -#define convert(iov, type) \ - ((type *)_convert((iov), sizeof(type), __alignof__(type), #type)) - -static void *_convert(struct iovec *iov, size_t size, size_t align, - const char *name) -{ - if (iov->iov_len != size) - errx(1, "Bad iovec size %zu for %s", iov->iov_len, name); - if ((unsigned long)iov->iov_base % align != 0) - errx(1, "Bad alignment %p for %s", iov->iov_base, name); - return iov->iov_base; -} - -/* Wrapper for the last available index. Makes it easier to change. */ -#define lg_last_avail(vq) ((vq)->last_avail_idx) - -/* - * The virtio configuration space is defined to be little-endian. x86 is - * little-endian too, but it's nice to be explicit so we have these helpers. - */ -#define cpu_to_le16(v16) (v16) -#define cpu_to_le32(v32) (v32) -#define cpu_to_le64(v64) (v64) -#define le16_to_cpu(v16) (v16) -#define le32_to_cpu(v32) (v32) -#define le64_to_cpu(v64) (v64) - -/* Is this iovec empty? */ -static bool iov_empty(const struct iovec iov[], unsigned int num_iov) -{ - unsigned int i; - - for (i = 0; i < num_iov; i++) - if (iov[i].iov_len) - return false; - return true; -} - -/* Take len bytes from the front of this iovec. */ -static void iov_consume(struct iovec iov[], unsigned num_iov, unsigned len) -{ - unsigned int i; - - for (i = 0; i < num_iov; i++) { - unsigned int used; - - used = iov[i].iov_len < len ? iov[i].iov_len : len; - iov[i].iov_base += used; - iov[i].iov_len -= used; - len -= used; - } - assert(len == 0); -} - -/* The device virtqueue descriptors are followed by feature bitmasks. */ -static u8 *get_feature_bits(struct device *dev) -{ - return (u8 *)(dev->desc + 1) - + dev->num_vq * sizeof(struct lguest_vqconfig); -} - -/*L:100 - * The Launcher code itself takes us out into userspace, that scary place where - * pointers run wild and free! Unfortunately, like most userspace programs, - * it's quite boring (which is why everyone likes to hack on the kernel!). - * Perhaps if you make up an Lguest Drinking Game at this point, it will get - * you through this section. Or, maybe not. - * - * The Launcher sets up a big chunk of memory to be the Guest's "physical" - * memory and stores it in "guest_base". In other words, Guest physical == - * Launcher virtual with an offset. - * - * This can be tough to get your head around, but usually it just means that we - * use these trivial conversion functions when the Guest gives us its - * "physical" addresses: - */ -static void *from_guest_phys(unsigned long addr) -{ - return guest_base + addr; -} - -static unsigned long to_guest_phys(const void *addr) -{ - return (addr - guest_base); -} - -/*L:130 - * Loading the Kernel. - * - * We start with couple of simple helper routines. open_or_die() avoids - * error-checking code cluttering the callers: - */ -static int open_or_die(const char *name, int flags) -{ - int fd = open(name, flags); - if (fd < 0) - err(1, "Failed to open %s", name); - return fd; -} - -/* map_zeroed_pages() takes a number of pages. */ -static void *map_zeroed_pages(unsigned int num) -{ - int fd = open_or_die("/dev/zero", O_RDONLY); - void *addr; - - /* - * We use a private mapping (ie. if we write to the page, it will be - * copied). We allocate an extra two pages PROT_NONE to act as guard - * pages against read/write attempts that exceed allocated space. - */ - addr = mmap(NULL, getpagesize() * (num+2), - PROT_NONE, MAP_PRIVATE, fd, 0); - - if (addr == MAP_FAILED) - err(1, "Mmapping %u pages of /dev/zero", num); - - if (mprotect(addr + getpagesize(), getpagesize() * num, - PROT_READ|PROT_WRITE) == -1) - err(1, "mprotect rw %u pages failed", num); - - /* - * One neat mmap feature is that you can close the fd, and it - * stays mapped. - */ - close(fd); - - /* Return address after PROT_NONE page */ - return addr + getpagesize(); -} - -/* Get some more pages for a device. */ -static void *get_pages(unsigned int num) -{ - void *addr = from_guest_phys(guest_limit); - - guest_limit += num * getpagesize(); - if (guest_limit > guest_max) - errx(1, "Not enough memory for devices"); - return addr; -} - -/* - * This routine is used to load the kernel or initrd. It tries mmap, but if - * that fails (Plan 9's kernel file isn't nicely aligned on page boundaries), - * it falls back to reading the memory in. - */ -static void map_at(int fd, void *addr, unsigned long offset, unsigned long len) -{ - ssize_t r; - - /* - * We map writable even though for some segments are marked read-only. - * The kernel really wants to be writable: it patches its own - * instructions. - * - * MAP_PRIVATE means that the page won't be copied until a write is - * done to it. This allows us to share untouched memory between - * Guests. - */ - if (mmap(addr, len, PROT_READ|PROT_WRITE, - MAP_FIXED|MAP_PRIVATE, fd, offset) != MAP_FAILED) - return; - - /* pread does a seek and a read in one shot: saves a few lines. */ - r = pread(fd, addr, len, offset); - if (r != len) - err(1, "Reading offset %lu len %lu gave %zi", offset, len, r); -} - -/* - * This routine takes an open vmlinux image, which is in ELF, and maps it into - * the Guest memory. ELF = Embedded Linking Format, which is the format used - * by all modern binaries on Linux including the kernel. - * - * The ELF headers give *two* addresses: a physical address, and a virtual - * address. We use the physical address; the Guest will map itself to the - * virtual address. - * - * We return the starting address. - */ -static unsigned long map_elf(int elf_fd, const Elf32_Ehdr *ehdr) -{ - Elf32_Phdr phdr[ehdr->e_phnum]; - unsigned int i; - - /* - * Sanity checks on the main ELF header: an x86 executable with a - * reasonable number of correctly-sized program headers. - */ - if (ehdr->e_type != ET_EXEC - || ehdr->e_machine != EM_386 - || ehdr->e_phentsize != sizeof(Elf32_Phdr) - || ehdr->e_phnum < 1 || ehdr->e_phnum > 65536U/sizeof(Elf32_Phdr)) - errx(1, "Malformed elf header"); - - /* - * An ELF executable contains an ELF header and a number of "program" - * headers which indicate which parts ("segments") of the program to - * load where. - */ - - /* We read in all the program headers at once: */ - if (lseek(elf_fd, ehdr->e_phoff, SEEK_SET) < 0) - err(1, "Seeking to program headers"); - if (read(elf_fd, phdr, sizeof(phdr)) != sizeof(phdr)) - err(1, "Reading program headers"); - - /* - * Try all the headers: there are usually only three. A read-only one, - * a read-write one, and a "note" section which we don't load. - */ - for (i = 0; i < ehdr->e_phnum; i++) { - /* If this isn't a loadable segment, we ignore it */ - if (phdr[i].p_type != PT_LOAD) - continue; - - verbose("Section %i: size %i addr %p\n", - i, phdr[i].p_memsz, (void *)phdr[i].p_paddr); - - /* We map this section of the file at its physical address. */ - map_at(elf_fd, from_guest_phys(phdr[i].p_paddr), - phdr[i].p_offset, phdr[i].p_filesz); - } - - /* The entry point is given in the ELF header. */ - return ehdr->e_entry; -} - -/*L:150 - * A bzImage, unlike an ELF file, is not meant to be loaded. You're supposed - * to jump into it and it will unpack itself. We used to have to perform some - * hairy magic because the unpacking code scared me. - * - * Fortunately, Jeremy Fitzhardinge convinced me it wasn't that hard and wrote - * a small patch to jump over the tricky bits in the Guest, so now we just read - * the funky header so we know where in the file to load, and away we go! - */ -static unsigned long load_bzimage(int fd) -{ - struct boot_params boot; - int r; - /* Modern bzImages get loaded at 1M. */ - void *p = from_guest_phys(0x100000); - - /* - * Go back to the start of the file and read the header. It should be - * a Linux boot header (see Documentation/x86/boot.txt) - */ - lseek(fd, 0, SEEK_SET); - read(fd, &boot, sizeof(boot)); - - /* Inside the setup_hdr, we expect the magic "HdrS" */ - if (memcmp(&boot.hdr.header, "HdrS", 4) != 0) - errx(1, "This doesn't look like a bzImage to me"); - - /* Skip over the extra sectors of the header. */ - lseek(fd, (boot.hdr.setup_sects+1) * 512, SEEK_SET); - - /* Now read everything into memory. in nice big chunks. */ - while ((r = read(fd, p, 65536)) > 0) - p += r; - - /* Finally, code32_start tells us where to enter the kernel. */ - return boot.hdr.code32_start; -} - -/*L:140 - * Loading the kernel is easy when it's a "vmlinux", but most kernels - * come wrapped up in the self-decompressing "bzImage" format. With a little - * work, we can load those, too. - */ -static unsigned long load_kernel(int fd) -{ - Elf32_Ehdr hdr; - - /* Read in the first few bytes. */ - if (read(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) - err(1, "Reading kernel"); - - /* If it's an ELF file, it starts with "\177ELF" */ - if (memcmp(hdr.e_ident, ELFMAG, SELFMAG) == 0) - return map_elf(fd, &hdr); - - /* Otherwise we assume it's a bzImage, and try to load it. */ - return load_bzimage(fd); -} - -/* - * This is a trivial little helper to align pages. Andi Kleen hated it because - * it calls getpagesize() twice: "it's dumb code." - * - * Kernel guys get really het up about optimization, even when it's not - * necessary. I leave this code as a reaction against that. - */ -static inline unsigned long page_align(unsigned long addr) -{ - /* Add upwards and truncate downwards. */ - return ((addr + getpagesize()-1) & ~(getpagesize()-1)); -} - -/*L:180 - * An "initial ram disk" is a disk image loaded into memory along with the - * kernel which the kernel can use to boot from without needing any drivers. - * Most distributions now use this as standard: the initrd contains the code to - * load the appropriate driver modules for the current machine. - * - * Importantly, James Morris works for RedHat, and Fedora uses initrds for its - * kernels. He sent me this (and tells me when I break it). - */ -static unsigned long load_initrd(const char *name, unsigned long mem) -{ - int ifd; - struct stat st; - unsigned long len; - - ifd = open_or_die(name, O_RDONLY); - /* fstat() is needed to get the file size. */ - if (fstat(ifd, &st) < 0) - err(1, "fstat() on initrd '%s'", name); - - /* - * We map the initrd at the top of memory, but mmap wants it to be - * page-aligned, so we round the size up for that. - */ - len = page_align(st.st_size); - map_at(ifd, from_guest_phys(mem - len), 0, st.st_size); - /* - * Once a file is mapped, you can close the file descriptor. It's a - * little odd, but quite useful. - */ - close(ifd); - verbose("mapped initrd %s size=%lu @ %p\n", name, len, (void*)mem-len); - - /* We return the initrd size. */ - return len; -} -/*:*/ - -/* - * Simple routine to roll all the commandline arguments together with spaces - * between them. - */ -static void concat(char *dst, char *args[]) -{ - unsigned int i, len = 0; - - for (i = 0; args[i]; i++) { - if (i) { - strcat(dst+len, " "); - len++; - } - strcpy(dst+len, args[i]); - len += strlen(args[i]); - } - /* In case it's empty. */ - dst[len] = '\0'; -} - -/*L:185 - * This is where we actually tell the kernel to initialize the Guest. We - * saw the arguments it expects when we looked at initialize() in lguest_user.c: - * the base of Guest "physical" memory, the top physical page to allow and the - * entry point for the Guest. - */ -static void tell_kernel(unsigned long start) -{ - unsigned long args[] = { LHREQ_INITIALIZE, - (unsigned long)guest_base, - guest_limit / getpagesize(), start }; - verbose("Guest: %p - %p (%#lx)\n", - guest_base, guest_base + guest_limit, guest_limit); - lguest_fd = open_or_die("/dev/lguest", O_RDWR); - if (write(lguest_fd, args, sizeof(args)) < 0) - err(1, "Writing to /dev/lguest"); -} -/*:*/ - -/*L:200 - * Device Handling. - * - * When the Guest gives us a buffer, it sends an array of addresses and sizes. - * We need to make sure it's not trying to reach into the Launcher itself, so - * we have a convenient routine which checks it and exits with an error message - * if something funny is going on: - */ -static void *_check_pointer(unsigned long addr, unsigned int size, - unsigned int line) -{ - /* - * Check if the requested address and size exceeds the allocated memory, - * or addr + size wraps around. - */ - if ((addr + size) > guest_limit || (addr + size) < addr) - errx(1, "%s:%i: Invalid address %#lx", __FILE__, line, addr); - /* - * We return a pointer for the caller's convenience, now we know it's - * safe to use. - */ - return from_guest_phys(addr); -} -/* A macro which transparently hands the line number to the real function. */ -#define check_pointer(addr,size) _check_pointer(addr, size, __LINE__) - -/* - * Each buffer in the virtqueues is actually a chain of descriptors. This - * function returns the next descriptor in the chain, or vq->vring.num if we're - * at the end. - */ -static unsigned next_desc(struct vring_desc *desc, - unsigned int i, unsigned int max) -{ - unsigned int next; - - /* If this descriptor says it doesn't chain, we're done. */ - if (!(desc[i].flags & VRING_DESC_F_NEXT)) - return max; - - /* Check they're not leading us off end of descriptors. */ - next = desc[i].next; - /* Make sure compiler knows to grab that: we don't want it changing! */ - wmb(); - - if (next >= max) - errx(1, "Desc next is %u", next); - - return next; -} - -/* - * This actually sends the interrupt for this virtqueue, if we've used a - * buffer. - */ -static void trigger_irq(struct virtqueue *vq) -{ - unsigned long buf[] = { LHREQ_IRQ, vq->config.irq }; - - /* Don't inform them if nothing used. */ - if (!vq->pending_used) - return; - vq->pending_used = 0; - - /* If they don't want an interrupt, don't send one... */ - if (vq->vring.avail->flags & VRING_AVAIL_F_NO_INTERRUPT) { - return; - } - - /* Send the Guest an interrupt tell them we used something up. */ - if (write(lguest_fd, buf, sizeof(buf)) != 0) - err(1, "Triggering irq %i", vq->config.irq); -} - -/* - * This looks in the virtqueue for the first available buffer, and converts - * it to an iovec for convenient access. Since descriptors consist of some - * number of output then some number of input descriptors, it's actually two - * iovecs, but we pack them into one and note how many of each there were. - * - * This function waits if necessary, and returns the descriptor number found. - */ -static unsigned wait_for_vq_desc(struct virtqueue *vq, - struct iovec iov[], - unsigned int *out_num, unsigned int *in_num) -{ - unsigned int i, head, max; - struct vring_desc *desc; - u16 last_avail = lg_last_avail(vq); - - /* There's nothing available? */ - while (last_avail == vq->vring.avail->idx) { - u64 event; - - /* - * Since we're about to sleep, now is a good time to tell the - * Guest about what we've used up to now. - */ - trigger_irq(vq); - - /* OK, now we need to know about added descriptors. */ - vq->vring.used->flags &= ~VRING_USED_F_NO_NOTIFY; - - /* - * They could have slipped one in as we were doing that: make - * sure it's written, then check again. - */ - mb(); - if (last_avail != vq->vring.avail->idx) { - vq->vring.used->flags |= VRING_USED_F_NO_NOTIFY; - break; - } - - /* Nothing new? Wait for eventfd to tell us they refilled. */ - if (read(vq->eventfd, &event, sizeof(event)) != sizeof(event)) - errx(1, "Event read failed?"); - - /* We don't need to be notified again. */ - vq->vring.used->flags |= VRING_USED_F_NO_NOTIFY; - } - - /* Check it isn't doing very strange things with descriptor numbers. */ - if ((u16)(vq->vring.avail->idx - last_avail) > vq->vring.num) - errx(1, "Guest moved used index from %u to %u", - last_avail, vq->vring.avail->idx); - - /* - * Grab the next descriptor number they're advertising, and increment - * the index we've seen. - */ - head = vq->vring.avail->ring[last_avail % vq->vring.num]; - lg_last_avail(vq)++; - - /* If their number is silly, that's a fatal mistake. */ - if (head >= vq->vring.num) - errx(1, "Guest says index %u is available", head); - - /* When we start there are none of either input nor output. */ - *out_num = *in_num = 0; - - max = vq->vring.num; - desc = vq->vring.desc; - i = head; - - /* - * If this is an indirect entry, then this buffer contains a descriptor - * table which we handle as if it's any normal descriptor chain. - */ - if (desc[i].flags & VRING_DESC_F_INDIRECT) { - if (desc[i].len % sizeof(struct vring_desc)) - errx(1, "Invalid size for indirect buffer table"); - - max = desc[i].len / sizeof(struct vring_desc); - desc = check_pointer(desc[i].addr, desc[i].len); - i = 0; - } - - do { - /* Grab the first descriptor, and check it's OK. */ - iov[*out_num + *in_num].iov_len = desc[i].len; - iov[*out_num + *in_num].iov_base - = check_pointer(desc[i].addr, desc[i].len); - /* If this is an input descriptor, increment that count. */ - if (desc[i].flags & VRING_DESC_F_WRITE) - (*in_num)++; - else { - /* - * If it's an output descriptor, they're all supposed - * to come before any input descriptors. - */ - if (*in_num) - errx(1, "Descriptor has out after in"); - (*out_num)++; - } - - /* If we've got too many, that implies a descriptor loop. */ - if (*out_num + *in_num > max) - errx(1, "Looped descriptor"); - } while ((i = next_desc(desc, i, max)) != max); - - return head; -} - -/* - * After we've used one of their buffers, we tell the Guest about it. Sometime - * later we'll want to send them an interrupt using trigger_irq(); note that - * wait_for_vq_desc() does that for us if it has to wait. - */ -static void add_used(struct virtqueue *vq, unsigned int head, int len) -{ - struct vring_used_elem *used; - - /* - * The virtqueue contains a ring of used buffers. Get a pointer to the - * next entry in that used ring. - */ - used = &vq->vring.used->ring[vq->vring.used->idx % vq->vring.num]; - used->id = head; - used->len = len; - /* Make sure buffer is written before we update index. */ - wmb(); - vq->vring.used->idx++; - vq->pending_used++; -} - -/* And here's the combo meal deal. Supersize me! */ -static void add_used_and_trigger(struct virtqueue *vq, unsigned head, int len) -{ - add_used(vq, head, len); - trigger_irq(vq); -} - -/* - * The Console - * - * We associate some data with the console for our exit hack. - */ -struct console_abort { - /* How many times have they hit ^C? */ - int count; - /* When did they start? */ - struct timeval start; -}; - -/* This is the routine which handles console input (ie. stdin). */ -static void console_input(struct virtqueue *vq) -{ - int len; - unsigned int head, in_num, out_num; - struct console_abort *abort = vq->dev->priv; - struct iovec iov[vq->vring.num]; - - /* Make sure there's a descriptor available. */ - head = wait_for_vq_desc(vq, iov, &out_num, &in_num); - if (out_num) - errx(1, "Output buffers in console in queue?"); - - /* Read into it. This is where we usually wait. */ - len = readv(STDIN_FILENO, iov, in_num); - if (len <= 0) { - /* Ran out of input? */ - warnx("Failed to get console input, ignoring console."); - /* - * For simplicity, dying threads kill the whole Launcher. So - * just nap here. - */ - for (;;) - pause(); - } - - /* Tell the Guest we used a buffer. */ - add_used_and_trigger(vq, head, len); - - /* - * Three ^C within one second? Exit. - * - * This is such a hack, but works surprisingly well. Each ^C has to - * be in a buffer by itself, so they can't be too fast. But we check - * that we get three within about a second, so they can't be too - * slow. - */ - if (len != 1 || ((char *)iov[0].iov_base)[0] != 3) { - abort->count = 0; - return; - } - - abort->count++; - if (abort->count == 1) - gettimeofday(&abort->start, NULL); - else if (abort->count == 3) { - struct timeval now; - gettimeofday(&now, NULL); - /* Kill all Launcher processes with SIGINT, like normal ^C */ - if (now.tv_sec <= abort->start.tv_sec+1) - kill(0, SIGINT); - abort->count = 0; - } -} - -/* This is the routine which handles console output (ie. stdout). */ -static void console_output(struct virtqueue *vq) -{ - unsigned int head, out, in; - struct iovec iov[vq->vring.num]; - - /* We usually wait in here, for the Guest to give us something. */ - head = wait_for_vq_desc(vq, iov, &out, &in); - if (in) - errx(1, "Input buffers in console output queue?"); - - /* writev can return a partial write, so we loop here. */ - while (!iov_empty(iov, out)) { - int len = writev(STDOUT_FILENO, iov, out); - if (len <= 0) { - warn("Write to stdout gave %i (%d)", len, errno); - break; - } - iov_consume(iov, out, len); - } - - /* - * We're finished with that buffer: if we're going to sleep, - * wait_for_vq_desc() will prod the Guest with an interrupt. - */ - add_used(vq, head, 0); -} - -/* - * The Network - * - * Handling output for network is also simple: we get all the output buffers - * and write them to /dev/net/tun. - */ -struct net_info { - int tunfd; -}; - -static void net_output(struct virtqueue *vq) -{ - struct net_info *net_info = vq->dev->priv; - unsigned int head, out, in; - struct iovec iov[vq->vring.num]; - - /* We usually wait in here for the Guest to give us a packet. */ - head = wait_for_vq_desc(vq, iov, &out, &in); - if (in) - errx(1, "Input buffers in net output queue?"); - /* - * Send the whole thing through to /dev/net/tun. It expects the exact - * same format: what a coincidence! - */ - if (writev(net_info->tunfd, iov, out) < 0) - warnx("Write to tun failed (%d)?", errno); - - /* - * Done with that one; wait_for_vq_desc() will send the interrupt if - * all packets are processed. - */ - add_used(vq, head, 0); -} - -/* - * Handling network input is a bit trickier, because I've tried to optimize it. - * - * First we have a helper routine which tells is if from this file descriptor - * (ie. the /dev/net/tun device) will block: - */ -static bool will_block(int fd) -{ - fd_set fdset; - struct timeval zero = { 0, 0 }; - FD_ZERO(&fdset); - FD_SET(fd, &fdset); - return select(fd+1, &fdset, NULL, NULL, &zero) != 1; -} - -/* - * This handles packets coming in from the tun device to our Guest. Like all - * service routines, it gets called again as soon as it returns, so you don't - * see a while(1) loop here. - */ -static void net_input(struct virtqueue *vq) -{ - int len; - unsigned int head, out, in; - struct iovec iov[vq->vring.num]; - struct net_info *net_info = vq->dev->priv; - - /* - * Get a descriptor to write an incoming packet into. This will also - * send an interrupt if they're out of descriptors. - */ - head = wait_for_vq_desc(vq, iov, &out, &in); - if (out) - errx(1, "Output buffers in net input queue?"); - - /* - * If it looks like we'll block reading from the tun device, send them - * an interrupt. - */ - if (vq->pending_used && will_block(net_info->tunfd)) - trigger_irq(vq); - - /* - * Read in the packet. This is where we normally wait (when there's no - * incoming network traffic). - */ - len = readv(net_info->tunfd, iov, in); - if (len <= 0) - warn("Failed to read from tun (%d).", errno); - - /* - * Mark that packet buffer as used, but don't interrupt here. We want - * to wait until we've done as much work as we can. - */ - add_used(vq, head, len); -} -/*:*/ - -/* This is the helper to create threads: run the service routine in a loop. */ -static int do_thread(void *_vq) -{ - struct virtqueue *vq = _vq; - - for (;;) - vq->service(vq); - return 0; -} - -/* - * When a child dies, we kill our entire process group with SIGTERM. This - * also has the side effect that the shell restores the console for us! - */ -static void kill_launcher(int signal) -{ - kill(0, SIGTERM); -} - -static void reset_device(struct device *dev) -{ - struct virtqueue *vq; - - verbose("Resetting device %s\n", dev->name); - - /* Clear any features they've acked. */ - memset(get_feature_bits(dev) + dev->feature_len, 0, dev->feature_len); - - /* We're going to be explicitly killing threads, so ignore them. */ - signal(SIGCHLD, SIG_IGN); - - /* Zero out the virtqueues, get rid of their threads */ - for (vq = dev->vq; vq; vq = vq->next) { - if (vq->thread != (pid_t)-1) { - kill(vq->thread, SIGTERM); - waitpid(vq->thread, NULL, 0); - vq->thread = (pid_t)-1; - } - memset(vq->vring.desc, 0, - vring_size(vq->config.num, LGUEST_VRING_ALIGN)); - lg_last_avail(vq) = 0; - } - dev->running = false; - - /* Now we care if threads die. */ - signal(SIGCHLD, (void *)kill_launcher); -} - -/*L:216 - * This actually creates the thread which services the virtqueue for a device. - */ -static void create_thread(struct virtqueue *vq) -{ - /* - * Create stack for thread. Since the stack grows upwards, we point - * the stack pointer to the end of this region. - */ - char *stack = malloc(32768); - unsigned long args[] = { LHREQ_EVENTFD, - vq->config.pfn*getpagesize(), 0 }; - - /* Create a zero-initialized eventfd. */ - vq->eventfd = eventfd(0, 0); - if (vq->eventfd < 0) - err(1, "Creating eventfd"); - args[2] = vq->eventfd; - - /* - * Attach an eventfd to this virtqueue: it will go off when the Guest - * does an LHCALL_NOTIFY for this vq. - */ - if (write(lguest_fd, &args, sizeof(args)) != 0) - err(1, "Attaching eventfd"); - - /* - * CLONE_VM: because it has to access the Guest memory, and SIGCHLD so - * we get a signal if it dies. - */ - vq->thread = clone(do_thread, stack + 32768, CLONE_VM | SIGCHLD, vq); - if (vq->thread == (pid_t)-1) - err(1, "Creating clone"); - - /* We close our local copy now the child has it. */ - close(vq->eventfd); -} - -static void start_device(struct device *dev) -{ - unsigned int i; - struct virtqueue *vq; - - verbose("Device %s OK: offered", dev->name); - for (i = 0; i < dev->feature_len; i++) - verbose(" %02x", get_feature_bits(dev)[i]); - verbose(", accepted"); - for (i = 0; i < dev->feature_len; i++) - verbose(" %02x", get_feature_bits(dev) - [dev->feature_len+i]); - - for (vq = dev->vq; vq; vq = vq->next) { - if (vq->service) - create_thread(vq); - } - dev->running = true; -} - -static void cleanup_devices(void) -{ - struct device *dev; - - for (dev = devices.dev; dev; dev = dev->next) - reset_device(dev); - - /* If we saved off the original terminal settings, restore them now. */ - if (orig_term.c_lflag & (ISIG|ICANON|ECHO)) - tcsetattr(STDIN_FILENO, TCSANOW, &orig_term); -} - -/* When the Guest tells us they updated the status field, we handle it. */ -static void update_device_status(struct device *dev) -{ - /* A zero status is a reset, otherwise it's a set of flags. */ - if (dev->desc->status == 0) - reset_device(dev); - else if (dev->desc->status & VIRTIO_CONFIG_S_FAILED) { - warnx("Device %s configuration FAILED", dev->name); - if (dev->running) - reset_device(dev); - } else { - if (dev->running) - err(1, "Device %s features finalized twice", dev->name); - start_device(dev); - } -} - -/*L:215 - * This is the generic routine we call when the Guest uses LHCALL_NOTIFY. In - * particular, it's used to notify us of device status changes during boot. - */ -static void handle_output(unsigned long addr) -{ - struct device *i; - - /* Check each device. */ - for (i = devices.dev; i; i = i->next) { - struct virtqueue *vq; - - /* - * Notifications to device descriptors mean they updated the - * device status. - */ - if (from_guest_phys(addr) == i->desc) { - update_device_status(i); - return; - } - - /* Devices should not be used before features are finalized. */ - for (vq = i->vq; vq; vq = vq->next) { - if (addr != vq->config.pfn*getpagesize()) - continue; - errx(1, "Notification on %s before setup!", i->name); - } - } - - /* - * Early console write is done using notify on a nul-terminated string - * in Guest memory. It's also great for hacking debugging messages - * into a Guest. - */ - if (addr >= guest_limit) - errx(1, "Bad NOTIFY %#lx", addr); - - write(STDOUT_FILENO, from_guest_phys(addr), - strnlen(from_guest_phys(addr), guest_limit - addr)); -} - -/*L:190 - * Device Setup - * - * All devices need a descriptor so the Guest knows it exists, and a "struct - * device" so the Launcher can keep track of it. We have common helper - * routines to allocate and manage them. - */ - -/* - * The layout of the device page is a "struct lguest_device_desc" followed by a - * number of virtqueue descriptors, then two sets of feature bits, then an - * array of configuration bytes. This routine returns the configuration - * pointer. - */ -static u8 *device_config(const struct device *dev) -{ - return (void *)(dev->desc + 1) - + dev->num_vq * sizeof(struct lguest_vqconfig) - + dev->feature_len * 2; -} - -/* - * This routine allocates a new "struct lguest_device_desc" from descriptor - * table page just above the Guest's normal memory. It returns a pointer to - * that descriptor. - */ -static struct lguest_device_desc *new_dev_desc(u16 type) -{ - struct lguest_device_desc d = { .type = type }; - void *p; - - /* Figure out where the next device config is, based on the last one. */ - if (devices.lastdev) - p = device_config(devices.lastdev) - + devices.lastdev->desc->config_len; - else - p = devices.descpage; - - /* We only have one page for all the descriptors. */ - if (p + sizeof(d) > (void *)devices.descpage + getpagesize()) - errx(1, "Too many devices"); - - /* p might not be aligned, so we memcpy in. */ - return memcpy(p, &d, sizeof(d)); -} - -/* - * Each device descriptor is followed by the description of its virtqueues. We - * specify how many descriptors the virtqueue is to have. - */ -static void add_virtqueue(struct device *dev, unsigned int num_descs, - void (*service)(struct virtqueue *)) -{ - unsigned int pages; - struct virtqueue **i, *vq = malloc(sizeof(*vq)); - void *p; - - /* First we need some memory for this virtqueue. */ - pages = (vring_size(num_descs, LGUEST_VRING_ALIGN) + getpagesize() - 1) - / getpagesize(); - p = get_pages(pages); - - /* Initialize the virtqueue */ - vq->next = NULL; - vq->last_avail_idx = 0; - vq->dev = dev; - - /* - * This is the routine the service thread will run, and its Process ID - * once it's running. - */ - vq->service = service; - vq->thread = (pid_t)-1; - - /* Initialize the configuration. */ - vq->config.num = num_descs; - vq->config.irq = devices.next_irq++; - vq->config.pfn = to_guest_phys(p) / getpagesize(); - - /* Initialize the vring. */ - vring_init(&vq->vring, num_descs, p, LGUEST_VRING_ALIGN); - - /* - * Append virtqueue to this device's descriptor. We use - * device_config() to get the end of the device's current virtqueues; - * we check that we haven't added any config or feature information - * yet, otherwise we'd be overwriting them. - */ - assert(dev->desc->config_len == 0 && dev->desc->feature_len == 0); - memcpy(device_config(dev), &vq->config, sizeof(vq->config)); - dev->num_vq++; - dev->desc->num_vq++; - - verbose("Virtqueue page %#lx\n", to_guest_phys(p)); - - /* - * Add to tail of list, so dev->vq is first vq, dev->vq->next is - * second. - */ - for (i = &dev->vq; *i; i = &(*i)->next); - *i = vq; -} - -/* - * The first half of the feature bitmask is for us to advertise features. The - * second half is for the Guest to accept features. - */ -static void add_feature(struct device *dev, unsigned bit) -{ - u8 *features = get_feature_bits(dev); - - /* We can't extend the feature bits once we've added config bytes */ - if (dev->desc->feature_len <= bit / CHAR_BIT) { - assert(dev->desc->config_len == 0); - dev->feature_len = dev->desc->feature_len = (bit/CHAR_BIT) + 1; - } - - features[bit / CHAR_BIT] |= (1 << (bit % CHAR_BIT)); -} - -/* - * This routine sets the configuration fields for an existing device's - * descriptor. It only works for the last device, but that's OK because that's - * how we use it. - */ -static void set_config(struct device *dev, unsigned len, const void *conf) -{ - /* Check we haven't overflowed our single page. */ - if (device_config(dev) + len > devices.descpage + getpagesize()) - errx(1, "Too many devices"); - - /* Copy in the config information, and store the length. */ - memcpy(device_config(dev), conf, len); - dev->desc->config_len = len; - - /* Size must fit in config_len field (8 bits)! */ - assert(dev->desc->config_len == len); -} - -/* - * This routine does all the creation and setup of a new device, including - * calling new_dev_desc() to allocate the descriptor and device memory. We - * don't actually start the service threads until later. - * - * See what I mean about userspace being boring? - */ -static struct device *new_device(const char *name, u16 type) -{ - struct device *dev = malloc(sizeof(*dev)); - - /* Now we populate the fields one at a time. */ - dev->desc = new_dev_desc(type); - dev->name = name; - dev->vq = NULL; - dev->feature_len = 0; - dev->num_vq = 0; - dev->running = false; - - /* - * Append to device list. Prepending to a single-linked list is - * easier, but the user expects the devices to be arranged on the bus - * in command-line order. The first network device on the command line - * is eth0, the first block device /dev/vda, etc. - */ - if (devices.lastdev) - devices.lastdev->next = dev; - else - devices.dev = dev; - devices.lastdev = dev; - - return dev; -} - -/* - * Our first setup routine is the console. It's a fairly simple device, but - * UNIX tty handling makes it uglier than it could be. - */ -static void setup_console(void) -{ - struct device *dev; - - /* If we can save the initial standard input settings... */ - if (tcgetattr(STDIN_FILENO, &orig_term) == 0) { - struct termios term = orig_term; - /* - * Then we turn off echo, line buffering and ^C etc: We want a - * raw input stream to the Guest. - */ - term.c_lflag &= ~(ISIG|ICANON|ECHO); - tcsetattr(STDIN_FILENO, TCSANOW, &term); - } - - dev = new_device("console", VIRTIO_ID_CONSOLE); - - /* We store the console state in dev->priv, and initialize it. */ - dev->priv = malloc(sizeof(struct console_abort)); - ((struct console_abort *)dev->priv)->count = 0; - - /* - * The console needs two virtqueues: the input then the output. When - * they put something the input queue, we make sure we're listening to - * stdin. When they put something in the output queue, we write it to - * stdout. - */ - add_virtqueue(dev, VIRTQUEUE_NUM, console_input); - add_virtqueue(dev, VIRTQUEUE_NUM, console_output); - - verbose("device %u: console\n", ++devices.device_num); -} -/*:*/ - -/*M:010 - * Inter-guest networking is an interesting area. Simplest is to have a - * --sharenet= option which opens or creates a named pipe. This can be - * used to send packets to another guest in a 1:1 manner. - * - * More sophisticated is to use one of the tools developed for project like UML - * to do networking. - * - * Faster is to do virtio bonding in kernel. Doing this 1:1 would be - * completely generic ("here's my vring, attach to your vring") and would work - * for any traffic. Of course, namespace and permissions issues need to be - * dealt with. A more sophisticated "multi-channel" virtio_net.c could hide - * multiple inter-guest channels behind one interface, although it would - * require some manner of hotplugging new virtio channels. - * - * Finally, we could use a virtio network switch in the kernel, ie. vhost. -:*/ - -static u32 str2ip(const char *ipaddr) -{ - unsigned int b[4]; - - if (sscanf(ipaddr, "%u.%u.%u.%u", &b[0], &b[1], &b[2], &b[3]) != 4) - errx(1, "Failed to parse IP address '%s'", ipaddr); - return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3]; -} - -static void str2mac(const char *macaddr, unsigned char mac[6]) -{ - unsigned int m[6]; - if (sscanf(macaddr, "%02x:%02x:%02x:%02x:%02x:%02x", - &m[0], &m[1], &m[2], &m[3], &m[4], &m[5]) != 6) - errx(1, "Failed to parse mac address '%s'", macaddr); - mac[0] = m[0]; - mac[1] = m[1]; - mac[2] = m[2]; - mac[3] = m[3]; - mac[4] = m[4]; - mac[5] = m[5]; -} - -/* - * This code is "adapted" from libbridge: it attaches the Host end of the - * network device to the bridge device specified by the command line. - * - * This is yet another James Morris contribution (I'm an IP-level guy, so I - * dislike bridging), and I just try not to break it. - */ -static void add_to_bridge(int fd, const char *if_name, const char *br_name) -{ - int ifidx; - struct ifreq ifr; - - if (!*br_name) - errx(1, "must specify bridge name"); - - ifidx = if_nametoindex(if_name); - if (!ifidx) - errx(1, "interface %s does not exist!", if_name); - - strncpy(ifr.ifr_name, br_name, IFNAMSIZ); - ifr.ifr_name[IFNAMSIZ-1] = '\0'; - ifr.ifr_ifindex = ifidx; - if (ioctl(fd, SIOCBRADDIF, &ifr) < 0) - err(1, "can't add %s to bridge %s", if_name, br_name); -} - -/* - * This sets up the Host end of the network device with an IP address, brings - * it up so packets will flow, the copies the MAC address into the hwaddr - * pointer. - */ -static void configure_device(int fd, const char *tapif, u32 ipaddr) -{ - struct ifreq ifr; - struct sockaddr_in sin; - - memset(&ifr, 0, sizeof(ifr)); - strcpy(ifr.ifr_name, tapif); - - /* Don't read these incantations. Just cut & paste them like I did! */ - sin.sin_family = AF_INET; - sin.sin_addr.s_addr = htonl(ipaddr); - memcpy(&ifr.ifr_addr, &sin, sizeof(sin)); - if (ioctl(fd, SIOCSIFADDR, &ifr) != 0) - err(1, "Setting %s interface address", tapif); - ifr.ifr_flags = IFF_UP; - if (ioctl(fd, SIOCSIFFLAGS, &ifr) != 0) - err(1, "Bringing interface %s up", tapif); -} - -static int get_tun_device(char tapif[IFNAMSIZ]) -{ - struct ifreq ifr; - int netfd; - - /* Start with this zeroed. Messy but sure. */ - memset(&ifr, 0, sizeof(ifr)); - - /* - * We open the /dev/net/tun device and tell it we want a tap device. A - * tap device is like a tun device, only somehow different. To tell - * the truth, I completely blundered my way through this code, but it - * works now! - */ - netfd = open_or_die("/dev/net/tun", O_RDWR); - ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_VNET_HDR; - strcpy(ifr.ifr_name, "tap%d"); - if (ioctl(netfd, TUNSETIFF, &ifr) != 0) - err(1, "configuring /dev/net/tun"); - - if (ioctl(netfd, TUNSETOFFLOAD, - TUN_F_CSUM|TUN_F_TSO4|TUN_F_TSO6|TUN_F_TSO_ECN) != 0) - err(1, "Could not set features for tun device"); - - /* - * We don't need checksums calculated for packets coming in this - * device: trust us! - */ - ioctl(netfd, TUNSETNOCSUM, 1); - - memcpy(tapif, ifr.ifr_name, IFNAMSIZ); - return netfd; -} - -/*L:195 - * Our network is a Host<->Guest network. This can either use bridging or - * routing, but the principle is the same: it uses the "tun" device to inject - * packets into the Host as if they came in from a normal network card. We - * just shunt packets between the Guest and the tun device. - */ -static void setup_tun_net(char *arg) -{ - struct device *dev; - struct net_info *net_info = malloc(sizeof(*net_info)); - int ipfd; - u32 ip = INADDR_ANY; - bool bridging = false; - char tapif[IFNAMSIZ], *p; - struct virtio_net_config conf; - - net_info->tunfd = get_tun_device(tapif); - - /* First we create a new network device. */ - dev = new_device("net", VIRTIO_ID_NET); - dev->priv = net_info; - - /* Network devices need a recv and a send queue, just like console. */ - add_virtqueue(dev, VIRTQUEUE_NUM, net_input); - add_virtqueue(dev, VIRTQUEUE_NUM, net_output); - - /* - * We need a socket to perform the magic network ioctls to bring up the - * tap interface, connect to the bridge etc. Any socket will do! - */ - ipfd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP); - if (ipfd < 0) - err(1, "opening IP socket"); - - /* If the command line was --tunnet=bridge: do bridging. */ - if (!strncmp(BRIDGE_PFX, arg, strlen(BRIDGE_PFX))) { - arg += strlen(BRIDGE_PFX); - bridging = true; - } - - /* A mac address may follow the bridge name or IP address */ - p = strchr(arg, ':'); - if (p) { - str2mac(p+1, conf.mac); - add_feature(dev, VIRTIO_NET_F_MAC); - *p = '\0'; - } - - /* arg is now either an IP address or a bridge name */ - if (bridging) - add_to_bridge(ipfd, tapif, arg); - else - ip = str2ip(arg); - - /* Set up the tun device. */ - configure_device(ipfd, tapif, ip); - - /* Expect Guest to handle everything except UFO */ - add_feature(dev, VIRTIO_NET_F_CSUM); - add_feature(dev, VIRTIO_NET_F_GUEST_CSUM); - add_feature(dev, VIRTIO_NET_F_GUEST_TSO4); - add_feature(dev, VIRTIO_NET_F_GUEST_TSO6); - add_feature(dev, VIRTIO_NET_F_GUEST_ECN); - add_feature(dev, VIRTIO_NET_F_HOST_TSO4); - add_feature(dev, VIRTIO_NET_F_HOST_TSO6); - add_feature(dev, VIRTIO_NET_F_HOST_ECN); - /* We handle indirect ring entries */ - add_feature(dev, VIRTIO_RING_F_INDIRECT_DESC); - set_config(dev, sizeof(conf), &conf); - - /* We don't need the socket any more; setup is done. */ - close(ipfd); - - devices.device_num++; - - if (bridging) - verbose("device %u: tun %s attached to bridge: %s\n", - devices.device_num, tapif, arg); - else - verbose("device %u: tun %s: %s\n", - devices.device_num, tapif, arg); -} -/*:*/ - -/* This hangs off device->priv. */ -struct vblk_info { - /* The size of the file. */ - off64_t len; - - /* The file descriptor for the file. */ - int fd; - -}; - -/*L:210 - * The Disk - * - * The disk only has one virtqueue, so it only has one thread. It is really - * simple: the Guest asks for a block number and we read or write that position - * in the file. - * - * Before we serviced each virtqueue in a separate thread, that was unacceptably - * slow: the Guest waits until the read is finished before running anything - * else, even if it could have been doing useful work. - * - * We could have used async I/O, except it's reputed to suck so hard that - * characters actually go missing from your code when you try to use it. - */ -static void blk_request(struct virtqueue *vq) -{ - struct vblk_info *vblk = vq->dev->priv; - unsigned int head, out_num, in_num, wlen; - int ret; - u8 *in; - struct virtio_blk_outhdr *out; - struct iovec iov[vq->vring.num]; - off64_t off; - - /* - * Get the next request, where we normally wait. It triggers the - * interrupt to acknowledge previously serviced requests (if any). - */ - head = wait_for_vq_desc(vq, iov, &out_num, &in_num); - - /* - * Every block request should contain at least one output buffer - * (detailing the location on disk and the type of request) and one - * input buffer (to hold the result). - */ - if (out_num == 0 || in_num == 0) - errx(1, "Bad virtblk cmd %u out=%u in=%u", - head, out_num, in_num); - - out = convert(&iov[0], struct virtio_blk_outhdr); - in = convert(&iov[out_num+in_num-1], u8); - /* - * For historical reasons, block operations are expressed in 512 byte - * "sectors". - */ - off = out->sector * 512; - - /* - * In general the virtio block driver is allowed to try SCSI commands. - * It'd be nice if we supported eject, for example, but we don't. - */ - if (out->type & VIRTIO_BLK_T_SCSI_CMD) { - fprintf(stderr, "Scsi commands unsupported\n"); - *in = VIRTIO_BLK_S_UNSUPP; - wlen = sizeof(*in); - } else if (out->type & VIRTIO_BLK_T_OUT) { - /* - * Write - * - * Move to the right location in the block file. This can fail - * if they try to write past end. - */ - if (lseek64(vblk->fd, off, SEEK_SET) != off) - err(1, "Bad seek to sector %llu", out->sector); - - ret = writev(vblk->fd, iov+1, out_num-1); - verbose("WRITE to sector %llu: %i\n", out->sector, ret); - - /* - * Grr... Now we know how long the descriptor they sent was, we - * make sure they didn't try to write over the end of the block - * file (possibly extending it). - */ - if (ret > 0 && off + ret > vblk->len) { - /* Trim it back to the correct length */ - ftruncate64(vblk->fd, vblk->len); - /* Die, bad Guest, die. */ - errx(1, "Write past end %llu+%u", off, ret); - } - - wlen = sizeof(*in); - *in = (ret >= 0 ? VIRTIO_BLK_S_OK : VIRTIO_BLK_S_IOERR); - } else if (out->type & VIRTIO_BLK_T_FLUSH) { - /* Flush */ - ret = fdatasync(vblk->fd); - verbose("FLUSH fdatasync: %i\n", ret); - wlen = sizeof(*in); - *in = (ret >= 0 ? VIRTIO_BLK_S_OK : VIRTIO_BLK_S_IOERR); - } else { - /* - * Read - * - * Move to the right location in the block file. This can fail - * if they try to read past end. - */ - if (lseek64(vblk->fd, off, SEEK_SET) != off) - err(1, "Bad seek to sector %llu", out->sector); - - ret = readv(vblk->fd, iov+1, in_num-1); - verbose("READ from sector %llu: %i\n", out->sector, ret); - if (ret >= 0) { - wlen = sizeof(*in) + ret; - *in = VIRTIO_BLK_S_OK; - } else { - wlen = sizeof(*in); - *in = VIRTIO_BLK_S_IOERR; - } - } - - /* Finished that request. */ - add_used(vq, head, wlen); -} - -/*L:198 This actually sets up a virtual block device. */ -static void setup_block_file(const char *filename) -{ - struct device *dev; - struct vblk_info *vblk; - struct virtio_blk_config conf; - - /* Creat the device. */ - dev = new_device("block", VIRTIO_ID_BLOCK); - - /* The device has one virtqueue, where the Guest places requests. */ - add_virtqueue(dev, VIRTQUEUE_NUM, blk_request); - - /* Allocate the room for our own bookkeeping */ - vblk = dev->priv = malloc(sizeof(*vblk)); - - /* First we open the file and store the length. */ - vblk->fd = open_or_die(filename, O_RDWR|O_LARGEFILE); - vblk->len = lseek64(vblk->fd, 0, SEEK_END); - - /* We support FLUSH. */ - add_feature(dev, VIRTIO_BLK_F_FLUSH); - - /* Tell Guest how many sectors this device has. */ - conf.capacity = cpu_to_le64(vblk->len / 512); - - /* - * Tell Guest not to put in too many descriptors at once: two are used - * for the in and out elements. - */ - add_feature(dev, VIRTIO_BLK_F_SEG_MAX); - conf.seg_max = cpu_to_le32(VIRTQUEUE_NUM - 2); - - /* Don't try to put whole struct: we have 8 bit limit. */ - set_config(dev, offsetof(struct virtio_blk_config, geometry), &conf); - - verbose("device %u: virtblock %llu sectors\n", - ++devices.device_num, le64_to_cpu(conf.capacity)); -} - -/*L:211 - * Our random number generator device reads from /dev/random into the Guest's - * input buffers. The usual case is that the Guest doesn't want random numbers - * and so has no buffers although /dev/random is still readable, whereas - * console is the reverse. - * - * The same logic applies, however. - */ -struct rng_info { - int rfd; -}; - -static void rng_input(struct virtqueue *vq) -{ - int len; - unsigned int head, in_num, out_num, totlen = 0; - struct rng_info *rng_info = vq->dev->priv; - struct iovec iov[vq->vring.num]; - - /* First we need a buffer from the Guests's virtqueue. */ - head = wait_for_vq_desc(vq, iov, &out_num, &in_num); - if (out_num) - errx(1, "Output buffers in rng?"); - - /* - * Just like the console write, we loop to cover the whole iovec. - * In this case, short reads actually happen quite a bit. - */ - while (!iov_empty(iov, in_num)) { - len = readv(rng_info->rfd, iov, in_num); - if (len <= 0) - err(1, "Read from /dev/random gave %i", len); - iov_consume(iov, in_num, len); - totlen += len; - } - - /* Tell the Guest about the new input. */ - add_used(vq, head, totlen); -} - -/*L:199 - * This creates a "hardware" random number device for the Guest. - */ -static void setup_rng(void) -{ - struct device *dev; - struct rng_info *rng_info = malloc(sizeof(*rng_info)); - - /* Our device's privat info simply contains the /dev/random fd. */ - rng_info->rfd = open_or_die("/dev/random", O_RDONLY); - - /* Create the new device. */ - dev = new_device("rng", VIRTIO_ID_RNG); - dev->priv = rng_info; - - /* The device has one virtqueue, where the Guest places inbufs. */ - add_virtqueue(dev, VIRTQUEUE_NUM, rng_input); - - verbose("device %u: rng\n", devices.device_num++); -} -/* That's the end of device setup. */ - -/*L:230 Reboot is pretty easy: clean up and exec() the Launcher afresh. */ -static void __attribute__((noreturn)) restart_guest(void) -{ - unsigned int i; - - /* - * Since we don't track all open fds, we simply close everything beyond - * stderr. - */ - for (i = 3; i < FD_SETSIZE; i++) - close(i); - - /* Reset all the devices (kills all threads). */ - cleanup_devices(); - - execv(main_args[0], main_args); - err(1, "Could not exec %s", main_args[0]); -} - -/*L:220 - * Finally we reach the core of the Launcher which runs the Guest, serves - * its input and output, and finally, lays it to rest. - */ -static void __attribute__((noreturn)) run_guest(void) -{ - for (;;) { - unsigned long notify_addr; - int readval; - - /* We read from the /dev/lguest device to run the Guest. */ - readval = pread(lguest_fd, ¬ify_addr, - sizeof(notify_addr), cpu_id); - - /* One unsigned long means the Guest did HCALL_NOTIFY */ - if (readval == sizeof(notify_addr)) { - verbose("Notify on address %#lx\n", notify_addr); - handle_output(notify_addr); - /* ENOENT means the Guest died. Reading tells us why. */ - } else if (errno == ENOENT) { - char reason[1024] = { 0 }; - pread(lguest_fd, reason, sizeof(reason)-1, cpu_id); - errx(1, "%s", reason); - /* ERESTART means that we need to reboot the guest */ - } else if (errno == ERESTART) { - restart_guest(); - /* Anything else means a bug or incompatible change. */ - } else - err(1, "Running guest failed"); - } -} -/*L:240 - * This is the end of the Launcher. The good news: we are over halfway - * through! The bad news: the most fiendish part of the code still lies ahead - * of us. - * - * Are you ready? Take a deep breath and join me in the core of the Host, in - * "make Host". -:*/ - -static struct option opts[] = { - { "verbose", 0, NULL, 'v' }, - { "tunnet", 1, NULL, 't' }, - { "block", 1, NULL, 'b' }, - { "rng", 0, NULL, 'r' }, - { "initrd", 1, NULL, 'i' }, - { "username", 1, NULL, 'u' }, - { "chroot", 1, NULL, 'c' }, - { NULL }, -}; -static void usage(void) -{ - errx(1, "Usage: lguest [--verbose] " - "[--tunnet=(:|bridge::)\n" - "|--block=|--initrd=]...\n" - " vmlinux [args...]"); -} - -/*L:105 The main routine is where the real work begins: */ -int main(int argc, char *argv[]) -{ - /* Memory, code startpoint and size of the (optional) initrd. */ - unsigned long mem = 0, start, initrd_size = 0; - /* Two temporaries. */ - int i, c; - /* The boot information for the Guest. */ - struct boot_params *boot; - /* If they specify an initrd file to load. */ - const char *initrd_name = NULL; - - /* Password structure for initgroups/setres[gu]id */ - struct passwd *user_details = NULL; - - /* Directory to chroot to */ - char *chroot_path = NULL; - - /* Save the args: we "reboot" by execing ourselves again. */ - main_args = argv; - - /* - * First we initialize the device list. We keep a pointer to the last - * device, and the next interrupt number to use for devices (1: - * remember that 0 is used by the timer). - */ - devices.lastdev = NULL; - devices.next_irq = 1; - - /* We're CPU 0. In fact, that's the only CPU possible right now. */ - cpu_id = 0; - - /* - * We need to know how much memory so we can set up the device - * descriptor and memory pages for the devices as we parse the command - * line. So we quickly look through the arguments to find the amount - * of memory now. - */ - for (i = 1; i < argc; i++) { - if (argv[i][0] != '-') { - mem = atoi(argv[i]) * 1024 * 1024; - /* - * We start by mapping anonymous pages over all of - * guest-physical memory range. This fills it with 0, - * and ensures that the Guest won't be killed when it - * tries to access it. - */ - guest_base = map_zeroed_pages(mem / getpagesize() - + DEVICE_PAGES); - guest_limit = mem; - guest_max = mem + DEVICE_PAGES*getpagesize(); - devices.descpage = get_pages(1); - break; - } - } - - /* The options are fairly straight-forward */ - while ((c = getopt_long(argc, argv, "v", opts, NULL)) != EOF) { - switch (c) { - case 'v': - verbose = true; - break; - case 't': - setup_tun_net(optarg); - break; - case 'b': - setup_block_file(optarg); - break; - case 'r': - setup_rng(); - break; - case 'i': - initrd_name = optarg; - break; - case 'u': - user_details = getpwnam(optarg); - if (!user_details) - err(1, "getpwnam failed, incorrect username?"); - break; - case 'c': - chroot_path = optarg; - break; - default: - warnx("Unknown argument %s", argv[optind]); - usage(); - } - } - /* - * After the other arguments we expect memory and kernel image name, - * followed by command line arguments for the kernel. - */ - if (optind + 2 > argc) - usage(); - - verbose("Guest base is at %p\n", guest_base); - - /* We always have a console device */ - setup_console(); - - /* Now we load the kernel */ - start = load_kernel(open_or_die(argv[optind+1], O_RDONLY)); - - /* Boot information is stashed at physical address 0 */ - boot = from_guest_phys(0); - - /* Map the initrd image if requested (at top of physical memory) */ - if (initrd_name) { - initrd_size = load_initrd(initrd_name, mem); - /* - * These are the location in the Linux boot header where the - * start and size of the initrd are expected to be found. - */ - boot->hdr.ramdisk_image = mem - initrd_size; - boot->hdr.ramdisk_size = initrd_size; - /* The bootloader type 0xFF means "unknown"; that's OK. */ - boot->hdr.type_of_loader = 0xFF; - } - - /* - * The Linux boot header contains an "E820" memory map: ours is a - * simple, single region. - */ - boot->e820_entries = 1; - boot->e820_map[0] = ((struct e820entry) { 0, mem, E820_RAM }); - /* - * The boot header contains a command line pointer: we put the command - * line after the boot header. - */ - boot->hdr.cmd_line_ptr = to_guest_phys(boot + 1); - /* We use a simple helper to copy the arguments separated by spaces. */ - concat((char *)(boot + 1), argv+optind+2); - - /* Set kernel alignment to 16M (CONFIG_PHYSICAL_ALIGN) */ - boot->hdr.kernel_alignment = 0x1000000; - - /* Boot protocol version: 2.07 supports the fields for lguest. */ - boot->hdr.version = 0x207; - - /* The hardware_subarch value of "1" tells the Guest it's an lguest. */ - boot->hdr.hardware_subarch = 1; - - /* Tell the entry path not to try to reload segment registers. */ - boot->hdr.loadflags |= KEEP_SEGMENTS; - - /* We tell the kernel to initialize the Guest. */ - tell_kernel(start); - - /* Ensure that we terminate if a device-servicing child dies. */ - signal(SIGCHLD, kill_launcher); - - /* If we exit via err(), this kills all the threads, restores tty. */ - atexit(cleanup_devices); - - /* If requested, chroot to a directory */ - if (chroot_path) { - if (chroot(chroot_path) != 0) - err(1, "chroot(\"%s\") failed", chroot_path); - - if (chdir("/") != 0) - err(1, "chdir(\"/\") failed"); - - verbose("chroot done\n"); - } - - /* If requested, drop privileges */ - if (user_details) { - uid_t u; - gid_t g; - - u = user_details->pw_uid; - g = user_details->pw_gid; - - if (initgroups(user_details->pw_name, g) != 0) - err(1, "initgroups failed"); - - if (setresgid(g, g, g) != 0) - err(1, "setresgid failed"); - - if (setresuid(u, u, u) != 0) - err(1, "setresuid failed"); - - verbose("Dropping privileges completed\n"); - } - - /* Finally, run the Guest. This doesn't return. */ - run_guest(); -} -/*:*/ - -/*M:999 - * Mastery is done: you now know everything I do. - * - * But surely you have seen code, features and bugs in your wanderings which - * you now yearn to attack? That is the real game, and I look forward to you - * patching and forking lguest into the Your-Name-Here-visor. - * - * Farewell, and good coding! - * Rusty Russell. - */ diff --git a/Documentation/virtual/lguest/lguest.txt b/Documentation/virtual/lguest/lguest.txt deleted file mode 100644 index bff0c554485..00000000000 --- a/Documentation/virtual/lguest/lguest.txt +++ /dev/null @@ -1,129 +0,0 @@ - __ - (___()'`; Rusty's Remarkably Unreliable Guide to Lguest - /, /` - or, A Young Coder's Illustrated Hypervisor - \\"--\\ http://lguest.ozlabs.org - -Lguest is designed to be a minimal 32-bit x86 hypervisor for the Linux kernel, -for Linux developers and users to experiment with virtualization with the -minimum of complexity. Nonetheless, it should have sufficient features to -make it useful for specific tasks, and, of course, you are encouraged to fork -and enhance it (see drivers/lguest/README). - -Features: - -- Kernel module which runs in a normal kernel. -- Simple I/O model for communication. -- Simple program to create new guests. -- Logo contains cute puppies: http://lguest.ozlabs.org - -Developer features: - -- Fun to hack on. -- No ABI: being tied to a specific kernel anyway, you can change anything. -- Many opportunities for improvement or feature implementation. - -Running Lguest: - -- The easiest way to run lguest is to use same kernel as guest and host. - You can configure them differently, but usually it's easiest not to. - - You will need to configure your kernel with the following options: - - "General setup": - "Prompt for development and/or incomplete code/drivers" = Y - (CONFIG_EXPERIMENTAL=y) - - "Processor type and features": - "Paravirtualized guest support" = Y - "Lguest guest support" = Y - "High Memory Support" = off/4GB - "Alignment value to which kernel should be aligned" = 0x100000 - (CONFIG_PARAVIRT=y, CONFIG_LGUEST_GUEST=y, CONFIG_HIGHMEM64G=n and - CONFIG_PHYSICAL_ALIGN=0x100000) - - "Device Drivers": - "Block devices" - "Virtio block driver (EXPERIMENTAL)" = M/Y - "Network device support" - "Universal TUN/TAP device driver support" = M/Y - "Virtio network driver (EXPERIMENTAL)" = M/Y - (CONFIG_VIRTIO_BLK=m, CONFIG_VIRTIO_NET=m and CONFIG_TUN=m) - - "Virtualization" - "Linux hypervisor example code" = M/Y - (CONFIG_LGUEST=m) - -- A tool called "lguest" is available in this directory: type "make" - to build it. If you didn't build your kernel in-tree, use "make - O=". - -- Create or find a root disk image. There are several useful ones - around, such as the xm-test tiny root image at - http://xm-test.xensource.com/ramdisks/initrd-1.1-i386.img - - For more serious work, I usually use a distribution ISO image and - install it under qemu, then make multiple copies: - - dd if=/dev/zero of=rootfile bs=1M count=2048 - qemu -cdrom image.iso -hda rootfile -net user -net nic -boot d - - Make sure that you install a getty on /dev/hvc0 if you want to log in on the - console! - -- "modprobe lg" if you built it as a module. - -- Run an lguest as root: - - Documentation/virtual/lguest/lguest 64 vmlinux --tunnet=192.168.19.1 \ - --block=rootfile root=/dev/vda - - Explanation: - 64: the amount of memory to use, in MB. - - vmlinux: the kernel image found in the top of your build directory. You - can also use a standard bzImage. - - --tunnet=192.168.19.1: configures a "tap" device for networking with this - IP address. - - --block=rootfile: a file or block device which becomes /dev/vda - inside the guest. - - root=/dev/vda: this (and anything else on the command line) are - kernel boot parameters. - -- Configuring networking. I usually have the host masquerade, using - "iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE" and "echo 1 > - /proc/sys/net/ipv4/ip_forward". In this example, I would configure - eth0 inside the guest at 192.168.19.2. - - Another method is to bridge the tap device to an external interface - using --tunnet=bridge:, and perhaps run dhcp on the guest - to obtain an IP address. The bridge needs to be configured first: - this option simply adds the tap interface to it. - - A simple example on my system: - - ifconfig eth0 0.0.0.0 - brctl addbr lg0 - ifconfig lg0 up - brctl addif lg0 eth0 - dhclient lg0 - - Then use --tunnet=bridge:lg0 when launching the guest. - - See: - - http://www.linuxfoundation.org/collaborate/workgroups/networking/bridge - - for general information on how to get bridging to work. - -- Random number generation. Using the --rng option will provide a - /dev/hwrng in the guest that will read from the host's /dev/random. - Use this option in conjunction with rng-tools (see ../hw_random.txt) - to provide entropy to the guest kernel's /dev/random. - -There is a helpful mailing list at http://ozlabs.org/mailman/listinfo/lguest - -Good luck! -Rusty Russell rusty@rustcorp.com.au. diff --git a/drivers/lguest/Makefile b/drivers/lguest/Makefile index 8ac947c7e7c..c4197503900 100644 --- a/drivers/lguest/Makefile +++ b/drivers/lguest/Makefile @@ -18,7 +18,7 @@ Mastery: PREFIX=M Beer: @for f in Preparation Guest Drivers Launcher Host Switcher Mastery; do echo "{==- $$f -==}"; make -s $$f; done; echo "{==-==}" Preparation Preparation! Guest Drivers Launcher Host Switcher Mastery: - @sh ../../Documentation/virtual/lguest/extract $(PREFIX) `find ../../* -name '*.[chS]' -wholename '*lguest*'` + @sh ../../tools/lguest/extract $(PREFIX) `find ../../* -name '*.[chS]' -wholename '*lguest*'` Puppy: @clear @printf " __ \n (___()'\`;\n /, /\`\n \\\\\\\"--\\\\\\ \n" diff --git a/tools/lguest/.gitignore b/tools/lguest/.gitignore new file mode 100644 index 00000000000..115587fd5f6 --- /dev/null +++ b/tools/lguest/.gitignore @@ -0,0 +1 @@ +lguest diff --git a/tools/lguest/Makefile b/tools/lguest/Makefile new file mode 100644 index 00000000000..0ac34206f7a --- /dev/null +++ b/tools/lguest/Makefile @@ -0,0 +1,8 @@ +# This creates the demonstration utility "lguest" which runs a Linux guest. +# Missing headers? Add "-I../../../include -I../../../arch/x86/include" +CFLAGS:=-m32 -Wall -Wmissing-declarations -Wmissing-prototypes -O3 -U_FORTIFY_SOURCE + +all: lguest + +clean: + rm -f lguest diff --git a/tools/lguest/extract b/tools/lguest/extract new file mode 100644 index 00000000000..7730bb6e4b9 --- /dev/null +++ b/tools/lguest/extract @@ -0,0 +1,58 @@ +#! /bin/sh + +set -e + +PREFIX=$1 +shift + +trap 'rm -r $TMPDIR' 0 +TMPDIR=`mktemp -d` + +exec 3>/dev/null +for f; do + while IFS=" +" read -r LINE; do + case "$LINE" in + *$PREFIX:[0-9]*:\**) + NUM=`echo "$LINE" | sed "s/.*$PREFIX:\([0-9]*\).*/\1/"` + if [ -f $TMPDIR/$NUM ]; then + echo "$TMPDIR/$NUM already exits prior to $f" + exit 1 + fi + exec 3>>$TMPDIR/$NUM + echo $f | sed 's,\.\./,,g' > $TMPDIR/.$NUM + /bin/echo "$LINE" | sed -e "s/$PREFIX:[0-9]*//" -e "s/:\*/*/" >&3 + ;; + *$PREFIX:[0-9]*) + NUM=`echo "$LINE" | sed "s/.*$PREFIX:\([0-9]*\).*/\1/"` + if [ -f $TMPDIR/$NUM ]; then + echo "$TMPDIR/$NUM already exits prior to $f" + exit 1 + fi + exec 3>>$TMPDIR/$NUM + echo $f | sed 's,\.\./,,g' > $TMPDIR/.$NUM + /bin/echo "$LINE" | sed "s/$PREFIX:[0-9]*//" >&3 + ;; + *:\**) + /bin/echo "$LINE" | sed -e "s/:\*/*/" -e "s,/\*\*/,," >&3 + echo >&3 + exec 3>/dev/null + ;; + *) + /bin/echo "$LINE" >&3 + ;; + esac + done < $f + echo >&3 + exec 3>/dev/null +done + +LASTFILE="" +for f in $TMPDIR/*; do + if [ "$LASTFILE" != $(cat $TMPDIR/.$(basename $f) ) ]; then + LASTFILE=$(cat $TMPDIR/.$(basename $f) ) + echo "[ $LASTFILE ]" + fi + cat $f +done + diff --git a/tools/lguest/lguest.c b/tools/lguest/lguest.c new file mode 100644 index 00000000000..f759f4f097c --- /dev/null +++ b/tools/lguest/lguest.c @@ -0,0 +1,2065 @@ +/*P:100 + * This is the Launcher code, a simple program which lays out the "physical" + * memory for the new Guest by mapping the kernel image and the virtual + * devices, then opens /dev/lguest to tell the kernel about the Guest and + * control it. +:*/ +#define _LARGEFILE64_SOURCE +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include "../../include/linux/lguest_launcher.h" +/*L:110 + * We can ignore the 43 include files we need for this program, but I do want + * to draw attention to the use of kernel-style types. + * + * As Linus said, "C is a Spartan language, and so should your naming be." I + * like these abbreviations, so we define them here. Note that u64 is always + * unsigned long long, which works on all Linux systems: this means that we can + * use %llu in printf for any u64. + */ +typedef unsigned long long u64; +typedef uint32_t u32; +typedef uint16_t u16; +typedef uint8_t u8; +/*:*/ + +#define BRIDGE_PFX "bridge:" +#ifndef SIOCBRADDIF +#define SIOCBRADDIF 0x89a2 /* add interface to bridge */ +#endif +/* We can have up to 256 pages for devices. */ +#define DEVICE_PAGES 256 +/* This will occupy 3 pages: it must be a power of 2. */ +#define VIRTQUEUE_NUM 256 + +/*L:120 + * verbose is both a global flag and a macro. The C preprocessor allows + * this, and although I wouldn't recommend it, it works quite nicely here. + */ +static bool verbose; +#define verbose(args...) \ + do { if (verbose) printf(args); } while(0) +/*:*/ + +/* The pointer to the start of guest memory. */ +static void *guest_base; +/* The maximum guest physical address allowed, and maximum possible. */ +static unsigned long guest_limit, guest_max; +/* The /dev/lguest file descriptor. */ +static int lguest_fd; + +/* a per-cpu variable indicating whose vcpu is currently running */ +static unsigned int __thread cpu_id; + +/* This is our list of devices. */ +struct device_list { + /* Counter to assign interrupt numbers. */ + unsigned int next_irq; + + /* Counter to print out convenient device numbers. */ + unsigned int device_num; + + /* The descriptor page for the devices. */ + u8 *descpage; + + /* A single linked list of devices. */ + struct device *dev; + /* And a pointer to the last device for easy append. */ + struct device *lastdev; +}; + +/* The list of Guest devices, based on command line arguments. */ +static struct device_list devices; + +/* The device structure describes a single device. */ +struct device { + /* The linked-list pointer. */ + struct device *next; + + /* The device's descriptor, as mapped into the Guest. */ + struct lguest_device_desc *desc; + + /* We can't trust desc values once Guest has booted: we use these. */ + unsigned int feature_len; + unsigned int num_vq; + + /* The name of this device, for --verbose. */ + const char *name; + + /* Any queues attached to this device */ + struct virtqueue *vq; + + /* Is it operational */ + bool running; + + /* Device-specific data. */ + void *priv; +}; + +/* The virtqueue structure describes a queue attached to a device. */ +struct virtqueue { + struct virtqueue *next; + + /* Which device owns me. */ + struct device *dev; + + /* The configuration for this queue. */ + struct lguest_vqconfig config; + + /* The actual ring of buffers. */ + struct vring vring; + + /* Last available index we saw. */ + u16 last_avail_idx; + + /* How many are used since we sent last irq? */ + unsigned int pending_used; + + /* Eventfd where Guest notifications arrive. */ + int eventfd; + + /* Function for the thread which is servicing this virtqueue. */ + void (*service)(struct virtqueue *vq); + pid_t thread; +}; + +/* Remember the arguments to the program so we can "reboot" */ +static char **main_args; + +/* The original tty settings to restore on exit. */ +static struct termios orig_term; + +/* + * We have to be careful with barriers: our devices are all run in separate + * threads and so we need to make sure that changes visible to the Guest happen + * in precise order. + */ +#define wmb() __asm__ __volatile__("" : : : "memory") +#define mb() __asm__ __volatile__("" : : : "memory") + +/* + * Convert an iovec element to the given type. + * + * This is a fairly ugly trick: we need to know the size of the type and + * alignment requirement to check the pointer is kosher. It's also nice to + * have the name of the type in case we report failure. + * + * Typing those three things all the time is cumbersome and error prone, so we + * have a macro which sets them all up and passes to the real function. + */ +#define convert(iov, type) \ + ((type *)_convert((iov), sizeof(type), __alignof__(type), #type)) + +static void *_convert(struct iovec *iov, size_t size, size_t align, + const char *name) +{ + if (iov->iov_len != size) + errx(1, "Bad iovec size %zu for %s", iov->iov_len, name); + if ((unsigned long)iov->iov_base % align != 0) + errx(1, "Bad alignment %p for %s", iov->iov_base, name); + return iov->iov_base; +} + +/* Wrapper for the last available index. Makes it easier to change. */ +#define lg_last_avail(vq) ((vq)->last_avail_idx) + +/* + * The virtio configuration space is defined to be little-endian. x86 is + * little-endian too, but it's nice to be explicit so we have these helpers. + */ +#define cpu_to_le16(v16) (v16) +#define cpu_to_le32(v32) (v32) +#define cpu_to_le64(v64) (v64) +#define le16_to_cpu(v16) (v16) +#define le32_to_cpu(v32) (v32) +#define le64_to_cpu(v64) (v64) + +/* Is this iovec empty? */ +static bool iov_empty(const struct iovec iov[], unsigned int num_iov) +{ + unsigned int i; + + for (i = 0; i < num_iov; i++) + if (iov[i].iov_len) + return false; + return true; +} + +/* Take len bytes from the front of this iovec. */ +static void iov_consume(struct iovec iov[], unsigned num_iov, unsigned len) +{ + unsigned int i; + + for (i = 0; i < num_iov; i++) { + unsigned int used; + + used = iov[i].iov_len < len ? iov[i].iov_len : len; + iov[i].iov_base += used; + iov[i].iov_len -= used; + len -= used; + } + assert(len == 0); +} + +/* The device virtqueue descriptors are followed by feature bitmasks. */ +static u8 *get_feature_bits(struct device *dev) +{ + return (u8 *)(dev->desc + 1) + + dev->num_vq * sizeof(struct lguest_vqconfig); +} + +/*L:100 + * The Launcher code itself takes us out into userspace, that scary place where + * pointers run wild and free! Unfortunately, like most userspace programs, + * it's quite boring (which is why everyone likes to hack on the kernel!). + * Perhaps if you make up an Lguest Drinking Game at this point, it will get + * you through this section. Or, maybe not. + * + * The Launcher sets up a big chunk of memory to be the Guest's "physical" + * memory and stores it in "guest_base". In other words, Guest physical == + * Launcher virtual with an offset. + * + * This can be tough to get your head around, but usually it just means that we + * use these trivial conversion functions when the Guest gives us its + * "physical" addresses: + */ +static void *from_guest_phys(unsigned long addr) +{ + return guest_base + addr; +} + +static unsigned long to_guest_phys(const void *addr) +{ + return (addr - guest_base); +} + +/*L:130 + * Loading the Kernel. + * + * We start with couple of simple helper routines. open_or_die() avoids + * error-checking code cluttering the callers: + */ +static int open_or_die(const char *name, int flags) +{ + int fd = open(name, flags); + if (fd < 0) + err(1, "Failed to open %s", name); + return fd; +} + +/* map_zeroed_pages() takes a number of pages. */ +static void *map_zeroed_pages(unsigned int num) +{ + int fd = open_or_die("/dev/zero", O_RDONLY); + void *addr; + + /* + * We use a private mapping (ie. if we write to the page, it will be + * copied). We allocate an extra two pages PROT_NONE to act as guard + * pages against read/write attempts that exceed allocated space. + */ + addr = mmap(NULL, getpagesize() * (num+2), + PROT_NONE, MAP_PRIVATE, fd, 0); + + if (addr == MAP_FAILED) + err(1, "Mmapping %u pages of /dev/zero", num); + + if (mprotect(addr + getpagesize(), getpagesize() * num, + PROT_READ|PROT_WRITE) == -1) + err(1, "mprotect rw %u pages failed", num); + + /* + * One neat mmap feature is that you can close the fd, and it + * stays mapped. + */ + close(fd); + + /* Return address after PROT_NONE page */ + return addr + getpagesize(); +} + +/* Get some more pages for a device. */ +static void *get_pages(unsigned int num) +{ + void *addr = from_guest_phys(guest_limit); + + guest_limit += num * getpagesize(); + if (guest_limit > guest_max) + errx(1, "Not enough memory for devices"); + return addr; +} + +/* + * This routine is used to load the kernel or initrd. It tries mmap, but if + * that fails (Plan 9's kernel file isn't nicely aligned on page boundaries), + * it falls back to reading the memory in. + */ +static void map_at(int fd, void *addr, unsigned long offset, unsigned long len) +{ + ssize_t r; + + /* + * We map writable even though for some segments are marked read-only. + * The kernel really wants to be writable: it patches its own + * instructions. + * + * MAP_PRIVATE means that the page won't be copied until a write is + * done to it. This allows us to share untouched memory between + * Guests. + */ + if (mmap(addr, len, PROT_READ|PROT_WRITE, + MAP_FIXED|MAP_PRIVATE, fd, offset) != MAP_FAILED) + return; + + /* pread does a seek and a read in one shot: saves a few lines. */ + r = pread(fd, addr, len, offset); + if (r != len) + err(1, "Reading offset %lu len %lu gave %zi", offset, len, r); +} + +/* + * This routine takes an open vmlinux image, which is in ELF, and maps it into + * the Guest memory. ELF = Embedded Linking Format, which is the format used + * by all modern binaries on Linux including the kernel. + * + * The ELF headers give *two* addresses: a physical address, and a virtual + * address. We use the physical address; the Guest will map itself to the + * virtual address. + * + * We return the starting address. + */ +static unsigned long map_elf(int elf_fd, const Elf32_Ehdr *ehdr) +{ + Elf32_Phdr phdr[ehdr->e_phnum]; + unsigned int i; + + /* + * Sanity checks on the main ELF header: an x86 executable with a + * reasonable number of correctly-sized program headers. + */ + if (ehdr->e_type != ET_EXEC + || ehdr->e_machine != EM_386 + || ehdr->e_phentsize != sizeof(Elf32_Phdr) + || ehdr->e_phnum < 1 || ehdr->e_phnum > 65536U/sizeof(Elf32_Phdr)) + errx(1, "Malformed elf header"); + + /* + * An ELF executable contains an ELF header and a number of "program" + * headers which indicate which parts ("segments") of the program to + * load where. + */ + + /* We read in all the program headers at once: */ + if (lseek(elf_fd, ehdr->e_phoff, SEEK_SET) < 0) + err(1, "Seeking to program headers"); + if (read(elf_fd, phdr, sizeof(phdr)) != sizeof(phdr)) + err(1, "Reading program headers"); + + /* + * Try all the headers: there are usually only three. A read-only one, + * a read-write one, and a "note" section which we don't load. + */ + for (i = 0; i < ehdr->e_phnum; i++) { + /* If this isn't a loadable segment, we ignore it */ + if (phdr[i].p_type != PT_LOAD) + continue; + + verbose("Section %i: size %i addr %p\n", + i, phdr[i].p_memsz, (void *)phdr[i].p_paddr); + + /* We map this section of the file at its physical address. */ + map_at(elf_fd, from_guest_phys(phdr[i].p_paddr), + phdr[i].p_offset, phdr[i].p_filesz); + } + + /* The entry point is given in the ELF header. */ + return ehdr->e_entry; +} + +/*L:150 + * A bzImage, unlike an ELF file, is not meant to be loaded. You're supposed + * to jump into it and it will unpack itself. We used to have to perform some + * hairy magic because the unpacking code scared me. + * + * Fortunately, Jeremy Fitzhardinge convinced me it wasn't that hard and wrote + * a small patch to jump over the tricky bits in the Guest, so now we just read + * the funky header so we know where in the file to load, and away we go! + */ +static unsigned long load_bzimage(int fd) +{ + struct boot_params boot; + int r; + /* Modern bzImages get loaded at 1M. */ + void *p = from_guest_phys(0x100000); + + /* + * Go back to the start of the file and read the header. It should be + * a Linux boot header (see Documentation/x86/boot.txt) + */ + lseek(fd, 0, SEEK_SET); + read(fd, &boot, sizeof(boot)); + + /* Inside the setup_hdr, we expect the magic "HdrS" */ + if (memcmp(&boot.hdr.header, "HdrS", 4) != 0) + errx(1, "This doesn't look like a bzImage to me"); + + /* Skip over the extra sectors of the header. */ + lseek(fd, (boot.hdr.setup_sects+1) * 512, SEEK_SET); + + /* Now read everything into memory. in nice big chunks. */ + while ((r = read(fd, p, 65536)) > 0) + p += r; + + /* Finally, code32_start tells us where to enter the kernel. */ + return boot.hdr.code32_start; +} + +/*L:140 + * Loading the kernel is easy when it's a "vmlinux", but most kernels + * come wrapped up in the self-decompressing "bzImage" format. With a little + * work, we can load those, too. + */ +static unsigned long load_kernel(int fd) +{ + Elf32_Ehdr hdr; + + /* Read in the first few bytes. */ + if (read(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) + err(1, "Reading kernel"); + + /* If it's an ELF file, it starts with "\177ELF" */ + if (memcmp(hdr.e_ident, ELFMAG, SELFMAG) == 0) + return map_elf(fd, &hdr); + + /* Otherwise we assume it's a bzImage, and try to load it. */ + return load_bzimage(fd); +} + +/* + * This is a trivial little helper to align pages. Andi Kleen hated it because + * it calls getpagesize() twice: "it's dumb code." + * + * Kernel guys get really het up about optimization, even when it's not + * necessary. I leave this code as a reaction against that. + */ +static inline unsigned long page_align(unsigned long addr) +{ + /* Add upwards and truncate downwards. */ + return ((addr + getpagesize()-1) & ~(getpagesize()-1)); +} + +/*L:180 + * An "initial ram disk" is a disk image loaded into memory along with the + * kernel which the kernel can use to boot from without needing any drivers. + * Most distributions now use this as standard: the initrd contains the code to + * load the appropriate driver modules for the current machine. + * + * Importantly, James Morris works for RedHat, and Fedora uses initrds for its + * kernels. He sent me this (and tells me when I break it). + */ +static unsigned long load_initrd(const char *name, unsigned long mem) +{ + int ifd; + struct stat st; + unsigned long len; + + ifd = open_or_die(name, O_RDONLY); + /* fstat() is needed to get the file size. */ + if (fstat(ifd, &st) < 0) + err(1, "fstat() on initrd '%s'", name); + + /* + * We map the initrd at the top of memory, but mmap wants it to be + * page-aligned, so we round the size up for that. + */ + len = page_align(st.st_size); + map_at(ifd, from_guest_phys(mem - len), 0, st.st_size); + /* + * Once a file is mapped, you can close the file descriptor. It's a + * little odd, but quite useful. + */ + close(ifd); + verbose("mapped initrd %s size=%lu @ %p\n", name, len, (void*)mem-len); + + /* We return the initrd size. */ + return len; +} +/*:*/ + +/* + * Simple routine to roll all the commandline arguments together with spaces + * between them. + */ +static void concat(char *dst, char *args[]) +{ + unsigned int i, len = 0; + + for (i = 0; args[i]; i++) { + if (i) { + strcat(dst+len, " "); + len++; + } + strcpy(dst+len, args[i]); + len += strlen(args[i]); + } + /* In case it's empty. */ + dst[len] = '\0'; +} + +/*L:185 + * This is where we actually tell the kernel to initialize the Guest. We + * saw the arguments it expects when we looked at initialize() in lguest_user.c: + * the base of Guest "physical" memory, the top physical page to allow and the + * entry point for the Guest. + */ +static void tell_kernel(unsigned long start) +{ + unsigned long args[] = { LHREQ_INITIALIZE, + (unsigned long)guest_base, + guest_limit / getpagesize(), start }; + verbose("Guest: %p - %p (%#lx)\n", + guest_base, guest_base + guest_limit, guest_limit); + lguest_fd = open_or_die("/dev/lguest", O_RDWR); + if (write(lguest_fd, args, sizeof(args)) < 0) + err(1, "Writing to /dev/lguest"); +} +/*:*/ + +/*L:200 + * Device Handling. + * + * When the Guest gives us a buffer, it sends an array of addresses and sizes. + * We need to make sure it's not trying to reach into the Launcher itself, so + * we have a convenient routine which checks it and exits with an error message + * if something funny is going on: + */ +static void *_check_pointer(unsigned long addr, unsigned int size, + unsigned int line) +{ + /* + * Check if the requested address and size exceeds the allocated memory, + * or addr + size wraps around. + */ + if ((addr + size) > guest_limit || (addr + size) < addr) + errx(1, "%s:%i: Invalid address %#lx", __FILE__, line, addr); + /* + * We return a pointer for the caller's convenience, now we know it's + * safe to use. + */ + return from_guest_phys(addr); +} +/* A macro which transparently hands the line number to the real function. */ +#define check_pointer(addr,size) _check_pointer(addr, size, __LINE__) + +/* + * Each buffer in the virtqueues is actually a chain of descriptors. This + * function returns the next descriptor in the chain, or vq->vring.num if we're + * at the end. + */ +static unsigned next_desc(struct vring_desc *desc, + unsigned int i, unsigned int max) +{ + unsigned int next; + + /* If this descriptor says it doesn't chain, we're done. */ + if (!(desc[i].flags & VRING_DESC_F_NEXT)) + return max; + + /* Check they're not leading us off end of descriptors. */ + next = desc[i].next; + /* Make sure compiler knows to grab that: we don't want it changing! */ + wmb(); + + if (next >= max) + errx(1, "Desc next is %u", next); + + return next; +} + +/* + * This actually sends the interrupt for this virtqueue, if we've used a + * buffer. + */ +static void trigger_irq(struct virtqueue *vq) +{ + unsigned long buf[] = { LHREQ_IRQ, vq->config.irq }; + + /* Don't inform them if nothing used. */ + if (!vq->pending_used) + return; + vq->pending_used = 0; + + /* If they don't want an interrupt, don't send one... */ + if (vq->vring.avail->flags & VRING_AVAIL_F_NO_INTERRUPT) { + return; + } + + /* Send the Guest an interrupt tell them we used something up. */ + if (write(lguest_fd, buf, sizeof(buf)) != 0) + err(1, "Triggering irq %i", vq->config.irq); +} + +/* + * This looks in the virtqueue for the first available buffer, and converts + * it to an iovec for convenient access. Since descriptors consist of some + * number of output then some number of input descriptors, it's actually two + * iovecs, but we pack them into one and note how many of each there were. + * + * This function waits if necessary, and returns the descriptor number found. + */ +static unsigned wait_for_vq_desc(struct virtqueue *vq, + struct iovec iov[], + unsigned int *out_num, unsigned int *in_num) +{ + unsigned int i, head, max; + struct vring_desc *desc; + u16 last_avail = lg_last_avail(vq); + + /* There's nothing available? */ + while (last_avail == vq->vring.avail->idx) { + u64 event; + + /* + * Since we're about to sleep, now is a good time to tell the + * Guest about what we've used up to now. + */ + trigger_irq(vq); + + /* OK, now we need to know about added descriptors. */ + vq->vring.used->flags &= ~VRING_USED_F_NO_NOTIFY; + + /* + * They could have slipped one in as we were doing that: make + * sure it's written, then check again. + */ + mb(); + if (last_avail != vq->vring.avail->idx) { + vq->vring.used->flags |= VRING_USED_F_NO_NOTIFY; + break; + } + + /* Nothing new? Wait for eventfd to tell us they refilled. */ + if (read(vq->eventfd, &event, sizeof(event)) != sizeof(event)) + errx(1, "Event read failed?"); + + /* We don't need to be notified again. */ + vq->vring.used->flags |= VRING_USED_F_NO_NOTIFY; + } + + /* Check it isn't doing very strange things with descriptor numbers. */ + if ((u16)(vq->vring.avail->idx - last_avail) > vq->vring.num) + errx(1, "Guest moved used index from %u to %u", + last_avail, vq->vring.avail->idx); + + /* + * Grab the next descriptor number they're advertising, and increment + * the index we've seen. + */ + head = vq->vring.avail->ring[last_avail % vq->vring.num]; + lg_last_avail(vq)++; + + /* If their number is silly, that's a fatal mistake. */ + if (head >= vq->vring.num) + errx(1, "Guest says index %u is available", head); + + /* When we start there are none of either input nor output. */ + *out_num = *in_num = 0; + + max = vq->vring.num; + desc = vq->vring.desc; + i = head; + + /* + * If this is an indirect entry, then this buffer contains a descriptor + * table which we handle as if it's any normal descriptor chain. + */ + if (desc[i].flags & VRING_DESC_F_INDIRECT) { + if (desc[i].len % sizeof(struct vring_desc)) + errx(1, "Invalid size for indirect buffer table"); + + max = desc[i].len / sizeof(struct vring_desc); + desc = check_pointer(desc[i].addr, desc[i].len); + i = 0; + } + + do { + /* Grab the first descriptor, and check it's OK. */ + iov[*out_num + *in_num].iov_len = desc[i].len; + iov[*out_num + *in_num].iov_base + = check_pointer(desc[i].addr, desc[i].len); + /* If this is an input descriptor, increment that count. */ + if (desc[i].flags & VRING_DESC_F_WRITE) + (*in_num)++; + else { + /* + * If it's an output descriptor, they're all supposed + * to come before any input descriptors. + */ + if (*in_num) + errx(1, "Descriptor has out after in"); + (*out_num)++; + } + + /* If we've got too many, that implies a descriptor loop. */ + if (*out_num + *in_num > max) + errx(1, "Looped descriptor"); + } while ((i = next_desc(desc, i, max)) != max); + + return head; +} + +/* + * After we've used one of their buffers, we tell the Guest about it. Sometime + * later we'll want to send them an interrupt using trigger_irq(); note that + * wait_for_vq_desc() does that for us if it has to wait. + */ +static void add_used(struct virtqueue *vq, unsigned int head, int len) +{ + struct vring_used_elem *used; + + /* + * The virtqueue contains a ring of used buffers. Get a pointer to the + * next entry in that used ring. + */ + used = &vq->vring.used->ring[vq->vring.used->idx % vq->vring.num]; + used->id = head; + used->len = len; + /* Make sure buffer is written before we update index. */ + wmb(); + vq->vring.used->idx++; + vq->pending_used++; +} + +/* And here's the combo meal deal. Supersize me! */ +static void add_used_and_trigger(struct virtqueue *vq, unsigned head, int len) +{ + add_used(vq, head, len); + trigger_irq(vq); +} + +/* + * The Console + * + * We associate some data with the console for our exit hack. + */ +struct console_abort { + /* How many times have they hit ^C? */ + int count; + /* When did they start? */ + struct timeval start; +}; + +/* This is the routine which handles console input (ie. stdin). */ +static void console_input(struct virtqueue *vq) +{ + int len; + unsigned int head, in_num, out_num; + struct console_abort *abort = vq->dev->priv; + struct iovec iov[vq->vring.num]; + + /* Make sure there's a descriptor available. */ + head = wait_for_vq_desc(vq, iov, &out_num, &in_num); + if (out_num) + errx(1, "Output buffers in console in queue?"); + + /* Read into it. This is where we usually wait. */ + len = readv(STDIN_FILENO, iov, in_num); + if (len <= 0) { + /* Ran out of input? */ + warnx("Failed to get console input, ignoring console."); + /* + * For simplicity, dying threads kill the whole Launcher. So + * just nap here. + */ + for (;;) + pause(); + } + + /* Tell the Guest we used a buffer. */ + add_used_and_trigger(vq, head, len); + + /* + * Three ^C within one second? Exit. + * + * This is such a hack, but works surprisingly well. Each ^C has to + * be in a buffer by itself, so they can't be too fast. But we check + * that we get three within about a second, so they can't be too + * slow. + */ + if (len != 1 || ((char *)iov[0].iov_base)[0] != 3) { + abort->count = 0; + return; + } + + abort->count++; + if (abort->count == 1) + gettimeofday(&abort->start, NULL); + else if (abort->count == 3) { + struct timeval now; + gettimeofday(&now, NULL); + /* Kill all Launcher processes with SIGINT, like normal ^C */ + if (now.tv_sec <= abort->start.tv_sec+1) + kill(0, SIGINT); + abort->count = 0; + } +} + +/* This is the routine which handles console output (ie. stdout). */ +static void console_output(struct virtqueue *vq) +{ + unsigned int head, out, in; + struct iovec iov[vq->vring.num]; + + /* We usually wait in here, for the Guest to give us something. */ + head = wait_for_vq_desc(vq, iov, &out, &in); + if (in) + errx(1, "Input buffers in console output queue?"); + + /* writev can return a partial write, so we loop here. */ + while (!iov_empty(iov, out)) { + int len = writev(STDOUT_FILENO, iov, out); + if (len <= 0) { + warn("Write to stdout gave %i (%d)", len, errno); + break; + } + iov_consume(iov, out, len); + } + + /* + * We're finished with that buffer: if we're going to sleep, + * wait_for_vq_desc() will prod the Guest with an interrupt. + */ + add_used(vq, head, 0); +} + +/* + * The Network + * + * Handling output for network is also simple: we get all the output buffers + * and write them to /dev/net/tun. + */ +struct net_info { + int tunfd; +}; + +static void net_output(struct virtqueue *vq) +{ + struct net_info *net_info = vq->dev->priv; + unsigned int head, out, in; + struct iovec iov[vq->vring.num]; + + /* We usually wait in here for the Guest to give us a packet. */ + head = wait_for_vq_desc(vq, iov, &out, &in); + if (in) + errx(1, "Input buffers in net output queue?"); + /* + * Send the whole thing through to /dev/net/tun. It expects the exact + * same format: what a coincidence! + */ + if (writev(net_info->tunfd, iov, out) < 0) + warnx("Write to tun failed (%d)?", errno); + + /* + * Done with that one; wait_for_vq_desc() will send the interrupt if + * all packets are processed. + */ + add_used(vq, head, 0); +} + +/* + * Handling network input is a bit trickier, because I've tried to optimize it. + * + * First we have a helper routine which tells is if from this file descriptor + * (ie. the /dev/net/tun device) will block: + */ +static bool will_block(int fd) +{ + fd_set fdset; + struct timeval zero = { 0, 0 }; + FD_ZERO(&fdset); + FD_SET(fd, &fdset); + return select(fd+1, &fdset, NULL, NULL, &zero) != 1; +} + +/* + * This handles packets coming in from the tun device to our Guest. Like all + * service routines, it gets called again as soon as it returns, so you don't + * see a while(1) loop here. + */ +static void net_input(struct virtqueue *vq) +{ + int len; + unsigned int head, out, in; + struct iovec iov[vq->vring.num]; + struct net_info *net_info = vq->dev->priv; + + /* + * Get a descriptor to write an incoming packet into. This will also + * send an interrupt if they're out of descriptors. + */ + head = wait_for_vq_desc(vq, iov, &out, &in); + if (out) + errx(1, "Output buffers in net input queue?"); + + /* + * If it looks like we'll block reading from the tun device, send them + * an interrupt. + */ + if (vq->pending_used && will_block(net_info->tunfd)) + trigger_irq(vq); + + /* + * Read in the packet. This is where we normally wait (when there's no + * incoming network traffic). + */ + len = readv(net_info->tunfd, iov, in); + if (len <= 0) + warn("Failed to read from tun (%d).", errno); + + /* + * Mark that packet buffer as used, but don't interrupt here. We want + * to wait until we've done as much work as we can. + */ + add_used(vq, head, len); +} +/*:*/ + +/* This is the helper to create threads: run the service routine in a loop. */ +static int do_thread(void *_vq) +{ + struct virtqueue *vq = _vq; + + for (;;) + vq->service(vq); + return 0; +} + +/* + * When a child dies, we kill our entire process group with SIGTERM. This + * also has the side effect that the shell restores the console for us! + */ +static void kill_launcher(int signal) +{ + kill(0, SIGTERM); +} + +static void reset_device(struct device *dev) +{ + struct virtqueue *vq; + + verbose("Resetting device %s\n", dev->name); + + /* Clear any features they've acked. */ + memset(get_feature_bits(dev) + dev->feature_len, 0, dev->feature_len); + + /* We're going to be explicitly killing threads, so ignore them. */ + signal(SIGCHLD, SIG_IGN); + + /* Zero out the virtqueues, get rid of their threads */ + for (vq = dev->vq; vq; vq = vq->next) { + if (vq->thread != (pid_t)-1) { + kill(vq->thread, SIGTERM); + waitpid(vq->thread, NULL, 0); + vq->thread = (pid_t)-1; + } + memset(vq->vring.desc, 0, + vring_size(vq->config.num, LGUEST_VRING_ALIGN)); + lg_last_avail(vq) = 0; + } + dev->running = false; + + /* Now we care if threads die. */ + signal(SIGCHLD, (void *)kill_launcher); +} + +/*L:216 + * This actually creates the thread which services the virtqueue for a device. + */ +static void create_thread(struct virtqueue *vq) +{ + /* + * Create stack for thread. Since the stack grows upwards, we point + * the stack pointer to the end of this region. + */ + char *stack = malloc(32768); + unsigned long args[] = { LHREQ_EVENTFD, + vq->config.pfn*getpagesize(), 0 }; + + /* Create a zero-initialized eventfd. */ + vq->eventfd = eventfd(0, 0); + if (vq->eventfd < 0) + err(1, "Creating eventfd"); + args[2] = vq->eventfd; + + /* + * Attach an eventfd to this virtqueue: it will go off when the Guest + * does an LHCALL_NOTIFY for this vq. + */ + if (write(lguest_fd, &args, sizeof(args)) != 0) + err(1, "Attaching eventfd"); + + /* + * CLONE_VM: because it has to access the Guest memory, and SIGCHLD so + * we get a signal if it dies. + */ + vq->thread = clone(do_thread, stack + 32768, CLONE_VM | SIGCHLD, vq); + if (vq->thread == (pid_t)-1) + err(1, "Creating clone"); + + /* We close our local copy now the child has it. */ + close(vq->eventfd); +} + +static void start_device(struct device *dev) +{ + unsigned int i; + struct virtqueue *vq; + + verbose("Device %s OK: offered", dev->name); + for (i = 0; i < dev->feature_len; i++) + verbose(" %02x", get_feature_bits(dev)[i]); + verbose(", accepted"); + for (i = 0; i < dev->feature_len; i++) + verbose(" %02x", get_feature_bits(dev) + [dev->feature_len+i]); + + for (vq = dev->vq; vq; vq = vq->next) { + if (vq->service) + create_thread(vq); + } + dev->running = true; +} + +static void cleanup_devices(void) +{ + struct device *dev; + + for (dev = devices.dev; dev; dev = dev->next) + reset_device(dev); + + /* If we saved off the original terminal settings, restore them now. */ + if (orig_term.c_lflag & (ISIG|ICANON|ECHO)) + tcsetattr(STDIN_FILENO, TCSANOW, &orig_term); +} + +/* When the Guest tells us they updated the status field, we handle it. */ +static void update_device_status(struct device *dev) +{ + /* A zero status is a reset, otherwise it's a set of flags. */ + if (dev->desc->status == 0) + reset_device(dev); + else if (dev->desc->status & VIRTIO_CONFIG_S_FAILED) { + warnx("Device %s configuration FAILED", dev->name); + if (dev->running) + reset_device(dev); + } else { + if (dev->running) + err(1, "Device %s features finalized twice", dev->name); + start_device(dev); + } +} + +/*L:215 + * This is the generic routine we call when the Guest uses LHCALL_NOTIFY. In + * particular, it's used to notify us of device status changes during boot. + */ +static void handle_output(unsigned long addr) +{ + struct device *i; + + /* Check each device. */ + for (i = devices.dev; i; i = i->next) { + struct virtqueue *vq; + + /* + * Notifications to device descriptors mean they updated the + * device status. + */ + if (from_guest_phys(addr) == i->desc) { + update_device_status(i); + return; + } + + /* Devices should not be used before features are finalized. */ + for (vq = i->vq; vq; vq = vq->next) { + if (addr != vq->config.pfn*getpagesize()) + continue; + errx(1, "Notification on %s before setup!", i->name); + } + } + + /* + * Early console write is done using notify on a nul-terminated string + * in Guest memory. It's also great for hacking debugging messages + * into a Guest. + */ + if (addr >= guest_limit) + errx(1, "Bad NOTIFY %#lx", addr); + + write(STDOUT_FILENO, from_guest_phys(addr), + strnlen(from_guest_phys(addr), guest_limit - addr)); +} + +/*L:190 + * Device Setup + * + * All devices need a descriptor so the Guest knows it exists, and a "struct + * device" so the Launcher can keep track of it. We have common helper + * routines to allocate and manage them. + */ + +/* + * The layout of the device page is a "struct lguest_device_desc" followed by a + * number of virtqueue descriptors, then two sets of feature bits, then an + * array of configuration bytes. This routine returns the configuration + * pointer. + */ +static u8 *device_config(const struct device *dev) +{ + return (void *)(dev->desc + 1) + + dev->num_vq * sizeof(struct lguest_vqconfig) + + dev->feature_len * 2; +} + +/* + * This routine allocates a new "struct lguest_device_desc" from descriptor + * table page just above the Guest's normal memory. It returns a pointer to + * that descriptor. + */ +static struct lguest_device_desc *new_dev_desc(u16 type) +{ + struct lguest_device_desc d = { .type = type }; + void *p; + + /* Figure out where the next device config is, based on the last one. */ + if (devices.lastdev) + p = device_config(devices.lastdev) + + devices.lastdev->desc->config_len; + else + p = devices.descpage; + + /* We only have one page for all the descriptors. */ + if (p + sizeof(d) > (void *)devices.descpage + getpagesize()) + errx(1, "Too many devices"); + + /* p might not be aligned, so we memcpy in. */ + return memcpy(p, &d, sizeof(d)); +} + +/* + * Each device descriptor is followed by the description of its virtqueues. We + * specify how many descriptors the virtqueue is to have. + */ +static void add_virtqueue(struct device *dev, unsigned int num_descs, + void (*service)(struct virtqueue *)) +{ + unsigned int pages; + struct virtqueue **i, *vq = malloc(sizeof(*vq)); + void *p; + + /* First we need some memory for this virtqueue. */ + pages = (vring_size(num_descs, LGUEST_VRING_ALIGN) + getpagesize() - 1) + / getpagesize(); + p = get_pages(pages); + + /* Initialize the virtqueue */ + vq->next = NULL; + vq->last_avail_idx = 0; + vq->dev = dev; + + /* + * This is the routine the service thread will run, and its Process ID + * once it's running. + */ + vq->service = service; + vq->thread = (pid_t)-1; + + /* Initialize the configuration. */ + vq->config.num = num_descs; + vq->config.irq = devices.next_irq++; + vq->config.pfn = to_guest_phys(p) / getpagesize(); + + /* Initialize the vring. */ + vring_init(&vq->vring, num_descs, p, LGUEST_VRING_ALIGN); + + /* + * Append virtqueue to this device's descriptor. We use + * device_config() to get the end of the device's current virtqueues; + * we check that we haven't added any config or feature information + * yet, otherwise we'd be overwriting them. + */ + assert(dev->desc->config_len == 0 && dev->desc->feature_len == 0); + memcpy(device_config(dev), &vq->config, sizeof(vq->config)); + dev->num_vq++; + dev->desc->num_vq++; + + verbose("Virtqueue page %#lx\n", to_guest_phys(p)); + + /* + * Add to tail of list, so dev->vq is first vq, dev->vq->next is + * second. + */ + for (i = &dev->vq; *i; i = &(*i)->next); + *i = vq; +} + +/* + * The first half of the feature bitmask is for us to advertise features. The + * second half is for the Guest to accept features. + */ +static void add_feature(struct device *dev, unsigned bit) +{ + u8 *features = get_feature_bits(dev); + + /* We can't extend the feature bits once we've added config bytes */ + if (dev->desc->feature_len <= bit / CHAR_BIT) { + assert(dev->desc->config_len == 0); + dev->feature_len = dev->desc->feature_len = (bit/CHAR_BIT) + 1; + } + + features[bit / CHAR_BIT] |= (1 << (bit % CHAR_BIT)); +} + +/* + * This routine sets the configuration fields for an existing device's + * descriptor. It only works for the last device, but that's OK because that's + * how we use it. + */ +static void set_config(struct device *dev, unsigned len, const void *conf) +{ + /* Check we haven't overflowed our single page. */ + if (device_config(dev) + len > devices.descpage + getpagesize()) + errx(1, "Too many devices"); + + /* Copy in the config information, and store the length. */ + memcpy(device_config(dev), conf, len); + dev->desc->config_len = len; + + /* Size must fit in config_len field (8 bits)! */ + assert(dev->desc->config_len == len); +} + +/* + * This routine does all the creation and setup of a new device, including + * calling new_dev_desc() to allocate the descriptor and device memory. We + * don't actually start the service threads until later. + * + * See what I mean about userspace being boring? + */ +static struct device *new_device(const char *name, u16 type) +{ + struct device *dev = malloc(sizeof(*dev)); + + /* Now we populate the fields one at a time. */ + dev->desc = new_dev_desc(type); + dev->name = name; + dev->vq = NULL; + dev->feature_len = 0; + dev->num_vq = 0; + dev->running = false; + + /* + * Append to device list. Prepending to a single-linked list is + * easier, but the user expects the devices to be arranged on the bus + * in command-line order. The first network device on the command line + * is eth0, the first block device /dev/vda, etc. + */ + if (devices.lastdev) + devices.lastdev->next = dev; + else + devices.dev = dev; + devices.lastdev = dev; + + return dev; +} + +/* + * Our first setup routine is the console. It's a fairly simple device, but + * UNIX tty handling makes it uglier than it could be. + */ +static void setup_console(void) +{ + struct device *dev; + + /* If we can save the initial standard input settings... */ + if (tcgetattr(STDIN_FILENO, &orig_term) == 0) { + struct termios term = orig_term; + /* + * Then we turn off echo, line buffering and ^C etc: We want a + * raw input stream to the Guest. + */ + term.c_lflag &= ~(ISIG|ICANON|ECHO); + tcsetattr(STDIN_FILENO, TCSANOW, &term); + } + + dev = new_device("console", VIRTIO_ID_CONSOLE); + + /* We store the console state in dev->priv, and initialize it. */ + dev->priv = malloc(sizeof(struct console_abort)); + ((struct console_abort *)dev->priv)->count = 0; + + /* + * The console needs two virtqueues: the input then the output. When + * they put something the input queue, we make sure we're listening to + * stdin. When they put something in the output queue, we write it to + * stdout. + */ + add_virtqueue(dev, VIRTQUEUE_NUM, console_input); + add_virtqueue(dev, VIRTQUEUE_NUM, console_output); + + verbose("device %u: console\n", ++devices.device_num); +} +/*:*/ + +/*M:010 + * Inter-guest networking is an interesting area. Simplest is to have a + * --sharenet= option which opens or creates a named pipe. This can be + * used to send packets to another guest in a 1:1 manner. + * + * More sophisticated is to use one of the tools developed for project like UML + * to do networking. + * + * Faster is to do virtio bonding in kernel. Doing this 1:1 would be + * completely generic ("here's my vring, attach to your vring") and would work + * for any traffic. Of course, namespace and permissions issues need to be + * dealt with. A more sophisticated "multi-channel" virtio_net.c could hide + * multiple inter-guest channels behind one interface, although it would + * require some manner of hotplugging new virtio channels. + * + * Finally, we could use a virtio network switch in the kernel, ie. vhost. +:*/ + +static u32 str2ip(const char *ipaddr) +{ + unsigned int b[4]; + + if (sscanf(ipaddr, "%u.%u.%u.%u", &b[0], &b[1], &b[2], &b[3]) != 4) + errx(1, "Failed to parse IP address '%s'", ipaddr); + return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3]; +} + +static void str2mac(const char *macaddr, unsigned char mac[6]) +{ + unsigned int m[6]; + if (sscanf(macaddr, "%02x:%02x:%02x:%02x:%02x:%02x", + &m[0], &m[1], &m[2], &m[3], &m[4], &m[5]) != 6) + errx(1, "Failed to parse mac address '%s'", macaddr); + mac[0] = m[0]; + mac[1] = m[1]; + mac[2] = m[2]; + mac[3] = m[3]; + mac[4] = m[4]; + mac[5] = m[5]; +} + +/* + * This code is "adapted" from libbridge: it attaches the Host end of the + * network device to the bridge device specified by the command line. + * + * This is yet another James Morris contribution (I'm an IP-level guy, so I + * dislike bridging), and I just try not to break it. + */ +static void add_to_bridge(int fd, const char *if_name, const char *br_name) +{ + int ifidx; + struct ifreq ifr; + + if (!*br_name) + errx(1, "must specify bridge name"); + + ifidx = if_nametoindex(if_name); + if (!ifidx) + errx(1, "interface %s does not exist!", if_name); + + strncpy(ifr.ifr_name, br_name, IFNAMSIZ); + ifr.ifr_name[IFNAMSIZ-1] = '\0'; + ifr.ifr_ifindex = ifidx; + if (ioctl(fd, SIOCBRADDIF, &ifr) < 0) + err(1, "can't add %s to bridge %s", if_name, br_name); +} + +/* + * This sets up the Host end of the network device with an IP address, brings + * it up so packets will flow, the copies the MAC address into the hwaddr + * pointer. + */ +static void configure_device(int fd, const char *tapif, u32 ipaddr) +{ + struct ifreq ifr; + struct sockaddr_in sin; + + memset(&ifr, 0, sizeof(ifr)); + strcpy(ifr.ifr_name, tapif); + + /* Don't read these incantations. Just cut & paste them like I did! */ + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = htonl(ipaddr); + memcpy(&ifr.ifr_addr, &sin, sizeof(sin)); + if (ioctl(fd, SIOCSIFADDR, &ifr) != 0) + err(1, "Setting %s interface address", tapif); + ifr.ifr_flags = IFF_UP; + if (ioctl(fd, SIOCSIFFLAGS, &ifr) != 0) + err(1, "Bringing interface %s up", tapif); +} + +static int get_tun_device(char tapif[IFNAMSIZ]) +{ + struct ifreq ifr; + int netfd; + + /* Start with this zeroed. Messy but sure. */ + memset(&ifr, 0, sizeof(ifr)); + + /* + * We open the /dev/net/tun device and tell it we want a tap device. A + * tap device is like a tun device, only somehow different. To tell + * the truth, I completely blundered my way through this code, but it + * works now! + */ + netfd = open_or_die("/dev/net/tun", O_RDWR); + ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_VNET_HDR; + strcpy(ifr.ifr_name, "tap%d"); + if (ioctl(netfd, TUNSETIFF, &ifr) != 0) + err(1, "configuring /dev/net/tun"); + + if (ioctl(netfd, TUNSETOFFLOAD, + TUN_F_CSUM|TUN_F_TSO4|TUN_F_TSO6|TUN_F_TSO_ECN) != 0) + err(1, "Could not set features for tun device"); + + /* + * We don't need checksums calculated for packets coming in this + * device: trust us! + */ + ioctl(netfd, TUNSETNOCSUM, 1); + + memcpy(tapif, ifr.ifr_name, IFNAMSIZ); + return netfd; +} + +/*L:195 + * Our network is a Host<->Guest network. This can either use bridging or + * routing, but the principle is the same: it uses the "tun" device to inject + * packets into the Host as if they came in from a normal network card. We + * just shunt packets between the Guest and the tun device. + */ +static void setup_tun_net(char *arg) +{ + struct device *dev; + struct net_info *net_info = malloc(sizeof(*net_info)); + int ipfd; + u32 ip = INADDR_ANY; + bool bridging = false; + char tapif[IFNAMSIZ], *p; + struct virtio_net_config conf; + + net_info->tunfd = get_tun_device(tapif); + + /* First we create a new network device. */ + dev = new_device("net", VIRTIO_ID_NET); + dev->priv = net_info; + + /* Network devices need a recv and a send queue, just like console. */ + add_virtqueue(dev, VIRTQUEUE_NUM, net_input); + add_virtqueue(dev, VIRTQUEUE_NUM, net_output); + + /* + * We need a socket to perform the magic network ioctls to bring up the + * tap interface, connect to the bridge etc. Any socket will do! + */ + ipfd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP); + if (ipfd < 0) + err(1, "opening IP socket"); + + /* If the command line was --tunnet=bridge: do bridging. */ + if (!strncmp(BRIDGE_PFX, arg, strlen(BRIDGE_PFX))) { + arg += strlen(BRIDGE_PFX); + bridging = true; + } + + /* A mac address may follow the bridge name or IP address */ + p = strchr(arg, ':'); + if (p) { + str2mac(p+1, conf.mac); + add_feature(dev, VIRTIO_NET_F_MAC); + *p = '\0'; + } + + /* arg is now either an IP address or a bridge name */ + if (bridging) + add_to_bridge(ipfd, tapif, arg); + else + ip = str2ip(arg); + + /* Set up the tun device. */ + configure_device(ipfd, tapif, ip); + + /* Expect Guest to handle everything except UFO */ + add_feature(dev, VIRTIO_NET_F_CSUM); + add_feature(dev, VIRTIO_NET_F_GUEST_CSUM); + add_feature(dev, VIRTIO_NET_F_GUEST_TSO4); + add_feature(dev, VIRTIO_NET_F_GUEST_TSO6); + add_feature(dev, VIRTIO_NET_F_GUEST_ECN); + add_feature(dev, VIRTIO_NET_F_HOST_TSO4); + add_feature(dev, VIRTIO_NET_F_HOST_TSO6); + add_feature(dev, VIRTIO_NET_F_HOST_ECN); + /* We handle indirect ring entries */ + add_feature(dev, VIRTIO_RING_F_INDIRECT_DESC); + set_config(dev, sizeof(conf), &conf); + + /* We don't need the socket any more; setup is done. */ + close(ipfd); + + devices.device_num++; + + if (bridging) + verbose("device %u: tun %s attached to bridge: %s\n", + devices.device_num, tapif, arg); + else + verbose("device %u: tun %s: %s\n", + devices.device_num, tapif, arg); +} +/*:*/ + +/* This hangs off device->priv. */ +struct vblk_info { + /* The size of the file. */ + off64_t len; + + /* The file descriptor for the file. */ + int fd; + +}; + +/*L:210 + * The Disk + * + * The disk only has one virtqueue, so it only has one thread. It is really + * simple: the Guest asks for a block number and we read or write that position + * in the file. + * + * Before we serviced each virtqueue in a separate thread, that was unacceptably + * slow: the Guest waits until the read is finished before running anything + * else, even if it could have been doing useful work. + * + * We could have used async I/O, except it's reputed to suck so hard that + * characters actually go missing from your code when you try to use it. + */ +static void blk_request(struct virtqueue *vq) +{ + struct vblk_info *vblk = vq->dev->priv; + unsigned int head, out_num, in_num, wlen; + int ret; + u8 *in; + struct virtio_blk_outhdr *out; + struct iovec iov[vq->vring.num]; + off64_t off; + + /* + * Get the next request, where we normally wait. It triggers the + * interrupt to acknowledge previously serviced requests (if any). + */ + head = wait_for_vq_desc(vq, iov, &out_num, &in_num); + + /* + * Every block request should contain at least one output buffer + * (detailing the location on disk and the type of request) and one + * input buffer (to hold the result). + */ + if (out_num == 0 || in_num == 0) + errx(1, "Bad virtblk cmd %u out=%u in=%u", + head, out_num, in_num); + + out = convert(&iov[0], struct virtio_blk_outhdr); + in = convert(&iov[out_num+in_num-1], u8); + /* + * For historical reasons, block operations are expressed in 512 byte + * "sectors". + */ + off = out->sector * 512; + + /* + * In general the virtio block driver is allowed to try SCSI commands. + * It'd be nice if we supported eject, for example, but we don't. + */ + if (out->type & VIRTIO_BLK_T_SCSI_CMD) { + fprintf(stderr, "Scsi commands unsupported\n"); + *in = VIRTIO_BLK_S_UNSUPP; + wlen = sizeof(*in); + } else if (out->type & VIRTIO_BLK_T_OUT) { + /* + * Write + * + * Move to the right location in the block file. This can fail + * if they try to write past end. + */ + if (lseek64(vblk->fd, off, SEEK_SET) != off) + err(1, "Bad seek to sector %llu", out->sector); + + ret = writev(vblk->fd, iov+1, out_num-1); + verbose("WRITE to sector %llu: %i\n", out->sector, ret); + + /* + * Grr... Now we know how long the descriptor they sent was, we + * make sure they didn't try to write over the end of the block + * file (possibly extending it). + */ + if (ret > 0 && off + ret > vblk->len) { + /* Trim it back to the correct length */ + ftruncate64(vblk->fd, vblk->len); + /* Die, bad Guest, die. */ + errx(1, "Write past end %llu+%u", off, ret); + } + + wlen = sizeof(*in); + *in = (ret >= 0 ? VIRTIO_BLK_S_OK : VIRTIO_BLK_S_IOERR); + } else if (out->type & VIRTIO_BLK_T_FLUSH) { + /* Flush */ + ret = fdatasync(vblk->fd); + verbose("FLUSH fdatasync: %i\n", ret); + wlen = sizeof(*in); + *in = (ret >= 0 ? VIRTIO_BLK_S_OK : VIRTIO_BLK_S_IOERR); + } else { + /* + * Read + * + * Move to the right location in the block file. This can fail + * if they try to read past end. + */ + if (lseek64(vblk->fd, off, SEEK_SET) != off) + err(1, "Bad seek to sector %llu", out->sector); + + ret = readv(vblk->fd, iov+1, in_num-1); + verbose("READ from sector %llu: %i\n", out->sector, ret); + if (ret >= 0) { + wlen = sizeof(*in) + ret; + *in = VIRTIO_BLK_S_OK; + } else { + wlen = sizeof(*in); + *in = VIRTIO_BLK_S_IOERR; + } + } + + /* Finished that request. */ + add_used(vq, head, wlen); +} + +/*L:198 This actually sets up a virtual block device. */ +static void setup_block_file(const char *filename) +{ + struct device *dev; + struct vblk_info *vblk; + struct virtio_blk_config conf; + + /* Creat the device. */ + dev = new_device("block", VIRTIO_ID_BLOCK); + + /* The device has one virtqueue, where the Guest places requests. */ + add_virtqueue(dev, VIRTQUEUE_NUM, blk_request); + + /* Allocate the room for our own bookkeeping */ + vblk = dev->priv = malloc(sizeof(*vblk)); + + /* First we open the file and store the length. */ + vblk->fd = open_or_die(filename, O_RDWR|O_LARGEFILE); + vblk->len = lseek64(vblk->fd, 0, SEEK_END); + + /* We support FLUSH. */ + add_feature(dev, VIRTIO_BLK_F_FLUSH); + + /* Tell Guest how many sectors this device has. */ + conf.capacity = cpu_to_le64(vblk->len / 512); + + /* + * Tell Guest not to put in too many descriptors at once: two are used + * for the in and out elements. + */ + add_feature(dev, VIRTIO_BLK_F_SEG_MAX); + conf.seg_max = cpu_to_le32(VIRTQUEUE_NUM - 2); + + /* Don't try to put whole struct: we have 8 bit limit. */ + set_config(dev, offsetof(struct virtio_blk_config, geometry), &conf); + + verbose("device %u: virtblock %llu sectors\n", + ++devices.device_num, le64_to_cpu(conf.capacity)); +} + +/*L:211 + * Our random number generator device reads from /dev/random into the Guest's + * input buffers. The usual case is that the Guest doesn't want random numbers + * and so has no buffers although /dev/random is still readable, whereas + * console is the reverse. + * + * The same logic applies, however. + */ +struct rng_info { + int rfd; +}; + +static void rng_input(struct virtqueue *vq) +{ + int len; + unsigned int head, in_num, out_num, totlen = 0; + struct rng_info *rng_info = vq->dev->priv; + struct iovec iov[vq->vring.num]; + + /* First we need a buffer from the Guests's virtqueue. */ + head = wait_for_vq_desc(vq, iov, &out_num, &in_num); + if (out_num) + errx(1, "Output buffers in rng?"); + + /* + * Just like the console write, we loop to cover the whole iovec. + * In this case, short reads actually happen quite a bit. + */ + while (!iov_empty(iov, in_num)) { + len = readv(rng_info->rfd, iov, in_num); + if (len <= 0) + err(1, "Read from /dev/random gave %i", len); + iov_consume(iov, in_num, len); + totlen += len; + } + + /* Tell the Guest about the new input. */ + add_used(vq, head, totlen); +} + +/*L:199 + * This creates a "hardware" random number device for the Guest. + */ +static void setup_rng(void) +{ + struct device *dev; + struct rng_info *rng_info = malloc(sizeof(*rng_info)); + + /* Our device's privat info simply contains the /dev/random fd. */ + rng_info->rfd = open_or_die("/dev/random", O_RDONLY); + + /* Create the new device. */ + dev = new_device("rng", VIRTIO_ID_RNG); + dev->priv = rng_info; + + /* The device has one virtqueue, where the Guest places inbufs. */ + add_virtqueue(dev, VIRTQUEUE_NUM, rng_input); + + verbose("device %u: rng\n", devices.device_num++); +} +/* That's the end of device setup. */ + +/*L:230 Reboot is pretty easy: clean up and exec() the Launcher afresh. */ +static void __attribute__((noreturn)) restart_guest(void) +{ + unsigned int i; + + /* + * Since we don't track all open fds, we simply close everything beyond + * stderr. + */ + for (i = 3; i < FD_SETSIZE; i++) + close(i); + + /* Reset all the devices (kills all threads). */ + cleanup_devices(); + + execv(main_args[0], main_args); + err(1, "Could not exec %s", main_args[0]); +} + +/*L:220 + * Finally we reach the core of the Launcher which runs the Guest, serves + * its input and output, and finally, lays it to rest. + */ +static void __attribute__((noreturn)) run_guest(void) +{ + for (;;) { + unsigned long notify_addr; + int readval; + + /* We read from the /dev/lguest device to run the Guest. */ + readval = pread(lguest_fd, ¬ify_addr, + sizeof(notify_addr), cpu_id); + + /* One unsigned long means the Guest did HCALL_NOTIFY */ + if (readval == sizeof(notify_addr)) { + verbose("Notify on address %#lx\n", notify_addr); + handle_output(notify_addr); + /* ENOENT means the Guest died. Reading tells us why. */ + } else if (errno == ENOENT) { + char reason[1024] = { 0 }; + pread(lguest_fd, reason, sizeof(reason)-1, cpu_id); + errx(1, "%s", reason); + /* ERESTART means that we need to reboot the guest */ + } else if (errno == ERESTART) { + restart_guest(); + /* Anything else means a bug or incompatible change. */ + } else + err(1, "Running guest failed"); + } +} +/*L:240 + * This is the end of the Launcher. The good news: we are over halfway + * through! The bad news: the most fiendish part of the code still lies ahead + * of us. + * + * Are you ready? Take a deep breath and join me in the core of the Host, in + * "make Host". +:*/ + +static struct option opts[] = { + { "verbose", 0, NULL, 'v' }, + { "tunnet", 1, NULL, 't' }, + { "block", 1, NULL, 'b' }, + { "rng", 0, NULL, 'r' }, + { "initrd", 1, NULL, 'i' }, + { "username", 1, NULL, 'u' }, + { "chroot", 1, NULL, 'c' }, + { NULL }, +}; +static void usage(void) +{ + errx(1, "Usage: lguest [--verbose] " + "[--tunnet=(:|bridge::)\n" + "|--block=|--initrd=]...\n" + " vmlinux [args...]"); +} + +/*L:105 The main routine is where the real work begins: */ +int main(int argc, char *argv[]) +{ + /* Memory, code startpoint and size of the (optional) initrd. */ + unsigned long mem = 0, start, initrd_size = 0; + /* Two temporaries. */ + int i, c; + /* The boot information for the Guest. */ + struct boot_params *boot; + /* If they specify an initrd file to load. */ + const char *initrd_name = NULL; + + /* Password structure for initgroups/setres[gu]id */ + struct passwd *user_details = NULL; + + /* Directory to chroot to */ + char *chroot_path = NULL; + + /* Save the args: we "reboot" by execing ourselves again. */ + main_args = argv; + + /* + * First we initialize the device list. We keep a pointer to the last + * device, and the next interrupt number to use for devices (1: + * remember that 0 is used by the timer). + */ + devices.lastdev = NULL; + devices.next_irq = 1; + + /* We're CPU 0. In fact, that's the only CPU possible right now. */ + cpu_id = 0; + + /* + * We need to know how much memory so we can set up the device + * descriptor and memory pages for the devices as we parse the command + * line. So we quickly look through the arguments to find the amount + * of memory now. + */ + for (i = 1; i < argc; i++) { + if (argv[i][0] != '-') { + mem = atoi(argv[i]) * 1024 * 1024; + /* + * We start by mapping anonymous pages over all of + * guest-physical memory range. This fills it with 0, + * and ensures that the Guest won't be killed when it + * tries to access it. + */ + guest_base = map_zeroed_pages(mem / getpagesize() + + DEVICE_PAGES); + guest_limit = mem; + guest_max = mem + DEVICE_PAGES*getpagesize(); + devices.descpage = get_pages(1); + break; + } + } + + /* The options are fairly straight-forward */ + while ((c = getopt_long(argc, argv, "v", opts, NULL)) != EOF) { + switch (c) { + case 'v': + verbose = true; + break; + case 't': + setup_tun_net(optarg); + break; + case 'b': + setup_block_file(optarg); + break; + case 'r': + setup_rng(); + break; + case 'i': + initrd_name = optarg; + break; + case 'u': + user_details = getpwnam(optarg); + if (!user_details) + err(1, "getpwnam failed, incorrect username?"); + break; + case 'c': + chroot_path = optarg; + break; + default: + warnx("Unknown argument %s", argv[optind]); + usage(); + } + } + /* + * After the other arguments we expect memory and kernel image name, + * followed by command line arguments for the kernel. + */ + if (optind + 2 > argc) + usage(); + + verbose("Guest base is at %p\n", guest_base); + + /* We always have a console device */ + setup_console(); + + /* Now we load the kernel */ + start = load_kernel(open_or_die(argv[optind+1], O_RDONLY)); + + /* Boot information is stashed at physical address 0 */ + boot = from_guest_phys(0); + + /* Map the initrd image if requested (at top of physical memory) */ + if (initrd_name) { + initrd_size = load_initrd(initrd_name, mem); + /* + * These are the location in the Linux boot header where the + * start and size of the initrd are expected to be found. + */ + boot->hdr.ramdisk_image = mem - initrd_size; + boot->hdr.ramdisk_size = initrd_size; + /* The bootloader type 0xFF means "unknown"; that's OK. */ + boot->hdr.type_of_loader = 0xFF; + } + + /* + * The Linux boot header contains an "E820" memory map: ours is a + * simple, single region. + */ + boot->e820_entries = 1; + boot->e820_map[0] = ((struct e820entry) { 0, mem, E820_RAM }); + /* + * The boot header contains a command line pointer: we put the command + * line after the boot header. + */ + boot->hdr.cmd_line_ptr = to_guest_phys(boot + 1); + /* We use a simple helper to copy the arguments separated by spaces. */ + concat((char *)(boot + 1), argv+optind+2); + + /* Set kernel alignment to 16M (CONFIG_PHYSICAL_ALIGN) */ + boot->hdr.kernel_alignment = 0x1000000; + + /* Boot protocol version: 2.07 supports the fields for lguest. */ + boot->hdr.version = 0x207; + + /* The hardware_subarch value of "1" tells the Guest it's an lguest. */ + boot->hdr.hardware_subarch = 1; + + /* Tell the entry path not to try to reload segment registers. */ + boot->hdr.loadflags |= KEEP_SEGMENTS; + + /* We tell the kernel to initialize the Guest. */ + tell_kernel(start); + + /* Ensure that we terminate if a device-servicing child dies. */ + signal(SIGCHLD, kill_launcher); + + /* If we exit via err(), this kills all the threads, restores tty. */ + atexit(cleanup_devices); + + /* If requested, chroot to a directory */ + if (chroot_path) { + if (chroot(chroot_path) != 0) + err(1, "chroot(\"%s\") failed", chroot_path); + + if (chdir("/") != 0) + err(1, "chdir(\"/\") failed"); + + verbose("chroot done\n"); + } + + /* If requested, drop privileges */ + if (user_details) { + uid_t u; + gid_t g; + + u = user_details->pw_uid; + g = user_details->pw_gid; + + if (initgroups(user_details->pw_name, g) != 0) + err(1, "initgroups failed"); + + if (setresgid(g, g, g) != 0) + err(1, "setresgid failed"); + + if (setresuid(u, u, u) != 0) + err(1, "setresuid failed"); + + verbose("Dropping privileges completed\n"); + } + + /* Finally, run the Guest. This doesn't return. */ + run_guest(); +} +/*:*/ + +/*M:999 + * Mastery is done: you now know everything I do. + * + * But surely you have seen code, features and bugs in your wanderings which + * you now yearn to attack? That is the real game, and I look forward to you + * patching and forking lguest into the Your-Name-Here-visor. + * + * Farewell, and good coding! + * Rusty Russell. + */ diff --git a/tools/lguest/lguest.txt b/tools/lguest/lguest.txt new file mode 100644 index 00000000000..bff0c554485 --- /dev/null +++ b/tools/lguest/lguest.txt @@ -0,0 +1,129 @@ + __ + (___()'`; Rusty's Remarkably Unreliable Guide to Lguest + /, /` - or, A Young Coder's Illustrated Hypervisor + \\"--\\ http://lguest.ozlabs.org + +Lguest is designed to be a minimal 32-bit x86 hypervisor for the Linux kernel, +for Linux developers and users to experiment with virtualization with the +minimum of complexity. Nonetheless, it should have sufficient features to +make it useful for specific tasks, and, of course, you are encouraged to fork +and enhance it (see drivers/lguest/README). + +Features: + +- Kernel module which runs in a normal kernel. +- Simple I/O model for communication. +- Simple program to create new guests. +- Logo contains cute puppies: http://lguest.ozlabs.org + +Developer features: + +- Fun to hack on. +- No ABI: being tied to a specific kernel anyway, you can change anything. +- Many opportunities for improvement or feature implementation. + +Running Lguest: + +- The easiest way to run lguest is to use same kernel as guest and host. + You can configure them differently, but usually it's easiest not to. + + You will need to configure your kernel with the following options: + + "General setup": + "Prompt for development and/or incomplete code/drivers" = Y + (CONFIG_EXPERIMENTAL=y) + + "Processor type and features": + "Paravirtualized guest support" = Y + "Lguest guest support" = Y + "High Memory Support" = off/4GB + "Alignment value to which kernel should be aligned" = 0x100000 + (CONFIG_PARAVIRT=y, CONFIG_LGUEST_GUEST=y, CONFIG_HIGHMEM64G=n and + CONFIG_PHYSICAL_ALIGN=0x100000) + + "Device Drivers": + "Block devices" + "Virtio block driver (EXPERIMENTAL)" = M/Y + "Network device support" + "Universal TUN/TAP device driver support" = M/Y + "Virtio network driver (EXPERIMENTAL)" = M/Y + (CONFIG_VIRTIO_BLK=m, CONFIG_VIRTIO_NET=m and CONFIG_TUN=m) + + "Virtualization" + "Linux hypervisor example code" = M/Y + (CONFIG_LGUEST=m) + +- A tool called "lguest" is available in this directory: type "make" + to build it. If you didn't build your kernel in-tree, use "make + O=". + +- Create or find a root disk image. There are several useful ones + around, such as the xm-test tiny root image at + http://xm-test.xensource.com/ramdisks/initrd-1.1-i386.img + + For more serious work, I usually use a distribution ISO image and + install it under qemu, then make multiple copies: + + dd if=/dev/zero of=rootfile bs=1M count=2048 + qemu -cdrom image.iso -hda rootfile -net user -net nic -boot d + + Make sure that you install a getty on /dev/hvc0 if you want to log in on the + console! + +- "modprobe lg" if you built it as a module. + +- Run an lguest as root: + + Documentation/virtual/lguest/lguest 64 vmlinux --tunnet=192.168.19.1 \ + --block=rootfile root=/dev/vda + + Explanation: + 64: the amount of memory to use, in MB. + + vmlinux: the kernel image found in the top of your build directory. You + can also use a standard bzImage. + + --tunnet=192.168.19.1: configures a "tap" device for networking with this + IP address. + + --block=rootfile: a file or block device which becomes /dev/vda + inside the guest. + + root=/dev/vda: this (and anything else on the command line) are + kernel boot parameters. + +- Configuring networking. I usually have the host masquerade, using + "iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE" and "echo 1 > + /proc/sys/net/ipv4/ip_forward". In this example, I would configure + eth0 inside the guest at 192.168.19.2. + + Another method is to bridge the tap device to an external interface + using --tunnet=bridge:, and perhaps run dhcp on the guest + to obtain an IP address. The bridge needs to be configured first: + this option simply adds the tap interface to it. + + A simple example on my system: + + ifconfig eth0 0.0.0.0 + brctl addbr lg0 + ifconfig lg0 up + brctl addif lg0 eth0 + dhclient lg0 + + Then use --tunnet=bridge:lg0 when launching the guest. + + See: + + http://www.linuxfoundation.org/collaborate/workgroups/networking/bridge + + for general information on how to get bridging to work. + +- Random number generation. Using the --rng option will provide a + /dev/hwrng in the guest that will read from the host's /dev/random. + Use this option in conjunction with rng-tools (see ../hw_random.txt) + to provide entropy to the guest kernel's /dev/random. + +There is a helpful mailing list at http://ozlabs.org/mailman/listinfo/lguest + +Good luck! +Rusty Russell rusty@rustcorp.com.au. -- cgit v1.2.3-70-g09d2 From 274343ad3e63c4dcee6744a75b5553940de4a0f6 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Thu, 12 Jan 2012 17:20:44 -0800 Subject: selftests: new very basic kernel selftests directory Bring a new kernel selftests directory in tools/testing/selftests. To add a new selftest, create a subdirectory with the sources and a makefile that creates a target named "run_test" then add the subdirectory name to the TARGET var in tools/testing/selftests/Makefile and tools/testing/selftests/run_tests script. This can help centralizing and maintaining any useful selftest that developers usually tend to let rust in peace on some random server. Suggested-by: Andrew Morton Signed-off-by: Frederic Weisbecker Cc: Thomas Gleixner Cc: Ingo Molnar Cc: "H. Peter Anvin" Cc: Jason Wessel Cc: Will Deacon Cc: Steven Rostedt Cc: Michal Marek Cc: Sam Ravnborg Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- tools/testing/selftests/Makefile | 11 +++++++++++ tools/testing/selftests/run_tests | 8 ++++++++ 2 files changed, 19 insertions(+) create mode 100644 tools/testing/selftests/Makefile create mode 100644 tools/testing/selftests/run_tests (limited to 'tools') diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile new file mode 100644 index 00000000000..298a5c0c1ea --- /dev/null +++ b/tools/testing/selftests/Makefile @@ -0,0 +1,11 @@ +TARGETS = + +all: + for TARGET in $(TARGETS); do \ + make -C $$TARGET; \ + done; + +clean: + for TARGET in $(TARGETS); do \ + make -C $$TARGET clean; \ + done; diff --git a/tools/testing/selftests/run_tests b/tools/testing/selftests/run_tests new file mode 100644 index 00000000000..701960d9e53 --- /dev/null +++ b/tools/testing/selftests/run_tests @@ -0,0 +1,8 @@ +#!/bin/bash + +TARGETS= + +for TARGET in $TARGETS +do + $TARGET/run_test +done -- cgit v1.2.3-70-g09d2 From 85bbddc37b2bf947a577d572b1c4c23bf829217f Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Thu, 12 Jan 2012 17:20:46 -0800 Subject: selftests: new x86 breakpoints selftest Bring a first selftest in the relevant directory. This tests several combinations of breakpoints and watchpoints in x86, as well as icebp traps and int3 traps. Given the amount of breakpoint regressions we raised after we merged the generic breakpoint infrastructure, such selftest became necessary and can still serve today as a basis for new patches that touch the do_debug() path. Signed-off-by: Frederic Weisbecker Cc: Thomas Gleixner Cc: Ingo Molnar Cc: H. Peter Anvin Cc: Jason Wessel Cc: Will Deacon Cc: Michal Marek Cc: Sam Ravnborg Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- tools/testing/selftests/Makefile | 2 +- tools/testing/selftests/breakpoints/Makefile | 20 ++ .../selftests/breakpoints/breakpoint_test.c | 394 +++++++++++++++++++++ tools/testing/selftests/run_tests | 2 +- 4 files changed, 416 insertions(+), 2 deletions(-) create mode 100644 tools/testing/selftests/breakpoints/Makefile create mode 100644 tools/testing/selftests/breakpoints/breakpoint_test.c (limited to 'tools') diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index 298a5c0c1ea..4ec84018cc1 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile @@ -1,4 +1,4 @@ -TARGETS = +TARGETS = breakpoints all: for TARGET in $(TARGETS); do \ diff --git a/tools/testing/selftests/breakpoints/Makefile b/tools/testing/selftests/breakpoints/Makefile new file mode 100644 index 00000000000..f362722cdce --- /dev/null +++ b/tools/testing/selftests/breakpoints/Makefile @@ -0,0 +1,20 @@ +# Taken from perf makefile +uname_M := $(shell uname -m 2>/dev/null || echo not) +ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/) +ifeq ($(ARCH),i386) + ARCH := x86 +endif +ifeq ($(ARCH),x86_64) + ARCH := x86 +endif + + +all: +ifeq ($(ARCH),x86) + gcc breakpoint_test.c -o run_test +else + echo "Not an x86 target, can't build breakpoints selftests" +endif + +clean: + rm -fr run_test diff --git a/tools/testing/selftests/breakpoints/breakpoint_test.c b/tools/testing/selftests/breakpoints/breakpoint_test.c new file mode 100644 index 00000000000..a0743f3b2b5 --- /dev/null +++ b/tools/testing/selftests/breakpoints/breakpoint_test.c @@ -0,0 +1,394 @@ +/* + * Copyright (C) 2011 Red Hat, Inc., Frederic Weisbecker + * + * Licensed under the terms of the GNU GPL License version 2 + * + * Selftests for breakpoints (and more generally the do_debug() path) in x86. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* Breakpoint access modes */ +enum { + BP_X = 1, + BP_RW = 2, + BP_W = 4, +}; + +static pid_t child_pid; + +/* + * Ensures the child and parent are always "talking" about + * the same test sequence. (ie: that we haven't forgotten + * to call check_trapped() somewhere). + */ +static int nr_tests; + +static void set_breakpoint_addr(void *addr, int n) +{ + int ret; + + ret = ptrace(PTRACE_POKEUSER, child_pid, + offsetof(struct user, u_debugreg[n]), addr); + if (ret) { + perror("Can't set breakpoint addr\n"); + exit(-1); + } +} + +static void toggle_breakpoint(int n, int type, int len, + int local, int global, int set) +{ + int ret; + + int xtype, xlen; + unsigned long vdr7, dr7; + + switch (type) { + case BP_X: + xtype = 0; + break; + case BP_W: + xtype = 1; + break; + case BP_RW: + xtype = 3; + break; + } + + switch (len) { + case 1: + xlen = 0; + break; + case 2: + xlen = 4; + break; + case 4: + xlen = 0xc; + break; + case 8: + xlen = 8; + break; + } + + dr7 = ptrace(PTRACE_PEEKUSER, child_pid, + offsetof(struct user, u_debugreg[7]), 0); + + vdr7 = (xlen | xtype) << 16; + vdr7 <<= 4 * n; + + if (local) { + vdr7 |= 1 << (2 * n); + vdr7 |= 1 << 8; + } + if (global) { + vdr7 |= 2 << (2 * n); + vdr7 |= 1 << 9; + } + + if (set) + dr7 |= vdr7; + else + dr7 &= ~vdr7; + + ret = ptrace(PTRACE_POKEUSER, child_pid, + offsetof(struct user, u_debugreg[7]), dr7); + if (ret) { + perror("Can't set dr7"); + exit(-1); + } +} + +/* Dummy variables to test read/write accesses */ +static unsigned long long dummy_var[4]; + +/* Dummy functions to test execution accesses */ +static void dummy_func(void) { } +static void dummy_func1(void) { } +static void dummy_func2(void) { } +static void dummy_func3(void) { } + +static void (*dummy_funcs[])(void) = { + dummy_func, + dummy_func1, + dummy_func2, + dummy_func3, +}; + +static int trapped; + +static void check_trapped(void) +{ + /* + * If we haven't trapped, wake up the parent + * so that it notices the failure. + */ + if (!trapped) + kill(getpid(), SIGUSR1); + trapped = 0; + + nr_tests++; +} + +static void write_var(int len) +{ + char *pcval; short *psval; int *pival; long long *plval; + int i; + + for (i = 0; i < 4; i++) { + switch (len) { + case 1: + pcval = (char *)&dummy_var[i]; + *pcval = 0xff; + break; + case 2: + psval = (short *)&dummy_var[i]; + *psval = 0xffff; + break; + case 4: + pival = (int *)&dummy_var[i]; + *pival = 0xffffffff; + break; + case 8: + plval = (long long *)&dummy_var[i]; + *plval = 0xffffffffffffffffLL; + break; + } + check_trapped(); + } +} + +static void read_var(int len) +{ + char cval; short sval; int ival; long long lval; + int i; + + for (i = 0; i < 4; i++) { + switch (len) { + case 1: + cval = *(char *)&dummy_var[i]; + break; + case 2: + sval = *(short *)&dummy_var[i]; + break; + case 4: + ival = *(int *)&dummy_var[i]; + break; + case 8: + lval = *(long long *)&dummy_var[i]; + break; + } + check_trapped(); + } +} + +/* + * Do the r/w/x accesses to trigger the breakpoints. And run + * the usual traps. + */ +static void trigger_tests(void) +{ + int len, local, global, i; + char val; + int ret; + + ret = ptrace(PTRACE_TRACEME, 0, NULL, 0); + if (ret) { + perror("Can't be traced?\n"); + return; + } + + /* Wake up father so that it sets up the first test */ + kill(getpid(), SIGUSR1); + + /* Test instruction breakpoints */ + for (local = 0; local < 2; local++) { + for (global = 0; global < 2; global++) { + if (!local && !global) + continue; + + for (i = 0; i < 4; i++) { + dummy_funcs[i](); + check_trapped(); + } + } + } + + /* Test write watchpoints */ + for (len = 1; len <= sizeof(long); len <<= 1) { + for (local = 0; local < 2; local++) { + for (global = 0; global < 2; global++) { + if (!local && !global) + continue; + write_var(len); + } + } + } + + /* Test read/write watchpoints (on read accesses) */ + for (len = 1; len <= sizeof(long); len <<= 1) { + for (local = 0; local < 2; local++) { + for (global = 0; global < 2; global++) { + if (!local && !global) + continue; + read_var(len); + } + } + } + + /* Icebp trap */ + asm(".byte 0xf1\n"); + check_trapped(); + + /* Int 3 trap */ + asm("int $3\n"); + check_trapped(); + + kill(getpid(), SIGUSR1); +} + +static void check_success(const char *msg) +{ + const char *msg2; + int child_nr_tests; + int status; + + /* Wait for the child to SIGTRAP */ + wait(&status); + + msg2 = "Failed"; + + if (WSTOPSIG(status) == SIGTRAP) { + child_nr_tests = ptrace(PTRACE_PEEKDATA, child_pid, + &nr_tests, 0); + if (child_nr_tests == nr_tests) + msg2 = "Ok"; + if (ptrace(PTRACE_POKEDATA, child_pid, &trapped, 1)) { + perror("Can't poke\n"); + exit(-1); + } + } + + nr_tests++; + + printf("%s [%s]\n", msg, msg2); +} + +static void launch_instruction_breakpoints(char *buf, int local, int global) +{ + int i; + + for (i = 0; i < 4; i++) { + set_breakpoint_addr(dummy_funcs[i], i); + toggle_breakpoint(i, BP_X, 1, local, global, 1); + ptrace(PTRACE_CONT, child_pid, NULL, 0); + sprintf(buf, "Test breakpoint %d with local: %d global: %d", + i, local, global); + check_success(buf); + toggle_breakpoint(i, BP_X, 1, local, global, 0); + } +} + +static void launch_watchpoints(char *buf, int mode, int len, + int local, int global) +{ + const char *mode_str; + int i; + + if (mode == BP_W) + mode_str = "write"; + else + mode_str = "read"; + + for (i = 0; i < 4; i++) { + set_breakpoint_addr(&dummy_var[i], i); + toggle_breakpoint(i, mode, len, local, global, 1); + ptrace(PTRACE_CONT, child_pid, NULL, 0); + sprintf(buf, "Test %s watchpoint %d with len: %d local: " + "%d global: %d", mode_str, i, len, local, global); + check_success(buf); + toggle_breakpoint(i, mode, len, local, global, 0); + } +} + +/* Set the breakpoints and check the child successfully trigger them */ +static void launch_tests(void) +{ + char buf[1024]; + int len, local, global, i; + + /* Instruction breakpoints */ + for (local = 0; local < 2; local++) { + for (global = 0; global < 2; global++) { + if (!local && !global) + continue; + launch_instruction_breakpoints(buf, local, global); + } + } + + /* Write watchpoint */ + for (len = 1; len <= sizeof(long); len <<= 1) { + for (local = 0; local < 2; local++) { + for (global = 0; global < 2; global++) { + if (!local && !global) + continue; + launch_watchpoints(buf, BP_W, len, + local, global); + } + } + } + + /* Read-Write watchpoint */ + for (len = 1; len <= sizeof(long); len <<= 1) { + for (local = 0; local < 2; local++) { + for (global = 0; global < 2; global++) { + if (!local && !global) + continue; + launch_watchpoints(buf, BP_RW, len, + local, global); + } + } + } + + /* Icebp traps */ + ptrace(PTRACE_CONT, child_pid, NULL, 0); + check_success("Test icebp"); + + /* Int 3 traps */ + ptrace(PTRACE_CONT, child_pid, NULL, 0); + check_success("Test int 3 trap"); + + ptrace(PTRACE_CONT, child_pid, NULL, 0); +} + +int main(int argc, char **argv) +{ + pid_t pid; + int ret; + + pid = fork(); + if (!pid) { + trigger_tests(); + return 0; + } + + child_pid = pid; + + wait(NULL); + + launch_tests(); + + wait(NULL); + + return 0; +} diff --git a/tools/testing/selftests/run_tests b/tools/testing/selftests/run_tests index 701960d9e53..320718a4e6b 100644 --- a/tools/testing/selftests/run_tests +++ b/tools/testing/selftests/run_tests @@ -1,6 +1,6 @@ #!/bin/bash -TARGETS= +TARGETS=breakpoints for TARGET in $TARGETS do -- cgit v1.2.3-70-g09d2 From 0a84f007f97ce6fc7c07a481a5b9808b187a0193 Mon Sep 17 00:00:00 2001 From: David Daney Date: Tue, 17 Jan 2012 13:41:01 -0800 Subject: perf tools: Fix broken build by defining _GNU_SOURCE in Makefile When building on my Debian/mips system, util/util.c fails to build because commit 1aed2671738785e8f5aea663a6fda91aa7ef59b5 (perf kvm: Do guest-only counting by default) indirectly includes stdio.h before the feature selection in util.h is done. This prevents _GNU_SOURCE in util.h from enabling the declaration of getline(), from now second inclusion of stdio.h, and the build is broken. There is another breakage in util/evsel.c caused by include ordering, but I didn't fully track down the commit that caused it. The root cause of all this is an inconsistent definition of _GNU_SOURCE, so I move the definition into the Makefile so that it is passed to all invocations of the compiler and used uniformly for all system header files. All other #define and #undef of _GNU_SOURCE are removed as they cause conflicts with the definition passed to the compiler. All the features.h definitions (_LARGEFILE64_SOURCE _FILE_OFFSET_BITS=64 and _GNU_SOURCE) are needed by the python glue code too, so they are moved to BASIC_CFLAGS, and the misleading comments about BASIC_CFLAGS are removed. This gives me a clean build on x86_64 (fc12) and mips (Debian). Cc: David Daney Cc: Ingo Molnar Cc: Joerg Roedel Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1326836461-11952-1-git-send-email-ddaney.cavm@gmail.com Signed-off-by: David Daney Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Makefile | 7 ++----- tools/perf/builtin-probe.c | 2 -- tools/perf/util/probe-event.c | 2 -- tools/perf/util/symbol.c | 1 - tools/perf/util/trace-event-parse.c | 3 +-- tools/perf/util/ui/browsers/hists.c | 2 -- tools/perf/util/ui/helpline.c | 1 - tools/perf/util/util.h | 1 - 8 files changed, 3 insertions(+), 16 deletions(-) (limited to 'tools') diff --git a/tools/perf/Makefile b/tools/perf/Makefile index ac86d67b636..7c12650165a 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -104,7 +104,7 @@ endif 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_CFLAGS = $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE ALL_LDFLAGS = $(LDFLAGS) STRIP ?= strip @@ -168,10 +168,7 @@ endif ### --- END CONFIGURATION SECTION --- -# Those must not be GNU-specific; they are shared with perl/ which may -# be built by a different compiler. (Note that this is an artifact now -# but it still might be nice to keep that distinction.) -BASIC_CFLAGS = -Iutil/include -Iarch/$(ARCH)/include +BASIC_CFLAGS = -Iutil/include -Iarch/$(ARCH)/include -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE BASIC_LDFLAGS = # Guard against environment variables diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index 59d43abfbfe..fb8566181f2 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c @@ -20,7 +20,6 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ -#define _GNU_SOURCE #include #include #include @@ -31,7 +30,6 @@ #include #include -#undef _GNU_SOURCE #include "perf.h" #include "builtin.h" #include "util/util.h" diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index eb25900e221..29cb6545981 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -19,7 +19,6 @@ * */ -#define _GNU_SOURCE #include #include #include @@ -33,7 +32,6 @@ #include #include -#undef _GNU_SOURCE #include "util.h" #include "event.h" #include "string.h" diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 215d50f2042..0975438c3e7 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -1,4 +1,3 @@ -#define _GNU_SOURCE #include #include #include diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index 6c164dc9ee9..1a8d4dc4f38 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c @@ -21,14 +21,13 @@ * The parts for function graph printing was taken and modified from the * Linux Kernel that were written by Frederic Weisbecker. */ -#define _GNU_SOURCE + #include #include #include #include #include -#undef _GNU_SOURCE #include "../perf.h" #include "util.h" #include "trace-event.h" diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c index 1212a386a03..e81aef1f256 100644 --- a/tools/perf/util/ui/browsers/hists.c +++ b/tools/perf/util/ui/browsers/hists.c @@ -1,6 +1,4 @@ -#define _GNU_SOURCE #include -#undef _GNU_SOURCE #include "../libslang.h" #include #include diff --git a/tools/perf/util/ui/helpline.c b/tools/perf/util/ui/helpline.c index 6ef3c569176..4f48f5901b3 100644 --- a/tools/perf/util/ui/helpline.c +++ b/tools/perf/util/ui/helpline.c @@ -1,4 +1,3 @@ -#define _GNU_SOURCE #include #include #include diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index b9c530cce79..ecf9898169c 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -40,7 +40,6 @@ #define decimal_length(x) ((int)(sizeof(x) * 2.56 + 0.5) + 1) #define _ALL_SOURCE 1 -#define _GNU_SOURCE 1 #define _BSD_SOURCE 1 #define HAS_BOOL -- cgit v1.2.3-70-g09d2 From d8d9c282a1abbe2baf6d22f959e6adf4c90629bf Mon Sep 17 00:00:00 2001 From: Stephane Eranian Date: Fri, 20 Jan 2012 10:49:12 +0100 Subject: perf tools: Fix strlen() bug in perf_event__synthesize_event_type() The event_type record has a max length for the event name. It's called MAX_EVENT_NAME. The name may be truncated to fit the max length. But the header.size still reflects the original name length. If that length is > MAX_EVENT_NAME, then the header.size field is bogus. Fix this by using the length of the name after the potential truncation. Cc: David Ahern Cc: Ingo Molnar Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20120120094912.GA4882@quad Signed-off-by: Stephane Eranian Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/header.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 3e7e0b09c12..ecd7f4dd7ee 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -2105,7 +2105,7 @@ int perf_event__synthesize_event_type(struct perf_tool *tool, strncpy(ev.event_type.event_type.name, name, MAX_EVENT_NAME - 1); ev.event_type.header.type = PERF_RECORD_HEADER_EVENT_TYPE; - size = strlen(name); + size = strlen(ev.event_type.event_type.name); size = ALIGN(size, sizeof(u64)); ev.event_type.header.size = sizeof(ev.event_type) - (sizeof(ev.event_type.event_type.name) - size); -- cgit v1.2.3-70-g09d2 From 509605dbe9395ce1abbfac1dba375f074ff57a53 Mon Sep 17 00:00:00 2001 From: Stephane Eranian Date: Mon, 30 Jan 2012 11:50:37 +0100 Subject: perf top: Fix number of samples displayed In recent versions of perf top, pressing the 'e' key to change the number of displayed samples had no effect. The number of samples was still dictated by the size of the terminal (stdio mode). That was quite annoying because typically only the first dozen samples really matter. This patch fixes this. Cc: David Ahern Cc: Ingo Molnar Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20120130105037.GA5160@quad Signed-off-by: Stephane Eranian Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 8f80df89603..dd162aa24ba 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -89,8 +89,6 @@ void get_term_dimensions(struct winsize *ws) static void perf_top__update_print_entries(struct perf_top *top) { - top->print_entries = top->winsize.ws_row; - if (top->print_entries > 9) top->print_entries -= 9; } @@ -100,6 +98,13 @@ static void perf_top__sig_winch(int sig __used, siginfo_t *info __used, void *ar struct perf_top *top = arg; get_term_dimensions(&top->winsize); + if (!top->print_entries + || (top->print_entries+4) > top->winsize.ws_row) { + top->print_entries = top->winsize.ws_row; + } else { + top->print_entries += 4; + top->winsize.ws_row = top->print_entries; + } perf_top__update_print_entries(top); } @@ -453,8 +458,10 @@ static void perf_top__handle_keypress(struct perf_top *top, int c) }; perf_top__sig_winch(SIGWINCH, NULL, top); sigaction(SIGWINCH, &act, NULL); - } else + } else { + perf_top__sig_winch(SIGWINCH, NULL, top); signal(SIGWINCH, SIG_DFL); + } break; case 'E': if (top->evlist->nr_entries > 1) { -- cgit v1.2.3-70-g09d2 From 7a0153ee15575a4d07b5da8c96b79e0b0fd41a12 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 6 Feb 2012 18:54:06 -0200 Subject: perf tools: Fix perf stack to non executable on x86_64 By adding following objects: bench/mem-memcpy-x86-64-asm.o the x86_64 perf binary ended up with executable stack. The reason was that above object are assembler sourced and is missing the GNU-stack note section. In such case the linker assumes that the final binary should not be restricted at all and mark the stack as RWX. Adding section ".note.GNU-stack" definition to mentioned object, with all flags disabled, thus omiting this object from linker stack flags decision. Problem introduced in: $ git describe ea7872b v2.6.37-rc2-19-gea7872b Reported-at: https://bugzilla.redhat.com/show_bug.cgi?id=783570 Reported-by: Clark Williams Acked-by: Eric Dumazet Cc: Corey Ashford Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Cc: stable@kernel.org Link: http://lkml.kernel.org/r/1328100848-5630-1-git-send-email-jolsa@redhat.com Signed-off-by: Jiri Olsa [ committer note: Backported fix to perf/urgent (3.3-rc2+) ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/bench/mem-memcpy-x86-64-asm.S | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'tools') diff --git a/tools/perf/bench/mem-memcpy-x86-64-asm.S b/tools/perf/bench/mem-memcpy-x86-64-asm.S index a57b66e853c..185a96d66dd 100644 --- a/tools/perf/bench/mem-memcpy-x86-64-asm.S +++ b/tools/perf/bench/mem-memcpy-x86-64-asm.S @@ -1,2 +1,8 @@ #include "../../../arch/x86/lib/memcpy_64.S" +/* + * We need to provide note.GNU-stack section, saying that we want + * NOT executable stack. Otherwise the final linking will assume that + * the ELF stack should not be restricted at all and set it RWX. + */ +.section .note.GNU-stack,"",@progbits -- cgit v1.2.3-70-g09d2 From bf32c9ebc9890764c7a9984e3a0c8a57a059753d Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Sun, 5 Feb 2012 18:11:05 +0100 Subject: perf tools: Fix prefix matching for kernel maps In some perf ancient versions we used '[kernel.kallsyms._text]' as the name for the kernel map. This got changed with commit: perf: 'perf kvm' tool for monitoring guest performance from host commit a1645ce12adb6c9cc9e19d7695466204e3f017fe Author: Zhang, Yanmin and we started to use following name '[kernel.kallsyms]_text'. This name change is important for the report code dealing with ancient perf data. When processing the kernel map event, we need to recognize the old naming (dont match the last ']') and initialize the kernel map correctly. The subsequent call to maps__set_kallsyms_ref_reloc_sym deals with the superfluous ']' to get correct symbol name. Cc: Corey Ashford Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1328461865-6127-1-git-send-email-jolsa@redhat.com Signed-off-by: Jiri Olsa Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/event.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 73ddaf06b8e..2044324b755 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -554,7 +554,7 @@ static int perf_event__process_kernel_mmap(struct perf_tool *tool __used, is_kernel_mmap = memcmp(event->mmap.filename, kmmap_prefix, - strlen(kmmap_prefix)) == 0; + strlen(kmmap_prefix) - 1) == 0; if (event->mmap.filename[0] == '/' || (!is_kernel_mmap && event->mmap.filename[0] == '[')) { -- cgit v1.2.3-70-g09d2 From a4a03fc7ef89020baca4f19174e6a43767c6d78a Mon Sep 17 00:00:00 2001 From: "Naveen N. Rao" Date: Fri, 3 Feb 2012 22:31:13 +0530 Subject: perf evsel: Fix an issue where perf report fails to show the proper percentage This patch fixes an issue where perf report shows nan% for certain perf.data files. The below is from a report for a do_fork probe: -nan% sshd [kernel.kallsyms] [k] do_fork -nan% packagekitd [kernel.kallsyms] [k] do_fork -nan% dbus-daemon [kernel.kallsyms] [k] do_fork -nan% bash [kernel.kallsyms] [k] do_fork A git bisect shows commit f3bda2c as the cause. However, looking back through the git history, I saw commit 640c03c which seems to have removed the required initialization for perf_sample->period. The problem only started showing after commit f3bda2c. The below patch re-introduces the initialization and it fixes the problem for me. With the below patch, for the same perf.data: 73.08% bash [kernel.kallsyms] [k] do_fork 8.97% 11-dhclient [kernel.kallsyms] [k] do_fork 6.41% sshd [kernel.kallsyms] [k] do_fork 3.85% 20-chrony [kernel.kallsyms] [k] do_fork 2.56% sendmail [kernel.kallsyms] [k] do_fork This patch applies over current linux-tip commit 9949284. Problem introduced in: $ git describe 640c03c v2.6.37-rc3-83-g640c03c Cc: Ananth N Mavinakayanahalli Cc: Ingo Molnar Cc: Robert Richter Cc: Srikar Dronamraju Cc: stable@kernel.org Link: http://lkml.kernel.org/r/20120203170113.5190.25558.stgit@localhost6.localdomain6 Signed-off-by: Naveen N. Rao Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evsel.c | 1 + 1 file changed, 1 insertion(+) (limited to 'tools') diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 667f3b78bb2..7132ee834e0 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -463,6 +463,7 @@ int perf_event__parse_sample(const union perf_event *event, u64 type, memset(data, 0, sizeof(*data)); data->cpu = data->pid = data->tid = -1; data->stream_id = data->id = data->time = -1ULL; + data->period = 1; if (event->header.type != PERF_RECORD_SAMPLE) { if (!sample_id_all) -- cgit v1.2.3-70-g09d2 From bf1c95abaf24b56c45f458051c693f31fd9b7052 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Mon, 27 Feb 2012 13:58:49 -0500 Subject: ktest: Fix make_min_config test when build fails The make_min_config does not take into account when the build fails, resulting in a invalid MIN_CONFIG .config file. When the build fails, it is ignored and the boot test is executed, using the previous built kernel. The configs that should be tested are not tested and they may be added or removed depending on the result of the last kernel that succeeded to be built. If the build fails, mark the current config as a failure and the configs that were disabled may still be needed. Signed-off-by: Steven Rostedt --- tools/testing/ktest/ktest.pl | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'tools') diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl index 62a134dc421..9507c4b251a 100755 --- a/tools/testing/ktest/ktest.pl +++ b/tools/testing/ktest/ktest.pl @@ -3244,9 +3244,11 @@ sub make_min_config { $in_bisect = 1; my $failed = 0; - build "oldconfig"; - start_monitor_and_boot or $failed = 1; - end_monitor; + build "oldconfig" or $failed = 1; + if (!$failed) { + start_monitor_and_boot or $failed = 1; + end_monitor; + } $in_bisect = 0; -- cgit v1.2.3-70-g09d2 From 30e68bcc67e41ab6dab4e4e1efc7ea8ca893c0af Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Mon, 20 Feb 2012 10:47:26 +0900 Subject: perf evlist: Return first evsel for non-sample event on old kernel On old kernels that don't support sample_id_all feature, perf_evlist__id2evsel() returns NULL for non-sampling events. This breaks perf top when multiple events are given on command line. Fix it by using first evsel in the evlist. This will also prevent getting the same (potential) problem in such new tool/ old kernel combo. Suggested-by: Arnaldo Carvalho de Melo Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1329702447-25045-1-git-send-email-namhyung.kim@lge.com Signed-off-by: Namhyung Kim Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evlist.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'tools') diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 3f16e08a5c8..ea32a061f1c 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -349,6 +349,10 @@ struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id) hlist_for_each_entry(sid, pos, head, node) if (sid->id == id) return sid->evsel; + + if (!perf_evlist__sample_id_all(evlist)) + return list_entry(evlist->entries.next, struct perf_evsel, node); + return NULL; } -- cgit v1.2.3-70-g09d2 From 26b7952494772f0e695271fbd6cf83a852f60f25 Mon Sep 17 00:00:00 2001 From: Prashanth Nageshappa Date: Fri, 24 Feb 2012 13:11:39 +0530 Subject: perf probe: Ensure offset provided is not greater than function length The perf probe command allows kprobe to be inserted at any offset from a function start, which results in adding kprobes to unintended location. Example: perf probe do_fork+10000 is allowed even though size of do_fork is ~904. This patch will ensure probe addition fails when the offset specified is greater than size of the function. Acked-by: Masami Hiramatsu Cc: Ananth N Mavinakayanahalli Cc: Srikar Dronamraju Cc: Steven Rostedt Cc: Andrew Morton Cc: Jason Baron Cc: Masami Hiramatsu Link: http://lkml.kernel.org/r/4F473F33.4060409@linux.vnet.ibm.com Signed-off-by: Prashanth Nageshappa Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/probe-finder.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index 5d732621a46..74bd2e63c4b 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c @@ -672,7 +672,7 @@ static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf) static int convert_to_trace_point(Dwarf_Die *sp_die, Dwarf_Addr paddr, bool retprobe, struct probe_trace_point *tp) { - Dwarf_Addr eaddr; + Dwarf_Addr eaddr, highaddr; const char *name; /* Copy the name of probe point */ @@ -683,6 +683,16 @@ static int convert_to_trace_point(Dwarf_Die *sp_die, Dwarf_Addr paddr, dwarf_diename(sp_die)); return -ENOENT; } + if (dwarf_highpc(sp_die, &highaddr) != 0) { + pr_warning("Failed to get end address of %s\n", + dwarf_diename(sp_die)); + return -ENOENT; + } + if (paddr > highaddr) { + pr_warning("Offset specified is greater than size of %s\n", + dwarf_diename(sp_die)); + return -EINVAL; + } tp->symbol = strdup(name); if (tp->symbol == NULL) return -ENOMEM; -- cgit v1.2.3-70-g09d2 From cfbd70c17c4535e64be92ea442a2a45078a18184 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Fri, 24 Feb 2012 12:31:38 -0700 Subject: perf tools: Ensure comm string is properly terminated If threads in a multi-threaded process have names shorter than the main thread the comm for the named threads is not properly terminated. E.g., for the process 'namedthreads' where each thread is named noploop%d where %d is the thread number: Before: perf script -f comm,tid,ip,sym,dso noploop:4ads 21616 400a49 noploop (/tmp/namedthreads) The 'ads' in the thread comm bleeds over from the process name. After: perf script -f comm,tid,ip,sym,dso noploop:4 21616 400a49 noploop (/tmp/namedthreads) Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1330111898-68071-1-git-send-email-dsahern@gmail.com Signed-off-by: David Ahern Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/event.c | 1 + 1 file changed, 1 insertion(+) (limited to 'tools') diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 2044324b755..2a6f33cd888 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -74,6 +74,7 @@ static pid_t perf_event__get_comm_tgid(pid_t pid, char *comm, size_t len) if (size >= len) size = len - 1; memcpy(comm, name, size); + comm[size] = '\0'; } else if (memcmp(bf, "Tgid:", 5) == 0) { char *tgids = bf + 5; -- cgit v1.2.3-70-g09d2 From 1c1bc9223387dacc48eb2b61b0baabe7e9cf47f6 Mon Sep 17 00:00:00 2001 From: Prashanth Nageshappa Date: Tue, 28 Feb 2012 09:43:01 +0530 Subject: perf probe: Ensure offset provided is not greater than function length without DWARF info too The 'perf probe' command allows kprobe to be inserted at any offset from a function start, which results in adding kprobes to unintended location. (example: perf probe do_fork+10000 is allowed even though size of do_fork is ~904). My previous patch https://lkml.org/lkml/2012/2/24/42 addressed the case where DWARF info was available for the kernel. This patch fixes the case where perf probe is used on a kernel without debuginfo available. Acked-by: Masami Hiramatsu Cc: Ananth N Mavinakayanahalli Cc: Jason Baron Cc: Masami Hiramatsu Cc: Srikar Dronamraju Cc: Steven Rostedt Cc: Andrew Morton Link: http://lkml.kernel.org/r/4F4C544D.1010909@linux.vnet.ibm.com Signed-off-by: Prashanth Nageshappa Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/probe-event.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'tools') diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 29cb6545981..e33554a562b 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -1867,6 +1867,12 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev, tev->point.symbol); ret = -ENOENT; goto error; + } else if (tev->point.offset > sym->end - sym->start) { + pr_warning("Offset specified is greater than size of %s\n", + tev->point.symbol); + ret = -ENOENT; + goto error; + } return 1; -- cgit v1.2.3-70-g09d2 From 6e557a6adfdbb511dbfa7a0a4aa2148f76a01c6d Mon Sep 17 00:00:00 2001 From: David Ahern Date: Mon, 6 Feb 2012 15:27:52 -0700 Subject: perf record: No build id option fails A recent refactoring of perf-record introduced the following: perf record -a -B Couldn't generating buildids. Use --no-buildid to profile anyway. sleep: Terminated I believe the triple negative was meant to be only a double negative. :-) While I'm there, fixed the grammar on the error message. Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Robert Richter Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1328567272-13190-1-git-send-email-dsahern@gmail.com Signed-off-by: David Ahern Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 0abfb18b911..39b6a4067f8 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -503,9 +503,9 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) return err; } - if (!!rec->no_buildid + if (!rec->no_buildid && !perf_header__has_feat(&session->header, HEADER_BUILD_ID)) { - pr_err("Couldn't generating buildids. " + pr_err("Couldn't generate buildids. " "Use --no-buildid to profile anyway.\n"); return -1; } -- cgit v1.2.3-70-g09d2 From 8f54ed4a2d8cf001456d3779bdb33985a050bf03 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Fri, 10 Feb 2012 18:05:05 +0100 Subject: perf tools: Change perf_guest default back to false Setting perf_guest to true by default makes no sense because the perf subcommands can not setup guest symbol information and thus not process and guest samples. The only exception is perf-kvm which changes the perf_guest value on its own. So change the default for perf_guest back to false. Cc: David Ahern Cc: Ingo Molnar Cc: Jason Wang Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1328893505-4115-3-git-send-email-joerg.roedel@amd.com Signed-off-by: Joerg Roedel Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index 813141047fc..fb25d132921 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c @@ -6,7 +6,7 @@ * XXX We need to find a better place for these things... */ bool perf_host = true; -bool perf_guest = true; +bool perf_guest = false; void event_attr_init(struct perf_event_attr *attr) { -- cgit v1.2.3-70-g09d2 From bc76efe64533305b55d1f0834fd03414da8a12b2 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 14 Feb 2012 14:05:30 -0200 Subject: perf tools: Handle kernels that don't support attr.exclude_{guest,host} Just fall back to resetting those fields, if set, warning the user that that feature is not available. If guest samples appear they will just be discarded because no struct machine will be found and thus the event will be accounted as not handled and dropped, see 0c09571. Reported-by: Namhyung Kim Tested-by: Joerg Roedel Cc: David Ahern Cc: Frederic Weisbecker Cc: Joerg Roedel Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-vuwxig36mzprl5n7nzvnxxsh@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 29 ++++++++++++++++++++--------- tools/perf/builtin-top.c | 23 +++++++++++++++++------ tools/perf/perf.h | 1 + tools/perf/util/top.h | 1 + 4 files changed, 39 insertions(+), 15 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 39b6a4067f8..227b6ae9978 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -204,6 +204,9 @@ static void perf_record__open(struct perf_record *rec) if (opts->group && pos != first) group_fd = first->fd; +fallback_missing_features: + if (opts->exclude_guest_missing) + attr->exclude_guest = attr->exclude_host = 0; retry_sample_id: attr->sample_id_all = opts->sample_id_all_avail ? 1 : 0; try_again: @@ -217,15 +220,23 @@ try_again: } else if (err == ENODEV && opts->cpu_list) { die("No such device - did you specify" " an out-of-range profile CPU?\n"); - } else if (err == EINVAL && opts->sample_id_all_avail) { - /* - * Old kernel, no attr->sample_id_type_all field - */ - opts->sample_id_all_avail = false; - if (!opts->sample_time && !opts->raw_samples && !time_needed) - attr->sample_type &= ~PERF_SAMPLE_TIME; - - goto retry_sample_id; + } else if (err == EINVAL) { + if (!opts->exclude_guest_missing && + (attr->exclude_guest || attr->exclude_host)) { + pr_debug("Old kernel, cannot exclude " + "guest or host samples.\n"); + opts->exclude_guest_missing = true; + goto fallback_missing_features; + } else if (opts->sample_id_all_avail) { + /* + * Old kernel, no attr->sample_id_type_all field + */ + opts->sample_id_all_avail = false; + if (!opts->sample_time && !opts->raw_samples && !time_needed) + attr->sample_type &= ~PERF_SAMPLE_TIME; + + goto retry_sample_id; + } } /* diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index dd162aa24ba..ecff31257eb 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -857,6 +857,9 @@ static void perf_top__start_counters(struct perf_top *top) attr->mmap = 1; attr->comm = 1; attr->inherit = top->inherit; +fallback_missing_features: + if (top->exclude_guest_missing) + attr->exclude_guest = attr->exclude_host = 0; retry_sample_id: attr->sample_id_all = top->sample_id_all_avail ? 1 : 0; try_again: @@ -868,12 +871,20 @@ try_again: if (err == EPERM || err == EACCES) { ui__error_paranoid(); goto out_err; - } else if (err == EINVAL && top->sample_id_all_avail) { - /* - * Old kernel, no attr->sample_id_type_all field - */ - top->sample_id_all_avail = false; - goto retry_sample_id; + } else if (err == EINVAL) { + if (!top->exclude_guest_missing && + (attr->exclude_guest || attr->exclude_host)) { + pr_debug("Old kernel, cannot exclude " + "guest or host samples.\n"); + top->exclude_guest_missing = true; + goto fallback_missing_features; + } else if (top->sample_id_all_avail) { + /* + * Old kernel, no attr->sample_id_type_all field + */ + top->sample_id_all_avail = false; + goto retry_sample_id; + } } /* * If it's cycles then fall back to hrtimer diff --git a/tools/perf/perf.h b/tools/perf/perf.h index 64f8bee31ce..16e7d20eee8 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h @@ -199,6 +199,7 @@ struct perf_record_opts { bool sample_address; bool sample_time; bool sample_id_all_avail; + bool exclude_guest_missing; bool system_wide; bool period; unsigned int freq; diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h index a248f3c2c60..f2eab81435a 100644 --- a/tools/perf/util/top.h +++ b/tools/perf/util/top.h @@ -34,6 +34,7 @@ struct perf_top { bool inherit; bool group; bool sample_id_all_avail; + bool exclude_guest_missing; bool dump_symtab; const char *cpu_list; struct hist_entry *sym_filter_entry; -- cgit v1.2.3-70-g09d2 From 8aa8a7c80ccdfac2df5ee48a51a4a7bee2143d4f Mon Sep 17 00:00:00 2001 From: Stephane Eranian Date: Tue, 13 Mar 2012 16:51:02 +0100 Subject: perf record: Fix buffer overrun bug in tracepoint_id_to_path() This patch fixes a buffer overrun bug in tracepoint_id_to_path(). The bug manisfested itself as a memory error reported by perf record. I ran into it with perf sched: $ perf sched rec noploop 2 noploop for 2 seconds [ perf record: Woken up 14 times to write data ] [ perf record: Captured and wrote 42.701 MB perf.data (~1865622 samples) ] Fatal: No memory to alloc tracepoints list It turned out that tracepoint_id_to_path() was reading the tracepoint id using read() but the buffer was not large enough to include the \n terminator for id with 4 digits or more. The patch fixes the problem by extending the buffer to a more reasonable size covering all possible id length include \n terminator. Note that atoll() stops at the first non digit character, thus it is not necessary to clear the buffer between each read. Signed-off-by: Stephane Eranian Acked-by: Arnaldo Carvalho de Melo Acked-by: Peter Zijlstra Cc: fweisbec@gmail.com Cc: dsahern@gmail.com Link: http://lkml.kernel.org/r/20120313155102.GA6465@quad Signed-off-by: Ingo Molnar --- tools/perf/util/parse-events.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index b029296d20d..c7a6f6faf91 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -165,7 +165,7 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config) struct tracepoint_path *path = NULL; DIR *sys_dir, *evt_dir; struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent; - char id_buf[4]; + char id_buf[24]; int fd; u64 id; char evt_path[MAXPATHLEN]; -- cgit v1.2.3-70-g09d2 From b832796caa1fda8516464a003c8c7cc547bc20c2 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Wed, 7 Mar 2012 11:42:49 +1100 Subject: perf tools: Incorrect use of snprintf results in SEGV I have a workload where perf top scribbles over the stack and we SEGV. What makes it interesting is that an snprintf is causing this. The workload is a c++ gem that has method names over 3000 characters long, but snprintf is designed to avoid overrunning buffers. So what went wrong? The problem is we assume snprintf returns the number of characters written: ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", self->level); ... ret += repsep_snprintf(bf + ret, size - ret, "%s", self->ms.sym->name); Unfortunately this is not how snprintf works. snprintf returns the number of characters that would have been written if there was enough space. In the above case, if the first snprintf returns a value larger than size, we pass a negative size into the second snprintf and happily scribble over the stack. If you have 3000 character c++ methods thats a lot of stack to trample. This patch fixes repsep_snprintf by clamping the value at size - 1 which is the maximum snprintf can write before adding the NULL terminator. I get the sinking feeling that there are a lot of other uses of snprintf that have this same bug, we should audit them all. Cc: David Ahern Cc: Eric B Munson Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Yanmin Zhang Cc: stable@kernel.org Link: http://lkml.kernel.org/r/20120307114249.44275ca3@kryten Signed-off-by: Anton Blanchard Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/sort.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'tools') diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 16da30d8d76..076c9d4e1ea 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -33,6 +33,9 @@ static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...) } } va_end(ap); + + if (n >= (int)size) + return size - 1; return n; } -- cgit v1.2.3-70-g09d2 From e7f01d1e3d8d501deb8abeaa269d5d48a703b8b0 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 14 Mar 2012 12:29:29 -0300 Subject: perf tools: Use scnprintf where applicable Several places were expecting that the value returned was the number of characters printed, not what would be printed if there was space. Fix it by using the scnprintf and vscnprintf variants we inherited from the kernel sources. Some corner cases where the number of printed characters were not accounted were fixed too. Reported-by: Anton Blanchard Cc: Anton Blanchard Cc: Eric B Munson Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Yanmin Zhang Cc: stable@kernel.org Link: http://lkml.kernel.org/n/tip-kwxo2eh29cxmd8ilixi2005x@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/powerpc/util/header.c | 2 +- tools/perf/arch/x86/util/header.c | 2 +- tools/perf/util/color.c | 9 +++++---- tools/perf/util/header.c | 4 ++-- tools/perf/util/hist.c | 30 +++++++++++++++--------------- tools/perf/util/strbuf.c | 7 ++++--- tools/perf/util/ui/browsers/hists.c | 12 ++++++------ tools/perf/util/ui/helpline.c | 2 +- 8 files changed, 35 insertions(+), 33 deletions(-) (limited to 'tools') diff --git a/tools/perf/arch/powerpc/util/header.c b/tools/perf/arch/powerpc/util/header.c index eba80c29294..2f7073d107f 100644 --- a/tools/perf/arch/powerpc/util/header.c +++ b/tools/perf/arch/powerpc/util/header.c @@ -25,7 +25,7 @@ get_cpuid(char *buffer, size_t sz) pvr = mfspr(SPRN_PVR); - nb = snprintf(buffer, sz, "%lu,%lu$", PVR_VER(pvr), PVR_REV(pvr)); + nb = scnprintf(buffer, sz, "%lu,%lu$", PVR_VER(pvr), PVR_REV(pvr)); /* look for end marker to ensure the entire data fit */ if (strchr(buffer, '$')) { diff --git a/tools/perf/arch/x86/util/header.c b/tools/perf/arch/x86/util/header.c index f94006068d2..146d12a1cec 100644 --- a/tools/perf/arch/x86/util/header.c +++ b/tools/perf/arch/x86/util/header.c @@ -48,7 +48,7 @@ get_cpuid(char *buffer, size_t sz) if (family >= 0x6) model += ((a >> 16) & 0xf) << 4; } - nb = snprintf(buffer, sz, "%s,%u,%u,%u$", vendor, family, model, step); + nb = scnprintf(buffer, sz, "%s,%u,%u,%u$", vendor, family, model, step); /* look for end marker to ensure the entire data fit */ if (strchr(buffer, '$')) { diff --git a/tools/perf/util/color.c b/tools/perf/util/color.c index 521c38a7919..11e46da17bb 100644 --- a/tools/perf/util/color.c +++ b/tools/perf/util/color.c @@ -1,3 +1,4 @@ +#include #include "cache.h" #include "color.h" @@ -182,12 +183,12 @@ static int __color_vsnprintf(char *bf, size_t size, const char *color, } if (perf_use_color_default && *color) - r += snprintf(bf, size, "%s", color); - r += vsnprintf(bf + r, size - r, fmt, args); + r += scnprintf(bf, size, "%s", color); + r += vscnprintf(bf + r, size - r, fmt, args); if (perf_use_color_default && *color) - r += snprintf(bf + r, size - r, "%s", PERF_COLOR_RESET); + r += scnprintf(bf + r, size - r, "%s", PERF_COLOR_RESET); if (trail) - r += snprintf(bf + r, size - r, "%s", trail); + r += scnprintf(bf + r, size - r, "%s", trail); return r; } diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index ecd7f4dd7ee..14bb035c5fd 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -280,7 +280,7 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir, if (realname == NULL || filename == NULL || linkname == NULL) goto out_free; - len = snprintf(filename, size, "%s%s%s", + len = scnprintf(filename, size, "%s%s%s", debugdir, is_kallsyms ? "/" : "", realname); if (mkdir_p(filename, 0755)) goto out_free; @@ -295,7 +295,7 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir, goto out_free; } - len = snprintf(linkname, size, "%s/.build-id/%.2s", + len = scnprintf(linkname, size, "%s/.build-id/%.2s", debugdir, sbuild_id); if (access(linkname, X_OK) && mkdir_p(linkname, 0755)) diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 6f505d1abac..e11e482bd18 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -768,7 +768,7 @@ static int hist_entry__pcnt_snprintf(struct hist_entry *he, char *s, sep ? "%.2f" : " %6.2f%%", (period * 100.0) / total); else - ret = snprintf(s, size, sep ? "%.2f" : " %6.2f%%", + ret = scnprintf(s, size, sep ? "%.2f" : " %6.2f%%", (period * 100.0) / total); if (symbol_conf.show_cpu_utilization) { ret += percent_color_snprintf(s + ret, size - ret, @@ -791,20 +791,20 @@ static int hist_entry__pcnt_snprintf(struct hist_entry *he, char *s, } } } else - ret = snprintf(s, size, sep ? "%" PRIu64 : "%12" PRIu64 " ", period); + ret = scnprintf(s, size, sep ? "%" PRIu64 : "%12" PRIu64 " ", period); if (symbol_conf.show_nr_samples) { if (sep) - ret += snprintf(s + ret, size - ret, "%c%" PRIu64, *sep, nr_events); + ret += scnprintf(s + ret, size - ret, "%c%" PRIu64, *sep, nr_events); else - ret += snprintf(s + ret, size - ret, "%11" PRIu64, nr_events); + ret += scnprintf(s + ret, size - ret, "%11" PRIu64, nr_events); } if (symbol_conf.show_total_period) { if (sep) - ret += snprintf(s + ret, size - ret, "%c%" PRIu64, *sep, period); + ret += scnprintf(s + ret, size - ret, "%c%" PRIu64, *sep, period); else - ret += snprintf(s + ret, size - ret, " %12" PRIu64, period); + ret += scnprintf(s + ret, size - ret, " %12" PRIu64, period); } if (pair_hists) { @@ -819,25 +819,25 @@ static int hist_entry__pcnt_snprintf(struct hist_entry *he, char *s, diff = new_percent - old_percent; if (fabs(diff) >= 0.01) - snprintf(bf, sizeof(bf), "%+4.2F%%", diff); + ret += scnprintf(bf, sizeof(bf), "%+4.2F%%", diff); else - snprintf(bf, sizeof(bf), " "); + ret += scnprintf(bf, sizeof(bf), " "); if (sep) - ret += snprintf(s + ret, size - ret, "%c%s", *sep, bf); + ret += scnprintf(s + ret, size - ret, "%c%s", *sep, bf); else - ret += snprintf(s + ret, size - ret, "%11.11s", bf); + ret += scnprintf(s + ret, size - ret, "%11.11s", bf); if (show_displacement) { if (displacement) - snprintf(bf, sizeof(bf), "%+4ld", displacement); + ret += scnprintf(bf, sizeof(bf), "%+4ld", displacement); else - snprintf(bf, sizeof(bf), " "); + ret += scnprintf(bf, sizeof(bf), " "); if (sep) - ret += snprintf(s + ret, size - ret, "%c%s", *sep, bf); + ret += scnprintf(s + ret, size - ret, "%c%s", *sep, bf); else - ret += snprintf(s + ret, size - ret, "%6.6s", bf); + ret += scnprintf(s + ret, size - ret, "%6.6s", bf); } } @@ -855,7 +855,7 @@ int hist_entry__snprintf(struct hist_entry *he, char *s, size_t size, if (se->elide) continue; - ret += snprintf(s + ret, size - ret, "%s", sep ?: " "); + ret += scnprintf(s + ret, size - ret, "%s", sep ?: " "); ret += se->se_snprintf(he, s + ret, size - ret, hists__col_len(hists, se->se_width_idx)); } diff --git a/tools/perf/util/strbuf.c b/tools/perf/util/strbuf.c index 92e068517c1..2eeb51baf07 100644 --- a/tools/perf/util/strbuf.c +++ b/tools/perf/util/strbuf.c @@ -1,4 +1,5 @@ #include "cache.h" +#include int prefixcmp(const char *str, const char *prefix) { @@ -89,14 +90,14 @@ void strbuf_addf(struct strbuf *sb, const char *fmt, ...) if (!strbuf_avail(sb)) strbuf_grow(sb, 64); va_start(ap, fmt); - len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap); + len = vscnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap); va_end(ap); if (len < 0) - die("your vsnprintf is broken"); + die("your vscnprintf is broken"); if (len > strbuf_avail(sb)) { strbuf_grow(sb, len); va_start(ap, fmt); - len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap); + len = vscnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap); va_end(ap); if (len > strbuf_avail(sb)) { die("this should not happen, your snprintf is broken"); diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c index e81aef1f256..bb9197c9c4a 100644 --- a/tools/perf/util/ui/browsers/hists.c +++ b/tools/perf/util/ui/browsers/hists.c @@ -837,15 +837,15 @@ static int hists__browser_title(struct hists *self, char *bf, size_t size, unsigned long nr_events = self->stats.nr_events[PERF_RECORD_SAMPLE]; nr_events = convert_unit(nr_events, &unit); - printed = snprintf(bf, size, "Events: %lu%c %s", nr_events, unit, ev_name); + printed = scnprintf(bf, size, "Events: %lu%c %s", nr_events, unit, ev_name); if (thread) - printed += snprintf(bf + printed, size - printed, + printed += scnprintf(bf + printed, size - printed, ", Thread: %s(%d)", (thread->comm_set ? thread->comm : ""), thread->pid); if (dso) - printed += snprintf(bf + printed, size - printed, + printed += scnprintf(bf + printed, size - printed, ", DSO: %s", dso->short_name); return printed; } @@ -1095,7 +1095,7 @@ static void perf_evsel_menu__write(struct ui_browser *browser, HE_COLORSET_NORMAL); nr_events = convert_unit(nr_events, &unit); - printed = snprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events, + printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events, unit, unit == ' ' ? "" : " ", ev_name); slsmg_printf("%s", bf); @@ -1105,8 +1105,8 @@ static void perf_evsel_menu__write(struct ui_browser *browser, if (!current_entry) ui_browser__set_color(browser, HE_COLORSET_TOP); nr_events = convert_unit(nr_events, &unit); - snprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!", nr_events, - unit, unit == ' ' ? "" : " "); + printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!", + nr_events, unit, unit == ' ' ? "" : " "); warn = bf; } diff --git a/tools/perf/util/ui/helpline.c b/tools/perf/util/ui/helpline.c index 4f48f5901b3..2f950c2641c 100644 --- a/tools/perf/util/ui/helpline.c +++ b/tools/perf/util/ui/helpline.c @@ -64,7 +64,7 @@ int ui_helpline__show_help(const char *format, va_list ap) static int backlog; pthread_mutex_lock(&ui__lock); - ret = vsnprintf(ui_helpline__last_msg + backlog, + ret = vscnprintf(ui_helpline__last_msg + backlog, sizeof(ui_helpline__last_msg) - backlog, format, ap); backlog += ret; -- cgit v1.2.3-70-g09d2 From eae7a755ee81129370c8f555b0d5672e6673735d Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Wed, 14 Mar 2012 12:42:34 -0300 Subject: perf tools, x86: Build perf on older user-space as well MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On ancient systems I get this build failure: util/../../../arch/x86/include/asm/unistd.h:67:29: error: asm/unistd_64.h: No such file or directory In file included from util/cache.h:7, from builtin-test.c:8: util/../perf.h: In function ‘sys_perf_event_open’:In file included from util/../perf.h:16 perf.h:170: error: ‘__NR_perf_event_open’ undeclared (first use in this function) The reason is that this old system does not have the split unistd.h headers yet, from which to pick up the syscall definitions. Add the syscall numbers to the already existing i386 and x86_64 blocks in perf.h, and also provide empty include file stubs. With this patch perf builds and works fine on 5 years old user-space as well. Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Link: http://lkml.kernel.org/n/tip-jctwg64le1w47tuaoeyftsg9@git.kernel.org Signed-off-by: Ingo Molnar Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Makefile | 2 ++ tools/perf/perf.h | 6 ++++++ tools/perf/util/include/asm/unistd_32.h | 1 + tools/perf/util/include/asm/unistd_64.h | 1 + 4 files changed, 10 insertions(+) create mode 100644 tools/perf/util/include/asm/unistd_32.h create mode 100644 tools/perf/util/include/asm/unistd_64.h (limited to 'tools') diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 7c12650165a..8a4b9bccf8b 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -249,6 +249,8 @@ LIB_H += util/include/asm/uaccess.h LIB_H += util/include/dwarf-regs.h LIB_H += util/include/asm/dwarf2.h LIB_H += util/include/asm/cpufeature.h +LIB_H += util/include/asm/unistd_32.h +LIB_H += util/include/asm/unistd_64.h LIB_H += perf.h LIB_H += util/annotate.h LIB_H += util/cache.h diff --git a/tools/perf/perf.h b/tools/perf/perf.h index 16e7d20eee8..3afa39ac1d4 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h @@ -10,6 +10,9 @@ void get_term_dimensions(struct winsize *ws); #define rmb() asm volatile("lock; addl $0,0(%%esp)" ::: "memory") #define cpu_relax() asm volatile("rep; nop" ::: "memory"); #define CPUINFO_PROC "model name" +#ifndef __NR_perf_event_open +# define __NR_perf_event_open 336 +#endif #endif #if defined(__x86_64__) @@ -17,6 +20,9 @@ void get_term_dimensions(struct winsize *ws); #define rmb() asm volatile("lfence" ::: "memory") #define cpu_relax() asm volatile("rep; nop" ::: "memory"); #define CPUINFO_PROC "model name" +#ifndef __NR_perf_event_open +# define __NR_perf_event_open 298 +#endif #endif #ifdef __powerpc__ diff --git a/tools/perf/util/include/asm/unistd_32.h b/tools/perf/util/include/asm/unistd_32.h new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/tools/perf/util/include/asm/unistd_32.h @@ -0,0 +1 @@ + diff --git a/tools/perf/util/include/asm/unistd_64.h b/tools/perf/util/include/asm/unistd_64.h new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/tools/perf/util/include/asm/unistd_64.h @@ -0,0 +1 @@ + -- cgit v1.2.3-70-g09d2