perfmonger 0.6.1 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -13
- data/.gitignore +6 -0
- data/.tachikoma.yml +1 -0
- data/.travis.yml +18 -6
- data/Gemfile +1 -3
- data/Guardfile +26 -0
- data/NEWS +21 -0
- data/README.md +8 -9
- data/Rakefile +33 -1
- data/core/Makefile +23 -0
- data/core/build.sh +48 -0
- data/core/perfmonger-player.go +165 -0
- data/core/perfmonger-recorder.go +296 -0
- data/core/perfmonger-summarizer.go +207 -0
- data/core/subsystem/Makefile +3 -0
- data/core/subsystem/perfmonger.go +60 -0
- data/core/subsystem/perfmonger_darwin.go +22 -0
- data/core/subsystem/perfmonger_linux.go +292 -0
- data/core/subsystem/perfmonger_linux_test.go +73 -0
- data/core/subsystem/stat.go +214 -0
- data/core/subsystem/stat_test.go +281 -0
- data/core/subsystem/usage.go +410 -0
- data/core/subsystem/usage_test.go +496 -0
- data/lib/exec/operationBinding.rb.svn-base +59 -0
- data/lib/exec/perfmonger-player_darwin_amd64 +0 -0
- data/lib/exec/perfmonger-player_linux_386 +0 -0
- data/lib/exec/perfmonger-player_linux_amd64 +0 -0
- data/lib/exec/perfmonger-recorder_darwin_amd64 +0 -0
- data/lib/exec/perfmonger-recorder_linux_386 +0 -0
- data/lib/exec/perfmonger-recorder_linux_amd64 +0 -0
- data/lib/exec/perfmonger-summarizer_darwin_amd64 +0 -0
- data/lib/exec/perfmonger-summarizer_linux_386 +0 -0
- data/lib/exec/perfmonger-summarizer_linux_amd64 +0 -0
- data/lib/exec/perfmonger-summary_linux_386 +0 -0
- data/lib/exec/perfmonger-summary_linux_amd64 +0 -0
- data/lib/perfmonger/cli.rb +8 -3
- data/lib/perfmonger/command/core.rb +62 -0
- data/lib/perfmonger/command/live.rb +39 -0
- data/lib/perfmonger/command/play.rb +56 -0
- data/lib/perfmonger/command/plot.rb +30 -22
- data/lib/perfmonger/command/record.rb +3 -2
- data/lib/perfmonger/command/record_option.rb +40 -59
- data/lib/perfmonger/command/server.rb +7 -2
- data/lib/perfmonger/command/stat.rb +2 -2
- data/lib/perfmonger/command/stat_option.rb +1 -1
- data/lib/perfmonger/command/summary.rb +11 -326
- data/lib/perfmonger/version.rb +1 -3
- data/lib/perfmonger.rb +3 -0
- data/misc/_perfmonger +128 -0
- data/misc/perfmonger-completion.bash +49 -0
- data/perfmonger.gemspec +6 -5
- data/spec/data/busy100.pgr +0 -0
- data/spec/fingerprint_spec.rb +35 -0
- data/spec/live_spec.rb +25 -0
- data/spec/perfmonger_spec.rb +37 -0
- data/spec/play_spec.rb +21 -0
- data/spec/plot_spec.rb +42 -0
- data/spec/record_spec.rb +15 -0
- data/spec/spec_helper.rb +33 -0
- data/spec/stat_spec.rb +15 -0
- data/spec/summary_spec.rb +51 -0
- data/spec/support/aruba.rb +11 -0
- data/wercker.yml +59 -0
- metadata +117 -45
- data/ext/perfmonger/extconf.rb +0 -19
- data/ext/perfmonger/perfmonger.h +0 -58
- data/ext/perfmonger/perfmonger_record.c +0 -754
- data/ext/perfmonger/sysstat/common.c +0 -627
- data/ext/perfmonger/sysstat/common.h +0 -207
- data/ext/perfmonger/sysstat/ioconf.c +0 -515
- data/ext/perfmonger/sysstat/ioconf.h +0 -84
- data/ext/perfmonger/sysstat/iostat.c +0 -1100
- data/ext/perfmonger/sysstat/iostat.h +0 -121
- data/ext/perfmonger/sysstat/libsysstat.h +0 -19
- data/ext/perfmonger/sysstat/mpstat.c +0 -953
- data/ext/perfmonger/sysstat/mpstat.h +0 -79
- data/ext/perfmonger/sysstat/rd_stats.c +0 -2388
- data/ext/perfmonger/sysstat/rd_stats.h +0 -651
- data/ext/perfmonger/sysstat/sysconfig.h +0 -13
- data/test/run-test.sh +0 -39
- data/test/spec/bin_spec.rb +0 -37
- data/test/spec/data/2devices.expected +0 -42
- data/test/spec/data/2devices.output +0 -42
- data/test/spec/spec_helper.rb +0 -20
- data/test/spec/summary_spec.rb +0 -193
- data/test/test-perfmonger.c +0 -145
- data/test/test.h +0 -9
| @@ -0,0 +1,296 @@ | |
| 1 | 
            +
            //usr/bin/env go run $0 $@ ; exit
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            package main
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            import (
         | 
| 6 | 
            +
            	"bufio"
         | 
| 7 | 
            +
            	"encoding/gob"
         | 
| 8 | 
            +
            	"flag"
         | 
| 9 | 
            +
            	"fmt"
         | 
| 10 | 
            +
            	"io"
         | 
| 11 | 
            +
            	"os"
         | 
| 12 | 
            +
            	"os/exec"
         | 
| 13 | 
            +
            	"os/signal"
         | 
| 14 | 
            +
            	"strings"
         | 
| 15 | 
            +
            	"time"
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            	"golang.org/x/crypto/ssh/terminal"
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            	ss "github.com/hayamiz/perfmonger/core/subsystem"
         | 
| 20 | 
            +
            )
         | 
