Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3c330108 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'perf-counters-for-linus' of...

Merge branch 'perf-counters-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/peterz/linux-2.6-perf

* 'perf-counters-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/peterz/linux-2.6-perf: (31 commits)
  perf_counter tools: Give perf top inherit option
  perf_counter tools: Fix vmlinux symbol generation breakage
  perf_counter: Detect debugfs location
  perf_counter: Add tracepoint support to perf list, perf stat
  perf symbol: C++ demangling
  perf: avoid structure size confusion by using a fixed size
  perf_counter: Fix throttle/unthrottle event logging
  perf_counter: Improve perf stat and perf record option parsing
  perf_counter: PERF_SAMPLE_ID and inherited counters
  perf_counter: Plug more stack leaks
  perf: Fix stack data leak
  perf_counter: Remove unused variables
  perf_counter: Make call graph option consistent
  perf_counter: Add perf record option to log addresses
  perf_counter: Log vfork as a fork event
  perf_counter: Synthesize VDSO mmap event
  perf_counter: Make sure we dont leak kernel memory to userspace
  perf_counter tools: Fix index boundary check
  perf_counter: Fix the tracepoint channel to perfcounters
  perf_counter, x86: Extend perf_counter Pentium M support
  ...
parents 612e900c 0fdc7e67
Loading
Loading
Loading
Loading
+233 −20
Original line number Diff line number Diff line
@@ -65,6 +65,52 @@ static DEFINE_PER_CPU(struct cpu_hw_counters, cpu_hw_counters) = {
	.enabled = 1,
};

/*
 * Not sure about some of these
 */
static const u64 p6_perfmon_event_map[] =
{
  [PERF_COUNT_HW_CPU_CYCLES]		= 0x0079,
  [PERF_COUNT_HW_INSTRUCTIONS]		= 0x00c0,
  [PERF_COUNT_HW_CACHE_REFERENCES]	= 0x0000,
  [PERF_COUNT_HW_CACHE_MISSES]		= 0x0000,
  [PERF_COUNT_HW_BRANCH_INSTRUCTIONS]	= 0x00c4,
  [PERF_COUNT_HW_BRANCH_MISSES]		= 0x00c5,
  [PERF_COUNT_HW_BUS_CYCLES]		= 0x0062,
};

static u64 p6_pmu_event_map(int event)
{
	return p6_perfmon_event_map[event];
}

/*
 * Counter setting that is specified not to count anything.
 * We use this to effectively disable a counter.
 *
 * L2_RQSTS with 0 MESI unit mask.
 */
#define P6_NOP_COUNTER			0x0000002EULL

static u64 p6_pmu_raw_event(u64 event)
{
#define P6_EVNTSEL_EVENT_MASK		0x000000FFULL
#define P6_EVNTSEL_UNIT_MASK		0x0000FF00ULL
#define P6_EVNTSEL_EDGE_MASK		0x00040000ULL
#define P6_EVNTSEL_INV_MASK		0x00800000ULL
#define P6_EVNTSEL_COUNTER_MASK		0xFF000000ULL

#define P6_EVNTSEL_MASK			\
	(P6_EVNTSEL_EVENT_MASK |	\
	 P6_EVNTSEL_UNIT_MASK  |	\
	 P6_EVNTSEL_EDGE_MASK  |	\
	 P6_EVNTSEL_INV_MASK   |	\
	 P6_EVNTSEL_COUNTER_MASK)

	return event & P6_EVNTSEL_MASK;
}


/*
 * Intel PerfMon v3. Used on Core2 and later.
 */
@@ -666,6 +712,7 @@ static int __hw_perf_counter_init(struct perf_counter *counter)
{
	struct perf_counter_attr *attr = &counter->attr;
	struct hw_perf_counter *hwc = &counter->hw;
	u64 config;
	int err;

	if (!x86_pmu_initialized())
@@ -718,14 +765,40 @@ static int __hw_perf_counter_init(struct perf_counter *counter)

	if (attr->config >= x86_pmu.max_events)
		return -EINVAL;

	/*
	 * The generic map:
	 */
	hwc->config |= x86_pmu.event_map(attr->config);
	config = x86_pmu.event_map(attr->config);

	if (config == 0)
		return -ENOENT;

	if (config == -1LL)
		return -EINVAL;

	hwc->config |= config;

	return 0;
}

