18c2ecf20Sopenharmony_ci/** 28c2ecf20Sopenharmony_ci * @file cpu_buffer.c 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * @remark Copyright 2002-2009 OProfile authors 58c2ecf20Sopenharmony_ci * @remark Read the file COPYING 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * @author John Levon <levon@movementarian.org> 88c2ecf20Sopenharmony_ci * @author Barry Kasindorf <barry.kasindorf@amd.com> 98c2ecf20Sopenharmony_ci * @author Robert Richter <robert.richter@amd.com> 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Each CPU has a local buffer that stores PC value/event 128c2ecf20Sopenharmony_ci * pairs. We also log context switches when we notice them. 138c2ecf20Sopenharmony_ci * Eventually each CPU's buffer is processed into the global 148c2ecf20Sopenharmony_ci * event buffer by sync_buffer(). 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * We use a local buffer for two reasons: an NMI or similar 178c2ecf20Sopenharmony_ci * interrupt cannot synchronise, and high sampling rates 188c2ecf20Sopenharmony_ci * would lead to catastrophic global synchronisation if 198c2ecf20Sopenharmony_ci * a global buffer was used. 208c2ecf20Sopenharmony_ci */ 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include <linux/sched.h> 238c2ecf20Sopenharmony_ci#include <linux/oprofile.h> 248c2ecf20Sopenharmony_ci#include <linux/errno.h> 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#include <asm/ptrace.h> 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#include "event_buffer.h" 298c2ecf20Sopenharmony_ci#include "cpu_buffer.h" 308c2ecf20Sopenharmony_ci#include "buffer_sync.h" 318c2ecf20Sopenharmony_ci#include "oprof.h" 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#define OP_BUFFER_FLAGS 0 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistatic struct trace_buffer *op_ring_buffer; 368c2ecf20Sopenharmony_ciDEFINE_PER_CPU(struct oprofile_cpu_buffer, op_cpu_buffer); 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistatic void wq_sync_buffer(struct work_struct *work); 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci#define DEFAULT_TIMER_EXPIRE (HZ / 10) 418c2ecf20Sopenharmony_cistatic int work_enabled; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ciunsigned long oprofile_get_cpu_buffer_size(void) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci return oprofile_cpu_buffer_size; 468c2ecf20Sopenharmony_ci} 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_civoid oprofile_cpu_buffer_inc_smpl_lost(void) 498c2ecf20Sopenharmony_ci{ 508c2ecf20Sopenharmony_ci struct oprofile_cpu_buffer *cpu_buf = this_cpu_ptr(&op_cpu_buffer); 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci cpu_buf->sample_lost_overflow++; 538c2ecf20Sopenharmony_ci} 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_civoid free_cpu_buffers(void) 568c2ecf20Sopenharmony_ci{ 578c2ecf20Sopenharmony_ci if (op_ring_buffer) 588c2ecf20Sopenharmony_ci ring_buffer_free(op_ring_buffer); 598c2ecf20Sopenharmony_ci op_ring_buffer = NULL; 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci#define RB_EVENT_HDR_SIZE 4 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ciint alloc_cpu_buffers(void) 658c2ecf20Sopenharmony_ci{ 668c2ecf20Sopenharmony_ci int i; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci unsigned long buffer_size = oprofile_cpu_buffer_size; 698c2ecf20Sopenharmony_ci unsigned long byte_size = buffer_size * (sizeof(struct op_sample) + 708c2ecf20Sopenharmony_ci RB_EVENT_HDR_SIZE); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci op_ring_buffer = ring_buffer_alloc(byte_size, OP_BUFFER_FLAGS); 738c2ecf20Sopenharmony_ci if (!op_ring_buffer) 748c2ecf20Sopenharmony_ci goto fail; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci for_each_possible_cpu(i) { 778c2ecf20Sopenharmony_ci struct oprofile_cpu_buffer *b = &per_cpu(op_cpu_buffer, i); 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci b->last_task = NULL; 808c2ecf20Sopenharmony_ci b->last_is_kernel = -1; 818c2ecf20Sopenharmony_ci b->tracing = 0; 828c2ecf20Sopenharmony_ci b->buffer_size = buffer_size; 838c2ecf20Sopenharmony_ci b->sample_received = 0; 848c2ecf20Sopenharmony_ci b->sample_lost_overflow = 0; 858c2ecf20Sopenharmony_ci b->backtrace_aborted = 0; 868c2ecf20Sopenharmony_ci b->sample_invalid_eip = 0; 878c2ecf20Sopenharmony_ci b->cpu = i; 888c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&b->work, wq_sync_buffer); 898c2ecf20Sopenharmony_ci } 908c2ecf20Sopenharmony_ci return 0; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cifail: 938c2ecf20Sopenharmony_ci free_cpu_buffers(); 948c2ecf20Sopenharmony_ci return -ENOMEM; 958c2ecf20Sopenharmony_ci} 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_civoid start_cpu_work(void) 988c2ecf20Sopenharmony_ci{ 998c2ecf20Sopenharmony_ci int i; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci work_enabled = 1; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci for_each_online_cpu(i) { 1048c2ecf20Sopenharmony_ci struct oprofile_cpu_buffer *b = &per_cpu(op_cpu_buffer, i); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci /* 1078c2ecf20Sopenharmony_ci * Spread the work by 1 jiffy per cpu so they dont all 1088c2ecf20Sopenharmony_ci * fire at once. 1098c2ecf20Sopenharmony_ci */ 1108c2ecf20Sopenharmony_ci schedule_delayed_work_on(i, &b->work, DEFAULT_TIMER_EXPIRE + i); 1118c2ecf20Sopenharmony_ci } 1128c2ecf20Sopenharmony_ci} 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_civoid end_cpu_work(void) 1158c2ecf20Sopenharmony_ci{ 1168c2ecf20Sopenharmony_ci work_enabled = 0; 1178c2ecf20Sopenharmony_ci} 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_civoid flush_cpu_work(void) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci int i; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci for_each_online_cpu(i) { 1248c2ecf20Sopenharmony_ci struct oprofile_cpu_buffer *b = &per_cpu(op_cpu_buffer, i); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci /* these works are per-cpu, no need for flush_sync */ 1278c2ecf20Sopenharmony_ci flush_delayed_work(&b->work); 1288c2ecf20Sopenharmony_ci } 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci/* 1328c2ecf20Sopenharmony_ci * This function prepares the cpu buffer to write a sample. 1338c2ecf20Sopenharmony_ci * 1348c2ecf20Sopenharmony_ci * Struct op_entry is used during operations on the ring buffer while 1358c2ecf20Sopenharmony_ci * struct op_sample contains the data that is stored in the ring 1368c2ecf20Sopenharmony_ci * buffer. Struct entry can be uninitialized. The function reserves a 1378c2ecf20Sopenharmony_ci * data array that is specified by size. Use 1388c2ecf20Sopenharmony_ci * op_cpu_buffer_write_commit() after preparing the sample. In case of 1398c2ecf20Sopenharmony_ci * errors a null pointer is returned, otherwise the pointer to the 1408c2ecf20Sopenharmony_ci * sample. 1418c2ecf20Sopenharmony_ci * 1428c2ecf20Sopenharmony_ci */ 1438c2ecf20Sopenharmony_cistruct op_sample 1448c2ecf20Sopenharmony_ci*op_cpu_buffer_write_reserve(struct op_entry *entry, unsigned long size) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci entry->event = ring_buffer_lock_reserve 1478c2ecf20Sopenharmony_ci (op_ring_buffer, sizeof(struct op_sample) + 1488c2ecf20Sopenharmony_ci size * sizeof(entry->sample->data[0])); 1498c2ecf20Sopenharmony_ci if (!entry->event) 1508c2ecf20Sopenharmony_ci return NULL; 1518c2ecf20Sopenharmony_ci entry->sample = ring_buffer_event_data(entry->event); 1528c2ecf20Sopenharmony_ci entry->size = size; 1538c2ecf20Sopenharmony_ci entry->data = entry->sample->data; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci return entry->sample; 1568c2ecf20Sopenharmony_ci} 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ciint op_cpu_buffer_write_commit(struct op_entry *entry) 1598c2ecf20Sopenharmony_ci{ 1608c2ecf20Sopenharmony_ci return ring_buffer_unlock_commit(op_ring_buffer, entry->event); 1618c2ecf20Sopenharmony_ci} 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_cistruct op_sample *op_cpu_buffer_read_entry(struct op_entry *entry, int cpu) 1648c2ecf20Sopenharmony_ci{ 1658c2ecf20Sopenharmony_ci struct ring_buffer_event *e; 1668c2ecf20Sopenharmony_ci e = ring_buffer_consume(op_ring_buffer, cpu, NULL, NULL); 1678c2ecf20Sopenharmony_ci if (!e) 1688c2ecf20Sopenharmony_ci return NULL; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci entry->event = e; 1718c2ecf20Sopenharmony_ci entry->sample = ring_buffer_event_data(e); 1728c2ecf20Sopenharmony_ci entry->size = (ring_buffer_event_length(e) - sizeof(struct op_sample)) 1738c2ecf20Sopenharmony_ci / sizeof(entry->sample->data[0]); 1748c2ecf20Sopenharmony_ci entry->data = entry->sample->data; 1758c2ecf20Sopenharmony_ci return entry->sample; 1768c2ecf20Sopenharmony_ci} 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ciunsigned long op_cpu_buffer_entries(int cpu) 1798c2ecf20Sopenharmony_ci{ 1808c2ecf20Sopenharmony_ci return ring_buffer_entries_cpu(op_ring_buffer, cpu); 1818c2ecf20Sopenharmony_ci} 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_cistatic int 1848c2ecf20Sopenharmony_ciop_add_code(struct oprofile_cpu_buffer *cpu_buf, unsigned long backtrace, 1858c2ecf20Sopenharmony_ci int is_kernel, struct task_struct *task) 1868c2ecf20Sopenharmony_ci{ 1878c2ecf20Sopenharmony_ci struct op_entry entry; 1888c2ecf20Sopenharmony_ci struct op_sample *sample; 1898c2ecf20Sopenharmony_ci unsigned long flags; 1908c2ecf20Sopenharmony_ci int size; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci flags = 0; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci if (backtrace) 1958c2ecf20Sopenharmony_ci flags |= TRACE_BEGIN; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci /* notice a switch from user->kernel or vice versa */ 1988c2ecf20Sopenharmony_ci is_kernel = !!is_kernel; 1998c2ecf20Sopenharmony_ci if (cpu_buf->last_is_kernel != is_kernel) { 2008c2ecf20Sopenharmony_ci cpu_buf->last_is_kernel = is_kernel; 2018c2ecf20Sopenharmony_ci flags |= KERNEL_CTX_SWITCH; 2028c2ecf20Sopenharmony_ci if (is_kernel) 2038c2ecf20Sopenharmony_ci flags |= IS_KERNEL; 2048c2ecf20Sopenharmony_ci } 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci /* notice a task switch */ 2078c2ecf20Sopenharmony_ci if (cpu_buf->last_task != task) { 2088c2ecf20Sopenharmony_ci cpu_buf->last_task = task; 2098c2ecf20Sopenharmony_ci flags |= USER_CTX_SWITCH; 2108c2ecf20Sopenharmony_ci } 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci if (!flags) 2138c2ecf20Sopenharmony_ci /* nothing to do */ 2148c2ecf20Sopenharmony_ci return 0; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci if (flags & USER_CTX_SWITCH) 2178c2ecf20Sopenharmony_ci size = 1; 2188c2ecf20Sopenharmony_ci else 2198c2ecf20Sopenharmony_ci size = 0; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci sample = op_cpu_buffer_write_reserve(&entry, size); 2228c2ecf20Sopenharmony_ci if (!sample) 2238c2ecf20Sopenharmony_ci return -ENOMEM; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci sample->eip = ESCAPE_CODE; 2268c2ecf20Sopenharmony_ci sample->event = flags; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci if (size) 2298c2ecf20Sopenharmony_ci op_cpu_buffer_add_data(&entry, (unsigned long)task); 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci op_cpu_buffer_write_commit(&entry); 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci return 0; 2348c2ecf20Sopenharmony_ci} 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_cistatic inline int 2378c2ecf20Sopenharmony_ciop_add_sample(struct oprofile_cpu_buffer *cpu_buf, 2388c2ecf20Sopenharmony_ci unsigned long pc, unsigned long event) 2398c2ecf20Sopenharmony_ci{ 2408c2ecf20Sopenharmony_ci struct op_entry entry; 2418c2ecf20Sopenharmony_ci struct op_sample *sample; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci sample = op_cpu_buffer_write_reserve(&entry, 0); 2448c2ecf20Sopenharmony_ci if (!sample) 2458c2ecf20Sopenharmony_ci return -ENOMEM; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci sample->eip = pc; 2488c2ecf20Sopenharmony_ci sample->event = event; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci return op_cpu_buffer_write_commit(&entry); 2518c2ecf20Sopenharmony_ci} 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci/* 2548c2ecf20Sopenharmony_ci * This must be safe from any context. 2558c2ecf20Sopenharmony_ci * 2568c2ecf20Sopenharmony_ci * is_kernel is needed because on some architectures you cannot 2578c2ecf20Sopenharmony_ci * tell if you are in kernel or user space simply by looking at 2588c2ecf20Sopenharmony_ci * pc. We tag this in the buffer by generating kernel enter/exit 2598c2ecf20Sopenharmony_ci * events whenever is_kernel changes 2608c2ecf20Sopenharmony_ci */ 2618c2ecf20Sopenharmony_cistatic int 2628c2ecf20Sopenharmony_cilog_sample(struct oprofile_cpu_buffer *cpu_buf, unsigned long pc, 2638c2ecf20Sopenharmony_ci unsigned long backtrace, int is_kernel, unsigned long event, 2648c2ecf20Sopenharmony_ci struct task_struct *task) 2658c2ecf20Sopenharmony_ci{ 2668c2ecf20Sopenharmony_ci struct task_struct *tsk = task ? task : current; 2678c2ecf20Sopenharmony_ci cpu_buf->sample_received++; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci if (pc == ESCAPE_CODE) { 2708c2ecf20Sopenharmony_ci cpu_buf->sample_invalid_eip++; 2718c2ecf20Sopenharmony_ci return 0; 2728c2ecf20Sopenharmony_ci } 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci if (op_add_code(cpu_buf, backtrace, is_kernel, tsk)) 2758c2ecf20Sopenharmony_ci goto fail; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci if (op_add_sample(cpu_buf, pc, event)) 2788c2ecf20Sopenharmony_ci goto fail; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci return 1; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_cifail: 2838c2ecf20Sopenharmony_ci cpu_buf->sample_lost_overflow++; 2848c2ecf20Sopenharmony_ci return 0; 2858c2ecf20Sopenharmony_ci} 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_cistatic inline void oprofile_begin_trace(struct oprofile_cpu_buffer *cpu_buf) 2888c2ecf20Sopenharmony_ci{ 2898c2ecf20Sopenharmony_ci cpu_buf->tracing = 1; 2908c2ecf20Sopenharmony_ci} 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_cistatic inline void oprofile_end_trace(struct oprofile_cpu_buffer *cpu_buf) 2938c2ecf20Sopenharmony_ci{ 2948c2ecf20Sopenharmony_ci cpu_buf->tracing = 0; 2958c2ecf20Sopenharmony_ci} 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_cistatic inline void 2988c2ecf20Sopenharmony_ci__oprofile_add_ext_sample(unsigned long pc, struct pt_regs * const regs, 2998c2ecf20Sopenharmony_ci unsigned long event, int is_kernel, 3008c2ecf20Sopenharmony_ci struct task_struct *task) 3018c2ecf20Sopenharmony_ci{ 3028c2ecf20Sopenharmony_ci struct oprofile_cpu_buffer *cpu_buf = this_cpu_ptr(&op_cpu_buffer); 3038c2ecf20Sopenharmony_ci unsigned long backtrace = oprofile_backtrace_depth; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci /* 3068c2ecf20Sopenharmony_ci * if log_sample() fail we can't backtrace since we lost the 3078c2ecf20Sopenharmony_ci * source of this event 3088c2ecf20Sopenharmony_ci */ 3098c2ecf20Sopenharmony_ci if (!log_sample(cpu_buf, pc, backtrace, is_kernel, event, task)) 3108c2ecf20Sopenharmony_ci /* failed */ 3118c2ecf20Sopenharmony_ci return; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci if (!backtrace) 3148c2ecf20Sopenharmony_ci return; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci oprofile_begin_trace(cpu_buf); 3178c2ecf20Sopenharmony_ci oprofile_ops.backtrace(regs, backtrace); 3188c2ecf20Sopenharmony_ci oprofile_end_trace(cpu_buf); 3198c2ecf20Sopenharmony_ci} 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_civoid oprofile_add_ext_hw_sample(unsigned long pc, struct pt_regs * const regs, 3228c2ecf20Sopenharmony_ci unsigned long event, int is_kernel, 3238c2ecf20Sopenharmony_ci struct task_struct *task) 3248c2ecf20Sopenharmony_ci{ 3258c2ecf20Sopenharmony_ci __oprofile_add_ext_sample(pc, regs, event, is_kernel, task); 3268c2ecf20Sopenharmony_ci} 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_civoid oprofile_add_ext_sample(unsigned long pc, struct pt_regs * const regs, 3298c2ecf20Sopenharmony_ci unsigned long event, int is_kernel) 3308c2ecf20Sopenharmony_ci{ 3318c2ecf20Sopenharmony_ci __oprofile_add_ext_sample(pc, regs, event, is_kernel, NULL); 3328c2ecf20Sopenharmony_ci} 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_civoid oprofile_add_sample(struct pt_regs * const regs, unsigned long event) 3358c2ecf20Sopenharmony_ci{ 3368c2ecf20Sopenharmony_ci int is_kernel; 3378c2ecf20Sopenharmony_ci unsigned long pc; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci if (likely(regs)) { 3408c2ecf20Sopenharmony_ci is_kernel = !user_mode(regs); 3418c2ecf20Sopenharmony_ci pc = profile_pc(regs); 3428c2ecf20Sopenharmony_ci } else { 3438c2ecf20Sopenharmony_ci is_kernel = 0; /* This value will not be used */ 3448c2ecf20Sopenharmony_ci pc = ESCAPE_CODE; /* as this causes an early return. */ 3458c2ecf20Sopenharmony_ci } 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci __oprofile_add_ext_sample(pc, regs, event, is_kernel, NULL); 3488c2ecf20Sopenharmony_ci} 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci/* 3518c2ecf20Sopenharmony_ci * Add samples with data to the ring buffer. 3528c2ecf20Sopenharmony_ci * 3538c2ecf20Sopenharmony_ci * Use oprofile_add_data(&entry, val) to add data and 3548c2ecf20Sopenharmony_ci * oprofile_write_commit(&entry) to commit the sample. 3558c2ecf20Sopenharmony_ci */ 3568c2ecf20Sopenharmony_civoid 3578c2ecf20Sopenharmony_cioprofile_write_reserve(struct op_entry *entry, struct pt_regs * const regs, 3588c2ecf20Sopenharmony_ci unsigned long pc, int code, int size) 3598c2ecf20Sopenharmony_ci{ 3608c2ecf20Sopenharmony_ci struct op_sample *sample; 3618c2ecf20Sopenharmony_ci int is_kernel = !user_mode(regs); 3628c2ecf20Sopenharmony_ci struct oprofile_cpu_buffer *cpu_buf = this_cpu_ptr(&op_cpu_buffer); 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci cpu_buf->sample_received++; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci /* no backtraces for samples with data */ 3678c2ecf20Sopenharmony_ci if (op_add_code(cpu_buf, 0, is_kernel, current)) 3688c2ecf20Sopenharmony_ci goto fail; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci sample = op_cpu_buffer_write_reserve(entry, size + 2); 3718c2ecf20Sopenharmony_ci if (!sample) 3728c2ecf20Sopenharmony_ci goto fail; 3738c2ecf20Sopenharmony_ci sample->eip = ESCAPE_CODE; 3748c2ecf20Sopenharmony_ci sample->event = 0; /* no flags */ 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci op_cpu_buffer_add_data(entry, code); 3778c2ecf20Sopenharmony_ci op_cpu_buffer_add_data(entry, pc); 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci return; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_cifail: 3828c2ecf20Sopenharmony_ci entry->event = NULL; 3838c2ecf20Sopenharmony_ci cpu_buf->sample_lost_overflow++; 3848c2ecf20Sopenharmony_ci} 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ciint oprofile_add_data(struct op_entry *entry, unsigned long val) 3878c2ecf20Sopenharmony_ci{ 3888c2ecf20Sopenharmony_ci if (!entry->event) 3898c2ecf20Sopenharmony_ci return 0; 3908c2ecf20Sopenharmony_ci return op_cpu_buffer_add_data(entry, val); 3918c2ecf20Sopenharmony_ci} 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ciint oprofile_add_data64(struct op_entry *entry, u64 val) 3948c2ecf20Sopenharmony_ci{ 3958c2ecf20Sopenharmony_ci if (!entry->event) 3968c2ecf20Sopenharmony_ci return 0; 3978c2ecf20Sopenharmony_ci if (op_cpu_buffer_get_size(entry) < 2) 3988c2ecf20Sopenharmony_ci /* 3998c2ecf20Sopenharmony_ci * the function returns 0 to indicate a too small 4008c2ecf20Sopenharmony_ci * buffer, even if there is some space left 4018c2ecf20Sopenharmony_ci */ 4028c2ecf20Sopenharmony_ci return 0; 4038c2ecf20Sopenharmony_ci if (!op_cpu_buffer_add_data(entry, (u32)val)) 4048c2ecf20Sopenharmony_ci return 0; 4058c2ecf20Sopenharmony_ci return op_cpu_buffer_add_data(entry, (u32)(val >> 32)); 4068c2ecf20Sopenharmony_ci} 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ciint oprofile_write_commit(struct op_entry *entry) 4098c2ecf20Sopenharmony_ci{ 4108c2ecf20Sopenharmony_ci if (!entry->event) 4118c2ecf20Sopenharmony_ci return -EINVAL; 4128c2ecf20Sopenharmony_ci return op_cpu_buffer_write_commit(entry); 4138c2ecf20Sopenharmony_ci} 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_civoid oprofile_add_pc(unsigned long pc, int is_kernel, unsigned long event) 4168c2ecf20Sopenharmony_ci{ 4178c2ecf20Sopenharmony_ci struct oprofile_cpu_buffer *cpu_buf = this_cpu_ptr(&op_cpu_buffer); 4188c2ecf20Sopenharmony_ci log_sample(cpu_buf, pc, 0, is_kernel, event, NULL); 4198c2ecf20Sopenharmony_ci} 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_civoid oprofile_add_trace(unsigned long pc) 4228c2ecf20Sopenharmony_ci{ 4238c2ecf20Sopenharmony_ci struct oprofile_cpu_buffer *cpu_buf = this_cpu_ptr(&op_cpu_buffer); 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci if (!cpu_buf->tracing) 4268c2ecf20Sopenharmony_ci return; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci /* 4298c2ecf20Sopenharmony_ci * broken frame can give an eip with the same value as an 4308c2ecf20Sopenharmony_ci * escape code, abort the trace if we get it 4318c2ecf20Sopenharmony_ci */ 4328c2ecf20Sopenharmony_ci if (pc == ESCAPE_CODE) 4338c2ecf20Sopenharmony_ci goto fail; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci if (op_add_sample(cpu_buf, pc, 0)) 4368c2ecf20Sopenharmony_ci goto fail; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci return; 4398c2ecf20Sopenharmony_cifail: 4408c2ecf20Sopenharmony_ci cpu_buf->tracing = 0; 4418c2ecf20Sopenharmony_ci cpu_buf->backtrace_aborted++; 4428c2ecf20Sopenharmony_ci return; 4438c2ecf20Sopenharmony_ci} 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci/* 4468c2ecf20Sopenharmony_ci * This serves to avoid cpu buffer overflow, and makes sure 4478c2ecf20Sopenharmony_ci * the task mortuary progresses 4488c2ecf20Sopenharmony_ci * 4498c2ecf20Sopenharmony_ci * By using schedule_delayed_work_on and then schedule_delayed_work 4508c2ecf20Sopenharmony_ci * we guarantee this will stay on the correct cpu 4518c2ecf20Sopenharmony_ci */ 4528c2ecf20Sopenharmony_cistatic void wq_sync_buffer(struct work_struct *work) 4538c2ecf20Sopenharmony_ci{ 4548c2ecf20Sopenharmony_ci struct oprofile_cpu_buffer *b = 4558c2ecf20Sopenharmony_ci container_of(work, struct oprofile_cpu_buffer, work.work); 4568c2ecf20Sopenharmony_ci if (b->cpu != smp_processor_id() && !cpu_online(b->cpu)) { 4578c2ecf20Sopenharmony_ci cancel_delayed_work(&b->work); 4588c2ecf20Sopenharmony_ci return; 4598c2ecf20Sopenharmony_ci } 4608c2ecf20Sopenharmony_ci sync_buffer(b->cpu); 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci /* don't re-add the work if we're shutting down */ 4638c2ecf20Sopenharmony_ci if (work_enabled) 4648c2ecf20Sopenharmony_ci schedule_delayed_work(&b->work, DEFAULT_TIMER_EXPIRE); 4658c2ecf20Sopenharmony_ci} 466