Skip to content

Commit

Permalink
Add per-cpu counters when a tracepoint is hit (#947)
Browse files Browse the repository at this point in the history
* Add per-cpu counters when a tracepoint is hit

* Fix code style, add counter also on page faults

* Fix error management

* Compatibility with olds kernels
  • Loading branch information
luca3m authored Oct 3, 2017
1 parent 0db6e3b commit b08ba64
Show file tree
Hide file tree
Showing 8 changed files with 136 additions and 7 deletions.
57 changes: 51 additions & 6 deletions driver/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ static unsigned int g_ppm_numdevs;
static int g_ppm_major;
bool g_tracers_enabled = false;
bool g_simple_mode_enabled = false;
static DEFINE_PER_CPU(long, g_n_tracepoint_hit);
static const struct file_operations g_ppm_fops = {
.open = ppm_open,
.release = ppm_release,
Expand Down Expand Up @@ -518,6 +519,7 @@ static int ppm_open(struct inode *inode, struct file *filp)

static int ppm_release(struct inode *inode, struct file *filp)
{
int cpu;
int ret;
struct ppm_ring_buffer_context *ring;
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 20)
Expand Down Expand Up @@ -604,6 +606,13 @@ static int ppm_release(struct inode *inode, struct file *filp)
* While we're here, disable simple mode if it's active
*/
g_simple_mode_enabled = false;

/*
* Reset tracepoint counter
*/
for_each_possible_cpu(cpu) {
per_cpu(g_n_tracepoint_hit, cpu) = 0;
}
} else {
ASSERT(false);
}
Expand All @@ -619,6 +628,7 @@ static int ppm_release(struct inode *inode, struct file *filp)

static long ppm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int cpu;
int ret;
struct task_struct *consumer_id = filp->private_data;
struct ppm_consumer_t *consumer = NULL;
Expand Down Expand Up @@ -723,7 +733,20 @@ static long ppm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)

ret = 0;
cleanup_ioctl_procinfo:
vfree((void*)proclist_info);
vfree((void *)proclist_info);
goto cleanup_ioctl_nolock;
}

if (cmd == PPM_IOCTL_GET_N_TRACEPOINT_HIT) {
long __user *counters = (long __user *) arg;

for_each_possible_cpu(cpu) {
if (put_user(per_cpu(g_n_tracepoint_hit, cpu), &counters[cpu])) {
ret = -EINVAL;
goto cleanup_ioctl_nolock;
}
}
ret = 0;
goto cleanup_ioctl_nolock;
}

Expand Down Expand Up @@ -1772,6 +1795,19 @@ static int record_event_consumer(struct ppm_consumer_t *consumer,
return res;
}

static inline void g_n_tracepoint_hit_inc(void)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)
this_cpu_inc(g_n_tracepoint_hit);
#else
/*
* per_cpu_var removed with:
* https://github.com/torvalds/linux/commit/dd17c8f72993f9461e9c19250e3f155d6d99df22
*/
this_cpu_inc(per_cpu_var(g_n_tracepoint_hit));
#endif
}

