1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
|
#include <linux/sched.h>
#include <linux/module.h>
#include <litmus/ftdev.h>
#include <litmus/litmus.h>
#include <litmus/trace.h>
/******************************************************************************/
/* Allocation */
/******************************************************************************/
static struct ftdev overhead_dev;
#define trace_ts_buf overhead_dev.minor[0].buf
static unsigned int ts_seq_no = 0;
static inline void __save_timestamp_cpu(unsigned long event,
uint8_t type, uint8_t cpu)
{
unsigned int seq_no;
struct timestamp *ts;
seq_no = fetch_and_inc((int *) &ts_seq_no);
if (ft_buffer_start_write(trace_ts_buf, (void**) &ts)) {
ts->event = event;
ts->timestamp = ft_timestamp();
ts->seq_no = seq_no;
ts->cpu = cpu;
ts->task_type = type;
ft_buffer_finish_write(trace_ts_buf, ts);
}
}
static inline void __save_timestamp(unsigned long event,
uint8_t type)
{
__save_timestamp_cpu(event, type, raw_smp_processor_id());
}
/* hack: fake timestamp to user-reported time, and record parts of the PID */
feather_callback void save_timestamp_time(unsigned long event, unsigned long ptr)
{
uint64_t* time = (uint64_t*) ptr;
unsigned int seq_no;
struct timestamp *ts;
seq_no = fetch_and_inc((int *) &ts_seq_no);
if (ft_buffer_start_write(trace_ts_buf, (void**) &ts)) {
ts->event = event;
ts->timestamp = *time;
ts->seq_no = seq_no;
/* type takes lowest byte of PID */
ts->task_type = (uint8_t) current->pid;
/* cpu takes second-lowest byte of PID*/
ts->cpu = (uint8_t) (current->pid >> 8);
ft_buffer_finish_write(trace_ts_buf, ts);
}
}
feather_callback void save_timestamp_pid(unsigned long event)
{
/* Abuse existing fields to partially export PID. */
__save_timestamp_cpu(event,
/* type takes lowest byte of PID */
(uint8_t) current->pid,
/* cpu takes second-lowest byte of PID*/
(uint8_t) (current->pid >> 8));
}
feather_callback void save_timestamp(unsigned long event)
{
__save_timestamp(event, TSK_UNKNOWN);
}
feather_callback void save_timestamp_def(unsigned long event,
unsigned long type)
{
__save_timestamp(event, (uint8_t) type);
}
feather_callback void save_timestamp_task(unsigned long event,
unsigned long t_ptr)
{
int rt = is_realtime((struct task_struct *) t_ptr);
__save_timestamp(event, rt ? TSK_RT : TSK_BE);
}
feather_callback void save_timestamp_cpu(unsigned long event,
unsigned long cpu)
{
__save_timestamp_cpu(event, TSK_UNKNOWN, cpu);
}
/******************************************************************************/
/* DEVICE FILE DRIVER */
/******************************************************************************/
/*
* should be 8M; it is the max we can ask to buddy system allocator (MAX_ORDER)
* and we might not get as much
*/
#define NO_TIMESTAMPS (2 << 11)
static int alloc_timestamp_buffer(struct ftdev* ftdev, unsigned int idx)
{
unsigned int count = NO_TIMESTAMPS;
while (count && !trace_ts_buf) {
printk("time stamp buffer: trying to allocate %u time stamps.\n", count);
ftdev->minor[idx].buf = alloc_ft_buffer(count, sizeof(struct timestamp));
count /= 2;
}
return ftdev->minor[idx].buf ? 0 : -ENOMEM;
}
static void free_timestamp_buffer(struct ftdev* ftdev, unsigned int idx)
{
free_ft_buffer(ftdev->minor[idx].buf);
ftdev->minor[idx].buf = NULL;
}
static int __init init_ft_overhead_trace(void)
{
int err;
printk("Initializing Feather-Trace overhead tracing device.\n");
err = ftdev_init(&overhead_dev, THIS_MODULE, 1, "ft_trace");
if (err)
goto err_out;
overhead_dev.alloc = alloc_timestamp_buffer;
overhead_dev.free = free_timestamp_buffer;
err = register_ftdev(&overhead_dev);
if (err)
goto err_dealloc;
return 0;
err_dealloc:
ftdev_exit(&overhead_dev);
err_out:
printk(KERN_WARNING "Could not register ft_trace module.\n");
return err;
}
static void __exit exit_ft_overhead_trace(void)
{
ftdev_exit(&overhead_dev);
}
module_init(init_ft_overhead_trace);
module_exit(exit_ft_overhead_trace);
|