| 21 | 
            +
             | 
| 22 | 
            +
            type RecorderOption struct {
         | 
| 23 | 
            +
            	interval            time.Duration
         | 
| 24 | 
            +
            	no_interval_backoff bool
         | 
| 25 | 
            +
            	timeout             time.Duration
         | 
| 26 | 
            +
            	start_delay         time.Duration
         | 
| 27 | 
            +
            	devsParts           []string
         | 
| 28 | 
            +
            	output              string
         | 
| 29 | 
            +
            	no_cpu              bool
         | 
| 30 | 
            +
            	no_disk             bool
         | 
| 31 | 
            +
            	no_net              bool
         | 
| 32 | 
            +
            	debug               bool
         | 
| 33 | 
            +
            	listDevices         bool
         | 
| 34 | 
            +
            	player_bin          string
         | 
| 35 | 
            +
            	disks               string
         | 
| 36 | 
            +
            	targetDisks         *map[string]bool
         | 
| 37 | 
            +
            }
         | 
| 38 | 
            +
             | 
| 39 | 
            +
            var option RecorderOption
         | 
| 40 | 
            +
             | 
| 41 | 
            +
            // By default, measurement interval backoff is enabled.
         | 
| 42 | 
            +
            // Minimum resoluton guaranteed: BACKOFF_RATIO / BACKOFF_THRESH
         | 
| 43 | 
            +
            const (
         | 
| 44 | 
            +
            	BACKOFF_THRESH = 1000.0
         | 
| 45 | 
            +
            	BACKOFF_RATIO  = 2.0
         | 
| 46 | 
            +
            )
         | 
| 47 | 
            +
             | 
| 48 | 
            +
            func parseArgs() {
         | 
| 49 | 
            +
            	// set options
         | 
| 50 | 
            +
            	flag.DurationVar(&option.interval, "interval",
         | 
| 51 | 
            +
            		time.Second, "Measurement interval")
         | 
| 52 | 
            +
            	flag.BoolVar(&option.no_interval_backoff, "no-interval-backoff",
         | 
| 53 | 
            +
            		false, "Disable interval backoff")
         | 
| 54 | 
            +
            	flag.DurationVar(&option.timeout, "timeout",
         | 
| 55 | 
            +
            		time.Second*0, "Measurement timeout")
         | 
| 56 | 
            +
            	flag.DurationVar(&option.start_delay, "start-delay",
         | 
| 57 | 
            +
            		time.Second*0, "Wait time before measurement")
         | 
| 58 | 
            +
            	flag.StringVar(&option.output, "output",
         | 
| 59 | 
            +
            		"-", "Output file name")
         | 
| 60 | 
            +
            	flag.BoolVar(&option.no_cpu, "no-cpu",
         | 
| 61 | 
            +
            		false, "Do not record CPU usage")
         | 
| 62 | 
            +
            	flag.BoolVar(&option.no_disk, "no-disk",
         | 
| 63 | 
            +
            		false, "Do not record disk usage")
         | 
| 64 | 
            +
            	flag.BoolVar(&option.no_net, "no-net",
         | 
| 65 | 
            +
            		false, "Do not record net usage")
         | 
| 66 | 
            +
            	flag.BoolVar(&option.debug, "debug",
         | 
| 67 | 
            +
            		false, "Enable debug mode")
         | 
| 68 | 
            +
            	flag.BoolVar(&option.listDevices, "list-devices",
         | 
| 69 | 
            +
            		false, "List devices and exits")
         | 
| 70 | 
            +
            	flag.StringVar(&option.disks, "disks",
         | 
| 71 | 
            +
            		"", "Disk devices to be monitored")
         | 
| 72 | 
            +
            	flag.StringVar(&option.player_bin, "player-bin",
         | 
| 73 | 
            +
            		"", "Run perfmonger-player to show JSON output")
         | 
| 74 | 
            +
             | 
| 75 | 
            +
            	flag.Parse()
         | 
| 76 | 
            +
             | 
| 77 | 
            +
            	if option.player_bin == "" && terminal.IsTerminal(int(os.Stdout.Fd())) &&
         | 
| 78 | 
            +
            		option.output == "-" {
         | 
| 79 | 
            +
            		fmt.Fprintf(os.Stderr, "[recording to data.pgr]\n")
         | 
| 80 | 
            +
            		option.output = "data.pgr"
         | 
| 81 | 
            +
            	}
         | 
| 82 | 
            +
             | 
| 83 | 
            +
            	if option.disks == "" {
         | 
| 84 | 
            +
            		option.targetDisks = nil
         | 
| 85 | 
            +
            	} else {
         | 
| 86 | 
            +
            		option.targetDisks = new(map[string]bool)
         | 
| 87 | 
            +
            		*option.targetDisks = make(map[string]bool)
         | 
| 88 | 
            +
            		for _, dev := range strings.Split(option.disks, ",") {
         | 
| 89 | 
            +
            			(*option.targetDisks)[dev] = true
         | 
| 90 | 
            +
            		}
         | 
| 91 | 
            +
            	}
         | 
| 92 | 
            +
             | 
| 93 | 
            +
            	if option.debug {
         | 
| 94 | 
            +
            		os.Stderr.WriteString(
         | 
| 95 | 
            +
            			fmt.Sprintf(
         | 
| 96 | 
            +
            				`== option
         | 
| 97 | 
            +
              - output   : %s
         | 
| 98 | 
            +
              - interval : %s
         | 
| 99 | 
            +
              - debug    : %t
         | 
| 100 | 
            +
              - remainings: %s
         | 
| 101 | 
            +
            `,
         | 
| 102 | 
            +
            				option.output,
         | 
| 103 | 
            +
            				option.interval.String(),
         | 
| 104 | 
            +
            				option.debug,
         | 
| 105 | 
            +
            				fmt.Sprint(flag.Args())))
         | 
| 106 | 
            +
            	}
         | 
| 107 | 
            +
            }
         | 
