Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 147316
b: refs/heads/master
c: 4e935e4
h: refs/heads/master
v: v3
  • Loading branch information
Peter Zijlstra authored and Ingo Molnar committed Apr 6, 2009
1 parent bf7c339 commit bfdc3e8
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 1 deletion.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: d7d59fb323833682b117b528d77eeb8ef587036a
refs/heads/master: 4e935e47177c3b26cf383e79849bae2a464d0160
75 changes: 75 additions & 0 deletions trunk/arch/x86/kernel/cpu/perf_counter.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

#include <asm/apic.h>
#include <asm/stacktrace.h>
#include <asm/nmi.h>

static bool perf_counters_initialized __read_mostly;

Expand Down Expand Up @@ -172,17 +173,89 @@ x86_perf_counter_update(struct perf_counter *counter,
atomic64_sub(delta, &hwc->period_left);
}

static atomic_t num_counters;
static DEFINE_MUTEX(pmc_reserve_mutex);

static bool reserve_pmc_hardware(void)
{
int i;

if (nmi_watchdog == NMI_LOCAL_APIC)
disable_lapic_nmi_watchdog();

for (i = 0; i < nr_counters_generic; i++) {
if (!reserve_perfctr_nmi(pmc_ops->perfctr + i))
goto perfctr_fail;
}

for (i = 0; i < nr_counters_generic; i++) {
if (!reserve_evntsel_nmi(pmc_ops->eventsel + i))
goto eventsel_fail;
}

return true;

eventsel_fail:
for (i--; i >= 0; i--)
release_evntsel_nmi(pmc_ops->eventsel + i);

i = nr_counters_generic;

perfctr_fail:
for (i--; i >= 0; i--)
release_perfctr_nmi(pmc_ops->perfctr + i);

if (nmi_watchdog == NMI_LOCAL_APIC)
enable_lapic_nmi_watchdog();

return false;
}

static void release_pmc_hardware(void)
{
int i;

for (i = 0; i < nr_counters_generic; i++) {
release_perfctr_nmi(pmc_ops->perfctr + i);
release_evntsel_nmi(pmc_ops->eventsel + i);
}

if (nmi_watchdog == NMI_LOCAL_APIC)
enable_lapic_nmi_watchdog();
}

static void hw_perf_counter_destroy(struct perf_counter *counter)
{
if (atomic_dec_and_mutex_lock(&num_counters, &pmc_reserve_mutex)) {
release_pmc_hardware();
mutex_unlock(&pmc_reserve_mutex);
}
}

/*
* Setup the hardware configuration for a given hw_event_type
*/
static int __hw_perf_counter_init(struct perf_counter *counter)
{
struct perf_counter_hw_event *hw_event = &counter->hw_event;
struct hw_perf_counter *hwc = &counter->hw;
int err;

if (unlikely(!perf_counters_initialized))
return -EINVAL;

err = 0;
if (atomic_inc_not_zero(&num_counters)) {
mutex_lock(&pmc_reserve_mutex);
if (atomic_read(&num_counters) == 0 && !reserve_pmc_hardware())
err = -EBUSY;
else
atomic_inc(&num_counters);
mutex_unlock(&pmc_reserve_mutex);
}
if (err)
return err;

/*
* Generate PMC IRQs:
* (keep 'enabled' bit clear for now)
Expand Down Expand Up @@ -230,6 +303,8 @@ static int __hw_perf_counter_init(struct perf_counter *counter)
hwc->config |= pmc_ops->event_map(perf_event_id(hw_event));
}

counter->destroy = hw_perf_counter_destroy;

return 0;
}

Expand Down

0 comments on commit bfdc3e8

Please sign in to comment.