diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/perf_counter.c | 46 |
1 files changed, 29 insertions, 17 deletions
diff --git a/kernel/perf_counter.c b/kernel/perf_counter.c index 4dc8600d2825..321c57e3556f 100644 --- a/kernel/perf_counter.c +++ b/kernel/perf_counter.c | |||
@@ -800,7 +800,7 @@ void perf_counter_task_sched_out(struct task_struct *task, int cpu) | |||
800 | update_context_time(ctx); | 800 | update_context_time(ctx); |
801 | 801 | ||
802 | regs = task_pt_regs(task); | 802 | regs = task_pt_regs(task); |
803 | perf_swcounter_event(PERF_COUNT_CONTEXT_SWITCHES, 1, 1, regs); | 803 | perf_swcounter_event(PERF_COUNT_CONTEXT_SWITCHES, 1, 1, regs, 0); |
804 | __perf_counter_sched_out(ctx, cpuctx); | 804 | __perf_counter_sched_out(ctx, cpuctx); |
805 | 805 | ||
806 | cpuctx->task_ctx = NULL; | 806 | cpuctx->task_ctx = NULL; |
@@ -1810,7 +1810,7 @@ static void perf_output_end(struct perf_output_handle *handle) | |||
1810 | } | 1810 | } |
1811 | 1811 | ||
1812 | static void perf_counter_output(struct perf_counter *counter, | 1812 | static void perf_counter_output(struct perf_counter *counter, |
1813 | int nmi, struct pt_regs *regs) | 1813 | int nmi, struct pt_regs *regs, u64 addr) |
1814 | { | 1814 | { |
1815 | int ret; | 1815 | int ret; |
1816 | u64 record_type = counter->hw_event.record_type; | 1816 | u64 record_type = counter->hw_event.record_type; |
@@ -1860,6 +1860,11 @@ static void perf_counter_output(struct perf_counter *counter, | |||
1860 | header.size += sizeof(u64); | 1860 | header.size += sizeof(u64); |
1861 | } | 1861 | } |
1862 | 1862 | ||
1863 | if (record_type & PERF_RECORD_ADDR) { | ||
1864 | header.type |= PERF_RECORD_ADDR; | ||
1865 | header.size += sizeof(u64); | ||
1866 | } | ||
1867 | |||
1863 | if (record_type & PERF_RECORD_GROUP) { | 1868 | if (record_type & PERF_RECORD_GROUP) { |
1864 | header.type |= PERF_RECORD_GROUP; | 1869 | header.type |= PERF_RECORD_GROUP; |
1865 | header.size += sizeof(u64) + | 1870 | header.size += sizeof(u64) + |
@@ -1892,6 +1897,9 @@ static void perf_counter_output(struct perf_counter *counter, | |||
1892 | if (record_type & PERF_RECORD_TIME) | 1897 | if (record_type & PERF_RECORD_TIME) |
1893 | perf_output_put(&handle, time); | 1898 | perf_output_put(&handle, time); |
1894 | 1899 | ||
1900 | if (record_type & PERF_RECORD_ADDR) | ||
1901 | perf_output_put(&handle, addr); | ||
1902 | |||
1895 | if (record_type & PERF_RECORD_GROUP) { | 1903 | if (record_type & PERF_RECORD_GROUP) { |
1896 | struct perf_counter *leader, *sub; | 1904 | struct perf_counter *leader, *sub; |
1897 | u64 nr = counter->nr_siblings; | 1905 | u64 nr = counter->nr_siblings; |
@@ -2158,7 +2166,7 @@ void perf_counter_munmap(unsigned long addr, unsigned long len, | |||
2158 | */ | 2166 | */ |
2159 | 2167 | ||
2160 | int perf_counter_overflow(struct perf_counter *counter, | 2168 | int perf_counter_overflow(struct perf_counter *counter, |
2161 | int nmi, struct pt_regs *regs) | 2169 | int nmi, struct pt_regs *regs, u64 addr) |
2162 | { | 2170 | { |
2163 | int events = atomic_read(&counter->event_limit); | 2171 | int events = atomic_read(&counter->event_limit); |
2164 | int ret = 0; | 2172 | int ret = 0; |
@@ -2175,7 +2183,7 @@ int perf_counter_overflow(struct perf_counter *counter, | |||
2175 | perf_counter_disable(counter); | 2183 | perf_counter_disable(counter); |
2176 | } | 2184 | } |
2177 | 2185 | ||
2178 | perf_counter_output(counter, nmi, regs); | 2186 | perf_counter_output(counter, nmi, regs, addr); |
2179 | return ret; | 2187 | return ret; |
2180 | } | 2188 | } |
2181 | 2189 | ||
@@ -2240,7 +2248,7 @@ static enum hrtimer_restart perf_swcounter_hrtimer(struct hrtimer *hrtimer) | |||
2240 | regs = task_pt_regs(current); | 2248 | regs = task_pt_regs(current); |
2241 | 2249 | ||
2242 | if (regs) { | 2250 | if (regs) { |
2243 | if (perf_counter_overflow(counter, 0, regs)) | 2251 | if (perf_counter_overflow(counter, 0, regs, 0)) |
2244 | ret = HRTIMER_NORESTART; | 2252 | ret = HRTIMER_NORESTART; |
2245 | } | 2253 | } |
2246 | 2254 | ||
@@ -2250,11 +2258,11 @@ static enum hrtimer_restart perf_swcounter_hrtimer(struct hrtimer *hrtimer) | |||
2250 | } | 2258 | } |
2251 | 2259 | ||
2252 | static void perf_swcounter_overflow(struct perf_counter *counter, | 2260 | static void perf_swcounter_overflow(struct perf_counter *counter, |
2253 | int nmi, struct pt_regs *regs) | 2261 | int nmi, struct pt_regs *regs, u64 addr) |
2254 | { | 2262 | { |
2255 | perf_swcounter_update(counter); | 2263 | perf_swcounter_update(counter); |
2256 | perf_swcounter_set_period(counter); | 2264 | perf_swcounter_set_period(counter); |
2257 | if (perf_counter_overflow(counter, nmi, regs)) | 2265 | if (perf_counter_overflow(counter, nmi, regs, addr)) |
2258 | /* soft-disable the counter */ | 2266 | /* soft-disable the counter */ |
2259 | ; | 2267 | ; |
2260 | 2268 | ||
@@ -2286,16 +2294,17 @@ static int perf_swcounter_match(struct perf_counter *counter, | |||
2286 | } | 2294 | } |
2287 | 2295 | ||
2288 | static void perf_swcounter_add(struct perf_counter *counter, u64 nr, | 2296 | static void perf_swcounter_add(struct perf_counter *counter, u64 nr, |
2289 | int nmi, struct pt_regs *regs) | 2297 | int nmi, struct pt_regs *regs, u64 addr) |
2290 | { | 2298 | { |
2291 | int neg = atomic64_add_negative(nr, &counter->hw.count); | 2299 | int neg = atomic64_add_negative(nr, &counter->hw.count); |
2292 | if (counter->hw.irq_period && !neg) | 2300 | if (counter->hw.irq_period && !neg) |
2293 | perf_swcounter_overflow(counter, nmi, regs); | 2301 | perf_swcounter_overflow(counter, nmi, regs, addr); |
2294 | } | 2302 | } |
2295 | 2303 | ||
2296 | static void perf_swcounter_ctx_event(struct perf_counter_context *ctx, | 2304 | static void perf_swcounter_ctx_event(struct perf_counter_context *ctx, |
2297 | enum perf_event_types type, u32 event, | 2305 | enum perf_event_types type, u32 event, |
2298 | u64 nr, int nmi, struct pt_regs *regs) | 2306 | u64 nr, int nmi, struct pt_regs *regs, |
2307 | u64 addr) | ||
2299 | { | 2308 | { |
2300 | struct perf_counter *counter; | 2309 | struct perf_counter *counter; |
2301 | 2310 | ||
@@ -2305,7 +2314,7 @@ static void perf_swcounter_ctx_event(struct perf_counter_context *ctx, | |||
2305 | rcu_read_lock(); | 2314 | rcu_read_lock(); |
2306 | list_for_each_entry_rcu(counter, &ctx->event_list, event_entry) { | 2315 | list_for_each_entry_rcu(counter, &ctx->event_list, event_entry) { |
2307 | if (perf_swcounter_match(counter, type, event, regs)) | 2316 | if (perf_swcounter_match(counter, type, event, regs)) |
2308 | perf_swcounter_add(counter, nr, nmi, regs); | 2317 | perf_swcounter_add(counter, nr, nmi, regs, addr); |
2309 | } | 2318 | } |
2310 | rcu_read_unlock(); | 2319 | rcu_read_unlock(); |
2311 | } | 2320 | } |
@@ -2325,7 +2334,8 @@ static int *perf_swcounter_recursion_context(struct perf_cpu_context *cpuctx) | |||
2325 | } | 2334 | } |
2326 | 2335 | ||
2327 | static void __perf_swcounter_event(enum perf_event_types type, u32 event, | 2336 | static void __perf_swcounter_event(enum perf_event_types type, u32 event, |
2328 | u64 nr, int nmi, struct pt_regs *regs) | 2337 | u64 nr, int nmi, struct pt_regs *regs, |
2338 | u64 addr) | ||
2329 | { | 2339 | { |
2330 | struct perf_cpu_context *cpuctx = &get_cpu_var(perf_cpu_context); | 2340 | struct perf_cpu_context *cpuctx = &get_cpu_var(perf_cpu_context); |
2331 | int *recursion = perf_swcounter_recursion_context(cpuctx); | 2341 | int *recursion = perf_swcounter_recursion_context(cpuctx); |
@@ -2336,10 +2346,11 @@ static void __perf_swcounter_event(enum perf_event_types type, u32 event, | |||
2336 | (*recursion)++; | 2346 | (*recursion)++; |
2337 | barrier(); | 2347 | barrier(); |
2338 | 2348 | ||
2339 | perf_swcounter_ctx_event(&cpuctx->ctx, type, event, nr, nmi, regs); | 2349 | perf_swcounter_ctx_event(&cpuctx->ctx, type, event, |
2350 | nr, nmi, regs, addr); | ||
2340 | if (cpuctx->task_ctx) { | 2351 | if (cpuctx->task_ctx) { |
2341 | perf_swcounter_ctx_event(cpuctx->task_ctx, type, event, | 2352 | perf_swcounter_ctx_event(cpuctx->task_ctx, type, event, |
2342 | nr, nmi, regs); | 2353 | nr, nmi, regs, addr); |
2343 | } | 2354 | } |
2344 | 2355 | ||
2345 | barrier(); | 2356 | barrier(); |
@@ -2349,9 +2360,10 @@ out: | |||
2349 | put_cpu_var(perf_cpu_context); | 2360 | put_cpu_var(perf_cpu_context); |
2350 | } | 2361 | } |
2351 | 2362 | ||
2352 | void perf_swcounter_event(u32 event, u64 nr, int nmi, struct pt_regs *regs) | 2363 | void |
2364 | perf_swcounter_event(u32 event, u64 nr, int nmi, struct pt_regs *regs, u64 addr) | ||
2353 | { | 2365 | { |
2354 | __perf_swcounter_event(PERF_TYPE_SOFTWARE, event, nr, nmi, regs); | 2366 | __perf_swcounter_event(PERF_TYPE_SOFTWARE, event, nr, nmi, regs, addr); |
2355 | } | 2367 | } |
2356 | 2368 | ||
2357 | static void perf_swcounter_read(struct perf_counter *counter) | 2369 | static void perf_swcounter_read(struct perf_counter *counter) |
@@ -2548,7 +2560,7 @@ void perf_tpcounter_event(int event_id) | |||
2548 | if (!regs) | 2560 | if (!regs) |
2549 | regs = task_pt_regs(current); | 2561 | regs = task_pt_regs(current); |
2550 | 2562 | ||
2551 | __perf_swcounter_event(PERF_TYPE_TRACEPOINT, event_id, 1, 1, regs); | 2563 | __perf_swcounter_event(PERF_TYPE_TRACEPOINT, event_id, 1, 1, regs, 0); |
2552 | } | 2564 | } |
2553 | 2565 | ||
2554 | extern int ftrace_profile_enable(int); | 2566 | extern int ftrace_profile_enable(int); |