| 108 | 
            +
             | 
| 109 | 
            +
            func main() {
         | 
| 110 | 
            +
            	var enc *gob.Encoder
         | 
| 111 | 
            +
            	var out *bufio.Writer
         | 
| 112 | 
            +
            	var err error
         | 
| 113 | 
            +
             | 
| 114 | 
            +
            	parseArgs()
         | 
| 115 | 
            +
             | 
| 116 | 
            +
            	hostname, _ := os.Hostname()
         | 
| 117 | 
            +
            	cheader := &ss.CommonHeader{ss.Linux, hostname, time.Now()}
         | 
| 118 | 
            +
             | 
| 119 | 
            +
            	platform_header := ss.NewPlatformHeader()
         | 
| 120 | 
            +
             | 
| 121 | 
            +
            	if option.listDevices {
         | 
| 122 | 
            +
            		for _, name := range platform_header.DevsParts {
         | 
| 123 | 
            +
            			os.Stderr.WriteString(name + "\n")
         | 
| 124 | 
            +
            		}
         | 
| 125 | 
            +
            		return
         | 
| 126 | 
            +
            	}
         | 
| 127 | 
            +
             | 
| 128 | 
            +
            	var player_cmd *exec.Cmd = nil
         | 
| 129 | 
            +
            	var player_stdin io.WriteCloser = nil
         | 
| 130 | 
            +
            	var player_stdout io.ReadCloser = nil
         | 
| 131 | 
            +
             | 
| 132 | 
            +
            	if option.player_bin != "" {
         | 
| 133 | 
            +
            		player_cmd = exec.Command(option.player_bin)
         | 
| 134 | 
            +
            		player_stdin, err = player_cmd.StdinPipe()
         | 
| 135 | 
            +
            		if err != nil {
         | 
| 136 | 
            +
            			fmt.Fprintf(os.Stderr, "Failed to get stdin of %s", option.player_bin)
         | 
| 137 | 
            +
            			player_cmd = nil
         | 
| 138 | 
            +
            			player_stdin = nil
         | 
| 139 | 
            +
            		}
         | 
| 140 | 
            +
            		player_stdout, err = player_cmd.StdoutPipe()
         | 
| 141 | 
            +
            		if err != nil {
         | 
| 142 | 
            +
            			fmt.Fprintf(os.Stderr, "Failed to get stdout of %s", option.player_bin)
         | 
| 143 | 
            +
            			player_cmd = nil
         | 
| 144 | 
            +
            			player_stdin = nil
         | 
| 145 | 
            +
            			player_stdout = nil
         | 
| 146 | 
            +
            		}
         | 
| 147 | 
            +
             | 
| 148 | 
            +
            		err = player_cmd.Start()
         | 
| 149 | 
            +
            		if err != nil {
         | 
| 150 | 
            +
            			fmt.Fprintf(os.Stderr, "Failed to start %s", option.player_bin)
         | 
| 151 | 
            +
            			player_cmd = nil
         | 
| 152 | 
            +
            			player_stdin = nil
         | 
| 153 | 
            +
            			player_stdout = nil
         | 
| 154 | 
            +
            		}
         | 
| 155 | 
            +
             | 
| 156 | 
            +
            		// read stdout of player and write to stdout
         | 
| 157 | 
            +
            		go func() {
         | 
| 158 | 
            +
            			var buf = make([]byte, 4096)
         | 
| 159 | 
            +
            			for {
         | 
| 160 | 
            +
            				n, err := player_stdout.Read(buf)
         | 
| 161 | 
            +
            				if err == io.EOF {
         | 
| 162 | 
            +
            					break
         | 
| 163 | 
            +
            				} else if err != nil {
         | 
| 164 | 
            +
            					panic(err)
         | 
| 165 | 
            +
            				}
         | 
| 166 | 
            +
             | 
| 167 | 
            +
            				if n == 0 {
         | 
| 168 | 
            +
            					continue
         | 
| 169 | 
            +
            				}
         | 
| 170 | 
            +
            				os.Stdout.Write(buf[0:n])
         | 
| 171 | 
            +
            			}
         | 
| 172 | 
            +
            		}()
         | 
| 173 | 
            +
            	}
         | 
| 174 | 
            +
             | 
| 175 | 
            +
            	if option.output == "-" {
         | 
| 176 | 
            +
            		out = bufio.NewWriter(os.Stdout)
         | 
| 177 | 
            +
            		if player_stdin != nil {
         | 
| 178 | 
            +
            			out = bufio.NewWriter(player_stdin)
         | 
| 179 | 
            +
            		}
         | 
| 180 | 
            +
            	} else {
         | 
| 181 | 
            +
            		file, err := os.Create(option.output)
         | 
| 182 | 
            +
            		if err != nil {
         | 
| 183 | 
            +
            			panic(err)
         | 
| 184 | 
            +
            		}
         | 
| 185 | 
            +
            		defer file.Close()
         | 
| 186 | 
            +
             | 
| 187 | 
            +
            		if player_stdin != nil {
         | 
| 188 | 
            +
            			out = bufio.NewWriter(io.MultiWriter(file, player_stdin))
         | 
| 189 | 
            +
            		} else {
         | 
| 190 | 
            +
            			out = bufio.NewWriter(file)
         | 
| 191 | 
            +
            		}
         | 
| 192 | 
            +
            	}
         | 
| 193 | 
            +
             | 
| 194 | 
            +
            	enc = gob.NewEncoder(out)
         | 
| 195 | 
            +
             | 
| 196 | 
            +
            	// Write the beginning sections
         | 
| 197 | 
            +
            	err = enc.Encode(cheader)
         | 
| 198 | 
            +
            	if err != nil {
         | 
| 199 | 
            +
            		panic(err)
         | 
| 200 | 
            +
            	}
         | 
| 201 | 
            +
             | 
| 202 | 
            +
            	err = enc.Encode(platform_header)
         | 
| 203 | 
            +
            	if err != nil {
         | 
| 204 | 
            +
            		panic(err)
         | 
| 205 | 
            +
            	}
         | 
| 206 | 
            +
             | 
| 207 | 
            +
            	// start delay
         | 
| 208 | 
            +
            	time.Sleep(option.start_delay)
         | 
| 209 | 
            +
             | 
| 210 | 
            +
            	var timeout_ch <-chan time.Time
         | 
| 211 | 
            +
            	var timeout_time time.Time
         | 
| 212 | 
            +
            	if option.timeout == time.Second*0 {
         | 
| 213 | 
            +
            		// dummy channel
         | 
| 214 | 
            +
            		timeout_ch = make(<-chan time.Time)
         | 
| 215 | 
            +
            		timeout_time = time.Now()
         | 
| 216 | 
            +
            	} else {
         | 
| 217 | 
            +
            		timeout_ch = time.After(option.timeout)
         | 
| 218 | 
            +
            		timeout_time = time.Now().Add(option.timeout)
         | 
| 219 | 
            +
            	}
         | 
| 220 | 
            +
             | 
| 221 | 
            +
            	// Loops
         | 
| 222 | 
            +
            	sigint_ch := make(chan os.Signal, 1)
         | 
| 223 | 
            +
            	running := true
         | 
| 224 | 
            +
            	next_time := time.Now()
         | 
| 225 | 
            +
            	record := ss.NewStatRecord()
         | 
| 226 | 
            +
            	backoff_counter := 0
         | 
| 227 | 
            +
             | 
| 228 | 
            +
            	// cause SIGINT to break loop
         | 
| 229 | 
            +
            	signal.Notify(sigint_ch, os.Interrupt)
         | 
| 230 | 
            +
             | 
| 231 | 
            +
            	for {
         | 
| 232 | 
            +
            		record.Time = time.Now()
         | 
| 233 | 
            +
             | 
| 234 | 
            +
            		if !option.no_cpu {
         | 
| 235 | 
            +
            			ss.ReadCpuStat(record)
         | 
| 236 | 
            +
            		}
         | 
| 237 | 
            +
            		if !option.no_disk {
         | 
| 238 | 
            +
            			ss.ReadDiskStats(record, option.targetDisks)
         | 
| 239 | 
            +
            		}
         | 
| 240 | 
            +
            		if !option.no_net {
         | 
| 241 | 
            +
            			ss.ReadNetStat(record)
         | 
| 242 | 
            +
            		}
         | 
| 243 | 
            +
             | 
| 244 | 
            +
            		err = enc.Encode(record)
         | 
| 245 | 
            +
            		if err != nil {
         | 
| 246 | 
            +
            			break
         | 
| 247 | 
            +
            		}
         | 
| 248 | 
            +
            		out.Flush()
         | 
| 249 | 
            +
             | 
| 250 | 
            +
            		if !running {
         | 
| 251 | 
            +
            			break
         | 
| 252 | 
            +
            		}
         | 
| 253 | 
            +
             | 
| 254 | 
            +
            		if !option.no_interval_backoff {
         | 
| 255 | 
            +
            			backoff_counter++
         | 
| 256 | 
            +
            			if backoff_counter >= BACKOFF_THRESH {
         | 
| 257 | 
            +
            				backoff_counter -= BACKOFF_THRESH
         | 
| 258 | 
            +
             | 
| 259 | 
            +
            				option.interval *= BACKOFF_RATIO
         | 
| 260 | 
            +
            				if option.interval.Seconds() > 3600.0 {
         | 
| 261 | 
            +
            					option.interval = time.Hour
         | 
| 262 | 
            +
            				}
         | 
| 263 | 
            +
            			}
         | 
| 264 | 
            +
            		}
         | 
| 265 | 
            +
             | 
| 266 | 
            +
            		next_time = next_time.Add(option.interval)
         | 
| 267 | 
            +
             | 
| 268 | 
            +
            		// wait for next iteration
         | 
| 269 | 
            +
            		select {
         | 
| 270 | 
            +
            		case <-sigint_ch:
         | 
| 271 | 
            +
            			running = false
         | 
| 272 | 
            +
            			break
         | 
| 273 | 
            +
            		case <-timeout_ch:
         | 
| 274 | 
            +
            			running = false
         | 
| 275 | 
            +
            			break
         | 
| 276 | 
            +
            		case <-time.After(next_time.Sub(time.Now())):
         | 
| 277 | 
            +
            			break
         | 
| 278 | 
            +
            		}
         | 
| 279 | 
            +
             | 
| 280 | 
            +
            		// If next_time and timeout_time is very close,
         | 
| 281 | 
            +
            		// avoid recording twice in a very short time
         | 
| 282 | 
            +
            		if option.timeout != time.Second*0 &&
         | 
| 283 | 
            +
            			timeout_time.Sub(next_time).Seconds() < 0.01 {
         | 
| 284 | 
            +
            			running = false
         | 
| 285 | 
            +
            		}
         | 
| 286 | 
            +
            	}
         | 
| 287 | 
            +
             | 
| 288 | 
            +
            	out.Flush()
         | 
| 289 | 
            +
             | 
| 290 | 
            +
            	if player_stdin != nil {
         | 
| 291 | 
            +
            		player_stdin.Close()
         | 
| 292 | 
            +
            		_ = player_cmd.Wait()
         | 
| 293 | 
            +
            	}
         | 
| 294 | 
            +
             | 
| 295 | 
            +
            	return
         | 
| 296 | 
            +
            }
         | 
