func main() { var enc *gob.Encoder var out *bufio.Writer var err error // Need to check '-background' before parsing args is_background := false for _, arg := range os.Args { if arg == "-background" { is_background = true } } if is_background { // Find existing session, or create new one user, err := user.Current() if err != nil { panic(err) } session_file := path.Join(os.TempDir(), fmt.Sprintf("perfmonger-%s-session.pid", user.Username)) lockfile := path.Join(os.TempDir(), ".perfmonger.lock") // make lock file if not exists session_exists := false if _, err := os.Stat(lockfile); err != nil { ioutil.WriteFile(lockfile, []byte(""), 0644) } fd, _ := syscall.Open(lockfile, syscall.O_RDONLY, 0000) syscall.Flock(fd, syscall.LOCK_EX) if _, err := os.Stat(session_file); err == nil { pidstr, err := ioutil.ReadFile(session_file) pid, err := strconv.Atoi(string(pidstr)) if err != nil { goto MakeNewSession } // check if PID in session file is valid proc, err := os.FindProcess(pid) err = proc.Signal(syscall.Signal(0)) if err == nil { session_exists = true goto Unlock } } MakeNewSession: err = ioutil.WriteFile(session_file, []byte(strconv.Itoa(os.Getpid())), 0644) if err != nil { panic(err) } defer os.Remove(session_file) Unlock: syscall.Flock(fd, syscall.LOCK_UN) syscall.Close(fd) if session_exists { fmt.Fprintf(os.Stderr, "[ERROR] another perfmonger is already running in background mode\n") return } } parseArgs() hostname, _ := os.Hostname() cheader := &ss.CommonHeader{ss.Linux, hostname, time.Now()} platform_header := ss.NewPlatformHeader() if option.listDevices { for _, name := range platform_header.DevsParts { os.Stderr.WriteString(name + "\n") } return } var player_cmd *exec.Cmd = nil var player_stdin io.WriteCloser = nil var player_stdout io.ReadCloser = nil if option.player_bin != "" { player_cmd = exec.Command(option.player_bin) player_stdin, err = player_cmd.StdinPipe() if err != nil { fmt.Fprintf(os.Stderr, "Failed to get stdin of %s", option.player_bin) player_cmd = nil player_stdin = nil } player_stdout, err = player_cmd.StdoutPipe() if err != nil { fmt.Fprintf(os.Stderr, "Failed to get stdout of %s", option.player_bin) player_cmd = nil player_stdin = nil player_stdout = nil } err = player_cmd.Start() if err != nil { fmt.Fprintf(os.Stderr, "Failed to start %s", option.player_bin) player_cmd = nil player_stdin = nil player_stdout = nil } // read stdout of player and write to stdout go func() { var buf = make([]byte, 4096) for { n, err := player_stdout.Read(buf) if err == io.EOF { break } else if err != nil { panic(err) } if n == 0 { continue } os.Stdout.Write(buf[0:n]) } }() } if option.output == "-" { out = bufio.NewWriter(os.Stdout) if player_stdin != nil { out = bufio.NewWriter(player_stdin) } } else { file, err := os.Create(option.output) if err != nil { panic(err) } defer file.Close() if player_stdin != nil { out = bufio.NewWriter(io.MultiWriter(file, player_stdin)) } else { out = bufio.NewWriter(file) } } enc = gob.NewEncoder(out) // Write the beginning sections err = enc.Encode(cheader) if err != nil { panic(err) } err = enc.Encode(platform_header) if err != nil { panic(err) } // start delay time.Sleep(option.start_delay) var timeout_ch <-chan time.Time var timeout_time time.Time if option.timeout == time.Second*0 { // dummy channel timeout_ch = make(<-chan time.Time) timeout_time = time.Now() } else { timeout_ch = time.After(option.timeout) timeout_time = time.Now().Add(option.timeout) } // Loops sigint_ch := make(chan os.Signal, 1) running := true next_time := time.Now() record := ss.NewStatRecord() backoff_counter := 0 // cause SIGINT to break loop signal.Notify(sigint_ch, os.Interrupt) for { record.Time = time.Now() if !option.no_cpu { ss.ReadCpuStat(record) } if !option.no_intr { ss.ReadInterruptStat(record) } if !option.no_disk { ss.ReadDiskStats(record, option.targetDisks) } if !option.no_net { ss.ReadNetStat(record) } err = enc.Encode(record) if err != nil { break } out.Flush() if !running { break } if !option.no_interval_backoff { backoff_counter++ if backoff_counter >= BACKOFF_THRESH { backoff_counter -= BACKOFF_THRESH option.interval *= BACKOFF_RATIO if option.interval.Seconds() > 3600.0 { option.interval = time.Hour } } } next_time = next_time.Add(option.interval) // wait for next iteration select { case <-sigint_ch: running = false break case <-timeout_ch: running = false break case <-time.After(next_time.Sub(time.Now())): break } // If next_time and timeout_time is very close, // avoid recording twice in a very short time if option.timeout != time.Second*0 && timeout_time.Sub(next_time).Seconds() < 0.01 { running = false } } out.Flush() if player_stdin != nil { player_stdin.Close() _ = player_cmd.Wait() } return }
func main() { var enc *gob.Encoder var out *bufio.Writer var err error parseArgs() hostname, _ := os.Hostname() cheader := &ss.CommonHeader{ss.Linux, hostname, time.Now()} platform_header := ss.NewPlatformHeader() if option.listDevices { for _, name := range platform_header.DevsParts { os.Stderr.WriteString(name + "\n") } return } var player_cmd *exec.Cmd = nil var player_stdin io.WriteCloser = nil var player_stdout io.ReadCloser = nil if option.player_bin != "" { player_cmd = exec.Command(option.player_bin) player_stdin, err = player_cmd.StdinPipe() if err != nil { fmt.Fprintf(os.Stderr, "Failed to get stdin of %s", option.player_bin) player_cmd = nil player_stdin = nil } player_stdout, err = player_cmd.StdoutPipe() if err != nil { fmt.Fprintf(os.Stderr, "Failed to get stdout of %s", option.player_bin) player_cmd = nil player_stdin = nil player_stdout = nil } err = player_cmd.Start() if err != nil { fmt.Fprintf(os.Stderr, "Failed to start %s", option.player_bin) player_cmd = nil player_stdin = nil player_stdout = nil } // read stdout of player and write to stdout go func() { var buf = make([]byte, 4096) for { n, err := player_stdout.Read(buf) if err == io.EOF { break } else if err != nil { panic(err) } if n == 0 { continue } os.Stdout.Write(buf[0:n]) } }() } if option.output == "-" { out = bufio.NewWriter(os.Stdout) if player_stdin != nil { out = bufio.NewWriter(player_stdin) } } else { file, err := os.Create(option.output) if err != nil { panic(err) } defer file.Close() if player_stdin != nil { out = bufio.NewWriter(io.MultiWriter(file, player_stdin)) } else { out = bufio.NewWriter(file) } } enc = gob.NewEncoder(out) // Write the beginning sections err = enc.Encode(cheader) if err != nil { panic(err) } err = enc.Encode(platform_header) if err != nil { panic(err) } // start delay time.Sleep(option.start_delay) var timeout_ch <-chan time.Time var timeout_time time.Time if option.timeout == time.Second*0 { // dummy channel timeout_ch = make(<-chan time.Time) timeout_time = time.Now() } else { timeout_ch = time.After(option.timeout) timeout_time = time.Now().Add(option.timeout) } // Loops sigint_ch := make(chan os.Signal, 1) running := true next_time := time.Now() record := ss.NewStatRecord() backoff_counter := 0 // cause SIGINT to break loop signal.Notify(sigint_ch, os.Interrupt) for { record.Time = time.Now() if !option.no_cpu { ss.ReadCpuStat(record) } if !option.no_disk { ss.ReadDiskStats(record, option.targetDisks) } if !option.no_net { ss.ReadNetStat(record) } err = enc.Encode(record) if err != nil { break } out.Flush() if !running { break } if !option.no_interval_backoff { backoff_counter++ if backoff_counter >= BACKOFF_THRESH { backoff_counter -= BACKOFF_THRESH option.interval *= BACKOFF_RATIO if option.interval.Seconds() > 3600.0 { option.interval = time.Hour } } } next_time = next_time.Add(option.interval) // wait for next iteration select { case <-sigint_ch: running = false break case <-timeout_ch: running = false break case <-time.After(next_time.Sub(time.Now())): break } // If next_time and timeout_time is very close, // avoid recording twice in a very short time if option.timeout != time.Second*0 && timeout_time.Sub(next_time).Seconds() < 0.01 { running = false } } out.Flush() if player_stdin != nil { player_stdin.Close() _ = player_cmd.Wait() } return }