static void p6_pmu_disable_all(void)
{
	struct cpu_hw_counters *cpuc = &__get_cpu_var(cpu_hw_counters);
	u64 val;

	if (!cpuc->enabled)
		return;

	cpuc->enabled = 0;
	barrier();

	/* p6 only has one enable register */
	rdmsrl(MSR_P6_EVNTSEL0, val);
	val &= ~ARCH_PERFMON_EVENTSEL0_ENABLE;
	wrmsrl(MSR_P6_EVNTSEL0, val);
}

static void intel_pmu_disable_all(void)
{
	wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, 0);
@@ -767,6 +840,23 @@ void hw_perf_disable(void)
	return x86_pmu.disable_all();
}

static void p6_pmu_enable_all(void)
{
	struct cpu_hw_counters *cpuc = &__get_cpu_var(cpu_hw_counters);
	unsigned long val;

	if (cpuc->enabled)
		return;

	cpuc->enabled = 1;
	barrier();

	/* p6 only has one enable register */
	rdmsrl(MSR_P6_EVNTSEL0, val);
	val |= ARCH_PERFMON_EVENTSEL0_ENABLE;
	wrmsrl(MSR_P6_EVNTSEL0, val);
}

static void intel_pmu_enable_all(void)
{
	wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, x86_pmu.intel_ctrl);
@@ -784,13 +874,13 @@ static void amd_pmu_enable_all(void)
	barrier();

	for (idx = 0; idx < x86_pmu.num_counters; idx++) {
		struct perf_counter *counter = cpuc->counters[idx];
		u64 val;

		if (!test_bit(idx, cpuc->active_mask))
			continue;
		rdmsrl(MSR_K7_EVNTSEL0 + idx, val);
		if (val & ARCH_PERFMON_EVENTSEL0_ENABLE)
			continue;

		val = counter->hw.config;
		val |= ARCH_PERFMON_EVENTSEL0_ENABLE;
		wrmsrl(MSR_K7_EVNTSEL0 + idx, val);
	}
@@ -819,16 +909,13 @@ static inline void intel_pmu_ack_status(u64 ack)

static inline void x86_pmu_enable_counter(struct hw_perf_counter *hwc, int idx)
{
	int err;
	err = checking_wrmsrl(hwc->config_base + idx,
	(void)checking_wrmsrl(hwc->config_base + idx,
			      hwc->config | ARCH_PERFMON_EVENTSEL0_ENABLE);
}

static inline void x86_pmu_disable_counter(struct hw_perf_counter *hwc, int idx)
{
	int err;
	err = checking_wrmsrl(hwc->config_base + idx,
			      hwc->config);
	(void)checking_wrmsrl(hwc->config_base + idx, hwc->config);
}

static inline void
@@ -836,13 +923,24 @@ intel_pmu_disable_fixed(struct hw_perf_counter *hwc, int __idx)
{
	int idx = __idx - X86_PMC_IDX_FIXED;
	u64 ctrl_val, mask;
	int err;

	mask = 0xfULL << (idx * 4);

	rdmsrl(hwc->config_base, ctrl_val);
	ctrl_val &= ~mask;
	err = checking_wrmsrl(hwc->config_base, ctrl_val);
	(void)checking_wrmsrl(hwc->config_base, ctrl_val);
}

static inline void
p6_pmu_disable_counter(struct hw_perf_counter *hwc, int idx)
{
	struct cpu_hw_counters *cpuc = &__get_cpu_var(cpu_hw_counters);
	u64 val = P6_NOP_COUNTER;

	if (cpuc->enabled)
		val |= ARCH_PERFMON_EVENTSEL0_ENABLE;

	(void)checking_wrmsrl(hwc->config_base + idx, val);
}

static inline void
@@ -943,6 +1041,19 @@ intel_pmu_enable_fixed(struct hw_perf_counter *hwc, int __idx)
	err = checking_wrmsrl(hwc->config_base, ctrl_val);
}