| @@ -0,0 +1,207 @@ | |
| 1 | 
            +
            //usr/bin/env go run $0 $@ ; exit
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            package main
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            import (
         | 
| 6 | 
            +
            	"bytes"
         | 
| 7 | 
            +
            	"encoding/gob"
         | 
| 8 | 
            +
            	"flag"
         | 
| 9 | 
            +
            	"fmt"
         | 
| 10 | 
            +
            	"io"
         | 
| 11 | 
            +
            	"os"
         | 
| 12 | 
            +
            	"sort"
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            	ss "github.com/hayamiz/perfmonger/core/subsystem"
         | 
| 15 | 
            +
            )
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            type SummaryOption struct {
         | 
| 18 | 
            +
            	logfile string
         | 
| 19 | 
            +
            	title   string
         | 
| 20 | 
            +
            	json    bool
         | 
| 21 | 
            +
            }
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            var option SummaryOption
         | 
| 24 | 
            +
             | 
| 25 | 
            +
            func parseArgs() {
         | 
| 26 | 
            +
            	flag.BoolVar(&option.json, "json",
         | 
| 27 | 
            +
            		false, "Show summary in JSON")
         | 
| 28 | 
            +
            	flag.StringVar(&option.title, "title",
         | 
| 29 | 
            +
            		"", "Title of summary")
         | 
| 30 | 
            +
             | 
| 31 | 
            +
            	flag.Parse()
         | 
| 32 | 
            +
             | 
| 33 | 
            +
            	if len(flag.Args()) < 1 {
         | 
| 34 | 
            +
            		os.Exit(1)
         | 
| 35 | 
            +
            	}
         | 
| 36 | 
            +
             | 
| 37 | 
            +
            	option.logfile = flag.Args()[0]
         | 
| 38 | 
            +
            }
         | 
