Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -669,6 +669,10 @@ suffix. Matching multiple components at once is also possible separating them
with a colon; they don't have to be consecutive as long as the ordering is
correct.

With the `-explicit-order` option, the tasks are selected for execution in
order corresponding to the command line arguments that matched them. Note that
this automatically limits spread to use only one worker per system.

For example, assuming the two jobs above, these parameters would all match
at least one of them:

Expand Down
2 changes: 2 additions & 0 deletions cmd/spread/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ var (
seed = flag.Int64("seed", 0, "Seed for job order permutation")
repeat = flag.Int("repeat", 0, "Number of times to repeat each task")
garbageCollect = flag.Bool("gc", false, "Garbage collect backend resources when possible")
explicitOrder = flag.Bool("explicit-order", false, "Order jobs explicitly")
)

func main() {
Expand Down Expand Up @@ -96,6 +97,7 @@ func run() error {
Seed: *seed,
Repeat: *repeat,
GarbageCollect: *garbageCollect,
ExplicitOrder: *explicitOrder,
}

project, err := spread.Load(".")
Expand Down
29 changes: 23 additions & 6 deletions spread/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -742,6 +742,7 @@ func checkSystems(context fmt.Stringer, systems []string) error {

type Filter interface {
Pass(job *Job) bool
PassOrder(*Job) (int, bool)
}

type filterExp struct {
Expand All @@ -755,10 +756,15 @@ type filter struct {
}

func (f *filter) Pass(job *Job) bool {
_, ok := f.PassOrder(job)
return ok
}

func (f *filter) PassOrder(job *Job) (int, bool) {
if len(f.exps) == 0 {
return true
return 0, true
}
for _, exp := range f.exps {
for i, exp := range f.exps {
if exp.firstSample > 0 {
if job.Sample < exp.firstSample {
continue
Expand All @@ -768,10 +774,10 @@ func (f *filter) Pass(job *Job) bool {
}
}
if exp.regexp.MatchString(job.Name) {
return true
return i, true
}
}
return false
return 0, false
}

func NewFilter(args []string) (Filter, error) {
Expand Down Expand Up @@ -846,6 +852,8 @@ func (p *Project) backendNames() []string {
func (p *Project) Jobs(options *Options) ([]*Job, error) {
var jobs []*Job

jobOrder := make(map[string]int)

hasFilter := options.Filter != nil
manualBackends := hasFilter
manualSystems := hasFilter
Expand Down Expand Up @@ -958,8 +966,12 @@ func (p *Project) Jobs(options *Options) ([]*Job, error) {
}
job.Environment = env.Variant(variant)

if options.Filter != nil && !options.Filter.Pass(job) {
continue
if options.Filter != nil {
order, ok := options.Filter.PassOrder(job)
if !ok {
continue
}
jobOrder[job.Name] = order
}

jobs = append(jobs, job)
Expand Down Expand Up @@ -1059,6 +1071,11 @@ func (p *Project) Jobs(options *Options) ([]*Job, error) {
}

sort.Sort(jobsByName(jobs))
if options.ExplicitOrder {
sort.SliceStable(jobs, func(i, j int) bool {
return jobOrder[jobs[i].Name] < jobOrder[jobs[j].Name]
})
}

return jobs, nil
}
Expand Down
20 changes: 16 additions & 4 deletions spread/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ type Options struct {
Seed int64
Repeat int
GarbageCollect bool
ExplicitOrder bool
}

type Runner struct {
Expand Down Expand Up @@ -197,6 +198,9 @@ func (r *Runner) loop() (err error) {
for _, job := range r.pending {
if job.Backend == backend && job.System == system {
if system.Workers > workers[system] {
if workers[system] > 0 && r.options.ExplicitOrder {
break
}
workers[system]++
r.alive++
} else {
Expand Down Expand Up @@ -225,10 +229,18 @@ func (r *Runner) loop() (err error) {
for _, system := range backend.Systems {
n := workers[system]
for i := 0; i < n; i++ {
// Use a different seed per worker, so that the work-stealing
// logic will have a better chance of producing the same
// ordering on each of the workers.
order := rand.New(rand.NewSource(seed + int64(i))).Perm(len(r.pending))
var order []int
if r.options.ExplicitOrder {
order = make([]int, len(r.pending))
for i := range order {
order[i] = i
}
} else {
// Use a different seed per worker, so that the work-stealing
// logic will have a better chance of producing the same
// ordering on each of the workers.
order = rand.New(rand.NewSource(seed + int64(i))).Perm(len(r.pending))
}
go r.worker(backend, system, order)
}
}
Expand Down
Loading