static void p6_pmu_enable_counter(struct hw_perf_counter *hwc, int idx)
{
	struct cpu_hw_counters *cpuc = &__get_cpu_var(cpu_hw_counters);
	u64 val;

	val = hwc->config;
	if (cpuc->enabled)
		val |= ARCH_PERFMON_EVENTSEL0_ENABLE;

	(void)checking_wrmsrl(hwc->config_base + idx, val);
}


static void intel_pmu_enable_counter(struct hw_perf_counter *hwc, int idx)
{
	if (unlikely(hwc->config_base == MSR_ARCH_PERFMON_FIXED_CTR_CTRL)) {
@@ -959,8 +1070,6 @@ static void amd_pmu_enable_counter(struct hw_perf_counter *hwc, int idx)

	if (cpuc->enabled)
		x86_pmu_enable_counter(hwc, idx);
	else
		x86_pmu_disable_counter(hwc, idx);
}

static int
@@ -1176,6 +1285,49 @@ static void intel_pmu_reset(void)
	local_irq_restore(flags);
}

static int p6_pmu_handle_irq(struct pt_regs *regs)
{
	struct perf_sample_data data;
	struct cpu_hw_counters *cpuc;
	struct perf_counter *counter;
	struct hw_perf_counter *hwc;
	int idx, handled = 0;
	u64 val;

	data.regs = regs;
	data.addr = 0;

	cpuc = &__get_cpu_var(cpu_hw_counters);

	for (idx = 0; idx < x86_pmu.num_counters; idx++) {
		if (!test_bit(idx, cpuc->active_mask))
			continue;

		counter = cpuc->counters[idx];
		hwc = &counter->hw;

		val = x86_perf_counter_update(counter, hwc, idx);
		if (val & (1ULL << (x86_pmu.counter_bits - 1)))
			continue;

		/*
		 * counter overflow
		 */
		handled		= 1;
		data.period	= counter->hw.last_period;

		if (!x86_perf_counter_set_period(counter, hwc, idx))
			continue;

		if (perf_counter_overflow(counter, 1, &data))
			p6_pmu_disable_counter(hwc, idx);
	}

	if (handled)
		inc_irq_stat(apic_perf_irqs);

	return handled;
}

/*
 * This handler is triggered by the local APIC, so the APIC IRQ handling
@@ -1185,14 +1337,13 @@ static int intel_pmu_handle_irq(struct pt_regs *regs)
{
	struct perf_sample_data data;
	struct cpu_hw_counters *cpuc;
	int bit, cpu, loops;
	int bit, loops;
	u64 ack, status;

	data.regs = regs;
	data.addr = 0;

	cpu = smp_processor_id();
	cpuc = &per_cpu(cpu_hw_counters, cpu);
	cpuc = &__get_cpu_var(cpu_hw_counters);

	perf_disable();
	status = intel_pmu_get_status();
@@ -1249,14 +1400,13 @@ static int amd_pmu_handle_irq(struct pt_regs *regs)
	struct cpu_hw_counters *cpuc;
	struct perf_counter *counter;
	struct hw_perf_counter *hwc;
	int cpu, idx, handled = 0;
	int idx, handled = 0;
	u64 val;

	data.regs = regs;
	data.addr = 0;

	cpu = smp_processor_id();
	cpuc = &per_cpu(cpu_hw_counters, cpu);
	cpuc = &__get_cpu_var(cpu_hw_counters);

	for (idx = 0; idx < x86_pmu.num_counters; idx++) {
		if (!test_bit(idx, cpuc->active_mask))
@@ -1353,6 +1503,32 @@ static __read_mostly struct notifier_block perf_counter_nmi_notifier = {
	.priority		= 1
};

static struct x86_pmu p6_pmu = {
	.name			= "p6",
	.handle_irq		= p6_pmu_handle_irq,
	.disable_all		= p6_pmu_disable_all,
	.enable_all		= p6_pmu_enable_all,
	.enable			= p6_pmu_enable_counter,
	.disable		= p6_pmu_disable_counter,
	.eventsel		= MSR_P6_EVNTSEL0,
	.perfctr		= MSR_P6_PERFCTR0,
	.event_map		= p6_pmu_event_map,
	.raw_event		= p6_pmu_raw_event,
	.max_events		= ARRAY_SIZE(p6_perfmon_event_map),
	.max_period		= (1ULL << 31) - 1,
	.version		= 0,
	.num_counters		= 2,
	/*
	 * Counters have 40 bits implemented. However they are designed such
	 * that bits [32-39] are sign extensions of bit 31. As such the
	 * effective width of a counter for P6-like PMU is 32 bits only.
	 *
	 * See IA-32 Intel Architecture Software developer manual Vol 3B
	 */
	.counter_bits		= 32,
	.counter_mask		= (1ULL << 32) - 1,
};