| 39 | 
            +
             | 
| 40 | 
            +
            func main() {
         | 
| 41 | 
            +
            	var cheader ss.CommonHeader
         | 
| 42 | 
            +
            	var pheader ss.PlatformHeader
         | 
| 43 | 
            +
             | 
| 44 | 
            +
            	parseArgs()
         | 
| 45 | 
            +
             | 
| 46 | 
            +
            	f, err := os.Open(option.logfile)
         | 
| 47 | 
            +
            	if err != nil {
         | 
| 48 | 
            +
            		panic(err)
         | 
| 49 | 
            +
            	}
         | 
| 50 | 
            +
            	dec := gob.NewDecoder(f)
         | 
| 51 | 
            +
             | 
| 52 | 
            +
            	err = dec.Decode(&cheader)
         | 
| 53 | 
            +
            	if err == io.EOF {
         | 
| 54 | 
            +
            		return
         | 
| 55 | 
            +
            	}
         | 
| 56 | 
            +
            	if err != nil {
         | 
| 57 | 
            +
            		panic(err)
         | 
| 58 | 
            +
            	}
         | 
| 59 | 
            +
            	err = dec.Decode(&pheader)
         | 
| 60 | 
            +
            	if err == io.EOF {
         | 
| 61 | 
            +
            		return
         | 
| 62 | 
            +
            	}
         | 
| 63 | 
            +
            	if err != nil {
         | 
| 64 | 
            +
            		panic(err)
         | 
| 65 | 
            +
            	}
         | 
| 66 | 
            +
             | 
| 67 | 
            +
            	var fst_record ss.StatRecord
         | 
| 68 | 
            +
            	// read first record
         | 
| 69 | 
            +
            	err = dec.Decode(&fst_record)
         | 
| 70 | 
            +
            	if err == io.EOF {
         | 
| 71 | 
            +
            		return
         | 
| 72 | 
            +
            	} else if err != nil {
         | 
| 73 | 
            +
            		panic(err)
         | 
| 74 | 
            +
            	}
         | 
| 75 | 
            +
             | 
| 76 | 
            +
            	// loop until last line
         | 
| 77 | 
            +
            	var lst_records [2]ss.StatRecord
         | 
| 78 | 
            +
            	idx := 0
         | 
| 79 | 
            +
            	for {
         | 
| 80 | 
            +
            		err = dec.Decode(&lst_records[idx])
         | 
| 81 | 
            +
            		if err == io.EOF {
         | 
| 82 | 
            +
            			idx ^= 1
         | 
| 83 | 
            +
            			break
         | 
| 84 | 
            +
            		} else if err != nil {
         | 
| 85 | 
            +
            			panic(err)
         | 
| 86 | 
            +
            		}
         | 
| 87 | 
            +
             | 
| 88 | 
            +
            		idx ^= 1
         | 
| 89 | 
            +
            	}
         | 
| 90 | 
            +
             | 
| 91 | 
            +
            	lst_record := lst_records[idx]
         | 
| 92 | 
            +
             | 
| 93 | 
            +
            	var cpu_usage *ss.CpuUsage = nil
         | 
| 94 | 
            +
            	var disk_usage *ss.DiskUsage = nil
         | 
| 95 | 
            +
            	var net_usage *ss.NetUsage = nil
         | 
| 96 | 
            +
             | 
| 97 | 
            +
            	if fst_record.Cpu != nil && lst_record.Cpu != nil {
         | 
| 98 | 
            +
            		cpu_usage, err = ss.GetCpuUsage(fst_record.Cpu, lst_record.Cpu)
         | 
| 99 | 
            +
            	}
         | 
| 100 | 
            +
             | 
| 101 | 
            +
            	if fst_record.Disk != nil && lst_record.Disk != nil {
         | 
| 102 | 
            +
            		disk_usage, err = ss.GetDiskUsage(
         | 
| 103 | 
            +
            			fst_record.Time, fst_record.Disk,
         | 
| 104 | 
            +
            			lst_record.Time, lst_record.Disk)
         | 
| 105 | 
            +
            	}
         | 
| 106 | 
            +
             | 
| 107 | 
            +
            	if fst_record.Disk != nil && lst_record.Disk != nil {
         | 
| 108 | 
            +
            		net_usage, err = ss.GetNetUsage(
         | 
| 109 | 
            +
            			fst_record.Time, fst_record.Net,
         | 
| 110 | 
            +
            			lst_record.Time, lst_record.Net)
         | 
| 111 | 
            +
            	}
         | 
| 112 | 
            +
             | 
| 113 | 
            +
            	interval := lst_record.Time.Sub(fst_record.Time)
         | 
| 114 | 
            +
             | 
| 115 | 
            +
            	if option.json {
         | 
| 116 | 
            +
            		buf := bytes.NewBuffer([]byte{})
         | 
| 117 | 
            +
             | 
| 118 | 
            +
            		buf.WriteString(fmt.Sprintf(`{"exectime":%.3f`, interval.Seconds()))
         | 
| 119 | 
            +
            		if cpu_usage != nil {
         | 
| 120 | 
            +
            			buf.WriteString(`,"cpu":`)
         | 
| 121 | 
            +
            			cpu_usage.WriteJsonTo(buf)
         | 
| 122 | 
            +
            		}
         | 
| 123 | 
            +
             | 
| 124 | 
            +
            		if disk_usage != nil {
         | 
| 125 | 
            +
            			buf.WriteString(`,"disk":`)
         | 
| 126 | 
            +
            			disk_usage.WriteJsonTo(buf)
         | 
| 127 | 
            +
            		}
         | 
| 128 | 
            +
             | 
| 129 | 
            +
            		if disk_usage != nil {
         | 
| 130 | 
            +
            			buf.WriteString(`,"net":`)
         | 
| 131 | 
            +
            			net_usage.WriteJsonTo(buf)
         | 
| 132 | 
            +
            		}
         | 
| 133 | 
            +
             | 
| 134 | 
            +
            		buf.WriteByte('}')
         | 
| 135 | 
            +
             | 
| 136 | 
            +
            		fmt.Println(buf.String())
         | 
| 137 | 
            +
            	} else {
         | 
| 138 | 
            +
            		if option.title == "" {
         | 
| 139 | 
            +
            			fmt.Println("== performance summary ==")
         | 
| 140 | 
            +
            		} else {
         | 
| 141 | 
            +
            			fmt.Printf("== performance summary of '%s' ==\n", option.title)
         | 
| 142 | 
            +
            		}
         | 
| 143 | 
            +
            		fmt.Printf(`
         | 
| 144 | 
            +
            Duration: %.3f sec
         | 
| 145 | 
            +
             | 
| 146 | 
            +
            `,
         | 
| 147 | 
            +
            			interval.Seconds())
         | 
| 148 | 
            +
            		if cpu_usage != nil {
         | 
| 149 | 
            +
            			fmt.Printf(`* Average CPU usage (MAX: %d %%)
         | 
| 150 | 
            +
              * Non-idle usage: %.2f %%
         | 
| 151 | 
            +
                   %%usr: %.2f %%
         | 
| 152 | 
            +
                   %%sys: %.2f %%
         | 
| 153 | 
            +
                   %%irq: %.2f %%
         | 
| 154 | 
            +
                  %%soft: %.2f %%
         | 
| 155 | 
            +
                 %%other: %.2f %%
         | 
| 156 | 
            +
              * Idle usage: %.2f %%
         | 
| 157 | 
            +
                %%iowait: %.2f %%
         | 
| 158 | 
            +
                  %%idle: %.2f %%
         | 
| 159 | 
            +
             | 
| 160 | 
            +
            `,
         | 
| 161 | 
            +
            				100*cpu_usage.NumCore,
         | 
| 162 | 
            +
            				100.0*float64(cpu_usage.NumCore)-cpu_usage.All.Idle-cpu_usage.All.Iowait,
         | 
| 163 | 
            +
            				cpu_usage.All.User+cpu_usage.All.Nice,
         | 
| 164 | 
            +
            				cpu_usage.All.Sys,
         | 
| 165 | 
            +
            				cpu_usage.All.Hardirq,
         | 
| 166 | 
            +
            				cpu_usage.All.Softirq,
         | 
| 167 | 
            +
            				cpu_usage.All.Steal,
         | 
| 168 | 
            +
            				cpu_usage.All.Idle+cpu_usage.All.Iowait,
         | 
| 169 | 
            +
            				cpu_usage.All.Iowait, cpu_usage.All.Idle)
         | 
| 170 | 
            +
            		}
         | 
| 171 | 
            +
             | 
| 172 | 
            +
            		if disk_usage != nil {
         | 
| 173 | 
            +
            			devices := []string{}
         | 
| 174 | 
            +
             | 
| 175 | 
            +
            			for device, _ := range *disk_usage {
         | 
| 176 | 
            +
            				if device != "total" {
         | 
| 177 | 
            +
            					devices = append(devices, device)
         | 
| 178 | 
            +
            				}
         | 
| 179 | 
            +
            			}
         | 
| 180 | 
            +
            			sort.Strings(devices)
         | 
| 181 | 
            +
            			if len(devices) > 1 {
         | 
| 182 | 
            +
            				devices = append(devices, "total")
         | 
| 183 | 
            +
            			}
         | 
| 184 | 
            +
             | 
| 185 | 
            +
            			for _, device := range devices {
         | 
| 186 | 
            +
            				e := (*disk_usage)[device]
         | 
| 187 | 
            +
            				fmt.Printf(`* Average DEVICE usage: %s
         | 
| 188 | 
            +
                    read IOPS: %.2f
         | 
| 189 | 
            +
                   write IOPS: %.2f
         | 
| 190 | 
            +
              read throughput: %.2f MB/s
         | 
| 191 | 
            +
             write throughput: %.2f MB/s
         | 
| 192 | 
            +
                 read latency: %.1f usec
         | 
| 193 | 
            +
                write latency: %.1f usec
         | 
| 194 | 
            +
                  read amount: %.2f MB
         | 
| 195 | 
            +
                 write amount: %.2f MB
         | 
| 196 | 
            +
             | 
| 197 | 
            +
            `,
         | 
| 198 | 
            +
            					device,
         | 
| 199 | 
            +
            					e.RdIops, e.WrIops,
         | 
| 200 | 
            +
            					e.RdSecps*512.0/1024.0/1024.0, e.WrSecps*512.0/1024.0/1024.0,
         | 
| 201 | 
            +
            					e.RdLatency*1000.0, e.WrLatency*1000.0,
         | 
| 202 | 
            +
            					float64(e.RdSectors*512)/1024.0/1024.0,
         | 
| 203 | 
            +
            					float64(e.WrSectors*512)/1024.0/1024.0)
         | 
| 204 | 
            +
            			}
         | 
| 205 | 
            +
            		}
         | 
| 206 | 
            +
            	}
         | 
| 207 | 
            +
            }
         | 
