/* * Add samples with data to the ring buffer. * * Use oprofile_add_data(&entry, val) to add data and * oprofile_write_commit(&entry) to commit the sample. */ void oprofile_write_reserve(struct op_entry *entry, struct pt_regs * const regs, unsigned long pc, int code, int size) { struct op_sample *sample; int is_kernel = !user_mode(regs); struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(op_cpu_buffer); cpu_buf->sample_received++; /* no backtraces for samples with data */ if (op_add_code(cpu_buf, 0, is_kernel, current)) goto fail; sample = op_cpu_buffer_write_reserve(entry, size + 2); if (!sample) goto fail; sample->eip = ESCAPE_CODE; sample->event = 0; /* no flags */ op_cpu_buffer_add_data(entry, code); op_cpu_buffer_add_data(entry, pc); return; fail: entry->event = NULL; cpu_buf->sample_lost_overflow++; }
int oprofile_add_data64(struct op_entry *entry, u64 val) { if (!entry->event) return 0; if (op_cpu_buffer_get_size(entry) < 2) return 0; if (!op_cpu_buffer_add_data(entry, (u32)val)) return 0; return op_cpu_buffer_add_data(entry, (u32)(val >> 32)); }
static int op_add_code(struct oprofile_cpu_buffer *cpu_buf, unsigned long backtrace, int is_kernel, struct task_struct *task) { struct op_entry entry; struct op_sample *sample; unsigned long flags; int size; flags = 0; if (backtrace) flags |= TRACE_BEGIN; /* notice a switch from user->kernel or vice versa */ is_kernel = !!is_kernel; if (cpu_buf->last_is_kernel != is_kernel) { cpu_buf->last_is_kernel = is_kernel; flags |= KERNEL_CTX_SWITCH; if (is_kernel) flags |= IS_KERNEL; } /* notice a task switch */ if (cpu_buf->last_task != task) { cpu_buf->last_task = task; flags |= USER_CTX_SWITCH; } if (!flags) /* nothing to do */ return 0; if (flags & USER_CTX_SWITCH) size = 1; else size = 0; sample = op_cpu_buffer_write_reserve(&entry, size); if (!sample) return -ENOMEM; sample->eip = ESCAPE_CODE; sample->event = flags; if (size) op_cpu_buffer_add_data(&entry, (unsigned long)task); op_cpu_buffer_write_commit(&entry); return 0; }
int oprofile_add_data64(struct op_entry *entry, u64 val) { if (!entry->event) return 0; if (op_cpu_buffer_get_size(entry) < 2) /* * the function returns 0 to indicate a too small * buffer, even if there is some space left */ return 0; if (!op_cpu_buffer_add_data(entry, (u32)val)) return 0; return op_cpu_buffer_add_data(entry, (u32)(val >> 32)); }
int oprofile_add_data(struct op_entry *entry, unsigned long val) { if (!entry->event) return 0; return op_cpu_buffer_add_data(entry, val); }