static struct x86_pmu intel_pmu = {
	.name			= "Intel",
	.handle_irq		= intel_pmu_handle_irq,
@@ -1392,6 +1568,37 @@ static struct x86_pmu amd_pmu = {
	.max_period		= (1ULL << 47) - 1,
};

static int p6_pmu_init(void)
{
	switch (boot_cpu_data.x86_model) {
	case 1:
	case 3:  /* Pentium Pro */
	case 5:
	case 6:  /* Pentium II */
	case 7:
	case 8:
	case 11: /* Pentium III */
		break;
	case 9:
	case 13:
		/* Pentium M */
		break;
	default:
		pr_cont("unsupported p6 CPU model %d ",
			boot_cpu_data.x86_model);
		return -ENODEV;
	}

	if (!cpu_has_apic) {
		pr_info("no Local APIC, try rebooting with lapic");
		return -ENODEV;
	}

	x86_pmu				= p6_pmu;

	return 0;
}

static int intel_pmu_init(void)
{
	union cpuid10_edx edx;
@@ -1400,8 +1607,14 @@ static int intel_pmu_init(void)
	unsigned int ebx;
	int version;

	if (!cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON))
	if (!cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON)) {
		/* check for P6 processor family */
	   if (boot_cpu_data.x86 == 6) {
		return p6_pmu_init();
	   } else {
		return -ENODEV;
	   }
	}

	/*
	 * Check whether the Architectural PerfMon supports
+4 −11
Original line number Diff line number Diff line
@@ -120,8 +120,9 @@ enum perf_counter_sample_format {
	PERF_SAMPLE_ID				= 1U << 6,
	PERF_SAMPLE_CPU				= 1U << 7,
	PERF_SAMPLE_PERIOD			= 1U << 8,
	PERF_SAMPLE_STREAM_ID			= 1U << 9,

	PERF_SAMPLE_MAX = 1U << 9,		/* non-ABI */
	PERF_SAMPLE_MAX = 1U << 10,		/* non-ABI */
};

/*
@@ -312,16 +313,7 @@ enum perf_event_type {
	 *	struct perf_event_header	header;
	 *	u64				time;
	 *	u64				id;
	 *	u64				sample_period;
	 * };
	 */
	PERF_EVENT_PERIOD		= 4,

	/*
	 * struct {
	 *	struct perf_event_header	header;
	 *	u64				time;
	 *	u64				id;
	 *	u64				stream_id;
	 * };
	 */
	PERF_EVENT_THROTTLE		= 5,
@@ -356,6 +348,7 @@ enum perf_event_type {
	 *	{ u64			time;     } && PERF_SAMPLE_TIME
	 *	{ u64			addr;     } && PERF_SAMPLE_ADDR
	 *	{ u64			id;	  } && PERF_SAMPLE_ID
	 *	{ u64			stream_id;} && PERF_SAMPLE_STREAM_ID
	 *	{ u32			cpu, res; } && PERF_SAMPLE_CPU
	 * 	{ u64			period;   } && PERF_SAMPLE_PERIOD
	 *
+1 −1
Original line number Diff line number Diff line
@@ -962,7 +962,7 @@ config PERF_COUNTERS

config EVENT_PROFILE
	bool "Tracepoint profile sources"
	depends on PERF_COUNTERS && EVENT_TRACER
	depends on PERF_COUNTERS && EVENT_TRACING
	default y

endmenu
+3 −6
Original line number Diff line number Diff line
@@ -1407,14 +1407,11 @@ long do_fork(unsigned long clone_flags,
		if (clone_flags & CLONE_VFORK) {
			p->vfork_done = &vfork;
			init_completion(&vfork);
		} else if (!(clone_flags & CLONE_VM)) {
			/*
			 * vfork will do an exec which will call
			 * set_task_comm()
			 */
			perf_counter_fork(p);
		}

		if (!(clone_flags & CLONE_THREAD))
			perf_counter_fork(p);

		audit_finish_fork(p);
		tracehook_report_clone(regs, clone_flags, nr, p);

+91 −94
Original line number Diff line number Diff line
@@ -146,6 +146,28 @@ static void put_ctx(struct perf_counter_context *ctx)
	}
}