| @@ -0,0 +1,60 @@ | |
| 1 | 
            +
            package subsystem
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            import (
         | 
| 4 | 
            +
            	"time"
         | 
| 5 | 
            +
            )
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            /*
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            PerfMonger binary format:
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            1. Common header
         | 
| 12 | 
            +
              * platform type tag
         | 
| 13 | 
            +
              * host info
         | 
| 14 | 
            +
              * timestamp
         | 
| 15 | 
            +
              * ...
         | 
| 16 | 
            +
            2. Platform-dependent header
         | 
| 17 | 
            +
              * List of devices
         | 
| 18 | 
            +
              * List of NICs
         | 
| 19 | 
            +
              * List of IRQs
         | 
| 20 | 
            +
              * CPU topology
         | 
| 21 | 
            +
              * ...
         | 
| 22 | 
            +
            3. Record section
         | 
| 23 | 
            +
              * Platform-dependent record data stream
         | 
| 24 | 
            +
             | 
| 25 | 
            +
            */
         | 
| 26 | 
            +
             | 
| 27 | 
            +
            //
         | 
| 28 | 
            +
            // Common header
         | 
| 29 | 
            +
            //
         | 
| 30 | 
            +
             | 
| 31 | 
            +
            const (
         | 
| 32 | 
            +
            	Linux  = 1
         | 
| 33 | 
            +
            	Darwin = 2
         | 
| 34 | 
            +
            )
         | 
