aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Rostedt <srostedt@redhat.com>2011-10-14 15:58:19 -0400
committerSteven Rostedt <rostedt@goodmis.org>2011-10-14 15:58:19 -0400
commit099a2dbde50bb23a0c22098c52c6143f9fb940d2 (patch)
tree51e63b0a29944171f5be4168057d9782922dfb7a
parent954cbf8b759dc8b7b372132e872ac8d695ce8f47 (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.h1
-rw-r--r--trace-record.c108
-rw-r--r--trace-recorder.c37
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);
213int tracecmd_start_recording(struct tracecmd_recorder *recorder, unsigned long sleep); 213int tracecmd_start_recording(struct tracecmd_recorder *recorder, unsigned long sleep);
214void tracecmd_stop_recording(struct tracecmd_recorder *recorder); 214void tracecmd_stop_recording(struct tracecmd_recorder *recorder);
215void tracecmd_stat_cpu(struct trace_seq *s, int cpu); 215void tracecmd_stat_cpu(struct trace_seq *s, int cpu);
216long tracecmd_flush_recording(struct tracecmd_recorder *recorder);
216 217
217/* --- Plugin handling --- */ 218/* --- Plugin handling --- */
218extern struct plugin_option trace_ftrace_options[]; 219extern 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
250static int create_recorder(int cpu, int extract);
251
246static void flush_threads(void) 252static 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
1273static 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 */
1285static 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
1496static 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
1534static void write_func_file(const char *file, struct func_list **list) 1518static 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
159long 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
159int tracecmd_start_recording(struct tracecmd_recorder *recorder, unsigned long sleep) 182int 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