TRACEPOINT_PROBE(syscall_enter_probe, struct pt_regs *regs, long id)
{
long table_index;
Expand All @@ -1790,7 +1826,7 @@ TRACEPOINT_PROBE(syscall_enter_probe, struct pt_regs *regs, long id)
* kernel flag), we switch to the ia32 syscall table.
*/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)
if(in_ia32_syscall()) {
if (in_ia32_syscall()) {
#else
if (unlikely(task_thread_info(current)->status & TS_COMPAT)) {
#endif
Expand All @@ -1812,7 +1848,7 @@ TRACEPOINT_PROBE(syscall_enter_probe, struct pt_regs *regs, long id)
* Simple mode event filtering
*/
if (g_simple_mode_enabled) {
if((drop_flags & UF_SIMPLEDRIVER_KEEP) == 0) {
if ((drop_flags & UF_SIMPLEDRIVER_KEEP) == 0) {
return;
}
}
Expand Down Expand Up @@ -1865,7 +1901,7 @@ TRACEPOINT_PROBE(syscall_exit_probe, struct pt_regs *regs, long ret)
* which is a very old syscall, not used anymore by most applications
*/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)
if(in_ia32_syscall() && id != __NR_execve) {
if (in_ia32_syscall() && id != __NR_execve) {
#else
if (unlikely((task_thread_info(current)->status & TS_COMPAT) && id != __NR_execve)) {
#endif
Expand All @@ -1876,6 +1912,8 @@ TRACEPOINT_PROBE(syscall_exit_probe, struct pt_regs *regs, long ret)
}
#endif

g_n_tracepoint_hit_inc();

table_index = id - SYSCALL_TABLE_ID0;
if (likely(table_index >= 0 && table_index < SYSCALL_TABLE_SIZE)) {
struct event_data_t event_data;
Expand All @@ -1887,7 +1925,7 @@ TRACEPOINT_PROBE(syscall_exit_probe, struct pt_regs *regs, long ret)
* Simple mode event filtering
*/
if (g_simple_mode_enabled) {
if((drop_flags & UF_SIMPLEDRIVER_KEEP) == 0) {
if ((drop_flags & UF_SIMPLEDRIVER_KEEP) == 0) {
return;
}
}
Expand Down Expand Up @@ -1926,6 +1964,8 @@ TRACEPOINT_PROBE(syscall_procexit_probe, struct task_struct *p)
{
struct event_data_t event_data;

g_n_tracepoint_hit_inc();

#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 20)
if (unlikely(current->flags & PF_KTHREAD)) {
#else
Expand Down Expand Up @@ -1959,6 +1999,8 @@ TRACEPOINT_PROBE(sched_switch_probe, bool preempt, struct task_struct *prev, str
{
struct event_data_t event_data;

g_n_tracepoint_hit_inc();

event_data.category = PPMC_CONTEXT_SWITCH;
event_data.event_info.context_data.sched_prev = prev;
event_data.event_info.context_data.sched_next = next;
Expand All @@ -1972,6 +2014,8 @@ TRACEPOINT_PROBE(signal_deliver_probe, int sig, struct siginfo *info, struct k_s
{
struct event_data_t event_data;

g_n_tracepoint_hit_inc();

event_data.category = PPMC_SIGNAL;
event_data.event_info.signal_data.sig = sig;
event_data.event_info.signal_data.info = info;
Expand All @@ -1990,6 +2034,7 @@ TRACEPOINT_PROBE(page_fault_probe, unsigned long address, struct pt_regs *regs,
* in the output by looking for the USER_FAULT/SUPERVISOR_FAULT
* flags
*/
g_n_tracepoint_hit_inc();

/* I still haven't decided if I'm interested in kernel threads or not.
* For the moment, I assume yes since I can see some value for it.
Expand Down Expand Up @@ -2325,7 +2370,7 @@ int sysdig_init(void)
g_ppm_numdevs = num_cpus;
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)
g_ppm_devs = kmalloc(g_ppm_numdevs * sizeof(struct ppm_device), GFP_KERNEL);
#else
#else
g_ppm_devs = kmalloc_array(g_ppm_numdevs, sizeof(struct ppm_device), GFP_KERNEL);
#endif
if (!g_ppm_devs) {
Expand Down
1 change: 1 addition & 0 deletions driver/ppm_events_public.h
Original file line number Diff line number Diff line change
Expand Up @@ -1326,6 +1326,7 @@ struct ppm_evt_hdr {
#define PPM_IOCTL_SET_TRACERS_CAPTURE _IO(PPM_IOCTL_MAGIC, 17)
#define PPM_IOCTL_SET_SIMPLE_MODE _IO(PPM_IOCTL_MAGIC, 18)
#define PPM_IOCTL_ENABLE_PAGE_FAULTS _IO(PPM_IOCTL_MAGIC, 19)
#define PPM_IOCTL_GET_N_TRACEPOINT_HIT _IO(PPM_IOCTL_MAGIC, 20)

extern const struct ppm_name_value socket_families[];
extern const struct ppm_name_value file_flags[];
Expand Down
27 changes: 27 additions & 0 deletions userspace/libscap/scap.c
Original file line number Diff line number Diff line change
Expand Up @@ -1524,3 +1524,30 @@ int32_t scap_enable_simpledriver_mode(scap_t* handle)
return SCAP_SUCCESS;
#endif
}

int32_t scap_get_n_tracepoint_hit(scap_t* handle, long* ret)
{
//
// Not supported on files
//
if(handle->m_mode != SCAP_MODE_LIVE)
{
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "getting n_tracepoint_hit not supported on this scap mode");
return SCAP_FAILURE;
}

#if !defined(HAS_CAPTURE)
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "live capture not supported on %s", PLATFORM_NAME);
return SCAP_FAILURE;
#else

if(ioctl(handle->m_devs[0].m_fd, PPM_IOCTL_GET_N_TRACEPOINT_HIT, ret))
{
snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "scap_get_n_tracepoint_hit failed");
ASSERT(false);
return SCAP_FAILURE;
}

return SCAP_SUCCESS;
#endif
}
1 change: 1 addition & 0 deletions userspace/libscap/scap.h
Original file line number Diff line number Diff line change
Expand Up @@ -944,6 +944,7 @@ int32_t scap_write_proclist_header(scap_t *handle, scap_dumper_t *d, uint32_t to
int32_t scap_write_proclist_trailer(scap_t *handle, scap_dumper_t *d, uint32_t totlen);
int32_t scap_write_proclist_entry(scap_t *handle, scap_dumper_t *d, struct scap_threadinfo *tinfo);
int32_t scap_enable_simpledriver_mode(scap_t* handle);
int32_t scap_get_n_tracepoint_hit(scap_t* handle, long* ret);

#ifdef __cplusplus
}
Expand Down
28 changes: 27 additions & 1 deletion userspace/libsinsp/sinsp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -519,8 +519,34 @@ void sinsp::set_simpledriver_mode()
{
if(scap_enable_simpledriver_mode(m_h) != SCAP_SUCCESS)
{
throw sinsp_exception(scap_getlasterr(m_h));
throw sinsp_exception(scap_getlasterr(m_h));
}
}

unsigned sinsp::m_num_possible_cpus = 0;

unsigned sinsp::num_possible_cpus()
{
if(m_num_possible_cpus == 0)
{
m_num_possible_cpus = read_num_possible_cpus();
if(m_num_possible_cpus == 0)
{
g_logger.log("Unable to read num_possible_cpus, falling back to 128", sinsp_logger::SEV_WARNING);
m_num_possible_cpus = 128;
}
}
return m_num_possible_cpus;
}

vector<long> sinsp::get_n_tracepoint_hit()
{
vector<long> ret(num_possible_cpus(), 0);
if(scap_get_n_tracepoint_hit(m_h, ret.data()) != SCAP_SUCCESS)
{
throw sinsp_exception(scap_getlasterr(m_h));
}
return ret;
}

std::string sinsp::get_error_desc(const std::string& msg)
Expand Down
3 changes: 3 additions & 0 deletions userspace/libsinsp/sinsp.h
Original file line number Diff line number Diff line change
Expand Up @@ -802,7 +802,9 @@ class SINSP_PUBLIC sinsp
scap_refresh_proc_table(m_h);
}
void set_simpledriver_mode();
vector<long> get_n_tracepoint_hit();

static unsigned num_possible_cpus();
VISIBILITY_PRIVATE

// Doxygen doesn't understand VISIBILITY_PRIVATE
Expand Down Expand Up @@ -1071,6 +1073,7 @@ VISIBILITY_PRIVATE
uint64_t m_last_procrequest_tod;
sinsp_proc_metainfo m_meinfo;

static unsigned int m_num_possible_cpus;
#if defined(HAS_CAPTURE)
int64_t m_sysdig_pid;
#endif
Expand Down
24 changes: 24 additions & 0 deletions userspace/libsinsp/utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1417,3 +1417,27 @@ bool set_socket_blocking(int sock, bool block)
}
return true;
}

unsigned int read_num_possible_cpus(void)
{
static const char *fcpu = "/sys/devices/system/cpu/possible";
unsigned int start, end, possible_cpus = 0;
char buff[128];
FILE *fp;

fp = fopen(fcpu, "r");
if (!fp) {
return possible_cpus;
}

while (fgets(buff, sizeof(buff), fp)) {
if (sscanf(buff, "%u-%u", &start, &end) == 2) {
possible_cpus = start == 0 ? end + 1 : 0;
break;
}
}

fclose(fp);

return possible_cpus;
}
2 changes: 2 additions & 0 deletions userspace/libsinsp/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -350,3 +350,5 @@ struct ci_compare
///////////////////////////////////////////////////////////////////////////////

bool set_socket_blocking(int sock, bool block);

unsigned int read_num_possible_cpus(void);

1 comment on commit b08ba64

@Mic92
Copy link
Contributor

@Mic92 Mic92 commented on b08ba64 Oct 4, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a release?

Please sign in to comment.