diff options
author | Bjoern Brandenburg <bbb@mpi-sws.org> | 2012-09-04 05:27:56 -0400 |
---|---|---|
committer | Bjoern Brandenburg <bbb@mpi-sws.org> | 2012-10-18 16:14:04 -0400 |
commit | b1a59c1438fa81ba1eca68fea665a913188076b2 (patch) | |
tree | abc7c7b5262ecbe1902f36f3284fd2f307b52402 | |
parent | 00b4b17dc1f65a1e5de4648200c826cc2eef37f4 (diff) |
Make Feather-Trace timestamp collection non-preemptive
If the tracing code is interrupted / preempted inbetween the time that
a sequence number is drawn and the time that the trace recorded is
allocated, then the trace file will contain "out of order" events.
These are difficult to detect during post-processing and can create
artificial "outliers". This patch briefly disables local interrutps to
avoid this.
While at it, de-duplicate the timestamp recording code.
-rw-r--r-- | litmus/trace.c | 138 |
1 files changed, 71 insertions, 67 deletions
diff --git a/litmus/trace.c b/litmus/trace.c index 45cd662c021d..4e3d116fe050 100644 --- a/litmus/trace.c +++ b/litmus/trace.c | |||
@@ -43,68 +43,97 @@ static inline unsigned int get_and_clear_irq_fired(void) | |||
43 | return atomic_xchg(&__raw_get_cpu_var(irq_fired_count), 0); | 43 | return atomic_xchg(&__raw_get_cpu_var(irq_fired_count), 0); |
44 | } | 44 | } |
45 | 45 | ||
46 | static inline void __save_irq_flags(struct timestamp *ts) | 46 | static inline void save_irq_flags(struct timestamp *ts, unsigned int irq_count) |
47 | { | 47 | { |
48 | unsigned int irq_count; | ||
49 | |||
50 | irq_count = get_and_clear_irq_fired(); | ||
51 | /* Store how many interrupts occurred. */ | 48 | /* Store how many interrupts occurred. */ |
52 | ts->irq_count = irq_count; | 49 | ts->irq_count = irq_count; |
53 | /* Extra flag because ts->irq_count overflows quickly. */ | 50 | /* Extra flag because ts->irq_count overflows quickly. */ |
54 | ts->irq_flag = irq_count > 0; | 51 | ts->irq_flag = irq_count > 0; |
52 | |||
55 | } | 53 | } |
56 | 54 | ||
57 | static inline void __save_timestamp_cpu(unsigned long event, | 55 | static inline void write_timestamp(uint8_t event, |
58 | uint8_t type, uint8_t cpu, | 56 | uint8_t type, |
59 | uint16_t pid_fragment) | 57 | uint8_t cpu, |
58 | uint16_t pid_fragment, | ||
59 | unsigned int irq_count, | ||
60 | int record_irq, | ||
61 | uint64_t timestamp, | ||
62 | int record_timestamp) | ||
60 | { | 63 | { |
64 | unsigned long flags; | ||
61 | unsigned int seq_no; | 65 | unsigned int seq_no; |
62 | struct timestamp *ts; | 66 | struct timestamp *ts; |
67 | |||
68 | /* Avoid preemptions while recording the timestamp. This reduces the | ||
69 | * number of "out of order" timestamps in the stream and makes | ||
70 | * post-processing easier. */ | ||
71 | |||
72 | local_irq_save(flags); | ||
73 | |||
63 | seq_no = fetch_and_inc((int *) &ts_seq_no); | 74 | seq_no = fetch_and_inc((int *) &ts_seq_no); |
64 | if (ft_buffer_start_write(trace_ts_buf, (void**) &ts)) { | 75 | if (ft_buffer_start_write(trace_ts_buf, (void**) &ts)) { |
65 | ts->event = event; | 76 | ts->event = event; |
66 | ts->seq_no = seq_no; | 77 | ts->seq_no = seq_no; |
78 | |||
79 | ts->task_type = type; | ||
67 | ts->pid = pid_fragment; | 80 | ts->pid = pid_fragment; |
81 | |||
68 | ts->cpu = cpu; | 82 | ts->cpu = cpu; |
69 | ts->task_type = type; | 83 | |
70 | __save_irq_flags(ts); | 84 | if (record_irq) |
71 | barrier(); | 85 | irq_count = get_and_clear_irq_fired(); |
72 | /* prevent re-ordering of ft_timestamp() */ | 86 | |
73 | ts->timestamp = ft_timestamp(); | 87 | save_irq_flags(ts, irq_count); |
88 | |||
89 | if (record_timestamp) | ||
90 | timestamp = ft_timestamp(); | ||
91 | |||
92 | ts->timestamp = timestamp; | ||
74 | ft_buffer_finish_write(trace_ts_buf, ts); | 93 | ft_buffer_finish_write(trace_ts_buf, ts); |
75 | } | 94 | } |
95 | |||
96 | local_irq_restore(flags); | ||
76 | } | 97 | } |
77 | 98 | ||
78 | static void __add_timestamp_user(struct timestamp *pre_recorded) | 99 | static void __add_timestamp_user(struct timestamp *pre_recorded) |
79 | { | 100 | { |
101 | unsigned long flags; | ||
80 | unsigned int seq_no; | 102 | unsigned int seq_no; |
81 | struct timestamp *ts; | 103 | struct timestamp *ts; |
104 | |||
105 | |||
106 | local_irq_save(flags); | ||
107 | |||
82 | seq_no = fetch_and_inc((int *) &ts_seq_no); | 108 | seq_no = fetch_and_inc((int *) &ts_seq_no); |
83 | if (ft_buffer_start_write(trace_ts_buf, (void**) &ts)) { | 109 | if (ft_buffer_start_write(trace_ts_buf, (void**) &ts)) { |
84 | *ts = *pre_recorded; | 110 | *ts = *pre_recorded; |
85 | ts->seq_no = seq_no; | 111 | ts->seq_no = seq_no; |
86 | ts->cpu = raw_smp_processor_id(); | 112 | ts->cpu = raw_smp_processor_id(); |
87 | __save_irq_flags(ts); | 113 | save_irq_flags(ts, get_and_clear_irq_fired()); |
88 | ft_buffer_finish_write(trace_ts_buf, ts); | 114 | ft_buffer_finish_write(trace_ts_buf, ts); |
89 | } | 115 | } |
90 | } | ||
91 | 116 | ||
92 | static inline void __save_timestamp(unsigned long event, | 117 | local_irq_restore(flags); |
93 | uint8_t type) | ||
94 | { | ||
95 | __save_timestamp_cpu(event, type, raw_smp_processor_id(), | ||
96 | current->pid); | ||
97 | } | 118 | } |
98 | 119 | ||
99 | feather_callback void save_timestamp(unsigned long event) | 120 | feather_callback void save_timestamp(unsigned long event) |
100 | { | 121 | { |
101 | __save_timestamp(event, TSK_UNKNOWN); | 122 | write_timestamp(event, TSK_UNKNOWN, |
123 | raw_smp_processor_id(), | ||
124 | current->pid, | ||
125 | 0, 1, | ||
126 | 0, 1); | ||
102 | } | 127 | } |
103 | 128 | ||
104 | feather_callback void save_timestamp_def(unsigned long event, | 129 | feather_callback void save_timestamp_def(unsigned long event, |
105 | unsigned long type) | 130 | unsigned long type) |
106 | { | 131 | { |
107 | __save_timestamp(event, (uint8_t) type); | 132 | write_timestamp(event, type, |
133 | raw_smp_processor_id(), | ||
134 | current->pid, | ||
135 | 0, 1, | ||
136 | 0, 1); | ||
108 | } | 137 | } |
109 | 138 | ||
110 | feather_callback void save_timestamp_task(unsigned long event, | 139 | feather_callback void save_timestamp_task(unsigned long event, |
@@ -112,16 +141,19 @@ feather_callback void save_timestamp_task(unsigned long event, | |||
112 | { | 141 | { |
113 | struct task_struct *t = (struct task_struct *) t_ptr; | 142 | struct task_struct *t = (struct task_struct *) t_ptr; |
114 | int rt = is_realtime(t); | 143 | int rt = is_realtime(t); |
115 | __save_timestamp_cpu(event, rt ? TSK_RT : TSK_BE, | 144 | |
116 | raw_smp_processor_id(), | 145 | write_timestamp(event, rt ? TSK_RT : TSK_BE, |
117 | t->pid); | 146 | raw_smp_processor_id(), |
147 | t->pid, | ||
148 | 0, 1, | ||
149 | 0, 1); | ||
118 | } | 150 | } |
119 | 151 | ||
120 | feather_callback void save_timestamp_cpu(unsigned long event, | 152 | feather_callback void save_timestamp_cpu(unsigned long event, |
121 | unsigned long cpu) | 153 | unsigned long cpu) |
122 | { | 154 | { |
123 | __save_timestamp_cpu(event, TSK_UNKNOWN, cpu, | 155 | write_timestamp(event, TSK_UNKNOWN, cpu, current->pid, |
124 | current->pid); | 156 | 0, 1, 0, 1); |
125 | } | 157 | } |
126 | 158 | ||
127 | feather_callback void save_task_latency(unsigned long event, | 159 | feather_callback void save_task_latency(unsigned long event, |
@@ -129,21 +161,10 @@ feather_callback void save_task_latency(unsigned long event, | |||
129 | { | 161 | { |
130 | lt_t now = litmus_clock(); | 162 | lt_t now = litmus_clock(); |
131 | lt_t *when = (lt_t*) when_ptr; | 163 | lt_t *when = (lt_t*) when_ptr; |
132 | unsigned int seq_no; | ||
133 | int cpu = raw_smp_processor_id(); | ||
134 | struct timestamp *ts; | ||
135 | 164 | ||
136 | seq_no = fetch_and_inc((int *) &ts_seq_no); | 165 | write_timestamp(event, TSK_RT, raw_smp_processor_id(), 0, |
137 | if (ft_buffer_start_write(trace_ts_buf, (void**) &ts)) { | 166 | 0, 1, |
138 | ts->event = event; | 167 | now - *when, 0); |
139 | ts->timestamp = now - *when; | ||
140 | ts->seq_no = seq_no; | ||
141 | ts->cpu = cpu; | ||
142 | ts->pid = 0; | ||
143 | ts->task_type = TSK_RT; | ||
144 | __save_irq_flags(ts); | ||
145 | ft_buffer_finish_write(trace_ts_buf, ts); | ||
146 | } | ||
147 | } | 168 | } |
148 | 169 | ||
149 | /* fake timestamp to user-reported time */ | 170 | /* fake timestamp to user-reported time */ |
@@ -151,19 +172,11 @@ void save_timestamp_time(unsigned long event, | |||
151 | unsigned long ptr) | 172 | unsigned long ptr) |
152 | { | 173 | { |
153 | uint64_t* time = (uint64_t*) ptr; | 174 | uint64_t* time = (uint64_t*) ptr; |
154 | unsigned int seq_no; | 175 | |
155 | struct timestamp *ts; | 176 | write_timestamp(event, is_realtime(current) ? TSK_RT : TSK_BE, |
156 | seq_no = fetch_and_inc((int *) &ts_seq_no); | 177 | raw_smp_processor_id(), current->pid, |
157 | if (ft_buffer_start_write(trace_ts_buf, (void**) &ts)) { | 178 | 0, 1, |
158 | ts->event = event; | 179 | *time, 0); |
159 | ts->seq_no = seq_no; | ||
160 | ts->pid = current->pid; | ||
161 | ts->cpu = raw_smp_processor_id(); | ||
162 | ts->task_type = is_realtime(current) ? TSK_RT : TSK_BE; | ||
163 | __save_irq_flags(ts); | ||
164 | ts->timestamp = *time; | ||
165 | ft_buffer_finish_write(trace_ts_buf, ts); | ||
166 | } | ||
167 | } | 180 | } |
168 | 181 | ||
169 | /* Record user-reported IRQ count */ | 182 | /* Record user-reported IRQ count */ |
@@ -171,20 +184,11 @@ void save_timestamp_irq(unsigned long event, | |||
171 | unsigned long irq_counter_ptr) | 184 | unsigned long irq_counter_ptr) |
172 | { | 185 | { |
173 | uint64_t* irqs = (uint64_t*) irq_counter_ptr; | 186 | uint64_t* irqs = (uint64_t*) irq_counter_ptr; |
174 | unsigned int seq_no; | 187 | |
175 | struct timestamp *ts; | 188 | write_timestamp(event, is_realtime(current) ? TSK_RT : TSK_BE, |
176 | seq_no = fetch_and_inc((int *) &ts_seq_no); | 189 | raw_smp_processor_id(), current->pid, |
177 | if (ft_buffer_start_write(trace_ts_buf, (void**) &ts)) { | 190 | *irqs, 0, |
178 | ts->event = event; | 191 | 0, 1); |
179 | ts->seq_no = seq_no; | ||
180 | ts->pid = current->pid; | ||
181 | ts->cpu = raw_smp_processor_id(); | ||
182 | ts->task_type = is_realtime(current) ? TSK_RT : TSK_BE; | ||
183 | ts->irq_count = *irqs; | ||
184 | ts->irq_flag = *irqs > 0; | ||
185 | ts->timestamp = ft_timestamp(); | ||
186 | ft_buffer_finish_write(trace_ts_buf, ts); | ||
187 | } | ||
188 | } | 192 | } |
189 | 193 | ||
190 | /******************************************************************************/ | 194 | /******************************************************************************/ |