diff options
author | Steven Rostedt <srostedt@redhat.com> | 2011-10-14 15:58:19 -0400 |
---|---|---|
committer | Steven Rostedt <rostedt@goodmis.org> | 2011-10-14 15:58:19 -0400 |
commit | 099a2dbde50bb23a0c22098c52c6143f9fb940d2 (patch) | |
tree | 51e63b0a29944171f5be4168057d9782922dfb7a | |
parent | 954cbf8b759dc8b7b372132e872ac8d695ce8f47 (diff) |
trace-cmd: Do not use threads for extract
Currently the trace-cmd extract function uses the forked threads to
read the data from the ring buffers. As this is not a live trace and
the program does not end till all the buffers are flushed to disk,
there is no need to use the threads. Just serially read each buffer
into a file and then pull them together normally.
This also fixes a bug that was triggered in the kernel where reading
the trace_pipe_raw file after EOF will yield the last page again,
causing the trace-cmd extract to produce duplicate pages.
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
-rw-r--r-- | trace-cmd.h | 1 | ||||
-rw-r--r-- | trace-record.c | 108 | ||||
-rw-r--r-- | trace-recorder.c | 37 |
3 files changed, 70 insertions, 76 deletions
diff --git a/trace-cmd.h b/trace-cmd.h index 5a7c6c0..3f522ee 100644 --- a/trace-cmd.h +++ b/trace-cmd.h | |||
@@ -213,6 +213,7 @@ struct tracecmd_recorder *tracecmd_create_recorder_fd(int fd, int cpu); | |||
213 | int tracecmd_start_recording(struct tracecmd_recorder *recorder, unsigned long sleep); | 213 | int tracecmd_start_recording(struct tracecmd_recorder *recorder, unsigned long sleep); |
214 | void tracecmd_stop_recording(struct tracecmd_recorder *recorder); | 214 | void tracecmd_stop_recording(struct tracecmd_recorder *recorder); |
215 | void tracecmd_stat_cpu(struct trace_seq *s, int cpu); | 215 | void tracecmd_stat_cpu(struct trace_seq *s, int cpu); |
216 | long tracecmd_flush_recording(struct tracecmd_recorder *recorder); | ||
216 | 217 | ||
217 | /* --- Plugin handling --- */ | 218 | /* --- Plugin handling --- */ |
218 | extern struct plugin_option trace_ftrace_options[]; | 219 | extern struct plugin_option trace_ftrace_options[]; |
diff --git a/trace-record.c b/trace-record.c index 90589cf..bf48e03 100644 --- a/trace-record.c +++ b/trace-record.c | |||
@@ -219,11 +219,15 @@ static void delete_thread_data(void) | |||
219 | return; | 219 | return; |
220 | 220 | ||
221 | for (i = 0; i < cpu_count; i++) { | 221 | for (i = 0; i < cpu_count; i++) { |
222 | if (pids[i]) { | 222 | if (pids) { |
223 | if (pids[i]) { | ||
224 | delete_temp_file(i); | ||
225 | if (pids[i] < 0) | ||
226 | pids[i] = 0; | ||
227 | } | ||
228 | } else | ||
229 | /* Extract does not allocate pids */ | ||
223 | delete_temp_file(i); | 230 | delete_temp_file(i); |
224 | if (pids[i] < 0) | ||
225 | pids[i] = 0; | ||
226 | } | ||
227 | } | 231 | } |
228 | } | 232 | } |
229 | 233 | ||
@@ -243,16 +247,20 @@ static void stop_threads(void) | |||
243 | } | 247 | } |
244 | } | 248 | } |
245 | 249 | ||
250 | static int create_recorder(int cpu, int extract); | ||
251 | |||
246 | static void flush_threads(void) | 252 | static void flush_threads(void) |
247 | { | 253 | { |
254 | long ret; | ||
248 | int i; | 255 | int i; |
249 | 256 | ||
250 | if (!cpu_count) | 257 | if (!cpu_count) |
251 | return; | 258 | return; |
252 | 259 | ||
253 | for (i = 0; i < cpu_count; i++) { | 260 | for (i = 0; i < cpu_count; i++) { |
254 | if (pids[i] > 0) | 261 | ret = create_recorder(i, 1); |
255 | kill(pids[i], SIGUSR1); | 262 | if (ret < 0) |
263 | die("error reading ring buffer"); | ||
256 | } | 264 | } |
257 | } | 265 | } |
258 | 266 | ||
@@ -1270,25 +1278,32 @@ static void set_prio(int prio) | |||
1270 | warning("failed to set priority"); | 1278 | warning("failed to set priority"); |
1271 | } | 1279 | } |
1272 | 1280 | ||
1273 | static int create_recorder(int cpu) | 1281 | /* |
1282 | * If extract is set, then this is going to set up the recorder, | ||
1283 | * connections and exit as the tracing is serialized by a single thread. | ||
1284 | */ | ||
1285 | static int create_recorder(int cpu, int extract) | ||
1274 | { | 1286 | { |
1287 | long ret; | ||
1275 | char *file; | 1288 | char *file; |
1276 | int pid; | 1289 | int pid; |
1277 | 1290 | ||
1278 | signal(SIGUSR1, flush); | 1291 | if (!extract) { |
1292 | signal(SIGUSR1, flush); | ||
1279 | 1293 | ||
1280 | pid = fork(); | 1294 | pid = fork(); |
1281 | if (pid < 0) | 1295 | if (pid < 0) |
1282 | die("fork"); | 1296 | die("fork"); |
1283 | 1297 | ||
1284 | if (pid) | 1298 | if (pid) |
1285 | return pid; | 1299 | return pid; |
1286 | 1300 | ||
1287 | if (rt_prio) | 1301 | if (rt_prio) |
1288 | set_prio(rt_prio); | 1302 | set_prio(rt_prio); |
1289 | 1303 | ||
1290 | /* do not kill tasks on error */ | 1304 | /* do not kill tasks on error */ |
1291 | cpu_count = 0; | 1305 | cpu_count = 0; |
1306 | } | ||
1292 | 1307 | ||
1293 | if (client_ports) { | 1308 | if (client_ports) { |
1294 | connect_port(cpu); | 1309 | connect_port(cpu); |
@@ -1301,6 +1316,13 @@ static int create_recorder(int cpu) | |||
1301 | 1316 | ||
1302 | if (!recorder) | 1317 | if (!recorder) |
1303 | die ("can't create recorder"); | 1318 | die ("can't create recorder"); |
1319 | |||
1320 | if (extract) { | ||
1321 | ret = tracecmd_flush_recording(recorder); | ||
1322 | tracecmd_free_recorder(recorder); | ||
1323 | return ret; | ||
1324 | } | ||
1325 | |||
1304 | while (!finished) { | 1326 | while (!finished) { |
1305 | if (tracecmd_start_recording(recorder, sleep_time) < 0) | 1327 | if (tracecmd_start_recording(recorder, sleep_time) < 0) |
1306 | break; | 1328 | break; |
@@ -1448,7 +1470,7 @@ static void start_threads(void) | |||
1448 | memset(pids, 0, sizeof(*pids) * cpu_count); | 1470 | memset(pids, 0, sizeof(*pids) * cpu_count); |
1449 | 1471 | ||
1450 | for (i = 0; i < cpu_count; i++) { | 1472 | for (i = 0; i < cpu_count; i++) { |
1451 | pids[i] = create_recorder(i); | 1473 | pids[i] = create_recorder(i, 0); |
1452 | } | 1474 | } |
1453 | } | 1475 | } |
1454 | 1476 | ||
@@ -1493,44 +1515,6 @@ static void record_data(char *date2ts) | |||
1493 | tracecmd_output_close(handle); | 1515 | tracecmd_output_close(handle); |
1494 | } | 1516 | } |
1495 | 1517 | ||
1496 | static int trace_empty(void) | ||
1497 | { | ||
1498 | char *path; | ||
1499 | FILE *fp; | ||
1500 | char *line = NULL; | ||
1501 | size_t size; | ||
1502 | ssize_t n; | ||
1503 | int ret = 1; | ||
1504 | |||
1505 | /* | ||
1506 | * Test if the trace file is empty. | ||
1507 | * | ||
1508 | * Yes, this is a heck of a hack. What is done here | ||
1509 | * is to read the trace file and ignore the | ||
1510 | * lines starting with '#', and if we get a line | ||
1511 | * that is without a '#' the trace is not empty. | ||
1512 | * Otherwise it is. | ||
1513 | */ | ||
1514 | path = tracecmd_get_tracing_file("trace"); | ||
1515 | fp = fopen(path, "r"); | ||
1516 | if (!fp) | ||
1517 | die("reading '%s'", path); | ||
1518 | |||
1519 | do { | ||
1520 | n = getline(&line, &size, fp); | ||
1521 | if (n > 0 && line && line[0] != '#') { | ||
1522 | ret = 0; | ||
1523 | break; | ||
1524 | } | ||
1525 | } while (line && n > 0); | ||
1526 | |||
1527 | tracecmd_put_tracing_file(path); | ||
1528 | |||
1529 | fclose(fp); | ||
1530 | |||
1531 | return ret; | ||
1532 | } | ||
1533 | |||
1534 | static void write_func_file(const char *file, struct func_list **list) | 1518 | static void write_func_file(const char *file, struct func_list **list) |
1535 | { | 1519 | { |
1536 | struct func_list *item; | 1520 | struct func_list *item; |
@@ -2202,17 +2186,15 @@ void trace_record (int argc, char **argv) | |||
2202 | 2186 | ||
2203 | s = malloc_or_die(sizeof(*s) * cpu_count); | 2187 | s = malloc_or_die(sizeof(*s) * cpu_count); |
2204 | 2188 | ||
2205 | if (record || extract) { | 2189 | if (record) { |
2206 | signal(SIGINT, finish); | 2190 | signal(SIGINT, finish); |
2207 | if (!latency) | 2191 | if (!latency) |
2208 | start_threads(); | 2192 | start_threads(); |
2209 | } | 2193 | } |
2210 | 2194 | ||
2211 | if (extract) { | 2195 | if (extract) { |
2212 | while (!finished && !trace_empty()) { | 2196 | flush_threads(); |
2213 | flush_threads(); | 2197 | |
2214 | sleep(1); | ||
2215 | } | ||
2216 | } else { | 2198 | } else { |
2217 | if (!record) { | 2199 | if (!record) { |
2218 | update_task_filter(); | 2200 | update_task_filter(); |
@@ -2233,10 +2215,9 @@ void trace_record (int argc, char **argv) | |||
2233 | } | 2215 | } |
2234 | 2216 | ||
2235 | disable_tracing(); | 2217 | disable_tracing(); |
2218 | stop_threads(); | ||
2236 | } | 2219 | } |
2237 | 2220 | ||
2238 | stop_threads(); | ||
2239 | |||
2240 | for (cpu = 0; cpu < cpu_count; cpu++) { | 2221 | for (cpu = 0; cpu < cpu_count; cpu++) { |
2241 | trace_seq_init(&s[cpu]); | 2222 | trace_seq_init(&s[cpu]); |
2242 | trace_seq_printf(&s[cpu], "CPU: %d\n", cpu); | 2223 | trace_seq_printf(&s[cpu], "CPU: %d\n", cpu); |
@@ -2263,7 +2244,6 @@ void trace_record (int argc, char **argv) | |||
2263 | record_data(date2ts); | 2244 | record_data(date2ts); |
2264 | delete_thread_data(); | 2245 | delete_thread_data(); |
2265 | 2246 | ||
2266 | |||
2267 | if (keep) | 2247 | if (keep) |
2268 | exit(0); | 2248 | exit(0); |
2269 | 2249 | ||
diff --git a/trace-recorder.c b/trace-recorder.c index e57ef9b..4a01fb9 100644 --- a/trace-recorder.c +++ b/trace-recorder.c | |||
@@ -156,10 +156,32 @@ static long splice_data(struct tracecmd_recorder *recorder) | |||
156 | return ret; | 156 | return ret; |
157 | } | 157 | } |
158 | 158 | ||
159 | long tracecmd_flush_recording(struct tracecmd_recorder *recorder) | ||
160 | { | ||
161 | char *buf[recorder->page_size]; | ||
162 | long total = 0; | ||
163 | long ret; | ||
164 | |||
165 | do { | ||
166 | ret = splice_data(recorder); | ||
167 | if (ret < 0) | ||
168 | return ret; | ||
169 | total += ret; | ||
170 | } while (ret); | ||
171 | |||
172 | /* splice only reads full pages */ | ||
173 | do { | ||
174 | ret = read(recorder->trace_fd, buf, recorder->page_size); | ||
175 | if (ret > 0) | ||
176 | write(recorder->fd, buf, ret); | ||
177 | } while (ret > 0); | ||
178 | |||
179 | return total; | ||
180 | } | ||
181 | |||
159 | int tracecmd_start_recording(struct tracecmd_recorder *recorder, unsigned long sleep) | 182 | int tracecmd_start_recording(struct tracecmd_recorder *recorder, unsigned long sleep) |
160 | { | 183 | { |
161 | struct timespec req; | 184 | struct timespec req; |
162 | char *buf[recorder->page_size]; | ||
163 | long ret; | 185 | long ret; |
164 | 186 | ||
165 | recorder->stop = 0; | 187 | recorder->stop = 0; |
@@ -175,21 +197,12 @@ int tracecmd_start_recording(struct tracecmd_recorder *recorder, unsigned long s | |||
175 | return ret; | 197 | return ret; |
176 | } while (!recorder->stop); | 198 | } while (!recorder->stop); |
177 | 199 | ||
178 | /* Flush via splice first */ | 200 | /* Flush out the rest */ |
179 | do { | 201 | ret = tracecmd_flush_recording(recorder); |
180 | ret = splice_data(recorder); | ||
181 | } while (ret > 0); | ||
182 | 202 | ||
183 | if (ret < 0) | 203 | if (ret < 0) |
184 | return ret; | 204 | return ret; |
185 | 205 | ||
186 | /* splice only reads full pages */ | ||
187 | do { | ||
188 | ret = read(recorder->trace_fd, buf, recorder->page_size); | ||
189 | if (ret > 0) | ||
190 | write(recorder->fd, buf, ret); | ||
191 | } while (ret > 0); | ||
192 | |||
193 | return 0; | 206 | return 0; |
194 | } | 207 | } |
195 | 208 | ||