Add timestamp to process event connector message
cover Add timestamp to process event connector message
This series of patches adds a timestamp field to the events sent
via the process event connector. The timestamp allows listeners to accurately account the duration(s) between a process' events and offers strong means with which to determine the order of events while also avoiding the addition of per-task data.
Series:
getnstimestamp.patch
proc-events-timestamp.patch
The first patch adds a new generic function, getnstimestamp(),
which gets an SMP-safe high-resolution monotonic timestamp.
The second patch adds a timestamp field to the events sent via
the process event connector and fills the field using the new timestamp function. It alters the size and layout of the event structure and hence would break compatibility if not incorporated with the first release of process events connector in a mainline kernel.
Cheers,
-Matt Helsley
RFC PATCH 1/2 Add getnstimestamp function
There are several functions that might seem appropriate for a timestamp:
get_cycles()current_kernel_time()do_gettimeofday()
<read jiffies/jiffies_64>
Each has problems with combinations of SMP-safety, low resolution, and monotonicity. This patch adds a new function that returns a monotonic SMP-safe timestamp with nanosecond resolution where available.
Changes:
Split timestamp into separate patch
Moved to kernel/time.c
Renamed to getnstimestamp
Fixed unintended-pointer-arithmetic bug
--
kernel/time.c +22 -0
@@ -562,10 +562,32 @@ void getnstimeofday(struct timespec *tv) tv->tv_nsec = x.tv_usec * NSEC_PER_USEC; }EXPORT_SYMBOL_GPL (getnstimeofday);#endif +void getnstimestamp (struct timespec *ts) +{ +unsigned int seq; +struct timespec wall2mono; + +/* synchronize with settimeofday() changes */ +do { + seq =read_seqbegin (&xtime_lock); +getnstimeofday (ts); + wall2mono = wall_to_monotonic; + }while (unlikely (read_seqretry (&xtime_lock, seq))); + +/* adjust to monotonicaly-increasing values */ + ts->tv_sec += wall2mono.tv_sec; + ts->tv_nsec += wall2mono.tv_nsec; +while (unlikely (ts->tv_nsec >=NSEC_PER_SEC )) { + ts->tv_nsec -=NSEC_PER_SEC ; + ts->tv_sec++; + } +} +EXPORT_SYMBOL_GPL (getnstimestamp); +/* Converts Gregorian date to seconds since 1970-01-01 00:00:00. * Assumes input in normal date format, i.e. 1980-12-31 23:59:59 * => year=1980, mon=12, day=31, hour=23, min=59, sec=59. * * [For the Julian calendar (which was used in Russia before 1917,
include/linux/time.h +1 -0
@@ -78,10 +78,11 @@ extern long do_utimes(char __user *filenstruct itimerval ;extern int do_setitimer (int which,struct itimerval *value,struct itimerval *ovalue);extern int do_getitimer (int which,struct itimerval *value);extern void getnstimeofday (struct timespec *tv); +extern void getnstimestamp (struct timespec *ts);extern struct timespec timespec_trunc (struct timespec t,unsigned gran);/** * timespec_to_ns - Convert timespec to nanoseconds
RFC PATCH 2/2 Add timestamp field to process events
In reply to Matt Helsley This patch adds a timestamp field to the events sent via the process
event connector. The timestamp allows listeners to accurately account the duration(s) between a process' events and offers strong means with which to determine the order of events with respect to a given task while also avoiding the addition of per-task data.
This alters the size and layout of the event structure and hence would
break compatibility if process events connector as it stands in 2.6.15-rc2 were released as a mainline kernel.
--
drivers/connector/cn_proc.c +5 -0
@@ -54,10 +54,11 @@ void proc_fork_connector(struct task_strreturn ; msg = (struct cn_msg *)buffer; ev = (struct proc_event *)msg->data;get_seq (&msg->seq, &ev->cpu); +getnstimestamp (&ev->timestamp); ev->what =PROC_EVENT_FORK ; ev->event_data.fork.parent_pid = task->real_parent->pid; ev->event_data.fork.parent_tgid = task->real_parent->tgid; ev->event_data.fork.child_pid = task->pid; ev->event_data.fork.child_tgid = task->tgid;
@@ -79,10 +80,11 @@ void proc_exec_connector(struct task_strreturn ; msg = (struct cn_msg *)buffer; ev = (struct proc_event *)msg->data;get_seq (&msg->seq, &ev->cpu); +getnstimestamp (&ev->timestamp); ev->what =PROC_EVENT_EXEC ; ev->event_data.exec.process_pid = task->pid; ev->event_data.exec.process_tgid = task->tgid;memcpy (&msg->id, &cn_proc_event_id,sizeof (msg->id));
@@ -112,10 +114,11 @@ void proc_id_connector(struct task_struc ev->event_data.id.r.rgid = task->gid; ev->event_data.id.e.egid = task->egid; }else return ;get_seq (&msg->seq, &ev->cpu); +getnstimestamp (&ev->timestamp);memcpy (&msg->id, &cn_proc_event_id,sizeof (msg->id)); msg->ack =0 ;/* not used */ msg->len =sizeof (*ev);cn_netlink_send (msg,CN_IDX_PROC ,GFP_KERNEL );
@@ -131,10 +134,11 @@ void proc_exit_connector(struct task_strreturn ; msg = (struct cn_msg *)buffer; ev = (struct proc_event *)msg->data;get_seq (&msg->seq, &ev->cpu); +getnstimestamp (&ev->timestamp); ev->what =PROC_EVENT_EXIT ; ev->event_data.exit.process_pid = task->pid; ev->event_data.exit.process_tgid = task->tgid; ev->event_data.exit.exit_code = task->exit_code; ev->event_data.exit.exit_signal = task->exit_signal;
@@ -163,10 +167,11 @@ static void cn_proc_ack(int err, int rcvreturn ; msg = (struct cn_msg *)buffer; ev = (struct proc_event *)msg->data; msg->seq = rcvd_seq; +getnstimestamp (&ev->timestamp); ev->cpu =-1 ; ev->what =PROC_EVENT_NONE ; ev->event_data.ack.err = err;memcpy (&msg->id, &cn_proc_event_id,sizeof (msg->id)); msg->ack = rcvd_ack +1 ;
include/linux/cn_proc.h +2 -0
@@ -24,10 +24,11 @@#ifndef CN_PROC_H #define CN_PROC_H #include <linux/types.h> +#include <linux/time.h> #include <linux/connector.h> /* * Userspace sends this enum to register with the kernel that it is listening * for events on the connector.
@@ -63,10 +64,11 @@ struct proc_event {/* "next" should be 0x00000400 */ /* "last" is the last process event: exit */ PROC_EVENT_EXIT = 0x80000000 } what;__u32 cpu; +struct timespec timestamp;union {/* must be last field of proc_event struct */ struct {__u32 err; } ack;