/* * Used to find, extract and dump state from * a running bootchartd process. */ int buffers_extract_and_dump (const char *output_path, Arguments *remote_args) { int i, pid, ret = 0; DumpState *state; assert (!chdir (output_path)); pid = bootchart_find_running_pid (remote_args); if (pid < 0) { log ("Failed to find the collector's pid\n"); return 1; } log ("Extracting profile data from pid %d\n", pid); /* the kernel for reasons of it's own really likes to return ESRCH - No such process from pread randomly, so retry a bit */ for (i = 0; i < 8; i++) { if (!(state = open_pid (pid))) return 1; if (find_chunks (state)) { ret = 1; log ("Couldn't find state structures on pid %d's stack%s\n", pid, i < 7 ? ", retrying" : " aborting"); close_pid (state, 1); } else { ret = 0; dump_buffers (state); close_wait_pid (state, 0); break; } } return ret; }
int main (int argc, char *argv[]) { Arguments args; int i, use_taskstat; int in_initrd, clean_environment = 1; int stat_fd, disk_fd, uptime_fd, meminfo_fd, pid, ret = 1; PidScanner *scanner = NULL; unsigned long reltime = 0; BufferFile *stat_file, *disk_file, *per_pid_file, *meminfo_file; PidEventClosure pid_ev_cl; int *fds[] = { &stat_fd, &disk_fd, &uptime_fd, &meminfo_fd, NULL }; const char *fd_names[] = { "/stat", "/diskstats", "/uptime", "/meminfo", NULL }; StackMap map = STACK_MAP_INIT; /* make me findable */ arguments_set_defaults (&args); arguments_parse (&args, argc, argv); if (args.usleep_time > 0) { usleep (args.usleep_time); return 0; } if (enter_environment (args.console_debug)) return 1; fprintf (stderr, "bootchart-collector started as pid %d with %d args: ", (int) getpid(), argc - 1); for (i = 1; i < argc; i++) fprintf (stderr, "'%s' ", argv[i]); fprintf (stderr, "\n"); if (args.dump_path) { Arguments remote_args; ret = buffers_extract_and_dump (args.dump_path, &remote_args); ret |= dump_header (args.dump_path); if (!remote_args.relative_time) ret |= dump_dmsg (args.dump_path); if (!ret) cleanup_dev (); goto exit; } if (!args.relative_time) { /* manually started */ in_initrd = am_in_initrd (); if (in_initrd && sanity_check_initrd ()) goto exit; } pid = bootchart_find_running_pid (NULL); if (args.probe_running) { clean_environment = pid < 0; ret = pid < 0; goto exit; } else { if (pid >= 0) { clean_environment = 0; fprintf (stderr, "bootchart collector already running as pid %d, exiting...\n", pid); goto exit; } } /* defaults */ if (!args.hz) args.hz = 50; for (i = 0; fds [i]; i++) { char *path = malloc (strlen (PROC_PATH) + strlen (fd_names[i]) + 1); strcpy (path, PROC_PATH); strcat (path, fd_names[i]); *fds[i] = open (path, O_RDONLY); if (*fds[i] < 0) { fprintf (stderr, "error opening '%s': %s'\n", path, strerror (errno)); exit (1); } } stat_file = buffer_file_new (&map, "proc_stat.log"); disk_file = buffer_file_new (&map, "proc_diskstats.log"); if ( (use_taskstat = init_taskstat()) ) per_pid_file = buffer_file_new (&map, "taskstats.log"); else per_pid_file = buffer_file_new (&map, "proc_ps.log"); meminfo_file = buffer_file_new (&map, "proc_meminfo.log"); pid_ev_cl.cmdline_file = buffer_file_new (&map, "cmdline2.log"); pid_ev_cl.paternity_file = buffer_file_new (&map, "paternity.log"); if (!stat_file || !disk_file || !per_pid_file || !meminfo_file || !pid_ev_cl.cmdline_file || !pid_ev_cl.paternity_file) { fprintf (stderr, "Error allocating output buffers\n"); return 1; } scanner = pid_scanner_new_netlink (pid_event_cb, &pid_ev_cl); if (!scanner) scanner = pid_scanner_new_proc (PROC_PATH, pid_event_cb, &pid_ev_cl); if (!scanner) return 1; if (args.relative_time) { reltime = get_uptime (uptime_fd); if (! reltime) exit (1); } while (1) { pid_t pid; char uptime[80]; size_t uptimelen; unsigned long u; if (in_initrd) { if (have_dev_tmpfs ()) { if (chroot_into_dev ()) { fprintf (stderr, "failed to chroot into /dev - exiting so run_init can proceed\n"); return 1; } in_initrd = 0; } } u = get_uptime (uptime_fd); if (!u) return 1; uptimelen = sprintf (uptime, "%lu\n", u - reltime); buffer_file_dump_frame_with_timestamp (stat_file, stat_fd, uptime, uptimelen); buffer_file_dump_frame_with_timestamp (disk_file, disk_fd, uptime, uptimelen); buffer_file_dump_frame_with_timestamp (meminfo_file, meminfo_fd, uptime, uptimelen); /* output data for each pid */ buffer_file_append (per_pid_file, uptime, uptimelen); pid_scanner_restart (scanner); while ((pid = pid_scanner_next (scanner))) { if (use_taskstat) dump_taskstat (per_pid_file, scanner); else dump_proc_stat (per_pid_file, pid); } buffer_file_append (per_pid_file, "\n", 1); usleep (1000000 / args.hz); } /* * In reality - we are always killed before we reach * this point */ if (use_taskstat) { if (close (netlink_socket) < 0) { perror ("failed to close netlink socket"); exit (1); } } for (i = 0; fds [i]; i++) { if (close (*fds[i]) < 0) { fprintf (stderr, "error closing file '%s': %s'\n", fd_names[i], strerror (errno)); return 1; } } ret = 0; exit: arguments_free (&args); if (scanner) ret |= pid_scanner_free (scanner); if (clean_environment) clean_enviroment(); return ret; }