blob: c606d2bd210f2cb1c21171cedfb4175707e8f01a [file] [log] [blame]
borenetdb182c72016-09-30 12:53:12 -07001// Copyright 2016 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5package main
6
7/*
8 Generate the tasks.json file.
9*/
10
11import (
borenetdb182c72016-09-30 12:53:12 -070012 "encoding/json"
Eric Boren27225492017-02-01 15:56:55 -050013 "flag"
borenetdb182c72016-09-30 12:53:12 -070014 "fmt"
Eric Boren27225492017-02-01 15:56:55 -050015 "io/ioutil"
borenetdb182c72016-09-30 12:53:12 -070016 "os"
17 "path"
Eric Boren27225492017-02-01 15:56:55 -050018 "regexp"
borenetdb182c72016-09-30 12:53:12 -070019 "sort"
20 "strings"
Eric Boren4b254b92016-11-08 12:55:32 -050021 "time"
borenetdb182c72016-09-30 12:53:12 -070022
23 "github.com/skia-dev/glog"
borenetdb182c72016-09-30 12:53:12 -070024 "go.skia.org/infra/go/util"
25 "go.skia.org/infra/task_scheduler/go/specs"
26)
27
28const (
Kevin Lubick797ef162016-12-15 10:45:08 -050029 DEFAULT_OS = DEFAULT_OS_LINUX
30 DEFAULT_OS_LINUX = "Ubuntu-14.04"
borenetdb182c72016-09-30 12:53:12 -070031
borenetdb182c72016-09-30 12:53:12 -070032 // Name prefix for upload jobs.
33 PREFIX_UPLOAD = "Upload"
34)
35
36var (
37 // "Constants"
38
Eric Boren27225492017-02-01 15:56:55 -050039 // Top-level list of all jobs to run at each commit; loaded from
40 // jobs.json.
41 JOBS []string
42
43 // Mapping of human-friendly Android device names to a pair of {device_type, device_os}.
44 ANDROID_MAPPING map[string][]string
45
46 // General configuration information.
47 CONFIG struct {
Eric Boren965861b2017-02-06 15:38:41 -050048 GsBucketGm string `json:"gs_bucket_gm"`
49 GsBucketNano string `json:"gs_bucket_nano"`
50 NoUpload []string `json:"no_upload"`
51 Pool string `json:"pool"`
borenetdb182c72016-09-30 12:53:12 -070052 }
53
Eric Boren27225492017-02-01 15:56:55 -050054 // Mapping of human-friendly GPU names to PCI IDs.
55 GPU_MAPPING map[string]string
borenetdb182c72016-09-30 12:53:12 -070056
57 // Defines the structure of job names.
58 jobNameSchema *JobNameSchema
Eric Boren27225492017-02-01 15:56:55 -050059
60 // Flags.
Eric Boren1f8be682017-02-07 09:16:30 -050061 androidMapFile = flag.String("android_map", "", "JSON file containing a mapping of human-friendly Android device names to a pair of {device_type, device_os}.")
62 builderNameSchemaFile = flag.String("builder_name_schema", "", "Path to the builder_name_schema.json file. If not specified, uses infra/bots/recipe_modules/builder_name_schema/builder_name_schema.json from this repo.")
63 assetsDir = flag.String("assets_dir", "", "Directory containing assets.")
64 cfgFile = flag.String("cfg_file", "", "JSON file containing general configuration information.")
65 gpuMapFile = flag.String("gpu_map", "", "JSON file containing a mapping of human-friendly GPU names to PCI IDs.")
66 jobsFile = flag.String("jobs", "", "JSON file containing jobs to run.")
borenetdb182c72016-09-30 12:53:12 -070067)
68
Eric Boren27225492017-02-01 15:56:55 -050069// linuxGceDimensions are the Swarming dimensions for Linux GCE
70// instances.
71func linuxGceDimensions() []string {
72 return []string{
73 "cpu:x86-64-avx2",
74 "gpu:none",
75 fmt.Sprintf("os:%s", DEFAULT_OS_LINUX),
76 fmt.Sprintf("pool:%s", CONFIG.Pool),
77 }
78}
79
borenetdb182c72016-09-30 12:53:12 -070080// deriveCompileTaskName returns the name of a compile task based on the given
81// job name.
82func deriveCompileTaskName(jobName string, parts map[string]string) string {
83 if parts["role"] == "Housekeeper" {
84 return "Build-Ubuntu-GCC-x86_64-Release-Shared"
85 } else if parts["role"] == "Test" || parts["role"] == "Perf" {
86 task_os := parts["os"]
87 ec := parts["extra_config"]
Kevin Lubickb03b5ac2016-11-14 13:42:27 -050088 ec = strings.TrimSuffix(ec, "_Skpbench")
Ben Wagner46df2a12017-02-21 19:10:24 -050089 ec = strings.TrimSuffix(ec, "_AbandonGpuContext")
90 ec = strings.TrimSuffix(ec, "_PreAbandonGpuContext")
borenetdb182c72016-09-30 12:53:12 -070091 if task_os == "Android" {
92 if ec == "Vulkan" {
93 ec = "Android_Vulkan"
borenetdb182c72016-09-30 12:53:12 -070094 }
borenet52383432016-10-17 10:17:53 -070095 task_os = "Ubuntu"
borenetdb182c72016-09-30 12:53:12 -070096 } else if task_os == "iOS" {
97 ec = task_os
98 task_os = "Mac"
99 } else if strings.Contains(task_os, "Win") {
100 task_os = "Win"
Kevin Lubick893c49e2017-01-17 15:15:40 -0500101 } else if strings.Contains(task_os, "Ubuntu") {
102 task_os = "Ubuntu"
borenetdb182c72016-09-30 12:53:12 -0700103 }
Eric Boren50831302016-11-18 13:10:51 -0500104 jobNameMap := map[string]string{
borenetdb182c72016-09-30 12:53:12 -0700105 "role": "Build",
106 "os": task_os,
107 "compiler": parts["compiler"],
108 "target_arch": parts["arch"],
109 "configuration": parts["configuration"],
Eric Boren50831302016-11-18 13:10:51 -0500110 }
111 if ec != "" {
112 jobNameMap["extra_config"] = ec
113 }
114 name, err := jobNameSchema.MakeJobName(jobNameMap)
borenetdb182c72016-09-30 12:53:12 -0700115 if err != nil {
116 glog.Fatal(err)
117 }
118 return name
119 } else {
120 return jobName
121 }
122}
123
124// swarmDimensions generates swarming bot dimensions for the given task.
125func swarmDimensions(parts map[string]string) []string {
borenetdb182c72016-09-30 12:53:12 -0700126 d := map[string]string{
Eric Boren27225492017-02-01 15:56:55 -0500127 "pool": CONFIG.Pool,
borenetdb182c72016-09-30 12:53:12 -0700128 }
129 if os, ok := parts["os"]; ok {
Eric Boren54ff2fc2016-12-02 12:09:10 -0500130 d["os"] = map[string]string{
Kevin Lubick893c49e2017-01-17 15:15:40 -0500131 "Android": "Android",
132 "Mac": "Mac-10.11",
133 "Ubuntu": DEFAULT_OS_LINUX,
Kevin Lubick9063eca2017-02-01 11:10:32 -0500134 "Ubuntu16": "Ubuntu-16.10",
Kevin Lubick893c49e2017-01-17 15:15:40 -0500135 "Win": "Windows-2008ServerR2-SP1",
136 "Win10": "Windows-10-14393",
137 "Win2k8": "Windows-2008ServerR2-SP1",
138 "Win8": "Windows-8.1-SP0",
139 "iOS": "iOS-9.3.1",
Eric Boren54ff2fc2016-12-02 12:09:10 -0500140 }[os]
Ben Wagner73557372016-12-29 16:27:03 -0500141 // Chrome Golo has a different Windows image.
142 if parts["model"] == "Golo" && os == "Win10" {
143 d["os"] = "Windows-10-10586"
Ben Wagner17f811b2016-12-22 08:40:14 -0500144 }
borenetdb182c72016-09-30 12:53:12 -0700145 } else {
146 d["os"] = DEFAULT_OS
147 }
borenetdb182c72016-09-30 12:53:12 -0700148 if parts["role"] == "Test" || parts["role"] == "Perf" {
149 if strings.Contains(parts["os"], "Android") {
150 // For Android, the device type is a better dimension
151 // than CPU or GPU.
Eric Boren27225492017-02-01 15:56:55 -0500152 deviceInfo, ok := ANDROID_MAPPING[parts["model"]]
153 if !ok {
154 glog.Fatalf("Entry %q not found in Android mapping: %v", parts["model"], ANDROID_MAPPING)
155 }
Eric Boren4b254b92016-11-08 12:55:32 -0500156 d["device_type"] = deviceInfo[0]
157 d["device_os"] = deviceInfo[1]
borenetdb182c72016-09-30 12:53:12 -0700158 } else if strings.Contains(parts["os"], "iOS") {
159 d["device"] = map[string]string{
Eric Boren792079cf2016-11-09 14:03:20 -0500160 "iPadMini4": "iPad5,1",
borenetdb182c72016-09-30 12:53:12 -0700161 }[parts["model"]]
borenetdb182c72016-09-30 12:53:12 -0700162 } else if parts["cpu_or_gpu"] == "CPU" {
163 d["gpu"] = "none"
164 d["cpu"] = map[string]string{
165 "AVX": "x86-64",
166 "AVX2": "x86-64-avx2",
167 "SSE4": "x86-64",
168 }[parts["cpu_or_gpu_value"]]
169 if strings.Contains(parts["os"], "Win") && parts["cpu_or_gpu_value"] == "AVX2" {
170 // AVX2 is not correctly detected on Windows. Fall back on other
171 // dimensions to ensure that we correctly target machines which we know
172 // have AVX2 support.
173 d["cpu"] = "x86-64"
174 d["os"] = "Windows-2008ServerR2-SP1"
175 }
176 } else {
Eric Boren27225492017-02-01 15:56:55 -0500177 gpu, ok := GPU_MAPPING[parts["cpu_or_gpu_value"]]
178 if !ok {
179 glog.Fatalf("Entry %q not found in GPU mapping: %v", parts["cpu_or_gpu_value"], GPU_MAPPING)
180 }
181 d["gpu"] = gpu
Ben Wagner08435892017-02-18 23:28:26 -0500182
183 // Hack: Specify machine_type dimension for NUCs and ShuttleCs. We
184 // temporarily have two types of machines with a GTX960. The only way to
185 // distinguish these bots is by machine_type.
186 machine_type, ok := map[string]string{
187 "NUC6i7KYK": "n1-highcpu-8",
188 "ShuttleC": "n1-standard-8",
189 }[parts["model"]]
190 if ok {
191 d["machine_type"] = machine_type
192 }
borenetdb182c72016-09-30 12:53:12 -0700193 }
194 } else {
195 d["gpu"] = "none"
196 }
197 rv := make([]string, 0, len(d))
198 for k, v := range d {
199 rv = append(rv, fmt.Sprintf("%s:%s", k, v))
200 }
201 sort.Strings(rv)
202 return rv
203}
204
borenetdb182c72016-09-30 12:53:12 -0700205// compile generates a compile task. Returns the name of the last task in the
206// generated chain of tasks, which the Job should add as a dependency.
boreneted20a702016-10-20 11:04:31 -0700207func compile(b *specs.TasksCfgBuilder, name string, parts map[string]string) string {
borenetdb182c72016-09-30 12:53:12 -0700208 // Collect the necessary CIPD packages.
209 pkgs := []*specs.CipdPackage{}
210
211 // Android bots require a toolchain.
212 if strings.Contains(name, "Android") {
borenetdb182c72016-09-30 12:53:12 -0700213 if strings.Contains(name, "Mac") {
boreneted20a702016-10-20 11:04:31 -0700214 pkgs = append(pkgs, b.MustGetCipdPackageFromAsset("android_ndk_darwin"))
Mike Klein86c2c0f2016-11-02 13:13:16 -0400215 } else if strings.Contains(name, "Win") {
Mike Kleine9215f02016-11-02 15:44:26 -0400216 pkg := b.MustGetCipdPackageFromAsset("android_ndk_windows")
217 pkg.Path = "n"
218 pkgs = append(pkgs, pkg)
borenetdb182c72016-09-30 12:53:12 -0700219 } else {
boreneted20a702016-10-20 11:04:31 -0700220 pkgs = append(pkgs, b.MustGetCipdPackageFromAsset("android_ndk_linux"))
borenetdb182c72016-09-30 12:53:12 -0700221 }
Kevin Lubick9c7dcac2017-01-18 09:24:56 -0500222 } else if strings.Contains(name, "Ubuntu") {
223 if strings.Contains(name, "Clang") {
224 pkgs = append(pkgs, b.MustGetCipdPackageFromAsset("clang_linux"))
225 }
226 if strings.Contains(name, "Vulkan") {
227 pkgs = append(pkgs, b.MustGetCipdPackageFromAsset("linux_vulkan_sdk"))
228 }
Mike Klein27dcee12016-11-09 16:31:42 -0500229 } else if strings.Contains(name, "Win") {
boreneted20a702016-10-20 11:04:31 -0700230 pkgs = append(pkgs, b.MustGetCipdPackageFromAsset("win_toolchain"))
borenetdb182c72016-09-30 12:53:12 -0700231 if strings.Contains(name, "Vulkan") {
boreneted20a702016-10-20 11:04:31 -0700232 pkgs = append(pkgs, b.MustGetCipdPackageFromAsset("win_vulkan_sdk"))
borenetdb182c72016-09-30 12:53:12 -0700233 }
234 }
235
236 // Add the task.
boreneted20a702016-10-20 11:04:31 -0700237 b.MustAddTask(name, &specs.TaskSpec{
borenetdb182c72016-09-30 12:53:12 -0700238 CipdPackages: pkgs,
239 Dimensions: swarmDimensions(parts),
240 ExtraArgs: []string{
241 "--workdir", "../../..", "swarm_compile",
skia.buildbots2478c732016-11-04 14:37:26 -0400242 fmt.Sprintf("repository=%s", specs.PLACEHOLDER_REPO),
borenetdb182c72016-09-30 12:53:12 -0700243 fmt.Sprintf("buildername=%s", name),
244 "mastername=fake-master",
245 "buildnumber=2",
246 "slavename=fake-buildslave",
borenet98b2e7a2016-10-13 06:23:45 -0700247 "nobuildbot=True",
borenetdb182c72016-09-30 12:53:12 -0700248 fmt.Sprintf("swarm_out_dir=%s", specs.PLACEHOLDER_ISOLATED_OUTDIR),
249 fmt.Sprintf("revision=%s", specs.PLACEHOLDER_REVISION),
borenet98b2e7a2016-10-13 06:23:45 -0700250 fmt.Sprintf("patch_storage=%s", specs.PLACEHOLDER_PATCH_STORAGE),
skia.buildbots2478c732016-11-04 14:37:26 -0400251 fmt.Sprintf("patch_issue=%s", specs.PLACEHOLDER_ISSUE),
252 fmt.Sprintf("patch_set=%s", specs.PLACEHOLDER_PATCHSET),
borenetdb182c72016-09-30 12:53:12 -0700253 },
254 Isolate: "compile_skia.isolate",
255 Priority: 0.8,
boreneted20a702016-10-20 11:04:31 -0700256 })
Eric Boren8615fe52016-12-12 14:30:12 -0500257 // All compile tasks are runnable as their own Job. Assert that the Job
258 // is listed in JOBS.
259 if !util.In(name, JOBS) {
260 glog.Fatalf("Job %q is missing from the JOBS list!", name)
261 }
borenetdb182c72016-09-30 12:53:12 -0700262 return name
263}
264
265// recreateSKPs generates a RecreateSKPs task. Returns the name of the last
266// task in the generated chain of tasks, which the Job should add as a
267// dependency.
boreneted20a702016-10-20 11:04:31 -0700268func recreateSKPs(b *specs.TasksCfgBuilder, name string) string {
Eric Boren4b254b92016-11-08 12:55:32 -0500269 b.MustAddTask(name, &specs.TaskSpec{
Eric Borenf5a90e82016-11-15 15:18:20 -0500270 CipdPackages: []*specs.CipdPackage{},
Eric Boren27225492017-02-01 15:56:55 -0500271 Dimensions: linuxGceDimensions(),
Eric Borenf5a90e82016-11-15 15:18:20 -0500272 ExecutionTimeout: 4 * time.Hour,
Eric Boren4b254b92016-11-08 12:55:32 -0500273 ExtraArgs: []string{
274 "--workdir", "../../..", "swarm_RecreateSKPs",
275 fmt.Sprintf("repository=%s", specs.PLACEHOLDER_REPO),
276 fmt.Sprintf("buildername=%s", name),
277 "mastername=fake-master",
278 "buildnumber=2",
279 "slavename=fake-buildslave",
280 "nobuildbot=True",
281 fmt.Sprintf("swarm_out_dir=%s", specs.PLACEHOLDER_ISOLATED_OUTDIR),
282 fmt.Sprintf("revision=%s", specs.PLACEHOLDER_REVISION),
283 fmt.Sprintf("patch_storage=%s", specs.PLACEHOLDER_PATCH_STORAGE),
284 fmt.Sprintf("patch_issue=%s", specs.PLACEHOLDER_ISSUE),
285 fmt.Sprintf("patch_set=%s", specs.PLACEHOLDER_PATCHSET),
286 },
Eric Borenf5a90e82016-11-15 15:18:20 -0500287 IoTimeout: 40 * time.Minute,
288 Isolate: "compile_skia.isolate",
289 Priority: 0.8,
Eric Boren4b254b92016-11-08 12:55:32 -0500290 })
borenetdb182c72016-09-30 12:53:12 -0700291 return name
292}
293
294// ctSKPs generates a CT SKPs task. Returns the name of the last task in the
295// generated chain of tasks, which the Job should add as a dependency.
boreneted20a702016-10-20 11:04:31 -0700296func ctSKPs(b *specs.TasksCfgBuilder, name string) string {
Eric Boren4b254b92016-11-08 12:55:32 -0500297 b.MustAddTask(name, &specs.TaskSpec{
298 CipdPackages: []*specs.CipdPackage{},
299 Dimensions: []string{"pool:SkiaCT"},
300 ExecutionTimeout: 24 * time.Hour,
301 ExtraArgs: []string{
302 "--workdir", "../../..", "swarm_ct_skps",
303 fmt.Sprintf("repository=%s", specs.PLACEHOLDER_REPO),
304 fmt.Sprintf("buildername=%s", name),
305 "mastername=fake-master",
306 "buildnumber=2",
307 "slavename=fake-buildslave",
308 "nobuildbot=True",
309 fmt.Sprintf("swarm_out_dir=%s", specs.PLACEHOLDER_ISOLATED_OUTDIR),
310 fmt.Sprintf("revision=%s", specs.PLACEHOLDER_REVISION),
311 fmt.Sprintf("patch_storage=%s", specs.PLACEHOLDER_PATCH_STORAGE),
312 fmt.Sprintf("patch_issue=%s", specs.PLACEHOLDER_ISSUE),
313 fmt.Sprintf("patch_set=%s", specs.PLACEHOLDER_PATCHSET),
314 },
315 IoTimeout: time.Hour,
316 Isolate: "ct_skps_skia.isolate",
317 Priority: 0.8,
318 })
borenetdb182c72016-09-30 12:53:12 -0700319 return name
320}
321
322// housekeeper generates a Housekeeper task. Returns the name of the last task
323// in the generated chain of tasks, which the Job should add as a dependency.
boreneted20a702016-10-20 11:04:31 -0700324func housekeeper(b *specs.TasksCfgBuilder, name, compileTaskName string) string {
Eric Boren4b254b92016-11-08 12:55:32 -0500325 b.MustAddTask(name, &specs.TaskSpec{
Eric Boren22f5ef72016-12-02 11:01:33 -0500326 CipdPackages: []*specs.CipdPackage{b.MustGetCipdPackageFromAsset("go")},
Eric Boren4b254b92016-11-08 12:55:32 -0500327 Dependencies: []string{compileTaskName},
Eric Boren27225492017-02-01 15:56:55 -0500328 Dimensions: linuxGceDimensions(),
Eric Boren4b254b92016-11-08 12:55:32 -0500329 ExtraArgs: []string{
330 "--workdir", "../../..", "swarm_housekeeper",
331 fmt.Sprintf("repository=%s", specs.PLACEHOLDER_REPO),
332 fmt.Sprintf("buildername=%s", name),
333 "mastername=fake-master",
334 "buildnumber=2",
335 "slavename=fake-buildslave",
336 "nobuildbot=True",
337 fmt.Sprintf("swarm_out_dir=%s", specs.PLACEHOLDER_ISOLATED_OUTDIR),
338 fmt.Sprintf("revision=%s", specs.PLACEHOLDER_REVISION),
339 fmt.Sprintf("patch_storage=%s", specs.PLACEHOLDER_PATCH_STORAGE),
340 fmt.Sprintf("patch_issue=%s", specs.PLACEHOLDER_ISSUE),
341 fmt.Sprintf("patch_set=%s", specs.PLACEHOLDER_PATCHSET),
342 },
343 Isolate: "housekeeper_skia.isolate",
344 Priority: 0.8,
345 })
borenetdb182c72016-09-30 12:53:12 -0700346 return name
347}
348
borenet2dbbfa52016-10-14 06:32:09 -0700349// infra generates an infra_tests task. Returns the name of the last task in the
350// generated chain of tasks, which the Job should add as a dependency.
boreneted20a702016-10-20 11:04:31 -0700351func infra(b *specs.TasksCfgBuilder, name string) string {
352 b.MustAddTask(name, &specs.TaskSpec{
borenet2dbbfa52016-10-14 06:32:09 -0700353 CipdPackages: []*specs.CipdPackage{},
Eric Boren27225492017-02-01 15:56:55 -0500354 Dimensions: linuxGceDimensions(),
borenet2dbbfa52016-10-14 06:32:09 -0700355 ExtraArgs: []string{
356 "--workdir", "../../..", "swarm_infra",
skia.buildbots2478c732016-11-04 14:37:26 -0400357 fmt.Sprintf("repository=%s", specs.PLACEHOLDER_REPO),
borenet2dbbfa52016-10-14 06:32:09 -0700358 fmt.Sprintf("buildername=%s", name),
359 "mastername=fake-master",
360 "buildnumber=2",
361 "slavename=fake-buildslave",
362 "nobuildbot=True",
363 fmt.Sprintf("swarm_out_dir=%s", specs.PLACEHOLDER_ISOLATED_OUTDIR),
364 fmt.Sprintf("revision=%s", specs.PLACEHOLDER_REVISION),
365 fmt.Sprintf("patch_storage=%s", specs.PLACEHOLDER_PATCH_STORAGE),
skia.buildbots2478c732016-11-04 14:37:26 -0400366 fmt.Sprintf("patch_issue=%s", specs.PLACEHOLDER_ISSUE),
367 fmt.Sprintf("patch_set=%s", specs.PLACEHOLDER_PATCHSET),
borenet2dbbfa52016-10-14 06:32:09 -0700368 },
369 Isolate: "infra_skia.isolate",
370 Priority: 0.8,
boreneted20a702016-10-20 11:04:31 -0700371 })
borenet2dbbfa52016-10-14 06:32:09 -0700372 return name
373}
374
borenetdb182c72016-09-30 12:53:12 -0700375// doUpload indicates whether the given Job should upload its results.
376func doUpload(name string) bool {
Eric Boren27225492017-02-01 15:56:55 -0500377 for _, s := range CONFIG.NoUpload {
378 m, err := regexp.MatchString(s, name)
379 if err != nil {
380 glog.Fatal(err)
381 }
382 if m {
borenetdb182c72016-09-30 12:53:12 -0700383 return false
384 }
385 }
386 return true
387}
388
389// test generates a Test task. Returns the name of the last task in the
390// generated chain of tasks, which the Job should add as a dependency.
boreneted20a702016-10-20 11:04:31 -0700391func test(b *specs.TasksCfgBuilder, name string, parts map[string]string, compileTaskName string, pkgs []*specs.CipdPackage) string {
Eric Boren4b254b92016-11-08 12:55:32 -0500392 s := &specs.TaskSpec{
Eric Boren1f2f64b2016-11-09 18:35:15 -0500393 CipdPackages: pkgs,
394 Dependencies: []string{compileTaskName},
395 Dimensions: swarmDimensions(parts),
396 ExecutionTimeout: 4 * time.Hour,
397 Expiration: 20 * time.Hour,
borenetdb182c72016-09-30 12:53:12 -0700398 ExtraArgs: []string{
399 "--workdir", "../../..", "swarm_test",
skia.buildbots2478c732016-11-04 14:37:26 -0400400 fmt.Sprintf("repository=%s", specs.PLACEHOLDER_REPO),
borenetdb182c72016-09-30 12:53:12 -0700401 fmt.Sprintf("buildername=%s", name),
402 "mastername=fake-master",
403 "buildnumber=2",
404 "slavename=fake-buildslave",
borenet98b2e7a2016-10-13 06:23:45 -0700405 "nobuildbot=True",
borenetdb182c72016-09-30 12:53:12 -0700406 fmt.Sprintf("swarm_out_dir=%s", specs.PLACEHOLDER_ISOLATED_OUTDIR),
407 fmt.Sprintf("revision=%s", specs.PLACEHOLDER_REVISION),
borenet98b2e7a2016-10-13 06:23:45 -0700408 fmt.Sprintf("patch_storage=%s", specs.PLACEHOLDER_PATCH_STORAGE),
skia.buildbots2478c732016-11-04 14:37:26 -0400409 fmt.Sprintf("patch_issue=%s", specs.PLACEHOLDER_ISSUE),
410 fmt.Sprintf("patch_set=%s", specs.PLACEHOLDER_PATCHSET),
borenetdb182c72016-09-30 12:53:12 -0700411 },
Eric Boren5d9f3bf2017-02-22 08:36:03 -0500412 IoTimeout: 40 * time.Minute,
413 Isolate: "test_skia.isolate",
414 MaxAttempts: 1,
415 Priority: 0.8,
Eric Boren4b254b92016-11-08 12:55:32 -0500416 }
417 if strings.Contains(parts["extra_config"], "Valgrind") {
418 s.ExecutionTimeout = 9 * time.Hour
419 s.Expiration = 48 * time.Hour
420 s.IoTimeout = time.Hour
421 } else if strings.Contains(parts["extra_config"], "MSAN") {
422 s.ExecutionTimeout = 9 * time.Hour
423 }
424 b.MustAddTask(name, s)
425
borenetdb182c72016-09-30 12:53:12 -0700426 // Upload results if necessary.
427 if doUpload(name) {
428 uploadName := fmt.Sprintf("%s%s%s", PREFIX_UPLOAD, jobNameSchema.Sep, name)
boreneted20a702016-10-20 11:04:31 -0700429 b.MustAddTask(uploadName, &specs.TaskSpec{
borenetdb182c72016-09-30 12:53:12 -0700430 Dependencies: []string{name},
Eric Boren27225492017-02-01 15:56:55 -0500431 Dimensions: linuxGceDimensions(),
borenetdb182c72016-09-30 12:53:12 -0700432 ExtraArgs: []string{
433 "--workdir", "../../..", "upload_dm_results",
skia.buildbots2478c732016-11-04 14:37:26 -0400434 fmt.Sprintf("repository=%s", specs.PLACEHOLDER_REPO),
borenetdb182c72016-09-30 12:53:12 -0700435 fmt.Sprintf("buildername=%s", name),
436 "mastername=fake-master",
437 "buildnumber=2",
438 "slavename=fake-buildslave",
borenet98b2e7a2016-10-13 06:23:45 -0700439 "nobuildbot=True",
borenetdb182c72016-09-30 12:53:12 -0700440 fmt.Sprintf("swarm_out_dir=%s", specs.PLACEHOLDER_ISOLATED_OUTDIR),
441 fmt.Sprintf("revision=%s", specs.PLACEHOLDER_REVISION),
borenet98b2e7a2016-10-13 06:23:45 -0700442 fmt.Sprintf("patch_storage=%s", specs.PLACEHOLDER_PATCH_STORAGE),
skia.buildbots2478c732016-11-04 14:37:26 -0400443 fmt.Sprintf("patch_issue=%s", specs.PLACEHOLDER_ISSUE),
444 fmt.Sprintf("patch_set=%s", specs.PLACEHOLDER_PATCHSET),
Eric Boren965861b2017-02-06 15:38:41 -0500445 fmt.Sprintf("gs_bucket=%s", CONFIG.GsBucketGm),
borenetdb182c72016-09-30 12:53:12 -0700446 },
447 Isolate: "upload_dm_results.isolate",
448 Priority: 0.8,
boreneted20a702016-10-20 11:04:31 -0700449 })
borenetdb182c72016-09-30 12:53:12 -0700450 return uploadName
451 }
452 return name
453}
454
455// perf generates a Perf task. Returns the name of the last task in the
456// generated chain of tasks, which the Job should add as a dependency.
boreneted20a702016-10-20 11:04:31 -0700457func perf(b *specs.TasksCfgBuilder, name string, parts map[string]string, compileTaskName string, pkgs []*specs.CipdPackage) string {
Kevin Lubickb03b5ac2016-11-14 13:42:27 -0500458 recipe := "swarm_perf"
459 isolate := "perf_skia.isolate"
460 if strings.Contains(parts["extra_config"], "Skpbench") {
461 recipe = "swarm_skpbench"
462 isolate = "skpbench_skia.isolate"
463 }
Eric Boren4b254b92016-11-08 12:55:32 -0500464 s := &specs.TaskSpec{
Eric Boren1f2f64b2016-11-09 18:35:15 -0500465 CipdPackages: pkgs,
466 Dependencies: []string{compileTaskName},
467 Dimensions: swarmDimensions(parts),
468 ExecutionTimeout: 4 * time.Hour,
469 Expiration: 20 * time.Hour,
borenetdb182c72016-09-30 12:53:12 -0700470 ExtraArgs: []string{
Kevin Lubickb03b5ac2016-11-14 13:42:27 -0500471 "--workdir", "../../..", recipe,
skia.buildbots2478c732016-11-04 14:37:26 -0400472 fmt.Sprintf("repository=%s", specs.PLACEHOLDER_REPO),
borenetdb182c72016-09-30 12:53:12 -0700473 fmt.Sprintf("buildername=%s", name),
474 "mastername=fake-master",
475 "buildnumber=2",
476 "slavename=fake-buildslave",
borenet98b2e7a2016-10-13 06:23:45 -0700477 "nobuildbot=True",
borenetdb182c72016-09-30 12:53:12 -0700478 fmt.Sprintf("swarm_out_dir=%s", specs.PLACEHOLDER_ISOLATED_OUTDIR),
479 fmt.Sprintf("revision=%s", specs.PLACEHOLDER_REVISION),
borenet98b2e7a2016-10-13 06:23:45 -0700480 fmt.Sprintf("patch_storage=%s", specs.PLACEHOLDER_PATCH_STORAGE),
skia.buildbots2478c732016-11-04 14:37:26 -0400481 fmt.Sprintf("patch_issue=%s", specs.PLACEHOLDER_ISSUE),
482 fmt.Sprintf("patch_set=%s", specs.PLACEHOLDER_PATCHSET),
borenetdb182c72016-09-30 12:53:12 -0700483 },
Eric Boren5d9f3bf2017-02-22 08:36:03 -0500484 IoTimeout: 40 * time.Minute,
485 Isolate: isolate,
486 MaxAttempts: 1,
487 Priority: 0.8,
Eric Boren4b254b92016-11-08 12:55:32 -0500488 }
489 if strings.Contains(parts["extra_config"], "Valgrind") {
490 s.ExecutionTimeout = 9 * time.Hour
491 s.Expiration = 48 * time.Hour
492 s.IoTimeout = time.Hour
493 } else if strings.Contains(parts["extra_config"], "MSAN") {
494 s.ExecutionTimeout = 9 * time.Hour
495 }
496 b.MustAddTask(name, s)
497
borenetdb182c72016-09-30 12:53:12 -0700498 // Upload results if necessary.
499 if strings.Contains(name, "Release") && doUpload(name) {
500 uploadName := fmt.Sprintf("%s%s%s", PREFIX_UPLOAD, jobNameSchema.Sep, name)
boreneted20a702016-10-20 11:04:31 -0700501 b.MustAddTask(uploadName, &specs.TaskSpec{
borenetdb182c72016-09-30 12:53:12 -0700502 Dependencies: []string{name},
Eric Boren27225492017-02-01 15:56:55 -0500503 Dimensions: linuxGceDimensions(),
borenetdb182c72016-09-30 12:53:12 -0700504 ExtraArgs: []string{
505 "--workdir", "../../..", "upload_nano_results",
skia.buildbots2478c732016-11-04 14:37:26 -0400506 fmt.Sprintf("repository=%s", specs.PLACEHOLDER_REPO),
borenetdb182c72016-09-30 12:53:12 -0700507 fmt.Sprintf("buildername=%s", name),
508 "mastername=fake-master",
509 "buildnumber=2",
510 "slavename=fake-buildslave",
borenet98b2e7a2016-10-13 06:23:45 -0700511 "nobuildbot=True",
borenetdb182c72016-09-30 12:53:12 -0700512 fmt.Sprintf("swarm_out_dir=%s", specs.PLACEHOLDER_ISOLATED_OUTDIR),
513 fmt.Sprintf("revision=%s", specs.PLACEHOLDER_REVISION),
borenet98b2e7a2016-10-13 06:23:45 -0700514 fmt.Sprintf("patch_storage=%s", specs.PLACEHOLDER_PATCH_STORAGE),
skia.buildbots2478c732016-11-04 14:37:26 -0400515 fmt.Sprintf("patch_issue=%s", specs.PLACEHOLDER_ISSUE),
516 fmt.Sprintf("patch_set=%s", specs.PLACEHOLDER_PATCHSET),
Eric Boren965861b2017-02-06 15:38:41 -0500517 fmt.Sprintf("gs_bucket=%s", CONFIG.GsBucketNano),
borenetdb182c72016-09-30 12:53:12 -0700518 },
519 Isolate: "upload_nano_results.isolate",
520 Priority: 0.8,
boreneted20a702016-10-20 11:04:31 -0700521 })
borenetdb182c72016-09-30 12:53:12 -0700522 return uploadName
523 }
524 return name
525}
526
527// process generates tasks and jobs for the given job name.
boreneted20a702016-10-20 11:04:31 -0700528func process(b *specs.TasksCfgBuilder, name string) {
borenetdb182c72016-09-30 12:53:12 -0700529 deps := []string{}
530
531 parts, err := jobNameSchema.ParseJobName(name)
532 if err != nil {
533 glog.Fatal(err)
534 }
535
536 // RecreateSKPs.
537 if strings.Contains(name, "RecreateSKPs") {
boreneted20a702016-10-20 11:04:31 -0700538 deps = append(deps, recreateSKPs(b, name))
borenetdb182c72016-09-30 12:53:12 -0700539 }
540
541 // CT bots.
542 if strings.Contains(name, "-CT_") {
boreneted20a702016-10-20 11:04:31 -0700543 deps = append(deps, ctSKPs(b, name))
borenetdb182c72016-09-30 12:53:12 -0700544 }
545
borenet2dbbfa52016-10-14 06:32:09 -0700546 // Infra tests.
547 if name == "Housekeeper-PerCommit-InfraTests" {
boreneted20a702016-10-20 11:04:31 -0700548 deps = append(deps, infra(b, name))
borenet2dbbfa52016-10-14 06:32:09 -0700549 }
550
borenetdb182c72016-09-30 12:53:12 -0700551 // Compile bots.
552 if parts["role"] == "Build" {
boreneted20a702016-10-20 11:04:31 -0700553 deps = append(deps, compile(b, name, parts))
borenetdb182c72016-09-30 12:53:12 -0700554 }
555
Eric Borenf5a90e82016-11-15 15:18:20 -0500556 // Most remaining bots need a compile task.
borenetdb182c72016-09-30 12:53:12 -0700557 compileTaskName := deriveCompileTaskName(name, parts)
borenet52383432016-10-17 10:17:53 -0700558 compileTaskParts, err := jobNameSchema.ParseJobName(compileTaskName)
559 if err != nil {
560 glog.Fatal(err)
561 }
Eric Boren628e78b2016-11-17 11:33:27 -0500562 // These bots do not need a compile task.
Eric Borenf5a90e82016-11-15 15:18:20 -0500563 if parts["role"] != "Build" &&
564 name != "Housekeeper-PerCommit-InfraTests" &&
Eric Boren71b762f2016-11-30 14:05:16 -0500565 !strings.Contains(name, "RecreateSKPs") &&
566 !strings.Contains(name, "-CT_") {
boreneted20a702016-10-20 11:04:31 -0700567 compile(b, compileTaskName, compileTaskParts)
borenet52383432016-10-17 10:17:53 -0700568 }
borenetdb182c72016-09-30 12:53:12 -0700569
570 // Housekeeper.
Eric Boren22f5ef72016-12-02 11:01:33 -0500571 if name == "Housekeeper-PerCommit" {
boreneted20a702016-10-20 11:04:31 -0700572 deps = append(deps, housekeeper(b, name, compileTaskName))
borenetdb182c72016-09-30 12:53:12 -0700573 }
574
575 // Common assets needed by the remaining bots.
576 pkgs := []*specs.CipdPackage{
boreneted20a702016-10-20 11:04:31 -0700577 b.MustGetCipdPackageFromAsset("skimage"),
578 b.MustGetCipdPackageFromAsset("skp"),
579 b.MustGetCipdPackageFromAsset("svg"),
borenetdb182c72016-09-30 12:53:12 -0700580 }
Eric Boren4b254b92016-11-08 12:55:32 -0500581 if strings.Contains(name, "Ubuntu") && strings.Contains(name, "SAN") {
582 pkgs = append(pkgs, b.MustGetCipdPackageFromAsset("clang_linux"))
583 }
Kevin Lubick35115eb2017-02-17 10:25:34 -0500584 if strings.Contains(name, "Ubuntu16") {
585 if strings.Contains(name, "Vulkan") {
586 pkgs = append(pkgs, b.MustGetCipdPackageFromAsset("linux_vulkan_sdk"))
587 }
Kevin Lubick0a51b482017-02-06 12:45:29 -0500588 if strings.Contains(name, "Release") {
589 pkgs = append(pkgs, b.MustGetCipdPackageFromAsset("linux_vulkan_intel_driver_release"))
590 } else {
591 pkgs = append(pkgs, b.MustGetCipdPackageFromAsset("linux_vulkan_intel_driver_debug"))
592 }
593 }
Kevin Lubickb03b5ac2016-11-14 13:42:27 -0500594 // Skpbench only needs skps
595 if strings.Contains(name, "Skpbench") {
596 pkgs = []*specs.CipdPackage{
597 b.MustGetCipdPackageFromAsset("skp"),
598 }
599 }
borenetdb182c72016-09-30 12:53:12 -0700600
601 // Test bots.
Eric Boren71b762f2016-11-30 14:05:16 -0500602 if parts["role"] == "Test" && !strings.Contains(name, "-CT_") {
boreneted20a702016-10-20 11:04:31 -0700603 deps = append(deps, test(b, name, parts, compileTaskName, pkgs))
borenetdb182c72016-09-30 12:53:12 -0700604 }
605
606 // Perf bots.
Eric Boren71b762f2016-11-30 14:05:16 -0500607 if parts["role"] == "Perf" && !strings.Contains(name, "-CT_") {
boreneted20a702016-10-20 11:04:31 -0700608 deps = append(deps, perf(b, name, parts, compileTaskName, pkgs))
borenetdb182c72016-09-30 12:53:12 -0700609 }
610
611 // Add the Job spec.
Eric Borenf5a90e82016-11-15 15:18:20 -0500612 j := &specs.JobSpec{
borenetdb182c72016-09-30 12:53:12 -0700613 Priority: 0.8,
614 TaskSpecs: deps,
Eric Borenf5a90e82016-11-15 15:18:20 -0500615 }
616 if name == "Housekeeper-Nightly-RecreateSKPs_Canary" {
617 j.Trigger = "nightly"
618 }
619 if name == "Housekeeper-Weekly-RecreateSKPs" {
620 j.Trigger = "weekly"
621 }
Eric Boren71b762f2016-11-30 14:05:16 -0500622 if name == "Test-Ubuntu-GCC-GCE-CPU-AVX2-x86_64-Debug-CT_DM_1m_SKPs" {
623 j.Trigger = "weekly"
624 }
Eric Boren8615fe52016-12-12 14:30:12 -0500625 b.MustAddJob(name, j)
borenetdb182c72016-09-30 12:53:12 -0700626}
627
Eric Boren27225492017-02-01 15:56:55 -0500628func loadJson(flag *string, defaultFlag string, val interface{}) {
629 if *flag == "" {
630 *flag = defaultFlag
631 }
632 b, err := ioutil.ReadFile(*flag)
633 if err != nil {
634 glog.Fatal(err)
635 }
636 if err := json.Unmarshal(b, val); err != nil {
637 glog.Fatal(err)
638 }
639}
640
borenetdb182c72016-09-30 12:53:12 -0700641// Regenerate the tasks.json file.
642func main() {
boreneted20a702016-10-20 11:04:31 -0700643 b := specs.MustNewTasksCfgBuilder()
Eric Boren27225492017-02-01 15:56:55 -0500644 b.SetAssetsDir(*assetsDir)
645 infraBots := path.Join(b.CheckoutRoot(), "infra", "bots")
646
647 // Load the jobs from a JSON file.
648 loadJson(jobsFile, path.Join(infraBots, "jobs.json"), &JOBS)
649
650 // Load the GPU mapping from a JSON file.
651 loadJson(gpuMapFile, path.Join(infraBots, "gpu_map.json"), &GPU_MAPPING)
652
653 // Load the Android device mapping from a JSON file.
654 loadJson(androidMapFile, path.Join(infraBots, "android_map.json"), &ANDROID_MAPPING)
655
656 // Load general config information from a JSON file.
657 loadJson(cfgFile, path.Join(infraBots, "cfg.json"), &CONFIG)
658
borenetdb182c72016-09-30 12:53:12 -0700659 // Create the JobNameSchema.
Eric Boren1f8be682017-02-07 09:16:30 -0500660 if *builderNameSchemaFile == "" {
661 *builderNameSchemaFile = path.Join(b.CheckoutRoot(), "infra", "bots", "recipe_modules", "builder_name_schema", "builder_name_schema.json")
662 }
663 schema, err := NewJobNameSchema(*builderNameSchemaFile)
borenetdb182c72016-09-30 12:53:12 -0700664 if err != nil {
665 glog.Fatal(err)
666 }
667 jobNameSchema = schema
668
borenetdb182c72016-09-30 12:53:12 -0700669 // Create Tasks and Jobs.
boreneted20a702016-10-20 11:04:31 -0700670 for _, name := range JOBS {
671 process(b, name)
borenetdb182c72016-09-30 12:53:12 -0700672 }
673
boreneted20a702016-10-20 11:04:31 -0700674 b.MustFinish()
borenetdb182c72016-09-30 12:53:12 -0700675}
676
677// TODO(borenet): The below really belongs in its own file, probably next to the
678// builder_name_schema.json file.
679
680// JobNameSchema is a struct used for (de)constructing Job names in a
681// predictable format.
682type JobNameSchema struct {
683 Schema map[string][]string `json:"builder_name_schema"`
684 Sep string `json:"builder_name_sep"`
685}
686
687// NewJobNameSchema returns a JobNameSchema instance based on the given JSON
688// file.
689func NewJobNameSchema(jsonFile string) (*JobNameSchema, error) {
690 var rv JobNameSchema
691 f, err := os.Open(jsonFile)
692 if err != nil {
693 return nil, err
694 }
695 defer util.Close(f)
696 if err := json.NewDecoder(f).Decode(&rv); err != nil {
697 return nil, err
698 }
699 return &rv, nil
700}
701
702// ParseJobName splits the given Job name into its component parts, according
703// to the schema.
704func (s *JobNameSchema) ParseJobName(n string) (map[string]string, error) {
705 split := strings.Split(n, s.Sep)
706 if len(split) < 2 {
707 return nil, fmt.Errorf("Invalid job name: %q", n)
708 }
709 role := split[0]
710 split = split[1:]
711 keys, ok := s.Schema[role]
712 if !ok {
713 return nil, fmt.Errorf("Invalid job name; %q is not a valid role.", role)
714 }
715 extraConfig := ""
716 if len(split) == len(keys)+1 {
717 extraConfig = split[len(split)-1]
718 split = split[:len(split)-1]
719 }
720 if len(split) != len(keys) {
721 return nil, fmt.Errorf("Invalid job name; %q has incorrect number of parts.", n)
722 }
723 rv := make(map[string]string, len(keys)+2)
724 rv["role"] = role
725 if extraConfig != "" {
726 rv["extra_config"] = extraConfig
727 }
728 for i, k := range keys {
729 rv[k] = split[i]
730 }
731 return rv, nil
732}
733
734// MakeJobName assembles the given parts of a Job name, according to the schema.
735func (s *JobNameSchema) MakeJobName(parts map[string]string) (string, error) {
736 role, ok := parts["role"]
737 if !ok {
738 return "", fmt.Errorf("Invalid job parts; jobs must have a role.")
739 }
740 keys, ok := s.Schema[role]
741 if !ok {
742 return "", fmt.Errorf("Invalid job parts; unknown role %q", role)
743 }
744 rvParts := make([]string, 0, len(parts))
745 rvParts = append(rvParts, role)
746 for _, k := range keys {
747 v, ok := parts[k]
748 if !ok {
749 return "", fmt.Errorf("Invalid job parts; missing %q", k)
750 }
751 rvParts = append(rvParts, v)
752 }
753 if _, ok := parts["extra_config"]; ok {
754 rvParts = append(rvParts, parts["extra_config"])
755 }
756 return strings.Join(rvParts, s.Sep), nil
757}