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

Commit d2113df1 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "perf: Add support for exclude_idle attribute"

parents 2d546ee2 573979de
Loading
Loading
Loading
Loading
+62 −3
Original line number Diff line number Diff line
@@ -232,6 +232,11 @@ static const unsigned armv8_a57_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
#define	ARMV8_EXCLUDE_EL0	(1 << 30)
#define	ARMV8_INCLUDE_EL2	(1 << 27)

struct arm_pmu_and_idle_nb {
	struct arm_pmu *cpu_pmu;
	struct notifier_block perf_cpu_idle_nb;
};

static inline u32 armv8pmu_pmcr_read(void)
{
	u32 val;
@@ -541,8 +546,6 @@ static int armv8pmu_set_event_filter(struct hw_perf_event *event,
{
	unsigned long config_base = 0;

	if (attr->exclude_idle)
		return -EPERM;
	if (attr->exclude_user)
		config_base |= ARMV8_EXCLUDE_EL0;
	if (attr->exclude_kernel)
@@ -575,6 +578,33 @@ static inline void armv8pmu_init_usermode(void)
}
#endif


static void armv8pmu_idle_update(struct arm_pmu *cpu_pmu)
{
	struct pmu_hw_events *hw_events;
	struct perf_event *event;
	int idx;

	if (!cpu_pmu)
		return;

	hw_events = this_cpu_ptr(cpu_pmu->hw_events);

	for (idx = 0; idx < cpu_pmu->num_events; ++idx) {

		if (!test_bit(idx, hw_events->used_mask))
			continue;

		event = hw_events->events[idx];

		if (!event || !event->attr.exclude_idle ||
				event->state != PERF_EVENT_STATE_ACTIVE)
			continue;

		cpu_pmu->pmu.read(event);
	}
}

static void armv8pmu_reset(void *info)
{
	struct arm_pmu *cpu_pmu = (struct arm_pmu *)info;
@@ -624,11 +654,40 @@ static void armv8pmu_read_num_pmnc_events(void *info)
	*nb_cnt += 1;
}

static int perf_cpu_idle_notifier(struct notifier_block *nb,
				unsigned long action, void *data)
{
	struct arm_pmu_and_idle_nb *pmu_nb = container_of(nb,
				struct arm_pmu_and_idle_nb, perf_cpu_idle_nb);

	if (action == IDLE_START)
		armv8pmu_idle_update(pmu_nb->cpu_pmu);

	return NOTIFY_OK;
}

int armv8pmu_probe_num_events(struct arm_pmu *arm_pmu)
{
	return smp_call_function_any(&arm_pmu->supported_cpus,
	int ret;
	struct arm_pmu_and_idle_nb *pmu_idle_nb;

	pmu_idle_nb = devm_kzalloc(&arm_pmu->plat_device->dev,
					sizeof(*pmu_idle_nb), GFP_KERNEL);
	if (!pmu_idle_nb)
		return -ENOMEM;

	pmu_idle_nb->cpu_pmu = arm_pmu;
	pmu_idle_nb->perf_cpu_idle_nb.notifier_call = perf_cpu_idle_notifier;
	idle_notifier_register(&pmu_idle_nb->perf_cpu_idle_nb);

	ret = smp_call_function_any(&arm_pmu->supported_cpus,
				    armv8pmu_read_num_pmnc_events,
				    &arm_pmu->num_events, 1);
	if (!ret)
		idle_notifier_unregister(&pmu_idle_nb->perf_cpu_idle_nb);
	return ret;


}

void armv8_pmu_init(struct arm_pmu *cpu_pmu)
+27 −3
Original line number Diff line number Diff line
@@ -158,6 +158,7 @@ enum event_type_t {
struct static_key_deferred perf_sched_events __read_mostly;
static DEFINE_PER_CPU(atomic_t, perf_cgroup_events);
static DEFINE_PER_CPU(int, perf_sched_cb_usages);
static DEFINE_PER_CPU(bool, is_idle);

static atomic_t nr_mmap_events __read_mostly;
static atomic_t nr_comm_events __read_mostly;
@@ -3388,9 +3389,12 @@ static int perf_event_read(struct perf_event *event, bool group)
			.group = group,
			.ret = 0,
		};
		if (!event->attr.exclude_idle ||
					!per_cpu(is_idle, event->oncpu)) {
			smp_call_function_single(event->oncpu,
				__perf_event_read, &data, 1);
			ret = data.ret;
		}
	} else if (event->state == PERF_EVENT_STATE_INACTIVE) {
		struct perf_event_context *ctx = event->ctx;
		unsigned long flags;
@@ -9479,6 +9483,25 @@ perf_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu)
	return NOTIFY_OK;
}

static int event_idle_notif(struct notifier_block *nb, unsigned long action,
							void *data)
{
	switch (action) {
	case IDLE_START:
		__this_cpu_write(is_idle, true);
		break;
	case IDLE_END:
		__this_cpu_write(is_idle, false);
		break;
	}

	return NOTIFY_OK;
}

static struct notifier_block perf_event_idle_nb = {
	.notifier_call = event_idle_notif,
};

void __init perf_event_init(void)
{
	int ret;
@@ -9492,6 +9515,7 @@ void __init perf_event_init(void)
	perf_pmu_register(&perf_task_clock, NULL, -1);
	perf_tp_register();
	perf_cpu_notifier(perf_cpu_notify);
	idle_notifier_register(&perf_event_idle_nb);
	register_reboot_notifier(&perf_reboot_notifier);

	ret = init_hw_breakpoint();