diff options
Diffstat (limited to 'tools')
57 files changed, 1984 insertions, 296 deletions
diff --git a/tools/Makefile b/tools/Makefile index 6bf68fe7dd29..f10b64d8c674 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -16,6 +16,7 @@ help: @echo ' gpio - GPIO tools' @echo ' hv - tools used when in Hyper-V clients' @echo ' iio - IIO tools' + @echo ' kvm_stat - top-like utility for displaying kvm statistics' @echo ' lguest - a minimal 32-bit x86 hypervisor' @echo ' net - misc networking tools' @echo ' perf - Linux performance measurement and analysis tool' @@ -110,10 +111,13 @@ tmon_install: freefall_install: $(call descend,laptop/$(@:_install=),install) +kvm_stat_install: + $(call descend,kvm/$(@:_install=),install) + install: acpi_install cgroup_install cpupower_install hv_install firewire_install lguest_install \ perf_install selftests_install turbostat_install usb_install \ virtio_install vm_install net_install x86_energy_perf_policy_install \ - tmon_install freefall_install objtool_install + tmon_install freefall_install objtool_install kvm_stat_install acpi_clean: $(call descend,power/acpi,clean) diff --git a/tools/build/Makefile.build b/tools/build/Makefile.build index ee566e8bd1cf..27f3583193e6 100644 --- a/tools/build/Makefile.build +++ b/tools/build/Makefile.build @@ -58,8 +58,8 @@ quiet_cmd_mkdir = MKDIR $(dir $@) quiet_cmd_cc_o_c = CC $@ cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $< -quiet_cmd_cc_i_c = CPP $@ - cmd_cc_i_c = $(CC) $(c_flags) -E -o $@ $< +quiet_cmd_cpp_i_c = CPP $@ + cmd_cpp_i_c = $(CC) $(c_flags) -E -o $@ $< quiet_cmd_cc_s_c = AS $@ cmd_cc_s_c = $(CC) $(c_flags) -S -o $@ $< @@ -83,11 +83,11 @@ $(OUTPUT)%.o: %.S FORCE $(OUTPUT)%.i: %.c FORCE $(call rule_mkdir) - $(call if_changed_dep,cc_i_c) + $(call if_changed_dep,cpp_i_c) $(OUTPUT)%.s: %.S FORCE $(call rule_mkdir) - $(call if_changed_dep,cc_i_c) + $(call if_changed_dep,cpp_i_c) $(OUTPUT)%.s: %.c FORCE $(call rule_mkdir) diff --git a/tools/kvm/kvm_stat/Makefile b/tools/kvm/kvm_stat/Makefile new file mode 100644 index 000000000000..5b1cba57e3b3 --- /dev/null +++ b/tools/kvm/kvm_stat/Makefile @@ -0,0 +1,41 @@ +include ../../scripts/Makefile.include +include ../../scripts/utilities.mak +BINDIR=usr/bin +MANDIR=usr/share/man +MAN1DIR=$(MANDIR)/man1 + +MAN1=kvm_stat.1 + +A2X=a2x +a2x_path := $(call get-executable,$(A2X)) + +all: man + +ifneq ($(findstring $(MAKEFLAGS),s),s) + ifneq ($(V),1) + QUIET_A2X = @echo ' A2X '$@; + endif +endif + +%.1: %.txt +ifeq ($(a2x_path),) + $(error "You need to install asciidoc for man pages") +else + $(QUIET_A2X)$(A2X) --doctype manpage --format manpage $< +endif + +clean: + rm -f $(MAN1) + +man: $(MAN1) + +install-man: man + install -d -m 755 $(INSTALL_ROOT)/$(MAN1DIR) + install -m 644 kvm_stat.1 $(INSTALL_ROOT)/$(MAN1DIR) + +install-tools: + install -d -m 755 $(INSTALL_ROOT)/$(BINDIR) + install -m 755 -p "kvm_stat" "$(INSTALL_ROOT)/$(BINDIR)/$(TARGET)" + +install: install-tools install-man +.PHONY: all clean man install-tools install-man install diff --git a/tools/kvm/kvm_stat/kvm_stat b/tools/kvm/kvm_stat/kvm_stat new file mode 100755 index 000000000000..581278c58488 --- /dev/null +++ b/tools/kvm/kvm_stat/kvm_stat @@ -0,0 +1,1127 @@ +#!/usr/bin/python +# +# top-like utility for displaying kvm statistics +# +# Copyright 2006-2008 Qumranet Technologies +# Copyright 2008-2011 Red Hat, Inc. +# +# Authors: +# Avi Kivity <avi@redhat.com> +# +# This work is licensed under the terms of the GNU GPL, version 2. See +# the COPYING file in the top-level directory. +"""The kvm_stat module outputs statistics about running KVM VMs + +Three different ways of output formatting are available: +- as a top-like text ui +- in a key -> value format +- in an all keys, all values format + +The data is sampled from the KVM's debugfs entries and its perf events. +""" + +import curses +import sys +import os +import time +import optparse +import ctypes +import fcntl +import resource +import struct +import re +from collections import defaultdict +from time import sleep + +VMX_EXIT_REASONS = { + 'EXCEPTION_NMI': 0, + 'EXTERNAL_INTERRUPT': 1, + 'TRIPLE_FAULT': 2, + 'PENDING_INTERRUPT': 7, + 'NMI_WINDOW': 8, + 'TASK_SWITCH': 9, + 'CPUID': 10, + 'HLT': 12, + 'INVLPG': 14, + 'RDPMC': 15, + 'RDTSC': 16, + 'VMCALL': 18, + 'VMCLEAR': 19, + 'VMLAUNCH': 20, + 'VMPTRLD': 21, + 'VMPTRST': 22, + 'VMREAD': 23, + 'VMRESUME': 24, + 'VMWRITE': 25, + 'VMOFF': 26, + 'VMON': 27, + 'CR_ACCESS': 28, + 'DR_ACCESS': 29, + 'IO_INSTRUCTION': 30, + 'MSR_READ': 31, + 'MSR_WRITE': 32, + 'INVALID_STATE': 33, + 'MWAIT_INSTRUCTION': 36, + 'MONITOR_INSTRUCTION': 39, + 'PAUSE_INSTRUCTION': 40, + 'MCE_DURING_VMENTRY': 41, + 'TPR_BELOW_THRESHOLD': 43, + 'APIC_ACCESS': 44, + 'EPT_VIOLATION': 48, + 'EPT_MISCONFIG': 49, + 'WBINVD': 54, + 'XSETBV': 55, + 'APIC_WRITE': 56, + 'INVPCID': 58, +} + +SVM_EXIT_REASONS = { + 'READ_CR0': 0x000, + 'READ_CR3': 0x003, + 'READ_CR4': 0x004, + 'READ_CR8': 0x008, + 'WRITE_CR0': 0x010, + 'WRITE_CR3': 0x013, + 'WRITE_CR4': 0x014, + 'WRITE_CR8': 0x018, + 'READ_DR0': 0x020, + 'READ_DR1': 0x021, + 'READ_DR2': 0x022, + 'READ_DR3': 0x023, + 'READ_DR4': 0x024, + 'READ_DR5': 0x025, + 'READ_DR6': 0x026, + 'READ_DR7': 0x027, + 'WRITE_DR0': 0x030, + 'WRITE_DR1': 0x031, + 'WRITE_DR2': 0x032, + 'WRITE_DR3': 0x033, + 'WRITE_DR4': 0x034, + 'WRITE_DR5': 0x035, + 'WRITE_DR6': 0x036, + 'WRITE_DR7': 0x037, + 'EXCP_BASE': 0x040, + 'INTR': 0x060, + 'NMI': 0x061, + 'SMI': 0x062, + 'INIT': 0x063, + 'VINTR': 0x064, + 'CR0_SEL_WRITE': 0x065, + 'IDTR_READ': 0x066, + 'GDTR_READ': 0x067, + 'LDTR_READ': 0x068, + 'TR_READ': 0x069, + 'IDTR_WRITE': 0x06a, + 'GDTR_WRITE': 0x06b, + 'LDTR_WRITE': 0x06c, + 'TR_WRITE': 0x06d, + 'RDTSC': 0x06e, + 'RDPMC': 0x06f, + 'PUSHF': 0x070, + 'POPF': 0x071, + 'CPUID': 0x072, + 'RSM': 0x073, + 'IRET': 0x074, + 'SWINT': 0x075, + 'INVD': 0x076, + 'PAUSE': 0x077, + 'HLT': 0x078, + 'INVLPG': 0x079, + 'INVLPGA': 0x07a, + 'IOIO': 0x07b, + 'MSR': 0x07c, + 'TASK_SWITCH': 0x07d, + 'FERR_FREEZE': 0x07e, + 'SHUTDOWN': 0x07f, + 'VMRUN': 0x080, + 'VMMCALL': 0x081, + 'VMLOAD': 0x082, + 'VMSAVE': 0x083, + 'STGI': 0x084, + 'CLGI': 0x085, + 'SKINIT': 0x086, + 'RDTSCP': 0x087, + 'ICEBP': 0x088, + 'WBINVD': 0x089, + 'MONITOR': 0x08a, + 'MWAIT': 0x08b, + 'MWAIT_COND': 0x08c, + 'XSETBV': 0x08d, + 'NPF': 0x400, +} + +# EC definition of HSR (from arch/arm64/include/asm/kvm_arm.h) +AARCH64_EXIT_REASONS = { + 'UNKNOWN': 0x00, + 'WFI': 0x01, + 'CP15_32': 0x03, + 'CP15_64': 0x04, + 'CP14_MR': 0x05, + 'CP14_LS': 0x06, + 'FP_ASIMD': 0x07, + 'CP10_ID': 0x08, + 'CP14_64': 0x0C, + 'ILL_ISS': 0x0E, + 'SVC32': 0x11, + 'HVC32': 0x12, + 'SMC32': 0x13, + 'SVC64': 0x15, + 'HVC64': 0x16, + 'SMC64': 0x17, + 'SYS64': 0x18, + 'IABT': 0x20, + 'IABT_HYP': 0x21, + 'PC_ALIGN': 0x22, + 'DABT': 0x24, + 'DABT_HYP': 0x25, + 'SP_ALIGN': 0x26, + 'FP_EXC32': 0x28, + 'FP_EXC64': 0x2C, + 'SERROR': 0x2F, + 'BREAKPT': 0x30, + 'BREAKPT_HYP': 0x31, + 'SOFTSTP': 0x32, + 'SOFTSTP_HYP': 0x33, + 'WATCHPT': 0x34, + 'WATCHPT_HYP': 0x35, + 'BKPT32': 0x38, + 'VECTOR32': 0x3A, + 'BRK64': 0x3C, +} + +# From include/uapi/linux/kvm.h, KVM_EXIT_xxx +USERSPACE_EXIT_REASONS = { + 'UNKNOWN': 0, + 'EXCEPTION': 1, + 'IO': 2, + 'HYPERCALL': 3, + 'DEBUG': 4, + 'HLT': 5, + 'MMIO': 6, + 'IRQ_WINDOW_OPEN': 7, + 'SHUTDOWN': 8, + 'FAIL_ENTRY': 9, + 'INTR': 10, + 'SET_TPR': 11, + 'TPR_ACCESS': 12, + 'S390_SIEIC': 13, + 'S390_RESET': 14, + 'DCR': 15, + 'NMI': 16, + 'INTERNAL_ERROR': 17, + 'OSI': 18, + 'PAPR_HCALL': 19, + 'S390_UCONTROL': 20, + 'WATCHDOG': 21, + 'S390_TSCH': 22, + 'EPR': 23, + 'SYSTEM_EVENT': 24, +} + +IOCTL_NUMBERS = { + 'SET_FILTER': 0x40082406, + 'ENABLE': 0x00002400, + 'DISABLE': 0x00002401, + 'RESET': 0x00002403, +} + +class Arch(object): + """Encapsulates global architecture specific data. + + Contains the performance event open syscall and ioctl numbers, as + well as the VM exit reasons for the architecture it runs on. + + """ + @staticmethod + def get_arch(): + machine = os.uname()[4] + + if machine.startswith('ppc'): + return ArchPPC() + elif machine.startswith('aarch64'): + return ArchA64() + elif machine.startswith('s390'): + return ArchS390() + else: + # X86_64 + for line in open('/proc/cpuinfo'): + if not line.startswith('flags'): + continue + + flags = line.split() + if 'vmx' in flags: + return ArchX86(VMX_EXIT_REASONS) + if 'svm' in flags: + return ArchX86(SVM_EXIT_REASONS) + return + +class ArchX86(Arch): + def __init__(self, exit_reasons): + self.sc_perf_evt_open = 298 + self.ioctl_numbers = IOCTL_NUMBERS + self.exit_reasons = exit_reasons + +class ArchPPC(Arch): + def __init__(self): + self.sc_perf_evt_open = 319 + self.ioctl_numbers = IOCTL_NUMBERS + self.ioctl_numbers['ENABLE'] = 0x20002400 + self.ioctl_numbers['DISABLE'] = 0x20002401 + self.ioctl_numbers['RESET'] = 0x20002403 + + # PPC comes in 32 and 64 bit and some generated ioctl + # numbers depend on the wordsize. + char_ptr_size = ctypes.sizeof(ctypes.c_char_p) + self.ioctl_numbers['SET_FILTER'] = 0x80002406 | char_ptr_size << 16 + self.exit_reasons = {} + +class ArchA64(Arch): + def __init__(self): + self.sc_perf_evt_open = 241 + self.ioctl_numbers = IOCTL_NUMBERS + self.exit_reasons = AARCH64_EXIT_REASONS + +class ArchS390(Arch): + def __init__(self): + self.sc_perf_evt_open = 331 + self.ioctl_numbers = IOCTL_NUMBERS + self.exit_reasons = None + +ARCH = Arch.get_arch() + + +def walkdir(path): + """Returns os.walk() data for specified directory. + + As it is only a wrapper it returns the same 3-tuple of (dirpath, + dirnames, filenames). + """ + return next(os.walk(path)) + + +def parse_int_list(list_string): + """Returns an int list from a string of comma separated integers and + integer ranges.""" + integers = [] + members = list_string.split(',') + + for member in members: + if '-' not in member: + integers.append(int(member)) + else: + int_range = member.split('-') + integers.extend(range(int(int_range[0]), + int(int_range[1]) + 1)) + + return integers + + +def get_online_cpus(): + """Returns a list of cpu id integers.""" + with open('/sys/devices/system/cpu/online') as cpu_list: + cpu_string = cpu_list.readline() + return parse_int_list(cpu_string) + + +def get_filters(): + """Returns a dict of trace events, their filter ids and + the values that can be filtered. + + Trace events can be filtered for special values by setting a + filter string via an ioctl. The string normally has the format + identifier==value. For each filter a new event will be created, to + be able to distinguish the events. + + """ + filters = {} + filters['kvm_userspace_exit'] = ('reason', USERSPACE_EXIT_REASONS) + if ARCH.exit_reasons: + filters['kvm_exit'] = ('exit_reason', ARCH.exit_reasons) + return filters + +libc = ctypes.CDLL('libc.so.6', use_errno=True) +syscall = libc.syscall + +class perf_event_attr(ctypes.Structure): + """Struct that holds the necessary data to set up a trace event. + + For an extensive explanation see perf_event_open(2) and + include/uapi/linux/perf_event.h, struct perf_event_attr + + All fields that are not initialized in the constructor are 0. + + """ + _fields_ = [('type', ctypes.c_uint32), + ('size', ctypes.c_uint32), + ('config', ctypes.c_uint64), + ('sample_freq', ctypes.c_uint64), + ('sample_type', ctypes.c_uint64), + ('read_format', ctypes.c_uint64), + ('flags', ctypes.c_uint64), + ('wakeup_events', ctypes.c_uint32), + ('bp_type', ctypes.c_uint32), + ('bp_addr', ctypes.c_uint64), + ('bp_len', ctypes.c_uint64), + ] + + def __init__(self): + super(self.__class__, self).__init__() + self.type = PERF_TYPE_TRACEPOINT + self.size = ctypes.sizeof(self) + self.read_format = PERF_FORMAT_GROUP + +def perf_event_open(attr, pid, cpu, group_fd, flags): + """Wrapper for the sys_perf_evt_open() syscall. + + Used to set up performance events, returns a file descriptor or -1 + on error. + + Attributes are: + - syscall number + - struct perf_event_attr * + - pid or -1 to monitor all pids + - cpu number or -1 to monitor all cpus + - The file descriptor of the group leader or -1 to create a group. + - flags + + """ + return syscall(ARCH.sc_perf_evt_open, ctypes.pointer(attr), + ctypes.c_int(pid), ctypes.c_int(cpu), + ctypes.c_int(group_fd), ctypes.c_long(flags)) + +PERF_TYPE_TRACEPOINT = 2 +PERF_FORMAT_GROUP = 1 << 3 + +PATH_DEBUGFS_TRACING = '/sys/kernel/debug/tracing' +PATH_DEBUGFS_KVM = '/sys/kernel/debug/kvm' + +class Group(object): + """Represents a perf event group.""" + + def __init__(self): + self.events = [] + + def add_event(self, event): + self.events.append(event) + + def read(self): + """Returns a dict with 'event name: value' for all events in the + group. + + Values are read by reading from the file descriptor of the + event that is the group leader. See perf_event_open(2) for + details. + + Read format for the used event configuration is: + struct read_format { + u64 nr; /* The number of events */ + struct { + u64 value; /* The value of the event */ + } values[nr]; + }; + + """ + length = 8 * (1 + len(self.events)) + read_format = 'xxxxxxxx' + 'Q' * len(self.events) + return dict(zip([event.name for event in self.events], + struct.unpack(read_format, + os.read(self.events[0].fd, length)))) + +class Event(object): + """Represents a performance event and manages its life cycle.""" + def __init__(self, name, group, trace_cpu, trace_pid, trace_point, + trace_filter, trace_set='kvm'): + self.name = name + self.fd = None + self.setup_event(group, trace_cpu, trace_pid, trace_point, + trace_filter, trace_set) + + def __del__(self): + """Closes the event's file descriptor. + + As no python file object was created for the file descriptor, + python will not reference count the descriptor and will not + close it itself automatically, so we do it. + + """ + if self.fd: + os.close(self.fd) + + def setup_event_attribute(self, trace_set, trace_point): + """Returns an initialized ctype perf_event_attr struct.""" + + id_path = os.path.join(PATH_DEBUGFS_TRACING, 'events', trace_set, + trace_point, 'id') + + event_attr = perf_event_attr() + event_attr.config = int(open(id_path).read()) + return event_attr + + def setup_event(self, group, trace_cpu, trace_pid, trace_point, + trace_filter, trace_set): + """Sets up the perf event in Linux. + + Issues the syscall to register the event in the kernel and + then sets the optional filter. + + """ + + event_attr = self.setup_event_attribute(trace_set, trace_point) + + # First event will be group leader. + group_leader = -1 + + # All others have to pass the leader's descriptor instead. + if group.events: + group_leader = group.events[0].fd + + fd = perf_event_open(event_attr, trace_pid, + trace_cpu, group_leader, 0) + if fd == -1: + err = ctypes.get_errno() + raise OSError(err, os.strerror(err), + 'while calling sys_perf_event_open().') + + if trace_filter: + fcntl.ioctl(fd, ARCH.ioctl_numbers['SET_FILTER'], + trace_filter) + + self.fd = fd + + def enable(self): + """Enables the trace event in the kernel. + + Enabling the group leader makes reading counters from it and the + events under it possible. + + """ + fcntl.ioctl(self.fd, ARCH.ioctl_numbers['ENABLE'], 0) + + def disable(self): + """Disables the trace event in the kernel. + + Disabling the group leader makes reading all counters under it + impossible. + + """ + fcntl.ioctl(self.fd, ARCH.ioctl_numbers['DISABLE'], 0) + + def reset(self): + """Resets the count of the trace event in the kernel.""" + fcntl.ioctl(self.fd, ARCH.ioctl_numbers['RESET'], 0) + +class TracepointProvider(object): + """Data provider for the stats class. + + Manages the events/groups from which it acquires its data. + + """ + def __init__(self): + self.group_leaders = [] + self.filters = get_filters() + self._fields = self.get_available_fields() + self._pid = 0 + + def get_available_fields(self): + """Returns a list of available event's of format 'event name(filter + name)'. + + All available events have directories under + /sys/kernel/debug/tracing/events/ which export information + about the specific event. Therefore, listing the dirs gives us + a list of all available events. + + Some events like the vm exit reasons can be filtered for + specific values. To take account for that, the routine below + creates special fields with the following format: + event name(filter name) + + """ + path = os.path.join(PATH_DEBUGFS_TRACING, 'events', 'kvm') + fields = walkdir(path)[1] + extra = [] + for field in fields: + if field in self.filters: + filter_name_, filter_dicts = self.filters[field] + for name in filter_dicts: + extra.append(field + '(' + name + ')') + fields += extra + return fields + + def setup_traces(self): + """Creates all event and group objects needed to be able to retrieve + data.""" + if self._pid > 0: + # Fetch list of all threads of the monitored pid, as qemu + # starts a thread for each vcpu. + path = os.path.join('/proc', str(self._pid), 'task') + groupids = walkdir(path)[1] + else: + groupids = get_online_cpus() + + # The constant is needed as a buffer for python libs, std + # streams and other files that the script opens. + newlim = len(groupids) * len(self._fields) + 50 + try: + softlim_, hardlim = resource.getrlimit(resource.RLIMIT_NOFILE) + + if hardlim < newlim: + # Now we need CAP_SYS_RESOURCE, to increase the hard limit. + resource.setrlimit(resource.RLIMIT_NOFILE, (newlim, newlim)) + else: + # Raising the soft limit is sufficient. + resource.setrlimit(resource.RLIMIT_NOFILE, (newlim, hardlim)) + + except ValueError: + sys.exit("NOFILE rlimit could not be raised to {0}".format(newlim)) + + for groupid in groupids: + group = Group() + for name in self._fields: + tracepoint = name + tracefilter = None + match = re.match(r'(.*)\((.*)\)', name) + if match: + tracepoint, sub = match.groups() + tracefilter = ('%s==%d\0' % + (self.filters[tracepoint][0], + self.filters[tracepoint][1][sub])) + + # From perf_event_open(2): + # pid > 0 and cpu == -1 + # This measures the specified process/thread on any CPU. + # + # pid == -1 and cpu >= 0 + # This measures all processes/threads on the specified CPU. + trace_cpu = groupid if self._pid == 0 else -1 + trace_pid = int(groupid) if self._pid != 0 else -1 + + group.add_event(Event(name=name, + group=group, + trace_cpu=trace_cpu, + trace_pid=trace_pid, + trace_point=tracepoint, + trace_filter=tracefilter)) + + self.group_leaders.append(group) + + def available_fields(self): + return self.get_available_fields() + + @property + def fields(self): + return self._fields + + @fields.setter + def fields(self, fields): + """Enables/disables the (un)wanted events""" + self._fields = fields + for group in self.group_leaders: + for index, event in enumerate(group.events): + if event.name in fields: + event.reset() + event.enable() + else: + # Do not disable the group leader. + # It would disable all of its events. + if index != 0: + event.disable() + + @property + def pid(self): + return self._pid + + @pid.setter + def pid(self, pid): + """Changes the monitored pid by setting new traces.""" + self._pid = pid + # The garbage collector will get rid of all Event/Group + # objects and open files after removing the references. + self.group_leaders = [] + self.setup_traces() + self.fields = self._fields + + def read(self): + """Returns 'event name: current value' for all enabled events.""" + ret = defaultdict(int) + for group in self.group_leaders: + for name, val in group.read().iteritems(): + if name in self._fields: + ret[name] += val + return ret + +class DebugfsProvider(object): + """Provides data from the files that KVM creates in the kvm debugfs + folder.""" + def __init__(self): + self._fields = self.get_available_fields() + self._pid = 0 + self.do_read = True + + def get_available_fields(self): + """"Returns a list of available fields. + + The fields are all available KVM debugfs files + + """ + return walkdir(PATH_DEBUGFS_KVM)[2] + + @property + def fields(self): + return self._fields + + @fields.setter + def fields(self, fields): + self._fields = fields + + @property + def pid(self): + return self._pid + + @pid.setter + def pid(self, pid): + if pid != 0: + self._pid = pid + + vms = walkdir(PATH_DEBUGFS_KVM)[1] + if len(vms) == 0: + self.do_read = False + + self.paths = filter(lambda x: "{}-".format(pid) in x, vms) + + else: + self.paths = [''] + self.do_read = True + + def read(self): + """Returns a dict with format:'file name / field -> current value'.""" + results = {} + + # If no debugfs filtering support is available, then don't read. + if not self.do_read: + return results + + for path in self.paths: + for field in self._fields: + results[field] = results.get(field, 0) \ + + self.read_field(field, path) + + return results + + def read_field(self, field, path): + """Returns the value of a single field from a specific VM.""" + try: + return int(open(os.path.join(PATH_DEBUGFS_KVM, + path, + field)) + .read()) + except IOError: + return 0 + +class Stats(object): + """Manages the data providers and the data they provide. + + It is used to set filters on the provider's data and collect all + provider data. + + """ + def __init__(self, providers, pid, fields=None): + self.providers = providers + self._pid_filter = pid + self._fields_filter = fields + self.values = {} + self.update_provider_pid() + self.update_provider_filters() + + def update_provider_filters(self): + """Propagates fields filters to providers.""" + def wanted(key): + if not self._fields_filter: + return True + return re.match(self._fields_filter, key) is not None + + # As we reset the counters when updating the fields we can + # also clear the cache of old values. + self.values = {} + for provider in self.providers: + provider_fields = [key for key in provider.get_available_fields() + if wanted(key)] + provider.fields = provider_fields + + def update_provider_pid(self): + """Propagates pid filters to providers.""" + for provider in self.providers: + provider.pid = self._pid_filter + + @property + def fields_filter(self): + return self._fields_filter + + @fields_filter.setter + def fields_filter(self, fields_filter): + self._fields_filter = fields_filter + self.update_provider_filters() + + @property + def pid_filter(self): + return self._pid_filter + + @pid_filter.setter + def pid_filter(self, pid): + self._pid_filter = pid + self.values = {} + self.update_provider_pid() + + def get(self): + """Returns a dict with field -> (value, delta to last value) of all + provider data.""" + for provider in self.providers: + new = provider.read() + for key in provider.fields: + oldval = self.values.get(key, (0, 0)) + newval = new.get(key, 0) + newdelta = None + if oldval is not None: + newdelta = newval - oldval[0] + self.values[key] = (newval, newdelta) + return self.values + +LABEL_WIDTH = 40 +NUMBER_WIDTH = 10 + +class Tui(object): + """Instruments curses to draw a nice text ui.""" + def __init__(self, stats): + self.stats = stats + self.screen = None + self.drilldown = False + self.update_drilldown() + + def __enter__(self): + """Initialises curses for later use. Based on curses.wrapper + implementation from the Python standard library.""" + self.screen = curses.initscr() + curses.noecho() + curses.cbreak() + + # The try/catch works around a minor bit of + # over-conscientiousness in the curses module, the error + # return from C start_color() is ignorable. + try: + curses.start_color() + except: + pass + + curses.use_default_colors() + return self + + def __exit__(self, *exception): + """Resets the terminal to its normal state. Based on curses.wrappre + implementation from the Python standard library.""" + if self.screen: + self.screen.keypad(0) + curses.echo() + curses.nocbreak() + curses.endwin() + + def update_drilldown(self): + """Sets or removes a filter that only allows fields without braces.""" + if not self.stats.fields_filter: + self.stats.fields_filter = r'^[^\(]*$' + + elif self.stats.fields_filter == r'^[^\(]*$': + self.stats.fields_filter = None + + def update_pid(self, pid): + """Propagates pid selection to stats object.""" + self.stats.pid_filter = pid + + def refresh(self, sleeptime): + """Refreshes on-screen data.""" + self.screen.erase() + if self.stats.pid_filter > 0: + self.screen.addstr(0, 0, 'kvm statistics - pid {0}' + .format(self.stats.pid_filter), + curses.A_BOLD) + else: + self.screen.addstr(0, 0, 'kvm statistics - summary', curses.A_BOLD) + self.screen.addstr(2, 1, 'Event') + self.screen.addstr(2, 1 + LABEL_WIDTH + NUMBER_WIDTH - + len('Total'), 'Total') + self.screen.addstr(2, 1 + LABEL_WIDTH + NUMBER_WIDTH + 8 - + len('Current'), 'Current') + row = 3 + stats = self.stats.get() + def sortkey(x): + if stats[x][1]: + return (-stats[x][1], -stats[x][0]) + else: + return (0, -stats[x][0]) + for key in sorted(stats.keys(), key=sortkey): + + if row >= self.screen.getmaxyx()[0]: + break + values = stats[key] + if not values[0] and not values[1]: + break + col = 1 + self.screen.addstr(row, col, key) + col += LABEL_WIDTH + self.screen.addstr(row, col, '%10d' % (values[0],)) + col += NUMBER_WIDTH + if values[1] is not None: + self.screen.addstr(row, col, '%8d' % (values[1] / sleeptime,)) + row += 1 + self.screen.refresh() + + def show_filter_selection(self): + """Draws filter selection mask. + + Asks for a valid regex and sets the fields filter accordingly. + + """ + while True: + self.screen.erase() + self.screen.addstr(0, 0, + "Show statistics for events matching a regex.", + curses.A_BOLD) + self.screen.addstr(2, 0, + "Current regex: {0}" + .format(self.stats.fields_filter)) + self.screen.addstr(3, 0, "New regex: ") + curses.echo() + regex = self.screen.getstr() + curses.noecho() + if len(regex) == 0: + return + try: + re.compile(regex) + self.stats.fields_filter = regex + return + except re.error: + continue + + def show_vm_selection(self): + """Draws PID selection mask. + + Asks for a pid until a valid pid or 0 has been entered. + + """ + while True: + self.screen.erase() + self.screen.addstr(0, 0, + 'Show statistics for specific pid.', + curses.A_BOLD) + self.screen.addstr(1, 0, + 'This might limit the shown data to the trace ' + 'statistics.') + + curses.echo() + self.screen.addstr(3, 0, "Pid [0 or pid]: ") + pid = self.screen.getstr() + curses.noecho() + + try: + pid = int(pid) + + if pid == 0: + self.update_pid(pid) + break + else: + if not os.path.isdir(os.path.join('/proc/', str(pid))): + continue + else: + self.update_pid(pid) + break + + except ValueError: + continue + + def show_stats(self): + """Refreshes the screen and processes user input.""" + sleeptime = 0.25 + while True: + self.refresh(sleeptime) + curses.halfdelay(int(sleeptime * 10)) + sleeptime = 3 + try: + char = self.screen.getkey() + if char == 'x': + self.drilldown = not self.drilldown + self.update_drilldown() + if char == 'q': + break + if char == 'f': + self.show_filter_selection() + if char == 'p': + self.show_vm_selection() + except KeyboardInterrupt: + break + except curses.error: + continue + +def batch(stats): + """Prints statistics in a key, value format.""" + s = stats.get() + time.sleep(1) + s = stats.get() + for key in sorted(s.keys()): + values = s[key] + print '%-42s%10d%10d' % (key, values[0], values[1]) + +def log(stats): + """Prints statistics as reiterating key block, multiple value blocks.""" + keys = sorted(stats.get().iterkeys()) + def banner(): + for k in keys: + print '%s' % k, + print + def statline(): + s = stats.get() + for k in keys: + print ' %9d' % s[k][1], + print + line = 0 + banner_repeat = 20 + while True: + time.sleep(1) + if line % banner_repeat == 0: + banner() + statline() + line += 1 + +def get_options(): + """Returns processed program arguments.""" + description_text = """ +This script displays various statistics about VMs running under KVM. +The statistics are gathered from the KVM debugfs entries and / or the +currently available perf traces. + +The monitoring takes additional cpu cycles and might affect the VM's +performance. + +Requirements: +- Access to: + /sys/kernel/debug/kvm + /sys/kernel/debug/trace/events/* + /proc/pid/task +- /proc/sys/kernel/perf_event_paranoid < 1 if user has no + CAP_SYS_ADMIN and perf events are used. +- CAP_SYS_RESOURCE if the hard limit is not high enough to allow + the large number of files that are possibly opened. +""" + + class PlainHelpFormatter(optparse.IndentedHelpFormatter): + def format_description(self, description): + if description: + return description + "\n" + else: + return "" + + optparser = optparse.OptionParser(description=description_text, + formatter=PlainHelpFormatter()) + optparser.add_option('-1', '--once', '--batch', + action='store_true', + default=False, + dest='once', + help='run in batch mode for one second', + ) + optparser.add_option('-l', '--log', + action='store_true', + default=False, + dest='log', + help='run in logging mode (like vmstat)', + ) + optparser.add_option('-t', '--tracepoints', + action='store_true', + default=False, + dest='tracepoints', + help='retrieve statistics from tracepoints', + ) + optparser.add_option('-d', '--debugfs', + action='store_true', + default=False, + dest='debugfs', + help='retrieve statistics from debugfs', + ) + optparser.add_option('-f', '--fields', + action='store', + default=None, + dest='fields', + help='fields to display (regex)', + ) + optparser.add_option('-p', '--pid', + action='store', + default=0, + type=int, + dest='pid', + help='restrict statistics to pid', + ) + (options, _) = optparser.parse_args(sys.argv) + return options + +def get_providers(options): + """Returns a list of data providers depending on the passed options.""" + providers = [] + + if options.tracepoints: + providers.append(TracepointProvider()) + if options.debugfs: + providers.append(DebugfsProvider()) + if len(providers) == 0: + providers.append(TracepointProvider()) + + return providers + +def check_access(options): + """Exits if the current user can't access all needed directories.""" + if not os.path.exists('/sys/kernel/debug'): + sys.stderr.write('Please enable CONFIG_DEBUG_FS in your kernel.') + sys.exit(1) + + if not os.path.exists(PATH_DEBUGFS_KVM): + sys.stderr.write("Please make sure, that debugfs is mounted and " + "readable by the current user:\n" + "('mount -t debugfs debugfs /sys/kernel/debug')\n" + "Also ensure, that the kvm modules are loaded.\n") + sys.exit(1) + + if not os.path.exists(PATH_DEBUGFS_TRACING) and (options.tracepoints + or not options.debugfs): + sys.stderr.write("Please enable CONFIG_TRACING in your kernel " + "when using the option -t (default).\n" + "If it is enabled, make {0} readable by the " + "current user.\n" + .format(PATH_DEBUGFS_TRACING)) + if options.tracepoints: + sys.exit(1) + + sys.stderr.write("Falling back to debugfs statistics!\n") + options.debugfs = True + sleep(5) + + return options + +def main(): + options = get_options() + options = check_access(options) + + if (options.pid > 0 and + not os.path.isdir(os.path.join('/proc/', + str(options.pid)))): + sys.stderr.write('Did you use a (unsupported) tid instead of a pid?\n') + sys.exit('Specified pid does not exist.') + + providers = get_providers(options) + stats = Stats(providers, options.pid, fields=options.fields) + + if options.log: + log(stats) + elif not options.once: + with Tui(stats) as tui: + tui.show_stats() + else: + batch(stats) + +if __name__ == "__main__": + main() diff --git a/tools/kvm/kvm_stat/kvm_stat.txt b/tools/kvm/kvm_stat/kvm_stat.txt new file mode 100644 index 000000000000..b92a153d7115 --- /dev/null +++ b/tools/kvm/kvm_stat/kvm_stat.txt @@ -0,0 +1,63 @@ +kvm_stat(1) +=========== + +NAME +---- +kvm_stat - Report KVM kernel module event counters + +SYNOPSIS +-------- +[verse] +'kvm_stat' [OPTION]... + +DESCRIPTION +----------- +kvm_stat prints counts of KVM kernel module trace events. These events signify +state transitions such as guest mode entry and exit. + +This tool is useful for observing guest behavior from the host perspective. +Often conclusions about performance or buggy behavior can be drawn from the +output. + +The set of KVM kernel module trace events may be specific to the kernel version +or architecture. It is best to check the KVM kernel module source code for the +meaning of events. + +OPTIONS +------- +-1:: +--once:: +--batch:: + run in batch mode for one second + +-l:: +--log:: + run in logging mode (like vmstat) + +-t:: +--tracepoints:: + retrieve statistics from tracepoints + +-d:: +--debugfs:: + retrieve statistics from debugfs + +-p<pid>:: +--pid=<pid>:: + limit statistics to one virtual machine (pid) + +-f<fields>:: +--fields=<fields>:: + fields to display (regex) + +-h:: +--help:: + show help message + +SEE ALSO +-------- +'perf'(1), 'trace-cmd'(1) + +AUTHOR +------ +Stefan Hajnoczi <stefanha@redhat.com> diff --git a/tools/objtool/Makefile b/tools/objtool/Makefile index 6765c7e949f3..f094f3c4ed84 100644 --- a/tools/objtool/Makefile +++ b/tools/objtool/Makefile @@ -30,6 +30,10 @@ INCLUDES := -I$(srctree)/tools/include CFLAGS += -Wall -Werror $(EXTRA_WARNINGS) -fomit-frame-pointer -O2 -g $(INCLUDES) LDFLAGS += -lelf $(LIBSUBCMD) +# Allow old libelf to be used: +elfshdr := $(shell echo '\#include <libelf.h>' | $(CC) $(CFLAGS) -x c -E - | grep elf_getshdr) +CFLAGS += $(if $(elfshdr),,-DLIBELF_USE_DEPRECATED) + AWK = awk export srctree OUTPUT CFLAGS ARCH AWK include $(srctree)/tools/build/Makefile.include diff --git a/tools/objtool/elf.h b/tools/objtool/elf.h index 7f3e00a2f907..aa1ff6596684 100644 --- a/tools/objtool/elf.h +++ b/tools/objtool/elf.h @@ -23,6 +23,11 @@ #include <linux/list.h> #include <linux/hashtable.h> +#ifdef LIBELF_USE_DEPRECATED +# define elf_getshdrnum elf_getshnum +# define elf_getshdrstrndx elf_getshstrndx +#endif + struct section { struct list_head list; GElf_Shdr sh; diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt index ebaf849e30ef..9cbddc290aff 100644 --- a/tools/perf/Documentation/perf-report.txt +++ b/tools/perf/Documentation/perf-report.txt @@ -103,12 +103,13 @@ OPTIONS If --branch-stack option is used, following sort keys are also available: - dso_from, dso_to, symbol_from, symbol_to, mispredict. - dso_from: name of library or module branched from - dso_to: name of library or module branched to - symbol_from: name of function branched from - symbol_to: name of function branched to + - srcline_from: source file and line branched from + - srcline_to: source file and line branched to - mispredict: "N" for predicted branch, "Y" for mispredicted branch - in_tx: branch in TSX transaction - abort: TSX transaction abort. @@ -248,7 +249,7 @@ OPTIONS Note that when using the --itrace option the synthesized callchain size will override this value if the synthesized callchain size is bigger. - Default: /proc/sys/kernel/perf_event_max_stack when present, 127 otherwise. + Default: 127 -G:: --inverted:: diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt index a856a1095893..4fc44c75263f 100644 --- a/tools/perf/Documentation/perf-script.txt +++ b/tools/perf/Documentation/perf-script.txt @@ -267,7 +267,7 @@ include::itrace.txt[] Note that when using the --itrace option the synthesized callchain size will override this value if the synthesized callchain size is bigger. - Default: /proc/sys/kernel/perf_event_max_stack when present, 127 otherwise. + Default: 127 --ns:: Use 9 decimal places when displaying time (i.e. show the nanoseconds) diff --git a/tools/perf/Documentation/perf-trace.txt b/tools/perf/Documentation/perf-trace.txt index 6afe20121bc0..1ab0782369b1 100644 --- a/tools/perf/Documentation/perf-trace.txt +++ b/tools/perf/Documentation/perf-trace.txt @@ -143,7 +143,8 @@ the thread executes on the designated CPUs. Default is to monitor all CPUs. Implies '--call-graph dwarf' when --call-graph not present on the command line, on systems where DWARF unwinding was built in. - Default: /proc/sys/kernel/perf_event_max_stack when present, 127 otherwise. + Default: /proc/sys/kernel/perf_event_max_stack when present for + live sessions (without --input/-i), 127 otherwise. --min-stack:: Set the stack depth limit when parsing the callchain, anything diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 814158393656..25c81734a950 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -324,8 +324,9 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused) OPT_BOOLEAN(0, "skip-missing", &annotate.skip_missing, "Skip symbols that cannot be annotated"), 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_CALLBACK(0, "symfs", NULL, "directory", + "Look for files with symbols relative to this directory", + symbol__config_symfs), OPT_BOOLEAN(0, "source", &symbol_conf.annotate_src, "Interleave source code with assembly code (default)"), OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw, diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c index 632efc6b79a0..d75bded21fe0 100644 --- a/tools/perf/builtin-buildid-cache.c +++ b/tools/perf/builtin-buildid-cache.c @@ -119,8 +119,8 @@ static int build_id_cache__add_kcore(const char *filename, bool force) if (build_id_cache__kcore_buildid(from_dir, sbuildid) < 0) return -1; - scnprintf(to_dir, sizeof(to_dir), "%s/[kernel.kcore]/%s", - buildid_dir, sbuildid); + scnprintf(to_dir, sizeof(to_dir), "%s/%s/%s", + buildid_dir, DSO__NAME_KCORE, sbuildid); if (!force && !build_id_cache__kcore_existing(from_dir, to_dir, sizeof(to_dir))) { @@ -131,8 +131,8 @@ static int build_id_cache__add_kcore(const char *filename, bool force) if (build_id_cache__kcore_dir(dir, sizeof(dir))) return -1; - scnprintf(to_dir, sizeof(to_dir), "%s/[kernel.kcore]/%s/%s", - buildid_dir, sbuildid, dir); + scnprintf(to_dir, sizeof(to_dir), "%s/%s/%s/%s", + buildid_dir, DSO__NAME_KCORE, sbuildid, dir); if (mkdir_p(to_dir, 0755)) return -1; diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 9ce354f469dc..f7645a42708e 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -812,8 +812,9 @@ static const struct option options[] = { OPT_STRING_NOEMPTY('t', "field-separator", &symbol_conf.field_sep, "separator", "separator for columns, no spaces will be added between " "columns '.' is reserved."), - OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", - "Look for files with symbols relative to this directory"), + OPT_CALLBACK(0, "symfs", NULL, "directory", + "Look for files with symbols relative to this directory", + symbol__config_symfs), OPT_UINTEGER('o', "order", &sort_compute, "Specify compute sorting."), OPT_CALLBACK(0, "percentage", NULL, "relative|absolute", "How to display percentage of filtered entries", parse_filter_percentage), diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index f3679c44d3f3..dc3fcb597e4c 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -40,6 +40,7 @@ #include <unistd.h> #include <sched.h> #include <sys/mman.h> +#include <asm/bug.h> struct record { @@ -82,27 +83,87 @@ static int process_synthesized_event(struct perf_tool *tool, return record__write(rec, event, event->header.size); } +static int +backward_rb_find_range(void *buf, int mask, u64 head, u64 *start, u64 *end) +{ + struct perf_event_header *pheader; + u64 evt_head = head; + int size = mask + 1; + + pr_debug2("backward_rb_find_range: buf=%p, head=%"PRIx64"\n", buf, head); + pheader = (struct perf_event_header *)(buf + (head & mask)); + *start = head; + while (true) { + if (evt_head - head >= (unsigned int)size) { + pr_debug("Finshed reading backward ring buffer: rewind\n"); + if (evt_head - head > (unsigned int)size) + evt_head -= pheader->size; + *end = evt_head; + return 0; + } + + pheader = (struct perf_event_header *)(buf + (evt_head & mask)); + + if (pheader->size == 0) { + pr_debug("Finshed reading backward ring buffer: get start\n"); + *end = evt_head; + return 0; + } + + evt_head += pheader->size; + pr_debug3("move evt_head: %"PRIx64"\n", evt_head); + } + WARN_ONCE(1, "Shouldn't get here\n"); + return -1; +} + +static int +rb_find_range(struct perf_evlist *evlist, + void *data, int mask, u64 head, u64 old, + u64 *start, u64 *end) +{ + if (!evlist->backward) { + *start = old; + *end = head; + return 0; + } + + return backward_rb_find_range(data, mask, head, start, end); +} + static int record__mmap_read(struct record *rec, int idx) { struct perf_mmap *md = &rec->evlist->mmap[idx]; u64 head = perf_mmap__read_head(md); u64 old = md->prev; + u64 end = head, start = old; unsigned char *data = md->base + page_size; unsigned long size; void *buf; int rc = 0; - if (old == head) + if (rb_find_range(rec->evlist, data, md->mask, head, + old, &start, &end)) + return -1; + + if (start == end) return 0; rec->samples++; - size = head - old; + size = end - start; + if (size > (unsigned long)(md->mask) + 1) { + WARN_ONCE(1, "failed to keep up with mmap data. (warn only once)\n"); + + md->prev = head; + perf_evlist__mmap_consume(rec->evlist, idx); + return 0; + } - if ((old & md->mask) + size != (head & md->mask)) { - buf = &data[old & md->mask]; - size = md->mask + 1 - (old & md->mask); - old += size; + if ((start & md->mask) + size != (end & md->mask)) { + buf = &data[start & md->mask]; + size = md->mask + 1 - (start & md->mask); + start += size; if (record__write(rec, buf, size) < 0) { rc = -1; @@ -110,16 +171,16 @@ static int record__mmap_read(struct record *rec, int idx) } } - buf = &data[old & md->mask]; - size = head - old; - old += size; + buf = &data[start & md->mask]; + size = end - start; + start += size; if (record__write(rec, buf, size) < 0) { rc = -1; goto out; } - md->prev = old; + md->prev = head; perf_evlist__mmap_consume(rec->evlist, idx); out: return rc; diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 87d40e3c4078..a87cb338bdf1 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -691,7 +691,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) .ordered_events = true, .ordering_requires_timestamps = true, }, - .max_stack = sysctl_perf_event_max_stack, + .max_stack = PERF_MAX_STACK_DEPTH, .pretty_printing_style = "normal", .socket_filter = -1, }; @@ -770,8 +770,9 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) "columns '.' is reserved."), OPT_BOOLEAN('U', "hide-unresolved", &symbol_conf.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_CALLBACK(0, "symfs", NULL, "directory", + "Look for files with symbols relative to this directory", + symbol__config_symfs), OPT_STRING('C', "cpu", &report.cpu_list, "cpu", "list of cpus to profile"), OPT_BOOLEAN('I', "show-info", &report.show_full_info, diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index efca81679bb3..e3ce2f34d3ad 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -2010,8 +2010,9 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) "file", "kallsyms pathname"), OPT_BOOLEAN('G', "hide-call-graph", &no_callchain, "When printing symbols do not display call chain"), - OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", - "Look for files with symbols relative to this directory"), + OPT_CALLBACK(0, "symfs", NULL, "directory", + "Look for files with symbols relative to this directory", + symbol__config_symfs), OPT_CALLBACK('F', "fields", NULL, "str", "comma separated output fields prepend with 'type:'. " "Valid types: hw,sw,trace,raw. " @@ -2067,8 +2068,6 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) NULL }; - scripting_max_stack = sysctl_perf_event_max_stack; - setup_scripting(); argc = parse_options_subcommand(argc, argv, options, script_subcommands, script_usage, diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index e459b685a4e9..ee7ada78d86f 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -66,6 +66,7 @@ #include <stdlib.h> #include <sys/prctl.h> #include <locale.h> +#include <math.h> #define DEFAULT_SEPARATOR " " #define CNTR_NOT_SUPPORTED "<not supported>" @@ -991,12 +992,12 @@ static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg) const char *fmt; if (csv_output) { - fmt = sc != 1.0 ? "%.2f%s" : "%.0f%s"; + fmt = floor(sc) != sc ? "%.2f%s" : "%.0f%s"; } else { if (big_num) - fmt = sc != 1.0 ? "%'18.2f%s" : "%'18.0f%s"; + fmt = floor(sc) != sc ? "%'18.2f%s" : "%'18.0f%s"; else - fmt = sc != 1.0 ? "%18.2f%s" : "%18.0f%s"; + fmt = floor(sc) != sc ? "%18.2f%s" : "%18.0f%s"; } aggr_printout(evsel, id, nr); @@ -1909,6 +1910,9 @@ static int add_default_attributes(void) } if (!evsel_list->nr_entries) { + if (target__has_cpu(&target)) + default_attrs0[0].config = PERF_COUNT_SW_CPU_CLOCK; + if (perf_evlist__add_default_attrs(evsel_list, default_attrs0) < 0) return -1; if (pmu_have_event("cpu", "stalled-cycles-frontend")) { @@ -2000,7 +2004,7 @@ static int process_stat_round_event(struct perf_tool *tool __maybe_unused, union perf_event *event, struct perf_session *session) { - struct stat_round_event *round = &event->stat_round; + struct stat_round_event *stat_round = &event->stat_round; struct perf_evsel *counter; struct timespec tsh, *ts = NULL; const char **argv = session->header.env.cmdline_argv; @@ -2009,12 +2013,12 @@ static int process_stat_round_event(struct perf_tool *tool __maybe_unused, evlist__for_each(evsel_list, counter) perf_stat_process_counter(&stat_config, counter); - if (round->type == PERF_STAT_ROUND_TYPE__FINAL) - update_stats(&walltime_nsecs_stats, round->time); + if (stat_round->type == PERF_STAT_ROUND_TYPE__FINAL) + update_stats(&walltime_nsecs_stats, stat_round->time); - if (stat_config.interval && round->time) { - tsh.tv_sec = round->time / NSECS_PER_SEC; - tsh.tv_nsec = round->time % NSECS_PER_SEC; + if (stat_config.interval && stat_round->time) { + tsh.tv_sec = stat_round->time / NSECS_PER_SEC; + tsh.tv_nsec = stat_round->time % NSECS_PER_SEC; ts = &tsh; } diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index 40cc9bb3506c..733a55422d03 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c @@ -1945,8 +1945,9 @@ int cmd_timechart(int argc, const char **argv, OPT_CALLBACK('p', "process", NULL, "process", "process selector. Pass a pid or process name.", parse_process), - OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", - "Look for files with symbols relative to this directory"), + OPT_CALLBACK(0, "symfs", NULL, "directory", + "Look for files with symbols relative to this directory", + symbol__config_symfs), OPT_INTEGER('n', "proc-num", &tchart.proc_num, "min. number of tasks to print"), OPT_BOOLEAN('t', "topology", &tchart.topology, diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 1793da585676..2a6cc254ad0c 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -732,7 +732,7 @@ static void perf_event__process_sample(struct perf_tool *tool, if (machine__resolve(machine, &al, sample) < 0) return; - if (!top->kptr_restrict_warned && + if (!machine->kptr_restrict_warned && symbol_conf.kptr_restrict && al.cpumode == PERF_RECORD_MISC_KERNEL) { ui__warning( @@ -743,7 +743,7 @@ static void perf_event__process_sample(struct perf_tool *tool, " modules" : ""); if (use_browser <= 0) sleep(5); - top->kptr_restrict_warned = true; + machine->kptr_restrict_warned = true; } if (al.sym == NULL) { @@ -759,7 +759,7 @@ static void perf_event__process_sample(struct perf_tool *tool, * --hide-kernel-symbols, even if the user specifies an * invalid --vmlinux ;-) */ - if (!top->kptr_restrict_warned && !top->vmlinux_warned && + if (!machine->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) { diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 6e5c325148e4..5c50fe70d6b3 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -576,84 +576,54 @@ static struct syscall_fmt { bool hexret; } syscall_fmts[] = { { .name = "access", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ - [1] = SCA_ACCMODE, /* mode */ }, }, + .arg_scnprintf = { [1] = SCA_ACCMODE, /* mode */ }, }, { .name = "arch_prctl", .errmsg = true, .alias = "prctl", }, { .name = "bpf", .errmsg = true, STRARRAY(0, cmd, bpf_cmd), }, { .name = "brk", .hexret = true, .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, }, - { .name = "chdir", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, }, - { .name = "chmod", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, }, - { .name = "chroot", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, }, + { .name = "chdir", .errmsg = true, }, + { .name = "chmod", .errmsg = true, }, + { .name = "chroot", .errmsg = true, }, { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), }, { .name = "clone", .errpid = true, }, { .name = "close", .errmsg = true, .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, }, { .name = "connect", .errmsg = true, }, - { .name = "creat", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, }, - { .name = "dup", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, - { .name = "dup2", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, - { .name = "dup3", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, + { .name = "creat", .errmsg = true, }, + { .name = "dup", .errmsg = true, }, + { .name = "dup2", .errmsg = true, }, + { .name = "dup3", .errmsg = true, }, { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), }, { .name = "eventfd2", .errmsg = true, .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, }, - { .name = "faccessat", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ - [1] = SCA_FILENAME, /* filename */ }, }, - { .name = "fadvise64", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, - { .name = "fallocate", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, - { .name = "fchdir", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, - { .name = "fchmod", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, + { .name = "faccessat", .errmsg = true, }, + { .name = "fadvise64", .errmsg = true, }, + { .name = "fallocate", .errmsg = true, }, + { .name = "fchdir", .errmsg = true, }, + { .name = "fchmod", .errmsg = true, }, { .name = "fchmodat", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ - [1] = SCA_FILENAME, /* filename */ }, }, - { .name = "fchown", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, + .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, }, + { .name = "fchown", .errmsg = true, }, { .name = "fchownat", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ - [1] = SCA_FILENAME, /* filename */ }, }, + .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, }, { .name = "fcntl", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FD, /* fd */ - [1] = SCA_STRARRAY, /* cmd */ }, + .arg_scnprintf = { [1] = SCA_STRARRAY, /* cmd */ }, .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, }, - { .name = "fdatasync", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, + { .name = "fdatasync", .errmsg = true, }, { .name = "flock", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FD, /* fd */ - [1] = SCA_FLOCK, /* cmd */ }, }, - { .name = "fsetxattr", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, - { .name = "fstat", .errmsg = true, .alias = "newfstat", - .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, - { .name = "fstatat", .errmsg = true, .alias = "newfstatat", - .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ - [1] = SCA_FILENAME, /* filename */ }, }, - { .name = "fstatfs", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, - { .name = "fsync", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, - { .name = "ftruncate", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, + .arg_scnprintf = { [1] = SCA_FLOCK, /* cmd */ }, }, + { .name = "fsetxattr", .errmsg = true, }, + { .name = "fstat", .errmsg = true, .alias = "newfstat", }, + { .name = "fstatat", .errmsg = true, .alias = "newfstatat", }, + { .name = "fstatfs", .errmsg = true, }, + { .name = "fsync", .errmsg = true, }, + { .name = "ftruncate", .errmsg = true, }, { .name = "futex", .errmsg = true, .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, }, { .name = "futimesat", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ - [1] = SCA_FILENAME, /* filename */ }, }, - { .name = "getdents", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, - { .name = "getdents64", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, + .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, }, + { .name = "getdents", .errmsg = true, }, + { .name = "getdents64", .errmsg = true, }, { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), }, { .name = "getpid", .errpid = true, }, { .name = "getpgid", .errpid = true, }, @@ -661,12 +631,10 @@ static struct syscall_fmt { { .name = "getrandom", .errmsg = true, .arg_scnprintf = { [2] = SCA_GETRANDOM_FLAGS, /* flags */ }, }, { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), }, - { .name = "getxattr", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, }, - { .name = "inotify_add_watch", .errmsg = true, - .arg_scnprintf = { [1] = SCA_FILENAME, /* pathname */ }, }, + { .name = "getxattr", .errmsg = true, }, + { .name = "inotify_add_watch", .errmsg = true, }, { .name = "ioctl", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FD, /* fd */ + .arg_scnprintf = { #if defined(__i386__) || defined(__x86_64__) /* * FIXME: Make this available to all arches. @@ -680,41 +648,28 @@ static struct syscall_fmt { { .name = "keyctl", .errmsg = true, STRARRAY(0, option, keyctl_options), }, { .name = "kill", .errmsg = true, .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, }, - { .name = "lchown", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, }, - { .name = "lgetxattr", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, }, + { .name = "lchown", .errmsg = true, }, + { .name = "lgetxattr", .errmsg = true, }, { .name = "linkat", .errmsg = true, .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, }, - { .name = "listxattr", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, }, - { .name = "llistxattr", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, }, - { .name = "lremovexattr", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, }, + { .name = "listxattr", .errmsg = true, }, + { .name = "llistxattr", .errmsg = true, }, + { .name = "lremovexattr", .errmsg = true, }, { .name = "lseek", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FD, /* fd */ - [2] = SCA_STRARRAY, /* whence */ }, + .arg_scnprintf = { [2] = SCA_STRARRAY, /* whence */ }, .arg_parm = { [2] = &strarray__whences, /* whence */ }, }, - { .name = "lsetxattr", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, }, - { .name = "lstat", .errmsg = true, .alias = "newlstat", - .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, }, - { .name = "lsxattr", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, }, + { .name = "lsetxattr", .errmsg = true, }, + { .name = "lstat", .errmsg = true, .alias = "newlstat", }, + { .name = "lsxattr", .errmsg = true, }, { .name = "madvise", .errmsg = true, .arg_scnprintf = { [0] = SCA_HEX, /* start */ [2] = SCA_MADV_BHV, /* behavior */ }, }, - { .name = "mkdir", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, }, + { .name = "mkdir", .errmsg = true, }, { .name = "mkdirat", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ - [1] = SCA_FILENAME, /* pathname */ }, }, - { .name = "mknod", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, }, + .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, }, + { .name = "mknod", .errmsg = true, }, { .name = "mknodat", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ - [1] = SCA_FILENAME, /* filename */ }, }, + .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, }, { .name = "mlock", .errmsg = true, .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, }, { .name = "mlockall", .errmsg = true, @@ -722,8 +677,7 @@ static struct syscall_fmt { { .name = "mmap", .hexret = true, .arg_scnprintf = { [0] = SCA_HEX, /* addr */ [2] = SCA_MMAP_PROT, /* prot */ - [3] = SCA_MMAP_FLAGS, /* flags */ - [4] = SCA_FD, /* fd */ }, }, + [3] = SCA_MMAP_FLAGS, /* flags */ }, }, { .name = "mprotect", .errmsg = true, .arg_scnprintf = { [0] = SCA_HEX, /* start */ [2] = SCA_MMAP_PROT, /* prot */ }, }, @@ -740,17 +694,14 @@ static struct syscall_fmt { { .name = "name_to_handle_at", .errmsg = true, .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, }, { .name = "newfstatat", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ - [1] = SCA_FILENAME, /* filename */ }, }, + .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, }, { .name = "open", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ - [1] = SCA_OPEN_FLAGS, /* flags */ }, }, + .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, }, { .name = "open_by_handle_at", .errmsg = true, .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ [2] = SCA_OPEN_FLAGS, /* flags */ }, }, { .name = "openat", .errmsg = true, .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ - [1] = SCA_FILENAME, /* filename */ [2] = SCA_OPEN_FLAGS, /* flags */ }, }, { .name = "perf_event_open", .errmsg = true, .arg_scnprintf = { [2] = SCA_INT, /* cpu */ @@ -760,39 +711,26 @@ static struct syscall_fmt { .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, }, { .name = "poll", .errmsg = true, .timeout = true, }, { .name = "ppoll", .errmsg = true, .timeout = true, }, - { .name = "pread", .errmsg = true, .alias = "pread64", - .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, - { .name = "preadv", .errmsg = true, .alias = "pread", - .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, + { .name = "pread", .errmsg = true, .alias = "pread64", }, + { .name = "preadv", .errmsg = true, .alias = "pread", }, { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), }, - { .name = "pwrite", .errmsg = true, .alias = "pwrite64", - .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, - { .name = "pwritev", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, - { .name = "read", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, - { .name = "readlink", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FILENAME, /* path */ }, }, + { .name = "pwrite", .errmsg = true, .alias = "pwrite64", }, + { .name = "pwritev", .errmsg = true, }, + { .name = "read", .errmsg = true, }, + { .name = "readlink", .errmsg = true, }, { .name = "readlinkat", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ - [1] = SCA_FILENAME, /* pathname */ }, }, - { .name = "readv", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, + .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, }, + { .name = "readv", .errmsg = true, }, { .name = "recvfrom", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FD, /* fd */ - [3] = SCA_MSG_FLAGS, /* flags */ }, }, + .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, }, { .name = "recvmmsg", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FD, /* fd */ - [3] = SCA_MSG_FLAGS, /* flags */ }, }, + .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, }, { .name = "recvmsg", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FD, /* fd */ - [2] = SCA_MSG_FLAGS, /* flags */ }, }, - { .name = "removexattr", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, }, + .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, }, + { .name = "removexattr", .errmsg = true, }, { .name = "renameat", .errmsg = true, .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, }, - { .name = "rmdir", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, }, + { .name = "rmdir", .errmsg = true, }, { .name = "rt_sigaction", .errmsg = true, .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, }, { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), }, @@ -807,22 +745,17 @@ static struct syscall_fmt { [1] = SCA_SECCOMP_FLAGS, /* flags */ }, }, { .name = "select", .errmsg = true, .timeout = true, }, { .name = "sendmmsg", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FD, /* fd */ - [3] = SCA_MSG_FLAGS, /* flags */ }, }, + .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, }, { .name = "sendmsg", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FD, /* fd */ - [2] = SCA_MSG_FLAGS, /* flags */ }, }, + .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, }, { .name = "sendto", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FD, /* fd */ - [3] = SCA_MSG_FLAGS, /* flags */ }, }, + .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, }, { .name = "set_tid_address", .errpid = true, }, { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), }, { .name = "setpgid", .errmsg = true, }, { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), }, - { .name = "setxattr", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, }, - { .name = "shutdown", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, + { .name = "setxattr", .errmsg = true, }, + { .name = "shutdown", .errmsg = true, }, { .name = "socket", .errmsg = true, .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */ [1] = SCA_SK_TYPE, /* type */ }, @@ -831,10 +764,8 @@ static struct syscall_fmt { .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */ [1] = SCA_SK_TYPE, /* type */ }, .arg_parm = { [0] = &strarray__socket_families, /* family */ }, }, - { .name = "stat", .errmsg = true, .alias = "newstat", - .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, }, - { .name = "statfs", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, }, + { .name = "stat", .errmsg = true, .alias = "newstat", }, + { .name = "statfs", .errmsg = true, }, { .name = "swapoff", .errmsg = true, .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, }, { .name = "swapon", .errmsg = true, @@ -845,29 +776,21 @@ static struct syscall_fmt { .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, }, { .name = "tkill", .errmsg = true, .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, }, - { .name = "truncate", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FILENAME, /* path */ }, }, + { .name = "truncate", .errmsg = true, }, { .name = "uname", .errmsg = true, .alias = "newuname", }, { .name = "unlinkat", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ - [1] = SCA_FILENAME, /* pathname */ }, }, - { .name = "utime", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, }, + .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, }, + { .name = "utime", .errmsg = true, }, { .name = "utimensat", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */ - [1] = SCA_FILENAME, /* filename */ }, }, - { .name = "utimes", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, }, - { .name = "vmsplice", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, + .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */ }, }, + { .name = "utimes", .errmsg = true, }, + { .name = "vmsplice", .errmsg = true, }, { .name = "wait4", .errpid = true, .arg_scnprintf = { [2] = SCA_WAITID_OPTIONS, /* options */ }, }, { .name = "waitid", .errpid = true, .arg_scnprintf = { [3] = SCA_WAITID_OPTIONS, /* options */ }, }, - { .name = "write", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, - { .name = "writev", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, + { .name = "write", .errmsg = true, }, + { .name = "writev", .errmsg = true, }, }; static int syscall_fmt__cmp(const void *name, const void *fmtp) @@ -1160,6 +1083,24 @@ static int trace__tool_process(struct perf_tool *tool, return trace__process_event(trace, machine, event, sample); } +static char *trace__machine__resolve_kernel_addr(void *vmachine, unsigned long long *addrp, char **modp) +{ + struct machine *machine = vmachine; + + if (machine->kptr_restrict_warned) + return NULL; + + if (symbol_conf.kptr_restrict) { + pr_warning("Kernel address maps (/proc/{kallsyms,modules}) are restricted.\n\n" + "Check /proc/sys/kernel/kptr_restrict.\n\n" + "Kernel samples will not be resolved.\n"); + machine->kptr_restrict_warned = true; + return NULL; + } + + return machine__resolve_kernel_addr(vmachine, addrp, modp); +} + static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist) { int err = symbol__init(NULL); @@ -1171,7 +1112,7 @@ static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist) if (trace->host == NULL) return -ENOMEM; - if (trace_event__register_resolver(trace->host, machine__resolve_kernel_addr) < 0) + if (trace_event__register_resolver(trace->host, trace__machine__resolve_kernel_addr) < 0) return -errno; err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target, @@ -1186,7 +1127,7 @@ static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist) static int syscall__set_arg_fmts(struct syscall *sc) { struct format_field *field; - int idx = 0; + int idx = 0, len; sc->arg_scnprintf = calloc(sc->nr_args, sizeof(void *)); if (sc->arg_scnprintf == NULL) @@ -1198,12 +1139,31 @@ static int syscall__set_arg_fmts(struct syscall *sc) for (field = sc->args; field; field = field->next) { if (sc->fmt && sc->fmt->arg_scnprintf[idx]) sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx]; + else if (strcmp(field->type, "const char *") == 0 && + (strcmp(field->name, "filename") == 0 || + strcmp(field->name, "path") == 0 || + strcmp(field->name, "pathname") == 0)) + sc->arg_scnprintf[idx] = SCA_FILENAME; else if (field->flags & FIELD_IS_POINTER) sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex; else if (strcmp(field->type, "pid_t") == 0) sc->arg_scnprintf[idx] = SCA_PID; else if (strcmp(field->type, "umode_t") == 0) sc->arg_scnprintf[idx] = SCA_MODE_T; + else if ((strcmp(field->type, "int") == 0 || + strcmp(field->type, "unsigned int") == 0 || + strcmp(field->type, "long") == 0) && + (len = strlen(field->name)) >= 2 && + strcmp(field->name + len - 2, "fd") == 0) { + /* + * /sys/kernel/tracing/events/syscalls/sys_enter* + * egrep 'field:.*fd;' .../format|sed -r 's/.*field:([a-z ]+) [a-z_]*fd.+/\1/g'|sort|uniq -c + * 65 int + * 23 unsigned int + * 7 unsigned long + */ + sc->arg_scnprintf[idx] = SCA_FD; + } ++idx; } @@ -1534,7 +1494,7 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel, if (sc->is_exit) { if (!(trace->duration_filter || trace->summary_only || trace->min_stack)) { trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output); - fprintf(trace->output, "%-70s\n", ttrace->entry_str); + fprintf(trace->output, "%-70s)\n", ttrace->entry_str); } } else { ttrace->entry_pending = true; @@ -2887,12 +2847,12 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) mmap_pages_user_set = false; if (trace.max_stack == UINT_MAX) { - trace.max_stack = sysctl_perf_event_max_stack; + trace.max_stack = input_name ? PERF_MAX_STACK_DEPTH : sysctl_perf_event_max_stack; max_stack_user_set = false; } #ifdef HAVE_DWARF_UNWIND_SUPPORT - if ((trace.min_stack || max_stack_user_set) && !callchain_param.enabled) + if ((trace.min_stack || max_stack_user_set) && !callchain_param.enabled && trace.trace_syscalls) record_opts__parse_callchain(&trace.opts, &callchain_param, "dwarf", false); #endif diff --git a/tools/perf/perf.c b/tools/perf/perf.c index 797000842d40..15982cee5ef3 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c @@ -549,6 +549,9 @@ int main(int argc, const char **argv) if (sysctl__read_int("kernel/perf_event_max_stack", &value) == 0) sysctl_perf_event_max_stack = value; + if (sysctl__read_int("kernel/perf_event_max_contexts_per_stack", &value) == 0) + sysctl_perf_event_max_contexts_per_stack = value; + cmd = extract_argv0_path(argv[0]); if (!cmd) cmd = "perf-help"; diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 4db73d5a0dbc..7e5a1e8874ce 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -354,9 +354,6 @@ static struct ins_ops nop_ops = { .scnprintf = nop__scnprintf, }; -/* - * Must be sorted by name! - */ static struct ins instructions[] = { { .name = "add", .ops = &mov_ops, }, { .name = "addl", .ops = &mov_ops, }, @@ -372,8 +369,8 @@ static struct ins instructions[] = { { .name = "bgt", .ops = &jump_ops, }, { .name = "bhi", .ops = &jump_ops, }, { .name = "bl", .ops = &call_ops, }, - { .name = "blt", .ops = &jump_ops, }, { .name = "bls", .ops = &jump_ops, }, + { .name = "blt", .ops = &jump_ops, }, { .name = "blx", .ops = &call_ops, }, { .name = "bne", .ops = &jump_ops, }, #endif @@ -449,18 +446,39 @@ static struct ins instructions[] = { { .name = "xbeginq", .ops = &jump_ops, }, }; -static int ins__cmp(const void *name, const void *insp) +static int ins__key_cmp(const void *name, const void *insp) { const struct ins *ins = insp; return strcmp(name, ins->name); } +static int ins__cmp(const void *a, const void *b) +{ + const struct ins *ia = a; + const struct ins *ib = b; + + return strcmp(ia->name, ib->name); +} + +static void ins__sort(void) +{ + const int nmemb = ARRAY_SIZE(instructions); + + qsort(instructions, nmemb, sizeof(struct ins), ins__cmp); +} + static struct ins *ins__find(const char *name) { const int nmemb = ARRAY_SIZE(instructions); + static bool sorted; + + if (!sorted) { + ins__sort(); + sorted = true; + } - return bsearch(name, instructions, nmemb, sizeof(struct ins), ins__cmp); + return bsearch(name, instructions, nmemb, sizeof(struct ins), ins__key_cmp); } int symbol__annotate_init(struct map *map __maybe_unused, struct symbol *sym) @@ -1122,7 +1140,7 @@ int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize) } else if (dso__is_kcore(dso)) { goto fallback; } else if (readlink(symfs_filename, command, sizeof(command)) < 0 || - strstr(command, "[kernel.kallsyms]") || + strstr(command, DSO__NAME_KALLSYMS) || access(symfs_filename, R_OK)) { free(filename); fallback: diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c index bff425e1232c..67e5966503b2 100644 --- a/tools/perf/util/build-id.c +++ b/tools/perf/util/build-id.c @@ -256,7 +256,7 @@ static int machine__write_buildid_table(struct machine *machine, int fd) size_t name_len; bool in_kernel = false; - if (!pos->hit) + if (!pos->hit && !dso__is_vdso(pos)) continue; if (dso__is_vdso(pos)) { diff --git a/tools/perf/util/db-export.c b/tools/perf/util/db-export.c index 8d96c80cc67e..c9a6dc173e74 100644 --- a/tools/perf/util/db-export.c +++ b/tools/perf/util/db-export.c @@ -298,8 +298,7 @@ static struct call_path *call_path_from_sample(struct db_export *dbe, */ callchain_param.order = ORDER_CALLER; err = thread__resolve_callchain(thread, &callchain_cursor, evsel, - sample, NULL, NULL, - sysctl_perf_event_max_stack); + sample, NULL, NULL, PERF_MAX_STACK_DEPTH); if (err) { callchain_param.order = saved_order; return NULL; diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index 3357479082ca..5d286f5d7906 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c @@ -7,6 +7,7 @@ #include "auxtrace.h" #include "util.h" #include "debug.h" +#include "vdso.h" char dso__symtab_origin(const struct dso *dso) { @@ -62,9 +63,7 @@ int dso__read_binary_type_filename(const struct dso *dso, } break; case DSO_BINARY_TYPE__BUILD_ID_CACHE: - /* skip the locally configured cache if a symfs is given */ - if (symbol_conf.symfs[0] || - (dso__build_id_filename(dso, filename, size) == NULL)) + if (dso__build_id_filename(dso, filename, size) == NULL) ret = -1; break; @@ -1169,7 +1168,7 @@ bool __dsos__read_build_ids(struct list_head *head, bool with_hits) struct dso *pos; list_for_each_entry(pos, head, node) { - if (with_hits && !pos->hit) + if (with_hits && !pos->hit && !dso__is_vdso(pos)) continue; if (pos->has_build_id) { have_build_id = true; diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index c4bfe11479a0..e82ba90cc969 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -44,6 +44,7 @@ void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus, perf_evlist__set_maps(evlist, cpus, threads); fdarray__init(&evlist->pollfd, 64); evlist->workload.pid = -1; + evlist->backward = false; } struct perf_evlist *perf_evlist__new(void) @@ -679,6 +680,33 @@ static struct perf_evsel *perf_evlist__event2evsel(struct perf_evlist *evlist, return NULL; } +static int perf_evlist__set_paused(struct perf_evlist *evlist, bool value) +{ + int i; + + for (i = 0; i < evlist->nr_mmaps; i++) { + int fd = evlist->mmap[i].fd; + int err; + + if (fd < 0) + continue; + err = ioctl(fd, PERF_EVENT_IOC_PAUSE_OUTPUT, value ? 1 : 0); + if (err) + return err; + } + return 0; +} + +int perf_evlist__pause(struct perf_evlist *evlist) +{ + return perf_evlist__set_paused(evlist, true); +} + +int perf_evlist__resume(struct perf_evlist *evlist) +{ + return perf_evlist__set_paused(evlist, false); +} + /* When check_messup is true, 'end' must points to a good entry */ static union perf_event * perf_mmap__read(struct perf_mmap *md, bool check_messup, u64 start, @@ -881,6 +909,7 @@ static void __perf_evlist__munmap(struct perf_evlist *evlist, int idx) if (evlist->mmap[idx].base != NULL) { munmap(evlist->mmap[idx].base, evlist->mmap_len); evlist->mmap[idx].base = NULL; + evlist->mmap[idx].fd = -1; atomic_set(&evlist->mmap[idx].refcnt, 0); } auxtrace_mmap__munmap(&evlist->mmap[idx].auxtrace_mmap); @@ -901,10 +930,14 @@ void perf_evlist__munmap(struct perf_evlist *evlist) static int perf_evlist__alloc_mmap(struct perf_evlist *evlist) { + int i; + evlist->nr_mmaps = cpu_map__nr(evlist->cpus); if (cpu_map__empty(evlist->cpus)) evlist->nr_mmaps = thread_map__nr(evlist->threads); evlist->mmap = zalloc(evlist->nr_mmaps * sizeof(struct perf_mmap)); + for (i = 0; i < evlist->nr_mmaps; i++) + evlist->mmap[i].fd = -1; return evlist->mmap != NULL ? 0 : -ENOMEM; } @@ -941,6 +974,7 @@ static int __perf_evlist__mmap(struct perf_evlist *evlist, int idx, evlist->mmap[idx].base = NULL; return -1; } + evlist->mmap[idx].fd = fd; if (auxtrace_mmap__mmap(&evlist->mmap[idx].auxtrace_mmap, &mp->auxtrace_mp, evlist->mmap[idx].base, fd)) diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 85d1b59802e8..d740fb877ab6 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -28,6 +28,7 @@ struct record_opts; struct perf_mmap { void *base; int mask; + int fd; atomic_t refcnt; u64 prev; struct auxtrace_mmap auxtrace_mmap; @@ -43,6 +44,7 @@ struct perf_evlist { bool overwrite; bool enabled; bool has_user_cpus; + bool backward; size_t mmap_len; int id_pos; int is_pos; @@ -135,6 +137,8 @@ void perf_evlist__mmap_read_catchup(struct perf_evlist *evlist, int idx); void perf_evlist__mmap_consume(struct perf_evlist *evlist, int idx); +int perf_evlist__pause(struct perf_evlist *evlist); +int perf_evlist__resume(struct perf_evlist *evlist); int perf_evlist__open(struct perf_evlist *evlist); void perf_evlist__close(struct perf_evlist *evlist); diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 52c7d8884741..5d7037ef7d3b 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -37,6 +37,7 @@ static struct { bool clockid; bool clockid_wrong; bool lbr_flags; + bool write_backward; } perf_missing_features; static clockid_t clockid; @@ -1376,6 +1377,8 @@ fallback_missing_features: if (perf_missing_features.lbr_flags) evsel->attr.branch_sample_type &= ~(PERF_SAMPLE_BRANCH_NO_FLAGS | PERF_SAMPLE_BRANCH_NO_CYCLES); + if (perf_missing_features.write_backward) + evsel->attr.write_backward = false; retry_sample_id: if (perf_missing_features.sample_id_all) evsel->attr.sample_id_all = 0; @@ -1438,6 +1441,12 @@ retry_open: err = -EINVAL; goto out_close; } + + if (evsel->overwrite && + perf_missing_features.write_backward) { + err = -EINVAL; + goto out_close; + } } } @@ -1500,6 +1509,10 @@ try_fallback: PERF_SAMPLE_BRANCH_NO_FLAGS))) { perf_missing_features.lbr_flags = true; goto fallback_missing_features; + } else if (!perf_missing_features.write_backward && + evsel->attr.write_backward) { + perf_missing_features.write_backward = true; + goto fallback_missing_features; } out_close: diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 8a644fef452c..c1f10159804c 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -112,6 +112,7 @@ struct perf_evsel { bool tracking; bool per_pkg; bool precise_max; + bool overwrite; /* parse modifier helper */ int exclude_GH; int nr_members; diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index cfab531437c7..d1f19e0012d4 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -117,6 +117,13 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h) hists__new_col_len(hists, HISTC_SYMBOL_TO, symlen); hists__set_unres_dso_col_len(hists, HISTC_DSO_TO); } + + if (h->branch_info->srcline_from) + hists__new_col_len(hists, HISTC_SRCLINE_FROM, + strlen(h->branch_info->srcline_from)); + if (h->branch_info->srcline_to) + hists__new_col_len(hists, HISTC_SRCLINE_TO, + strlen(h->branch_info->srcline_to)); } if (h->mem_info) { @@ -1042,6 +1049,8 @@ void hist_entry__delete(struct hist_entry *he) if (he->branch_info) { map__zput(he->branch_info->from.map); map__zput(he->branch_info->to.map); + free_srcline(he->branch_info->srcline_from); + free_srcline(he->branch_info->srcline_to); zfree(&he->branch_info); } diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 0f84bfb42bb1..7b54ccf1b737 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -52,6 +52,8 @@ enum hist_column { HISTC_MEM_IADDR_SYMBOL, HISTC_TRANSACTION, HISTC_CYCLES, + HISTC_SRCLINE_FROM, + HISTC_SRCLINE_TO, HISTC_TRACE, HISTC_NR_COLS, /* Last entry */ }; diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index f9644f79686c..b1772180c820 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -43,6 +43,7 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid) machine->symbol_filter = NULL; machine->id_hdr_size = 0; + machine->kptr_restrict_warned = false; machine->comm_exec = false; machine->kernel_start = 0; @@ -709,7 +710,7 @@ static struct dso *machine__get_kernel(struct machine *machine) if (machine__is_host(machine)) { vmlinux_name = symbol_conf.vmlinux_name; if (!vmlinux_name) - vmlinux_name = "[kernel.kallsyms]"; + vmlinux_name = DSO__NAME_KALLSYMS; kernel = machine__findnew_kernel(machine, vmlinux_name, "[kernel]", DSO_TYPE_KERNEL); @@ -1135,10 +1136,10 @@ int machine__create_kernel_maps(struct machine *machine) { struct dso *kernel = machine__get_kernel(machine); const char *name; - u64 addr = machine__get_running_kernel_start(machine, &name); + u64 addr; int ret; - if (!addr || kernel == NULL) + if (kernel == NULL) return -1; ret = __machine__create_kernel_maps(machine, kernel); @@ -1160,8 +1161,9 @@ int machine__create_kernel_maps(struct machine *machine) */ map_groups__fixup_end(&machine->kmaps); - if (maps__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps, name, - addr)) { + addr = machine__get_running_kernel_start(machine, &name); + if (!addr) { + } else if (maps__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps, name, addr)) { machine__destroy_kernel_maps(machine); return -1; } @@ -1769,11 +1771,6 @@ static int resolve_lbr_callchain_sample(struct thread *thread, */ int mix_chain_nr = i + 1 + lbr_nr + 1; - if (mix_chain_nr > (int)sysctl_perf_event_max_stack + PERF_MAX_BRANCH_DEPTH) { - pr_warning("corrupted callchain. skipping...\n"); - return 0; - } - for (j = 0; j < mix_chain_nr; j++) { if (callchain_param.order == ORDER_CALLEE) { if (j < i + 1) @@ -1811,9 +1808,9 @@ static int thread__resolve_callchain_sample(struct thread *thread, { struct branch_stack *branch = sample->branch_stack; struct ip_callchain *chain = sample->callchain; - int chain_nr = min(max_stack, (int)chain->nr); + int chain_nr = chain->nr; u8 cpumode = PERF_RECORD_MISC_USER; - int i, j, err; + int i, j, err, nr_entries; int skip_idx = -1; int first_call = 0; @@ -1828,8 +1825,7 @@ static int thread__resolve_callchain_sample(struct thread *thread, * Based on DWARF debug information, some architectures skip * a callchain entry saved by the kernel. */ - if (chain->nr < sysctl_perf_event_max_stack) - skip_idx = arch_skip_callchain_idx(thread, chain); + skip_idx = arch_skip_callchain_idx(thread, chain); /* * Add branches to call stack for easier browsing. This gives @@ -1889,12 +1885,8 @@ static int thread__resolve_callchain_sample(struct thread *thread, } check_calls: - if (chain->nr > sysctl_perf_event_max_stack && (int)chain->nr > max_stack) { - pr_warning("corrupted callchain. skipping...\n"); - return 0; - } - - for (i = first_call; i < chain_nr; i++) { + for (i = first_call, nr_entries = 0; + i < chain_nr && nr_entries < max_stack; i++) { u64 ip; if (callchain_param.order == ORDER_CALLEE) @@ -1908,6 +1900,9 @@ check_calls: #endif ip = chain->ips[j]; + if (ip < PERF_CONTEXT_MAX) + ++nr_entries; + err = add_callchain_ip(thread, cursor, parent, root_al, &cpumode, ip); if (err) diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h index 83f46790c52f..41ac9cfd416b 100644 --- a/tools/perf/util/machine.h +++ b/tools/perf/util/machine.h @@ -28,6 +28,7 @@ struct machine { pid_t pid; u16 id_hdr_size; bool comm_exec; + bool kptr_restrict_warned; char *root_dir; struct rb_root threads; pthread_rwlock_t threads_lock; diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c index 62c7f6988e0e..5d1eb1ccd96c 100644 --- a/tools/perf/util/scripting-engines/trace-event-perl.c +++ b/tools/perf/util/scripting-engines/trace-event-perl.c @@ -264,8 +264,7 @@ static SV *perl_process_callchain(struct perf_sample *sample, goto exit; if (thread__resolve_callchain(al->thread, &callchain_cursor, evsel, - sample, NULL, NULL, - sysctl_perf_event_max_stack) != 0) { + sample, NULL, NULL, scripting_max_stack) != 0) { pr_err("Failed to resolve callchain. Skipping\n"); goto exit; } diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 20e69edd5006..c4e9bd70723c 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -353,6 +353,88 @@ struct sort_entry sort_srcline = { .se_width_idx = HISTC_SRCLINE, }; +/* --sort srcline_from */ + +static int64_t +sort__srcline_from_cmp(struct hist_entry *left, struct hist_entry *right) +{ + if (!left->branch_info->srcline_from) { + struct map *map = left->branch_info->from.map; + if (!map) + left->branch_info->srcline_from = SRCLINE_UNKNOWN; + else + left->branch_info->srcline_from = get_srcline(map->dso, + map__rip_2objdump(map, + left->branch_info->from.al_addr), + left->branch_info->from.sym, true); + } + if (!right->branch_info->srcline_from) { + struct map *map = right->branch_info->from.map; + if (!map) + right->branch_info->srcline_from = SRCLINE_UNKNOWN; + else + right->branch_info->srcline_from = get_srcline(map->dso, + map__rip_2objdump(map, + right->branch_info->from.al_addr), + right->branch_info->from.sym, true); + } + return strcmp(right->branch_info->srcline_from, left->branch_info->srcline_from); +} + +static int hist_entry__srcline_from_snprintf(struct hist_entry *he, char *bf, + size_t size, unsigned int width) +{ + return repsep_snprintf(bf, size, "%-*.*s", width, width, he->branch_info->srcline_from); +} + +struct sort_entry sort_srcline_from = { + .se_header = "From Source:Line", + .se_cmp = sort__srcline_from_cmp, + .se_snprintf = hist_entry__srcline_from_snprintf, + .se_width_idx = HISTC_SRCLINE_FROM, +}; + +/* --sort srcline_to */ + +static int64_t +sort__srcline_to_cmp(struct hist_entry *left, struct hist_entry *right) +{ + if (!left->branch_info->srcline_to) { + struct map *map = left->branch_info->to.map; + if (!map) + left->branch_info->srcline_to = SRCLINE_UNKNOWN; + else + left->branch_info->srcline_to = get_srcline(map->dso, + map__rip_2objdump(map, + left->branch_info->to.al_addr), + left->branch_info->from.sym, true); + } + if (!right->branch_info->srcline_to) { + struct map *map = right->branch_info->to.map; + if (!map) + right->branch_info->srcline_to = SRCLINE_UNKNOWN; + else + right->branch_info->srcline_to = get_srcline(map->dso, + map__rip_2objdump(map, + right->branch_info->to.al_addr), + right->branch_info->to.sym, true); + } + return strcmp(right->branch_info->srcline_to, left->branch_info->srcline_to); +} + +static int hist_entry__srcline_to_snprintf(struct hist_entry *he, char *bf, + size_t size, unsigned int width) +{ + return repsep_snprintf(bf, size, "%-*.*s", width, width, he->branch_info->srcline_to); +} + +struct sort_entry sort_srcline_to = { + .se_header = "To Source:Line", + .se_cmp = sort__srcline_to_cmp, + .se_snprintf = hist_entry__srcline_to_snprintf, + .se_width_idx = HISTC_SRCLINE_TO, +}; + /* --sort srcfile */ static char no_srcfile[1]; @@ -1347,6 +1429,8 @@ static struct sort_dimension bstack_sort_dimensions[] = { DIM(SORT_IN_TX, "in_tx", sort_in_tx), DIM(SORT_ABORT, "abort", sort_abort), DIM(SORT_CYCLES, "cycles", sort_cycles), + DIM(SORT_SRCLINE_FROM, "srcline_from", sort_srcline_from), + DIM(SORT_SRCLINE_TO, "srcline_to", sort_srcline_to), }; #undef DIM diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index 42927f448bcb..ebb59cacd092 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h @@ -215,6 +215,8 @@ enum sort_type { SORT_ABORT, SORT_IN_TX, SORT_CYCLES, + SORT_SRCLINE_FROM, + SORT_SRCLINE_TO, /* memory mode specific sort keys */ __SORT_MEMORY_MODE, diff --git a/tools/perf/util/stat-shadow.c b/tools/perf/util/stat-shadow.c index fdb71961143e..aa9efe08762b 100644 --- a/tools/perf/util/stat-shadow.c +++ b/tools/perf/util/stat-shadow.c @@ -94,7 +94,8 @@ void perf_stat__update_shadow_stats(struct perf_evsel *counter, u64 *count, { int ctx = evsel_context(counter); - if (perf_evsel__match(counter, SOFTWARE, SW_TASK_CLOCK)) + if (perf_evsel__match(counter, SOFTWARE, SW_TASK_CLOCK) || + perf_evsel__match(counter, SOFTWARE, SW_CPU_CLOCK)) update_stats(&runtime_nsecs_stats[cpu], count[0]); else if (perf_evsel__match(counter, HARDWARE, HW_CPU_CYCLES)) update_stats(&runtime_cycles_stats[ctx][cpu], count[0]); @@ -188,7 +189,7 @@ static void print_stalled_cycles_backend(int cpu, color = get_ratio_color(GRC_STALLED_CYCLES_BE, ratio); - out->print_metric(out->ctx, color, "%6.2f%%", "backend cycles idle", ratio); + out->print_metric(out->ctx, color, "%7.2f%%", "backend cycles idle", ratio); } static void print_branch_misses(int cpu, @@ -444,7 +445,8 @@ void perf_stat__print_shadow_stats(struct perf_evsel *evsel, ratio = total / avg; print_metric(ctxp, NULL, "%8.0f", "cycles / elision", ratio); - } else if (perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK)) { + } else if (perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK) || + perf_evsel__match(evsel, SOFTWARE, SW_CPU_CLOCK)) { if ((ratio = avg_stats(&walltime_nsecs_stats)) != 0) print_metric(ctxp, NULL, "%8.3f", "CPUs utilized", avg / ratio); diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 7fb33304fb4e..20f9cb32b703 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -1662,8 +1662,8 @@ static char *dso__find_kallsyms(struct dso *dso, struct map *map) build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id); - scnprintf(path, sizeof(path), "%s/[kernel.kcore]/%s", buildid_dir, - sbuild_id); + scnprintf(path, sizeof(path), "%s/%s/%s", buildid_dir, + DSO__NAME_KCORE, sbuild_id); /* Use /proc/kallsyms if possible */ if (is_host) { @@ -1699,8 +1699,8 @@ static char *dso__find_kallsyms(struct dso *dso, struct map *map) if (!find_matching_kcore(map, path, sizeof(path))) return strdup(path); - scnprintf(path, sizeof(path), "%s/[kernel.kallsyms]/%s", - buildid_dir, sbuild_id); + scnprintf(path, sizeof(path), "%s/%s/%s", + buildid_dir, DSO__NAME_KALLSYMS, sbuild_id); if (access(path, F_OK)) { pr_err("No kallsyms or vmlinux with build-id %s was found\n", @@ -1769,7 +1769,7 @@ do_kallsyms: if (err > 0 && !dso__is_kcore(dso)) { dso->binary_type = DSO_BINARY_TYPE__KALLSYMS; - dso__set_long_name(dso, "[kernel.kallsyms]", false); + dso__set_long_name(dso, DSO__NAME_KALLSYMS, false); map__fixup_start(map); map__fixup_end(map); } @@ -2033,3 +2033,26 @@ void symbol__exit(void) symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL; symbol_conf.initialized = false; } + +int symbol__config_symfs(const struct option *opt __maybe_unused, + const char *dir, int unset __maybe_unused) +{ + char *bf = NULL; + int ret; + + symbol_conf.symfs = strdup(dir); + if (symbol_conf.symfs == NULL) + return -ENOMEM; + + /* skip the locally configured cache if a symfs is given, and + * config buildid dir to symfs/.debug + */ + ret = asprintf(&bf, "%s/%s", dir, ".debug"); + if (ret < 0) + return -ENOMEM; + + set_buildid_dir(bf); + + free(bf); + return 0; +} diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 2b5e4ed76fcb..b10d558a8803 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -44,6 +44,9 @@ Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, #define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */ #endif +#define DSO__NAME_KALLSYMS "[kernel.kallsyms]" +#define DSO__NAME_KCORE "[kernel.kcore]" + /** struct symbol - symtab entry * * @ignore - resolvable but tools ignore it (e.g. idle routines) @@ -183,6 +186,8 @@ struct branch_info { struct addr_map_symbol from; struct addr_map_symbol to; struct branch_flags flags; + char *srcline_from; + char *srcline_to; }; struct mem_info { @@ -287,6 +292,8 @@ bool symbol_type__is_a(char symbol_type, enum map_type map_type); bool symbol__restricted_filename(const char *filename, const char *restricted_filename); bool symbol__is_idle(struct symbol *sym); +int symbol__config_symfs(const struct option *opt __maybe_unused, + const char *dir, int unset __maybe_unused); int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss, struct symsrc *runtime_ss, symbol_filter_t filter, diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h index f92c37abb0a8..b2940c88734a 100644 --- a/tools/perf/util/top.h +++ b/tools/perf/util/top.h @@ -27,7 +27,6 @@ struct perf_top { int max_stack; bool hide_kernel_symbols, hide_user_symbols, zero; bool use_tui, use_stdio; - bool kptr_restrict_warned; bool vmlinux_warned; bool dump_symtab; struct hist_entry *sym_filter_entry; diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index eab077ad6ca9..23504ad5d6dd 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c @@ -33,7 +33,8 @@ struct callchain_param callchain_param = { unsigned int page_size; int cacheline_size; -unsigned int sysctl_perf_event_max_stack = PERF_MAX_STACK_DEPTH; +int sysctl_perf_event_max_stack = PERF_MAX_STACK_DEPTH; +int sysctl_perf_event_max_contexts_per_stack = PERF_MAX_CONTEXTS_PER_STACK; bool test_attr__enabled; diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 7651633a8dc7..1e8c3167b9fb 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -261,7 +261,8 @@ void sighandler_dump_stack(int sig); extern unsigned int page_size; extern int cacheline_size; -extern unsigned int sysctl_perf_event_max_stack; +extern int sysctl_perf_event_max_stack; +extern int sysctl_perf_event_max_contexts_per_stack; struct parse_tag { char tag; diff --git a/tools/testing/nvdimm/Kbuild b/tools/testing/nvdimm/Kbuild index a34bfd0c8928..785985677159 100644 --- a/tools/testing/nvdimm/Kbuild +++ b/tools/testing/nvdimm/Kbuild @@ -7,6 +7,7 @@ ldflags-y += --wrap=ioremap_nocache ldflags-y += --wrap=iounmap ldflags-y += --wrap=memunmap ldflags-y += --wrap=__devm_request_region +ldflags-y += --wrap=__devm_release_region ldflags-y += --wrap=__request_region ldflags-y += --wrap=__release_region ldflags-y += --wrap=devm_memremap_pages @@ -15,6 +16,7 @@ ldflags-y += --wrap=phys_to_pfn_t DRIVERS := ../../../drivers NVDIMM_SRC := $(DRIVERS)/nvdimm ACPI_SRC := $(DRIVERS)/acpi +DAX_SRC := $(DRIVERS)/dax obj-$(CONFIG_LIBNVDIMM) += libnvdimm.o obj-$(CONFIG_BLK_DEV_PMEM) += nd_pmem.o @@ -22,6 +24,8 @@ obj-$(CONFIG_ND_BTT) += nd_btt.o obj-$(CONFIG_ND_BLK) += nd_blk.o obj-$(CONFIG_X86_PMEM_LEGACY) += nd_e820.o obj-$(CONFIG_ACPI_NFIT) += nfit.o +obj-$(CONFIG_DEV_DAX) += dax.o +obj-$(CONFIG_DEV_DAX_PMEM) += dax_pmem.o nfit-y := $(ACPI_SRC)/nfit.o nfit-y += config_check.o @@ -38,6 +42,12 @@ nd_blk-y += config_check.o nd_e820-y := $(NVDIMM_SRC)/e820.o nd_e820-y += config_check.o +dax-y := $(DAX_SRC)/dax.o +dax-y += config_check.o + +dax_pmem-y := $(DAX_SRC)/pmem.o +dax_pmem-y += config_check.o + libnvdimm-y := $(NVDIMM_SRC)/core.o libnvdimm-y += $(NVDIMM_SRC)/bus.o libnvdimm-y += $(NVDIMM_SRC)/dimm_devs.o @@ -49,6 +59,7 @@ libnvdimm-y += $(NVDIMM_SRC)/label.o libnvdimm-$(CONFIG_ND_CLAIM) += $(NVDIMM_SRC)/claim.o libnvdimm-$(CONFIG_BTT) += $(NVDIMM_SRC)/btt_devs.o libnvdimm-$(CONFIG_NVDIMM_PFN) += $(NVDIMM_SRC)/pfn_devs.o +libnvdimm-$(CONFIG_NVDIMM_DAX) += $(NVDIMM_SRC)/dax_devs.o libnvdimm-y += config_check.o obj-m += test/ diff --git a/tools/testing/nvdimm/config_check.c b/tools/testing/nvdimm/config_check.c index f2c7615554eb..adf18bfeca00 100644 --- a/tools/testing/nvdimm/config_check.c +++ b/tools/testing/nvdimm/config_check.c @@ -12,4 +12,6 @@ void check(void) BUILD_BUG_ON(!IS_MODULE(CONFIG_ND_BTT)); BUILD_BUG_ON(!IS_MODULE(CONFIG_ND_BLK)); BUILD_BUG_ON(!IS_MODULE(CONFIG_ACPI_NFIT)); + BUILD_BUG_ON(!IS_MODULE(CONFIG_DEV_DAX)); + BUILD_BUG_ON(!IS_MODULE(CONFIG_DEV_DAX_PMEM)); } diff --git a/tools/testing/nvdimm/test/iomap.c b/tools/testing/nvdimm/test/iomap.c index 0c1a7e65bb81..c842095f2801 100644 --- a/tools/testing/nvdimm/test/iomap.c +++ b/tools/testing/nvdimm/test/iomap.c @@ -239,13 +239,11 @@ struct resource *__wrap___devm_request_region(struct device *dev, } EXPORT_SYMBOL(__wrap___devm_request_region); -void __wrap___release_region(struct resource *parent, resource_size_t start, - resource_size_t n) +static bool nfit_test_release_region(struct resource *parent, + resource_size_t start, resource_size_t n) { - struct nfit_test_resource *nfit_res; - if (parent == &iomem_resource) { - nfit_res = get_nfit_res(start); + struct nfit_test_resource *nfit_res = get_nfit_res(start); if (nfit_res) { struct resource *res = nfit_res->res + 1; @@ -254,11 +252,26 @@ void __wrap___release_region(struct resource *parent, resource_size_t start, __func__, start, n, res); else memset(res, 0, sizeof(*res)); - return; + return true; } } - __release_region(parent, start, n); + return false; +} + +void __wrap___release_region(struct resource *parent, resource_size_t start, + resource_size_t n) +{ + if (!nfit_test_release_region(parent, start, n)) + __release_region(parent, start, n); } EXPORT_SYMBOL(__wrap___release_region); +void __wrap___devm_release_region(struct device *dev, struct resource *parent, + resource_size_t start, resource_size_t n) +{ + if (!nfit_test_release_region(parent, start, n)) + __devm_release_region(dev, parent, start, n); +} +EXPORT_SYMBOL(__wrap___devm_release_region); + MODULE_LICENSE("GPL v2"); diff --git a/tools/testing/nvdimm/test/nfit.c b/tools/testing/nvdimm/test/nfit.c index 3187322eeed7..c919866853a0 100644 --- a/tools/testing/nvdimm/test/nfit.c +++ b/tools/testing/nvdimm/test/nfit.c @@ -330,12 +330,49 @@ static int nfit_test_cmd_clear_error(struct nd_cmd_clear_error *clear_err, return 0; } +static int nfit_test_cmd_smart(struct nd_cmd_smart *smart, unsigned int buf_len) +{ + static const struct nd_smart_payload smart_data = { + .flags = ND_SMART_HEALTH_VALID | ND_SMART_TEMP_VALID + | ND_SMART_SPARES_VALID | ND_SMART_ALARM_VALID + | ND_SMART_USED_VALID | ND_SMART_SHUTDOWN_VALID, + .health = ND_SMART_NON_CRITICAL_HEALTH, + .temperature = 23 * 16, + .spares = 75, + .alarm_flags = ND_SMART_SPARE_TRIP | ND_SMART_TEMP_TRIP, + .life_used = 5, + .shutdown_state = 0, + .vendor_size = 0, + }; + + if (buf_len < sizeof(*smart)) + return -EINVAL; + memcpy(smart->data, &smart_data, sizeof(smart_data)); + return 0; +} + +static int nfit_test_cmd_smart_threshold(struct nd_cmd_smart_threshold *smart_t, + unsigned int buf_len) +{ + static const struct nd_smart_threshold_payload smart_t_data = { + .alarm_control = ND_SMART_SPARE_TRIP | ND_SMART_TEMP_TRIP, + .temperature = 40 * 16, + .spares = 5, + }; + + if (buf_len < sizeof(*smart_t)) + return -EINVAL; + memcpy(smart_t->data, &smart_t_data, sizeof(smart_t_data)); + return 0; +} + static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm, unsigned int cmd, void *buf, unsigned int buf_len, int *cmd_rc) { struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc); struct nfit_test *t = container_of(acpi_desc, typeof(*t), acpi_desc); + unsigned int func = cmd; int i, rc = 0, __cmd_rc; if (!cmd_rc) @@ -344,8 +381,23 @@ static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc, if (nvdimm) { struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); + unsigned long cmd_mask = nvdimm_cmd_mask(nvdimm); - if (!nfit_mem || !test_bit(cmd, &nfit_mem->dsm_mask)) + if (!nfit_mem) + return -ENOTTY; + + if (cmd == ND_CMD_CALL) { + struct nd_cmd_pkg *call_pkg = buf; + + buf_len = call_pkg->nd_size_in + call_pkg->nd_size_out; + buf = (void *) call_pkg->nd_payload; + func = call_pkg->nd_command; + if (call_pkg->nd_family != nfit_mem->family) + return -ENOTTY; + } + + if (!test_bit(cmd, &cmd_mask) + || !test_bit(func, &nfit_mem->dsm_mask)) return -ENOTTY; /* lookup label space for the given dimm */ @@ -356,7 +408,7 @@ static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc, if (i >= ARRAY_SIZE(handle)) return -ENXIO; - switch (cmd) { + switch (func) { case ND_CMD_GET_CONFIG_SIZE: rc = nfit_test_cmd_get_config_size(buf, buf_len); break; @@ -368,16 +420,22 @@ static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc, rc = nfit_test_cmd_set_config_data(buf, buf_len, t->label[i]); break; + case ND_CMD_SMART: + rc = nfit_test_cmd_smart(buf, buf_len); + break; + case ND_CMD_SMART_THRESHOLD: + rc = nfit_test_cmd_smart_threshold(buf, buf_len); + break; default: return -ENOTTY; } } else { struct ars_state *ars_state = &t->ars_state; - if (!nd_desc || !test_bit(cmd, &nd_desc->dsm_mask)) + if (!nd_desc || !test_bit(cmd, &nd_desc->cmd_mask)) return -ENOTTY; - switch (cmd) { + switch (func) { case ND_CMD_ARS_CAP: rc = nfit_test_cmd_ars_cap(buf, buf_len); break; @@ -1251,13 +1309,15 @@ static void nfit_test0_setup(struct nfit_test *t) post_ars_status(&t->ars_state, t->spa_set_dma[0], SPA0_SIZE); acpi_desc = &t->acpi_desc; - set_bit(ND_CMD_GET_CONFIG_SIZE, &acpi_desc->dimm_dsm_force_en); - set_bit(ND_CMD_GET_CONFIG_DATA, &acpi_desc->dimm_dsm_force_en); - set_bit(ND_CMD_SET_CONFIG_DATA, &acpi_desc->dimm_dsm_force_en); - set_bit(ND_CMD_ARS_CAP, &acpi_desc->bus_dsm_force_en); - set_bit(ND_CMD_ARS_START, &acpi_desc->bus_dsm_force_en); - set_bit(ND_CMD_ARS_STATUS, &acpi_desc->bus_dsm_force_en); - set_bit(ND_CMD_CLEAR_ERROR, &acpi_desc->bus_dsm_force_en); + set_bit(ND_CMD_GET_CONFIG_SIZE, &acpi_desc->dimm_cmd_force_en); + set_bit(ND_CMD_GET_CONFIG_DATA, &acpi_desc->dimm_cmd_force_en); + set_bit(ND_CMD_SET_CONFIG_DATA, &acpi_desc->dimm_cmd_force_en); + set_bit(ND_CMD_SMART, &acpi_desc->dimm_cmd_force_en); + set_bit(ND_CMD_ARS_CAP, &acpi_desc->bus_cmd_force_en); + set_bit(ND_CMD_ARS_START, &acpi_desc->bus_cmd_force_en); + set_bit(ND_CMD_ARS_STATUS, &acpi_desc->bus_cmd_force_en); + set_bit(ND_CMD_CLEAR_ERROR, &acpi_desc->bus_cmd_force_en); + set_bit(ND_CMD_SMART_THRESHOLD, &acpi_desc->dimm_cmd_force_en); } static void nfit_test1_setup(struct nfit_test *t) @@ -1315,10 +1375,10 @@ static void nfit_test1_setup(struct nfit_test *t) post_ars_status(&t->ars_state, t->spa_set_dma[0], SPA2_SIZE); acpi_desc = &t->acpi_desc; - set_bit(ND_CMD_ARS_CAP, &acpi_desc->bus_dsm_force_en); - set_bit(ND_CMD_ARS_START, &acpi_desc->bus_dsm_force_en); - set_bit(ND_CMD_ARS_STATUS, &acpi_desc->bus_dsm_force_en); - set_bit(ND_CMD_CLEAR_ERROR, &acpi_desc->bus_dsm_force_en); + set_bit(ND_CMD_ARS_CAP, &acpi_desc->bus_cmd_force_en); + set_bit(ND_CMD_ARS_START, &acpi_desc->bus_cmd_force_en); + set_bit(ND_CMD_ARS_STATUS, &acpi_desc->bus_cmd_force_en); + set_bit(ND_CMD_CLEAR_ERROR, &acpi_desc->bus_cmd_force_en); } static int nfit_test_blk_do_io(struct nd_blk_region *ndbr, resource_size_t dpa, diff --git a/tools/testing/selftests/ftrace/ftracetest b/tools/testing/selftests/ftrace/ftracetest index da48812ab95e..4c6a0bf8ba79 100755 --- a/tools/testing/selftests/ftrace/ftracetest +++ b/tools/testing/selftests/ftrace/ftracetest @@ -88,7 +88,12 @@ parse_opts() { # opts # Parameters DEBUGFS_DIR=`grep debugfs /proc/mounts | cut -f2 -d' ' | head -1` -TRACING_DIR=$DEBUGFS_DIR/tracing +if [ -z "$DEBUGFS_DIR" ]; then + TRACING_DIR=`grep tracefs /proc/mounts | cut -f2 -d' ' | head -1` +else + TRACING_DIR=$DEBUGFS_DIR/tracing +fi + TOP_DIR=`absdir $0` TEST_DIR=$TOP_DIR/test.d TEST_CASES=`find_testcases $TEST_DIR` @@ -102,7 +107,7 @@ parse_opts $* [ $DEBUG -ne 0 ] && set -x # Verify parameters -if [ -z "$DEBUGFS_DIR" -o ! -d "$TRACING_DIR" ]; then +if [ -z "$TRACING_DIR" -o ! -d "$TRACING_DIR" ]; then errexit "No ftrace directory found" fi diff --git a/tools/testing/selftests/ftrace/test.d/event/event-pid.tc b/tools/testing/selftests/ftrace/test.d/event/event-pid.tc new file mode 100644 index 000000000000..d4ab27b522f8 --- /dev/null +++ b/tools/testing/selftests/ftrace/test.d/event/event-pid.tc @@ -0,0 +1,72 @@ +#!/bin/sh +# description: event tracing - restricts events based on pid + +do_reset() { + echo > set_event + echo > set_event_pid + echo 0 > options/event-fork + clear_trace +} + +fail() { #msg + do_reset + echo $1 + exit $FAIL +} + +yield() { + ping localhost -c 1 || sleep .001 || usleep 1 || sleep 1 +} + +if [ ! -f set_event -o ! -d events/sched ]; then + echo "event tracing is not supported" + exit_unsupported +fi + +if [ ! -f set_event_pid ]; then + echo "event pid filtering is not supported" + exit_unsupported +fi + +reset_tracer +do_reset + +echo 1 > events/sched/sched_switch/enable + +yield + +count=`cat trace | grep sched_switch | wc -l` +if [ $count -eq 0 ]; then + fail "sched_switch events are not recorded" +fi + +do_reset + +read mypid rest < /proc/self/stat + +echo $mypid > set_event_pid +echo 'sched:sched_switch' > set_event + +yield + +count=`cat trace | grep sched_switch | grep -v "pid=$mypid" | wc -l` +if [ $count -ne 0 ]; then + fail "sched_switch events from other task are recorded" +fi + +do_reset + +echo $mypid > set_event_pid +echo 1 > options/event-fork +echo 1 > events/sched/sched_switch/enable + +yield + +count=`cat trace | grep sched_switch | grep -v "pid=$mypid" | wc -l` +if [ $count -eq 0 ]; then + fail "sched_switch events from other task are not recorded" +fi + +do_reset + +exit 0 diff --git a/tools/testing/selftests/ftrace/test.d/instances/instance-event.tc b/tools/testing/selftests/ftrace/test.d/instances/instance-event.tc index 5f2abd03f16b..4c5a061a5b4e 100644 --- a/tools/testing/selftests/ftrace/test.d/instances/instance-event.tc +++ b/tools/testing/selftests/ftrace/test.d/instances/instance-event.tc @@ -92,28 +92,23 @@ instance_slam() { } instance_slam & -x=`jobs -l` -p1=`echo $x | cut -d' ' -f2` +p1=$! echo $p1 instance_slam & -x=`jobs -l | tail -1` -p2=`echo $x | cut -d' ' -f2` +p2=$! echo $p2 instance_slam & -x=`jobs -l | tail -1` -p3=`echo $x | cut -d' ' -f2` +p3=$! echo $p3 instance_slam & -x=`jobs -l | tail -1` -p4=`echo $x | cut -d' ' -f2` +p4=$! echo $p4 instance_slam & -x=`jobs -l | tail -1` -p5=`echo $x | cut -d' ' -f2` +p5=$! echo $p5 ls -lR >/dev/null diff --git a/tools/testing/selftests/intel_pstate/run.sh b/tools/testing/selftests/intel_pstate/run.sh index bdaf37e92684..7868c106b8b1 100755 --- a/tools/testing/selftests/intel_pstate/run.sh +++ b/tools/testing/selftests/intel_pstate/run.sh @@ -32,7 +32,7 @@ EVALUATE_ONLY=0 max_cpus=$(($(nproc)-1)) # compile programs -gcc -o aperf aperf.c -lm +gcc aperf.c -Wall -D_GNU_SOURCE -o aperf -lm [ $? -ne 0 ] && echo "Problem compiling aperf.c." && exit 1 gcc -o msr msr.c -lm [ $? -ne 0 ] && echo "Problem compiling msr.c." && exit 1 diff --git a/tools/testing/selftests/net/reuseport_bpf.c b/tools/testing/selftests/net/reuseport_bpf.c index 96ba386b1b7b..4a8217448f20 100644 --- a/tools/testing/selftests/net/reuseport_bpf.c +++ b/tools/testing/selftests/net/reuseport_bpf.c @@ -111,9 +111,9 @@ static void attach_ebpf(int fd, uint16_t mod) memset(&attr, 0, sizeof(attr)); attr.prog_type = BPF_PROG_TYPE_SOCKET_FILTER; attr.insn_cnt = ARRAY_SIZE(prog); - attr.insns = (uint64_t)prog; - attr.license = (uint64_t)bpf_license; - attr.log_buf = (uint64_t)bpf_log_buf; + attr.insns = (unsigned long) &prog; + attr.license = (unsigned long) &bpf_license; + attr.log_buf = (unsigned long) &bpf_log_buf; attr.log_size = sizeof(bpf_log_buf); attr.log_level = 1; attr.kern_version = 0; @@ -351,8 +351,8 @@ static void test_filter_no_reuseport(const struct test_params p) memset(&eprog, 0, sizeof(eprog)); eprog.prog_type = BPF_PROG_TYPE_SOCKET_FILTER; eprog.insn_cnt = ARRAY_SIZE(ecode); - eprog.insns = (uint64_t)ecode; - eprog.license = (uint64_t)bpf_license; + eprog.insns = (unsigned long) &ecode; + eprog.license = (unsigned long) &bpf_license; eprog.kern_version = 0; memset(&cprog, 0, sizeof(cprog)); diff --git a/tools/testing/selftests/seccomp/seccomp_bpf.c b/tools/testing/selftests/seccomp/seccomp_bpf.c index 7947e568e057..2e58549b2f02 100644 --- a/tools/testing/selftests/seccomp/seccomp_bpf.c +++ b/tools/testing/selftests/seccomp/seccomp_bpf.c @@ -1234,6 +1234,10 @@ TEST_F(TRACE_poke, getpid_runs_normally) # define ARCH_REGS struct user_pt_regs # define SYSCALL_NUM regs[8] # define SYSCALL_RET regs[0] +#elif defined(__hppa__) +# define ARCH_REGS struct user_regs_struct +# define SYSCALL_NUM gr[20] +# define SYSCALL_RET gr[28] #elif defined(__powerpc__) # define ARCH_REGS struct pt_regs # define SYSCALL_NUM gpr[0] @@ -1303,7 +1307,7 @@ void change_syscall(struct __test_metadata *_metadata, EXPECT_EQ(0, ret); #if defined(__x86_64__) || defined(__i386__) || defined(__powerpc__) || \ - defined(__s390__) + defined(__s390__) || defined(__hppa__) { regs.SYSCALL_NUM = syscall; } @@ -1505,6 +1509,8 @@ TEST_F(TRACE_syscall, syscall_dropped) # define __NR_seccomp 383 # elif defined(__aarch64__) # define __NR_seccomp 277 +# elif defined(__hppa__) +# define __NR_seccomp 338 # elif defined(__powerpc__) # define __NR_seccomp 358 # elif defined(__s390__) diff --git a/tools/testing/selftests/vm/thuge-gen.c b/tools/testing/selftests/vm/thuge-gen.c index c87957295f74..0bc737a75150 100644 --- a/tools/testing/selftests/vm/thuge-gen.c +++ b/tools/testing/selftests/vm/thuge-gen.c @@ -30,7 +30,9 @@ #define MAP_HUGE_1GB (30 << MAP_HUGE_SHIFT) #define MAP_HUGE_SHIFT 26 #define MAP_HUGE_MASK 0x3f +#if !defined(MAP_HUGETLB) #define MAP_HUGETLB 0x40000 +#endif #define SHM_HUGETLB 04000 /* segment will use huge TLB pages */ #define SHM_HUGE_SHIFT 26 diff --git a/tools/virtio/ringtest/Makefile b/tools/virtio/ringtest/Makefile index feaa64ac4630..6ba745529833 100644 --- a/tools/virtio/ringtest/Makefile +++ b/tools/virtio/ringtest/Makefile @@ -1,6 +1,6 @@ all: -all: ring virtio_ring_0_9 virtio_ring_poll +all: ring virtio_ring_0_9 virtio_ring_poll virtio_ring_inorder CFLAGS += -Wall CFLAGS += -pthread -O2 -ggdb @@ -10,13 +10,16 @@ main.o: main.c main.h ring.o: ring.c main.h virtio_ring_0_9.o: virtio_ring_0_9.c main.h virtio_ring_poll.o: virtio_ring_poll.c virtio_ring_0_9.c main.h +virtio_ring_inorder.o: virtio_ring_inorder.c virtio_ring_0_9.c main.h ring: ring.o main.o virtio_ring_0_9: virtio_ring_0_9.o main.o virtio_ring_poll: virtio_ring_poll.o main.o +virtio_ring_inorder: virtio_ring_inorder.o main.o clean: -rm main.o -rm ring.o ring -rm virtio_ring_0_9.o virtio_ring_0_9 -rm virtio_ring_poll.o virtio_ring_poll + -rm virtio_ring_inorder.o virtio_ring_inorder .PHONY: all clean diff --git a/tools/virtio/ringtest/main.c b/tools/virtio/ringtest/main.c index 3a5ff438bd62..147abb452a6c 100644 --- a/tools/virtio/ringtest/main.c +++ b/tools/virtio/ringtest/main.c @@ -115,7 +115,7 @@ static void run_guest(void) do { if (started < bufs && started - completed < max_outstanding) { - r = add_inbuf(0, NULL, "Hello, world!"); + r = add_inbuf(0, "Buffer\n", "Hello, world!"); if (__builtin_expect(r == 0, true)) { ++started; if (!--tokick) { diff --git a/tools/virtio/ringtest/virtio_ring_0_9.c b/tools/virtio/ringtest/virtio_ring_0_9.c index 47c9a1a18d36..761866212aac 100644 --- a/tools/virtio/ringtest/virtio_ring_0_9.c +++ b/tools/virtio/ringtest/virtio_ring_0_9.c @@ -26,6 +26,14 @@ struct vring ring; * high bits of ring id ^ 0x8000). */ /* #ifdef RING_POLL */ +/* enabling the below activates experimental in-order code + * (which skips ring updates and reads and writes len in descriptor). + */ +/* #ifdef INORDER */ + +#if defined(RING_POLL) && defined(INORDER) +#error "RING_POLL and INORDER are mutually exclusive" +#endif /* how much padding is needed to avoid false cache sharing */ #define HOST_GUEST_PADDING 0x80 @@ -35,7 +43,11 @@ struct guest { unsigned short last_used_idx; unsigned short num_free; unsigned short kicked_avail_idx; +#ifndef INORDER unsigned short free_head; +#else + unsigned short reserved_free_head; +#endif unsigned char reserved[HOST_GUEST_PADDING - 10]; } guest; @@ -66,8 +78,10 @@ void alloc_ring(void) guest.avail_idx = 0; guest.kicked_avail_idx = -1; guest.last_used_idx = 0; +#ifndef INORDER /* Put everything in free lists. */ guest.free_head = 0; +#endif for (i = 0; i < ring_size - 1; i++) ring.desc[i].next = i + 1; host.used_idx = 0; @@ -84,13 +98,20 @@ void alloc_ring(void) /* guest side */ int add_inbuf(unsigned len, void *buf, void *datap) { - unsigned head, avail; + unsigned head; +#ifndef INORDER + unsigned avail; +#endif struct vring_desc *desc; if (!guest.num_free) return -1; +#ifdef INORDER + head = (ring_size - 1) & (guest.avail_idx++); +#else head = guest.free_head; +#endif guest.num_free--; desc = ring.desc; @@ -102,7 +123,9 @@ int add_inbuf(unsigned len, void *buf, void *datap) * descriptors. */ desc[head].flags &= ~VRING_DESC_F_NEXT; +#ifndef INORDER guest.free_head = desc[head].next; +#endif data[head].data = datap; @@ -113,8 +136,12 @@ int add_inbuf(unsigned len, void *buf, void *datap) ring.avail->ring[avail & (ring_size - 1)] = (head | (avail & ~(ring_size - 1))) ^ 0x8000; #else +#ifndef INORDER + /* Barrier A (for pairing) */ + smp_release(); avail = (ring_size - 1) & (guest.avail_idx++); ring.avail->ring[avail] = head; +#endif /* Barrier A (for pairing) */ smp_release(); #endif @@ -141,15 +168,27 @@ void *get_buf(unsigned *lenp, void **bufp) return NULL; /* Barrier B (for pairing) */ smp_acquire(); +#ifdef INORDER + head = (ring_size - 1) & guest.last_used_idx; + index = head; +#else head = (ring_size - 1) & guest.last_used_idx; index = ring.used->ring[head].id; #endif + +#endif +#ifdef INORDER + *lenp = ring.desc[index].len; +#else *lenp = ring.used->ring[head].len; +#endif datap = data[index].data; *bufp = (void*)(unsigned long)ring.desc[index].addr; data[index].data = NULL; +#ifndef INORDER ring.desc[index].next = guest.free_head; guest.free_head = index; +#endif guest.num_free++; guest.last_used_idx++; return datap; @@ -283,16 +322,24 @@ bool use_buf(unsigned *lenp, void **bufp) smp_acquire(); used_idx &= ring_size - 1; +#ifdef INORDER + head = used_idx; +#else head = ring.avail->ring[used_idx]; +#endif desc = &ring.desc[head]; #endif *lenp = desc->len; *bufp = (void *)(unsigned long)desc->addr; +#ifdef INORDER + desc->len = desc->len - 1; +#else /* now update used ring */ ring.used->ring[used_idx].id = head; ring.used->ring[used_idx].len = desc->len - 1; +#endif /* Barrier B (for pairing) */ smp_release(); host.used_idx++; diff --git a/tools/virtio/ringtest/virtio_ring_inorder.c b/tools/virtio/ringtest/virtio_ring_inorder.c new file mode 100644 index 000000000000..2438ca58a2ad --- /dev/null +++ b/tools/virtio/ringtest/virtio_ring_inorder.c @@ -0,0 +1,2 @@ +#define INORDER 1 +#include "virtio_ring_0_9.c" |