static void unclone_ctx(struct perf_counter_context *ctx)
{
	if (ctx->parent_ctx) {
		put_ctx(ctx->parent_ctx);
		ctx->parent_ctx = NULL;
	}
}

/*
 * If we inherit counters we want to return the parent counter id
 * to userspace.
 */
static u64 primary_counter_id(struct perf_counter *counter)
{
	u64 id = counter->id;

	if (counter->parent)
		id = counter->parent->id;

	return id;
}

/*
 * Get the perf_counter_context for a task and lock it.
 * This has to cope with with the fact that until it is locked,
@@ -1288,7 +1310,6 @@ static void perf_counter_cpu_sched_in(struct perf_cpu_context *cpuctx, int cpu)
#define MAX_INTERRUPTS (~0ULL)

static void perf_log_throttle(struct perf_counter *counter, int enable);
static void perf_log_period(struct perf_counter *counter, u64 period);

static void perf_adjust_period(struct perf_counter *counter, u64 events)
{
@@ -1307,8 +1328,6 @@ static void perf_adjust_period(struct perf_counter *counter, u64 events)
	if (!sample_period)
		sample_period = 1;

	perf_log_period(counter, sample_period);

	hwc->sample_period = sample_period;
}

@@ -1463,10 +1482,8 @@ static void perf_counter_enable_on_exec(struct task_struct *task)
	/*
	 * Unclone this context if we enabled any counter.
	 */
	if (enabled && ctx->parent_ctx) {
		put_ctx(ctx->parent_ctx);
		ctx->parent_ctx = NULL;
	}
	if (enabled)
		unclone_ctx(ctx);

	spin_unlock(&ctx->lock);