| 35 | 
            +
             | 
| 36 | 
            +
            type PlatformType int
         | 
| 37 | 
            +
             | 
| 38 | 
            +
            type CommonHeader struct {
         | 
| 39 | 
            +
            	Platform  PlatformType
         | 
| 40 | 
            +
            	Hostname  string
         | 
| 41 | 
            +
            	StartTime time.Time
         | 
| 42 | 
            +
            }
         | 
| 43 | 
            +
             | 
| 44 | 
            +
            //
         | 
| 45 | 
            +
            // Platform-dependent header
         | 
| 46 | 
            +
            //
         | 
| 47 | 
            +
             | 
| 48 | 
            +
            type LinuxDevice struct {
         | 
| 49 | 
            +
            	Name  string
         | 
| 50 | 
            +
            	Parts []string
         | 
| 51 | 
            +
            }
         | 
| 52 | 
            +
             | 
| 53 | 
            +
            type LinuxHeader struct {
         | 
| 54 | 
            +
            	Devices   map[string]LinuxDevice
         | 
| 55 | 
            +
            	DevsParts []string
         | 
| 56 | 
            +
            }
         | 
| 57 | 
            +
             | 
| 58 | 
            +
            type DarwinHeader struct {
         | 
| 59 | 
            +
            	DevsParts []string
         | 
| 60 | 
            +
            }
         | 
| @@ -0,0 +1,22 @@ | |
| 1 | 
            +
            // +build darwin
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            package subsystem
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            type PlatformHeader DarwinHeader
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            func NewPlatformHeader() *DarwinHeader {
         | 
| 8 | 
            +
            	header := new(DarwinHeader)
         | 
| 9 | 
            +
            	return header
         | 
| 10 | 
            +
            }
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            func ReadCpuStat(record *StatRecord) error {
         | 
| 13 | 
            +
            	return nil
         | 
| 14 | 
            +
            }
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            func ReadDiskStats(record *StatRecord, targets *map[string]bool) error {
         | 
| 17 | 
            +
            	return nil
         | 
| 18 | 
            +
            }
         | 
| 19 | 
            +
             | 
| 20 | 
            +
            func ReadNetStat(record *StatRecord) error {
         | 
| 21 | 
            +
            	return nil
         | 
| 22 | 
            +
            }
         |