diff --git a/src/sibench/job.go b/src/sibench/job.go index 7f803b8..306f7a1 100644 --- a/src/sibench/job.go +++ b/src/sibench/job.go @@ -44,5 +44,6 @@ type Job struct { /* extra */ useBytes bool // Boolean value to specify if you want the output in Bytes and not Bits + script string // An optional script to be invoked at key points within each phase } diff --git a/src/sibench/main.go b/src/sibench/main.go index 26d58f5..29d1d7a 100644 --- a/src/sibench/main.go +++ b/src/sibench/main.go @@ -83,6 +83,9 @@ type Arguments struct { SliceSize int SliceCount int + // Script options + Script string + // Synthesized options Bucket string BandwidthInBits uint64 @@ -107,29 +110,32 @@ Usage: sibench rados run [-v LEVEL] [-p PORT] [-o FILE] [--individual-stats] [-s SIZE] [-c COUNT] [-b BW] [-x MIX] [-r TIME] [-u TIME] [-d TIME] [-w FACTOR] [-g GEN] [--slice-dir DIR] [--slice-count COUNT] [--slice-size BYTES] [--use-bytes] - [--ceph-pool POOL] [--ceph-user USER] (--ceph-key KEY) + [--ceph-pool POOL] [--ceph-user USER] (--ceph-key KEY) [--script SCRIPT] [--clean-up] [--skip-read-verification] [--servers SERVERS] ... sibench cephfs run [-v LEVEL] [-p PORT] [-o FILE] [--individual-stats] [-s SIZE] [-c COUNT] [-b BW] [-x MIX] [-r TIME] [-u TIME] [-d TIME] [-w FACTOR] [-g GEN] [--slice-dir DIR] [--slice-count COUNT] [--slice-size BYTES] [--use-bytes] - [-m DIR] [--ceph-dir DIR] [--ceph-user USER] (--ceph-key KEY) + [-m DIR] [--ceph-dir DIR] [--ceph-user USER] (--ceph-key KEY) [--script SCRIPT] [--clean-up] [--skip-read-verification] [--servers SERVERS] ... sibench rbd run [-v LEVEL] [-p PORT] [-o FILE] [--individual-stats] [-s SIZE] [-c COUNT] [-b BW] [-x MIX] [-r TIME] [-u TIME] [-d TIME] [-w FACTOR] [-g GEN] [--slice-dir DIR] [--slice-count COUNT] [--slice-size BYTES] [--use-bytes] [--ceph-pool POOL] [--ceph-datapool POOL] [--ceph-user USER] (--ceph-key KEY) - [--clean-up] [--skip-read-verification] [--servers SERVERS] ...` + [--script SCRIPT] [--clean-up] [--skip-read-verification] [--servers SERVERS] + ...` } s += ` sibench block run [-v LEVEL] [-p PORT] [-o FILE] [--individual-stats] [-s SIZE] [-c COUNT] [-b BW] [-x MIX] [-r TIME] [-u TIME] [-d TIME] [-w FACTOR] [-g GEN] [--slice-dir DIR] [--slice-count COUNT] [--slice-size BYTES] [--use-bytes] - [--block-device DEVICE] [--clean-up] [--skip-read-verification] [--servers SERVERS] + [--block-device DEVICE] [--script SCRIPT] [--clean-up] + [--skip-read-verification] [--servers SERVERS] sibench file run [-v LEVEL] [-p PORT] [-o FILE] [--individual-stats] [-s SIZE] [-c COUNT] [-b BW] [-x MIX] [-r TIME] [-u TIME] [-d TIME] [-w FACTOR] [-g GEN] [--slice-dir DIR] [--slice-count COUNT] [--slice-size BYTES] [--use-bytes] - [--file-dir DIR] [--clean-up] [--skip-read-verification] [--servers SERVERS] + [--script SCRIPT] [--file-dir DIR] [--clean-up] [--skip-read-verification] + [--servers SERVERS] sibench -h | --help Options: @@ -167,6 +173,7 @@ Options: --slice-count COUNT The number of slices to construct for workload generation [default: 10000] --slice-size BYTES The size of each slice in bytes. [default: 4097] --profile-prefix FILE Enable profiling, using tne given prefix for any output. + --script SCRIPT Specifies a script to be run at key points in each phase. ` return s } @@ -353,6 +360,7 @@ func startRun(args *Arguments) { j.rampUp = uint64(args.RampUp) j.rampDown = uint64(args.RampDown) j.useBytes = args.UseBytes + j.script = args.Script j.order.JobId = 1 j.order.CleanUpOnClose = args.CleanUp diff --git a/src/sibench/manager.go b/src/sibench/manager.go index 5dbc428..dfcb679 100644 --- a/src/sibench/manager.go +++ b/src/sibench/manager.go @@ -9,6 +9,7 @@ import ( "io" "logger" "os" + "os/exec" "os/signal" "strings" "syscall" @@ -137,6 +138,25 @@ func banner(msg string, padChar byte) string { } +/** + * Runs a script, if we have one, at key points in the run. + */ +func (m *Manager) runScript(phase string, event string) { + if m.job.script == "" { + return + } + + logger.Debugf("Running phase script: '%s %s %s'\n", m.job.script, phase, event) + + cmd := exec.Command(m.job.script, phase, event) + err := cmd.Run() + + if err != nil { + logger.Errorf("Failure running phase script: '%s %s %ws' - %v\n", m.job.script, phase, event, err) + } +} + + /* * Sends an operation request to the servers. * If waitForResponse is true, then we block until all the servers have responded. @@ -404,9 +424,19 @@ func (m *Manager) runPhaseForTime(msg string, secs uint64, startOp Opcode, stopO logger.Infof("%v: %v\n", i, summary.String(m.job.order.ObjectSize, m.job.useBytes)) i++ - // Draw some lines to indicate the ramp-up/ramp-down demarcation. - if (uint64(i) == m.job.rampUp) || (uint64(i) == m.job.rampUp + m.job.runTime) { + isRampUp := (uint64(i) == m.job.rampUp) + isRampDown := (uint64(i) == m.job.rampUp + m.job.runTime) + + if isRampUp || isRampDown { + // Draw some lines to indicate the ramp-up/ramp-down demarcation. logger.Infof("-----------------------------------------------------------\n") + + // Run the script (if we have one) with suitable args. + if isRampUp { + go m.runScript(msg, "UP") + } else { + go m.runScript(msg, "DOWN") + } } summary.Zero()