@@ -1526,7 +1543,6 @@ __perf_counter_init_context(struct perf_counter_context *ctx,

static struct perf_counter_context *find_get_context(pid_t pid, int cpu)
{
	struct perf_counter_context *parent_ctx;
	struct perf_counter_context *ctx;
	struct perf_cpu_context *cpuctx;
	struct task_struct *task;
@@ -1586,11 +1602,7 @@ static struct perf_counter_context *find_get_context(pid_t pid, int cpu)
 retry:
	ctx = perf_lock_task_context(task, &flags);
	if (ctx) {
		parent_ctx = ctx->parent_ctx;
		if (parent_ctx) {
			put_ctx(parent_ctx);
			ctx->parent_ctx = NULL;		/* no longer a clone */
		}
		unclone_ctx(ctx);
		spin_unlock_irqrestore(&ctx->lock, flags);
	}

@@ -1704,7 +1716,7 @@ perf_read_hw(struct perf_counter *counter, char __user *buf, size_t count)
		values[n++] = counter->total_time_running +
			atomic64_read(&counter->child_total_time_running);
	if (counter->attr.read_format & PERF_FORMAT_ID)
		values[n++] = counter->id;
		values[n++] = primary_counter_id(counter);
	mutex_unlock(&counter->child_mutex);

	if (count < n * sizeof(u64))
@@ -1811,8 +1823,6 @@ static int perf_counter_period(struct perf_counter *counter, u64 __user *arg)

		counter->attr.sample_freq = value;
	} else {
		perf_log_period(counter, value);

		counter->attr.sample_period = value;
		counter->hw.sample_period = value;
	}
@@ -2661,6 +2671,9 @@ static void perf_counter_output(struct perf_counter *counter, int nmi,
	if (sample_type & PERF_SAMPLE_ID)
		header.size += sizeof(u64);

	if (sample_type & PERF_SAMPLE_STREAM_ID)
		header.size += sizeof(u64);

	if (sample_type & PERF_SAMPLE_CPU) {
		header.size += sizeof(cpu_entry);

@@ -2704,7 +2717,13 @@ static void perf_counter_output(struct perf_counter *counter, int nmi,
	if (sample_type & PERF_SAMPLE_ADDR)
		perf_output_put(&handle, data->addr);

	if (sample_type & PERF_SAMPLE_ID)
	if (sample_type & PERF_SAMPLE_ID) {
		u64 id = primary_counter_id(counter);

		perf_output_put(&handle, id);
	}

	if (sample_type & PERF_SAMPLE_STREAM_ID)
		perf_output_put(&handle, counter->id);

	if (sample_type & PERF_SAMPLE_CPU)
@@ -2727,7 +2746,7 @@ static void perf_counter_output(struct perf_counter *counter, int nmi,
			if (sub != counter)
				sub->pmu->read(sub);

			group_entry.id = sub->id;
			group_entry.id = primary_counter_id(sub);
			group_entry.counter = atomic64_read(&sub->count);

			perf_output_put(&handle, group_entry);
@@ -2787,15 +2806,8 @@ perf_counter_read_event(struct perf_counter *counter,
	}

	if (counter->attr.read_format & PERF_FORMAT_ID) {
		u64 id;

		event.header.size += sizeof(u64);
		if (counter->parent)
			id = counter->parent->id;
		else
			id = counter->id;

		event.format[i++] = id;
		event.format[i++] = primary_counter_id(counter);
	}

	ret = perf_output_begin(&handle, counter, event.header.size, 0, 0);
@@ -2896,8 +2908,11 @@ void perf_counter_fork(struct task_struct *task)
		.event  = {
			.header = {
				.type = PERF_EVENT_FORK,
				.misc = 0,
				.size = sizeof(fork_event.event),
			},
			/* .pid  */
			/* .ppid */
		},
	};

@@ -2969,8 +2984,10 @@ static void perf_counter_comm_event(struct perf_comm_event *comm_event)
	struct perf_cpu_context *cpuctx;
	struct perf_counter_context *ctx;
	unsigned int size;
	char *comm = comm_event->task->comm;
	char comm[TASK_COMM_LEN];

	memset(comm, 0, sizeof(comm));
	strncpy(comm, comm_event->task->comm, sizeof(comm));
	size = ALIGN(strlen(comm)+1, sizeof(u64));

	comm_event->comm = comm;
@@ -3005,8 +3022,16 @@ void perf_counter_comm(struct task_struct *task)

	comm_event = (struct perf_comm_event){
		.task	= task,
		/* .comm      */
		/* .comm_size */
		.event  = {
			.header = { .type = PERF_EVENT_COMM, },
			.header = {
				.type = PERF_EVENT_COMM,
				.misc = 0,
				/* .size */
			},
			/* .pid */
			/* .tid */
		},
	};

@@ -3089,8 +3114,15 @@ static void perf_counter_mmap_event(struct perf_mmap_event *mmap_event)
	char *buf = NULL;
	const char *name;

	memset(tmp, 0, sizeof(tmp));

	if (file) {
		buf = kzalloc(PATH_MAX, GFP_KERNEL);
		/*
		 * d_path works from the end of the buffer backwards, so we
		 * need to add enough zero bytes after the string to handle
		 * the 64bit alignment we do later.
		 */
		buf = kzalloc(PATH_MAX + sizeof(u64), GFP_KERNEL);
		if (!buf) {
			name = strncpy(tmp, "//enomem", sizeof(tmp));
			goto got_name;
@@ -3101,9 +3133,11 @@ static void perf_counter_mmap_event(struct perf_mmap_event *mmap_event)
			goto got_name;
		}
	} else {
		name = arch_vma_name(mmap_event->vma);
		if (name)
		if (arch_vma_name(mmap_event->vma)) {
			name = strncpy(tmp, arch_vma_name(mmap_event->vma),
				       sizeof(tmp));
			goto got_name;
		}

		if (!vma->vm_mm) {
			name = strncpy(tmp, "[vdso]", sizeof(tmp));
@@ -3148,8 +3182,16 @@ void __perf_counter_mmap(struct vm_area_struct *vma)

	mmap_event = (struct perf_mmap_event){
		.vma	= vma,
		/* .file_name */
		/* .file_size */
		.event  = {
			.header = { .type = PERF_EVENT_MMAP, },
			.header = {
				.type = PERF_EVENT_MMAP,
				.misc = 0,
				/* .size */
			},
			/* .pid */
			/* .tid */
			.start  = vma->vm_start,
			.len    = vma->vm_end - vma->vm_start,
			.pgoff  = vma->vm_pgoff,
@@ -3159,49 +3201,6 @@ void __perf_counter_mmap(struct vm_area_struct *vma)
	perf_counter_mmap_event(&mmap_event);
}

/*
 * Log sample_period changes so that analyzing tools can re-normalize the
 * event flow.
 */

struct freq_event {
	struct perf_event_header	header;
	u64				time;
	u64				id;
	u64				period;
};

static void perf_log_period(struct perf_counter *counter, u64 period)
{
	struct perf_output_handle handle;
	struct freq_event event;
	int ret;

	if (counter->hw.sample_period == period)
		return;

	if (counter->attr.sample_type & PERF_SAMPLE_PERIOD)
		return;

	event = (struct freq_event) {
		.header = {
			.type = PERF_EVENT_PERIOD,
			.misc = 0,
			.size = sizeof(event),
		},
		.time = sched_clock(),
		.id = counter->id,
		.period = period,
	};

	ret = perf_output_begin(&handle, counter, sizeof(event), 1, 0);
	if (ret)
		return;

	perf_output_put(&handle, event);
	perf_output_end(&handle);
}

/*
 * IRQ throttle logging
 */
@@ -3215,16 +3214,21 @@ static void perf_log_throttle(struct perf_counter *counter, int enable)
		struct perf_event_header	header;
		u64				time;
		u64				id;
		u64				stream_id;
	} throttle_event = {
		.header = {
			.type = PERF_EVENT_THROTTLE + 1,
			.type = PERF_EVENT_THROTTLE,
			.misc = 0,
			.size = sizeof(throttle_event),
		},
		.time		= sched_clock(),
		.id	= counter->id,
		.id		= primary_counter_id(counter),
		.stream_id	= counter->id,
	};

	if (enable)
		throttle_event.header.type = PERF_EVENT_UNTHROTTLE;

	ret = perf_output_begin(&handle, counter, sizeof(throttle_event), 1, 0);
	if (ret)
		return;
@@ -3672,7 +3676,7 @@ static const struct pmu perf_ops_task_clock = {
void perf_tpcounter_event(int event_id)
{
	struct perf_sample_data data = {
		.regs = get_irq_regs();
		.regs = get_irq_regs(),
		.addr = 0,
	};

@@ -3688,16 +3692,12 @@ extern void ftrace_profile_disable(int);

static void tp_perf_counter_destroy(struct perf_counter *counter)
{
	ftrace_profile_disable(perf_event_id(&counter->attr));
	ftrace_profile_disable(counter->attr.config);
}

static const struct pmu *tp_perf_counter_init(struct perf_counter *counter)
{
	int event_id = perf_event_id(&counter->attr);
	int ret;

	ret = ftrace_profile_enable(event_id);
	if (ret)
	if (ftrace_profile_enable(counter->attr.config))
		return NULL;

	counter->destroy = tp_perf_counter_destroy;
@@ -4256,15 +4256,12 @@ void perf_counter_exit_task(struct task_struct *child)
	 */
	spin_lock(&child_ctx->lock);
	child->perf_counter_ctxp = NULL;
	if (child_ctx->parent_ctx) {
	/*
		 * This context is a clone; unclone it so it can't get
	 * If this context is a clone; unclone it so it can't get
	 * swapped to another process while we're removing all
	 * the counters from it.
	 */
		put_ctx(child_ctx->parent_ctx);
		child_ctx->parent_ctx = NULL;
	}
	unclone_ctx(child_ctx);
	spin_unlock(&child_ctx->lock);
	local_irq_restore(flags);

Loading