2016-09-30 19:53:12 +00:00
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package main
/ *
Generate the tasks . json file .
* /
import (
"encoding/json"
2017-02-01 20:56:55 +00:00
"flag"
2016-09-30 19:53:12 +00:00
"fmt"
2017-02-01 20:56:55 +00:00
"io/ioutil"
2016-09-30 19:53:12 +00:00
"os"
"path"
2017-02-01 20:56:55 +00:00
"regexp"
2016-09-30 19:53:12 +00:00
"sort"
"strings"
2016-11-08 17:55:32 +00:00
"time"
2016-09-30 19:53:12 +00:00
"github.com/skia-dev/glog"
"go.skia.org/infra/go/util"
"go.skia.org/infra/task_scheduler/go/specs"
)
const (
2017-04-04 13:06:16 +00:00
BUNDLE_RECIPES_NAME = "Housekeeper-PerCommit-BundleRecipes"
2016-12-15 15:45:08 +00:00
DEFAULT_OS = DEFAULT_OS_LINUX
DEFAULT_OS_LINUX = "Ubuntu-14.04"
2016-09-30 19:53:12 +00:00
// Name prefix for upload jobs.
PREFIX_UPLOAD = "Upload"
)
var (
// "Constants"
2017-02-01 20:56:55 +00:00
// Top-level list of all jobs to run at each commit; loaded from
// jobs.json.
JOBS [ ] string
// Mapping of human-friendly Android device names to a pair of {device_type, device_os}.
ANDROID_MAPPING map [ string ] [ ] string
// General configuration information.
CONFIG struct {
2017-02-06 20:38:41 +00:00
GsBucketGm string ` json:"gs_bucket_gm" `
GsBucketNano string ` json:"gs_bucket_nano" `
NoUpload [ ] string ` json:"no_upload" `
Pool string ` json:"pool" `
2016-09-30 19:53:12 +00:00
}
2017-02-01 20:56:55 +00:00
// Mapping of human-friendly GPU names to PCI IDs.
GPU_MAPPING map [ string ] string
2016-09-30 19:53:12 +00:00
// Defines the structure of job names.
jobNameSchema * JobNameSchema
2017-02-01 20:56:55 +00:00
// Flags.
2017-02-07 14:16:30 +00:00
androidMapFile = flag . String ( "android_map" , "" , "JSON file containing a mapping of human-friendly Android device names to a pair of {device_type, device_os}." )
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." )
assetsDir = flag . String ( "assets_dir" , "" , "Directory containing assets." )
cfgFile = flag . String ( "cfg_file" , "" , "JSON file containing general configuration information." )
gpuMapFile = flag . String ( "gpu_map" , "" , "JSON file containing a mapping of human-friendly GPU names to PCI IDs." )
jobsFile = flag . String ( "jobs" , "" , "JSON file containing jobs to run." )
2016-09-30 19:53:12 +00:00
)
2017-02-01 20:56:55 +00:00
// linuxGceDimensions are the Swarming dimensions for Linux GCE
// instances.
func linuxGceDimensions ( ) [ ] string {
return [ ] string {
"cpu:x86-64-avx2" ,
"gpu:none" ,
fmt . Sprintf ( "os:%s" , DEFAULT_OS_LINUX ) ,
fmt . Sprintf ( "pool:%s" , CONFIG . Pool ) ,
}
}
2016-09-30 19:53:12 +00:00
// deriveCompileTaskName returns the name of a compile task based on the given
// job name.
func deriveCompileTaskName ( jobName string , parts map [ string ] string ) string {
if parts [ "role" ] == "Housekeeper" {
return "Build-Ubuntu-GCC-x86_64-Release-Shared"
} else if parts [ "role" ] == "Test" || parts [ "role" ] == "Perf" {
task_os := parts [ "os" ]
ec := parts [ "extra_config" ]
2016-11-14 18:42:27 +00:00
ec = strings . TrimSuffix ( ec , "_Skpbench" )
2017-02-22 00:10:24 +00:00
ec = strings . TrimSuffix ( ec , "_AbandonGpuContext" )
ec = strings . TrimSuffix ( ec , "_PreAbandonGpuContext" )
2017-02-22 00:27:07 +00:00
if ec == "Valgrind" {
// skia:6267
ec = ""
}
2016-09-30 19:53:12 +00:00
if task_os == "Android" {
if ec == "Vulkan" {
ec = "Android_Vulkan"
}
2016-10-17 17:17:53 +00:00
task_os = "Ubuntu"
2017-03-08 19:01:01 +00:00
} else if task_os == "Chromecast" {
task_os = "Ubuntu"
ec = "Chromecast"
2017-04-05 11:32:45 +00:00
} else if strings . HasPrefix ( task_os , "Chromebook" ) {
ec = task_os
task_os = "Ubuntu"
2016-09-30 19:53:12 +00:00
} else if task_os == "iOS" {
ec = task_os
task_os = "Mac"
} else if strings . Contains ( task_os , "Win" ) {
task_os = "Win"
2017-01-17 20:15:40 +00:00
} else if strings . Contains ( task_os , "Ubuntu" ) {
task_os = "Ubuntu"
2016-09-30 19:53:12 +00:00
}
2016-11-18 18:10:51 +00:00
jobNameMap := map [ string ] string {
2016-09-30 19:53:12 +00:00
"role" : "Build" ,
"os" : task_os ,
"compiler" : parts [ "compiler" ] ,
"target_arch" : parts [ "arch" ] ,
"configuration" : parts [ "configuration" ] ,
2016-11-18 18:10:51 +00:00
}
if ec != "" {
jobNameMap [ "extra_config" ] = ec
}
name , err := jobNameSchema . MakeJobName ( jobNameMap )
2016-09-30 19:53:12 +00:00
if err != nil {
glog . Fatal ( err )
}
return name
} else {
return jobName
}
}
// swarmDimensions generates swarming bot dimensions for the given task.
func swarmDimensions ( parts map [ string ] string ) [ ] string {
d := map [ string ] string {
2017-02-01 20:56:55 +00:00
"pool" : CONFIG . Pool ,
2016-09-30 19:53:12 +00:00
}
if os , ok := parts [ "os" ] ; ok {
2016-12-02 17:09:10 +00:00
d [ "os" ] = map [ string ] string {
2017-03-21 13:25:34 +00:00
"Android" : "Android" ,
"Chromecast" : "Android" ,
"Mac" : "Mac-10.11" ,
"Ubuntu" : DEFAULT_OS_LINUX ,
"Ubuntu16" : "Ubuntu-16.10" ,
"Win" : "Windows-2008ServerR2-SP1" ,
"Win10" : "Windows-10-14393" ,
"Win2k8" : "Windows-2008ServerR2-SP1" ,
"Win8" : "Windows-8.1-SP0" ,
"iOS" : "iOS-9.3.1" ,
2016-12-02 17:09:10 +00:00
} [ os ]
2016-12-29 21:27:03 +00:00
// Chrome Golo has a different Windows image.
if parts [ "model" ] == "Golo" && os == "Win10" {
d [ "os" ] = "Windows-10-10586"
2016-12-22 13:40:14 +00:00
}
2016-09-30 19:53:12 +00:00
} else {
d [ "os" ] = DEFAULT_OS
}
if parts [ "role" ] == "Test" || parts [ "role" ] == "Perf" {
2017-03-21 13:25:34 +00:00
if strings . Contains ( parts [ "os" ] , "Android" ) || strings . Contains ( parts [ "os" ] , "Chromecast" ) {
2016-09-30 19:53:12 +00:00
// For Android, the device type is a better dimension
// than CPU or GPU.
2017-02-01 20:56:55 +00:00
deviceInfo , ok := ANDROID_MAPPING [ parts [ "model" ] ]
if ! ok {
glog . Fatalf ( "Entry %q not found in Android mapping: %v" , parts [ "model" ] , ANDROID_MAPPING )
}
2016-11-08 17:55:32 +00:00
d [ "device_type" ] = deviceInfo [ 0 ]
d [ "device_os" ] = deviceInfo [ 1 ]
2016-09-30 19:53:12 +00:00
} else if strings . Contains ( parts [ "os" ] , "iOS" ) {
d [ "device" ] = map [ string ] string {
2016-11-09 19:03:20 +00:00
"iPadMini4" : "iPad5,1" ,
2016-09-30 19:53:12 +00:00
} [ parts [ "model" ] ]
} else if parts [ "cpu_or_gpu" ] == "CPU" {
d [ "gpu" ] = "none"
d [ "cpu" ] = map [ string ] string {
"AVX" : "x86-64" ,
"AVX2" : "x86-64-avx2" ,
"SSE4" : "x86-64" ,
} [ parts [ "cpu_or_gpu_value" ] ]
if strings . Contains ( parts [ "os" ] , "Win" ) && parts [ "cpu_or_gpu_value" ] == "AVX2" {
// AVX2 is not correctly detected on Windows. Fall back on other
// dimensions to ensure that we correctly target machines which we know
// have AVX2 support.
2017-04-06 17:32:44 +00:00
d [ "cpu" ] = "x86-64"
2016-09-30 19:53:12 +00:00
d [ "os" ] = "Windows-2008ServerR2-SP1"
}
} else {
2017-02-01 20:56:55 +00:00
gpu , ok := GPU_MAPPING [ parts [ "cpu_or_gpu_value" ] ]
if ! ok {
glog . Fatalf ( "Entry %q not found in GPU mapping: %v" , parts [ "cpu_or_gpu_value" ] , GPU_MAPPING )
}
d [ "gpu" ] = gpu
2017-02-19 04:28:26 +00:00
// Hack: Specify machine_type dimension for NUCs and ShuttleCs. We
// temporarily have two types of machines with a GTX960. The only way to
// distinguish these bots is by machine_type.
machine_type , ok := map [ string ] string {
"NUC6i7KYK" : "n1-highcpu-8" ,
"ShuttleC" : "n1-standard-8" ,
} [ parts [ "model" ] ]
if ok {
d [ "machine_type" ] = machine_type
}
2016-09-30 19:53:12 +00:00
}
} else {
d [ "gpu" ] = "none"
2017-03-22 19:54:54 +00:00
if d [ "os" ] == DEFAULT_OS_LINUX {
return linuxGceDimensions ( )
}
2016-09-30 19:53:12 +00:00
}
2017-03-22 19:54:54 +00:00
2016-09-30 19:53:12 +00:00
rv := make ( [ ] string , 0 , len ( d ) )
for k , v := range d {
rv = append ( rv , fmt . Sprintf ( "%s:%s" , k , v ) )
}
sort . Strings ( rv )
return rv
}
2017-04-04 13:06:16 +00:00
// bundleRecipes generates the task to bundle and isolate the recipes.
func bundleRecipes ( b * specs . TasksCfgBuilder ) string {
b . MustAddTask ( BUNDLE_RECIPES_NAME , & specs . TaskSpec {
CipdPackages : [ ] * specs . CipdPackage { } ,
Dimensions : linuxGceDimensions ( ) ,
ExtraArgs : [ ] string {
"--workdir" , "../../.." , "bundle_recipes" ,
fmt . Sprintf ( "repository=%s" , specs . PLACEHOLDER_REPO ) ,
fmt . Sprintf ( "buildername=%s" , BUNDLE_RECIPES_NAME ) ,
"mastername=fake-master" ,
"buildnumber=2" ,
"slavename=fake-buildslave" ,
"nobuildbot=True" ,
fmt . Sprintf ( "swarm_out_dir=%s" , specs . PLACEHOLDER_ISOLATED_OUTDIR ) ,
fmt . Sprintf ( "revision=%s" , specs . PLACEHOLDER_REVISION ) ,
fmt . Sprintf ( "patch_storage=%s" , specs . PLACEHOLDER_PATCH_STORAGE ) ,
fmt . Sprintf ( "patch_issue=%s" , specs . PLACEHOLDER_ISSUE ) ,
fmt . Sprintf ( "patch_set=%s" , specs . PLACEHOLDER_PATCHSET ) ,
} ,
Isolate : "bundle_recipes.isolate" ,
Priority : 0.95 ,
} )
return BUNDLE_RECIPES_NAME
}
2016-09-30 19:53:12 +00:00
// compile generates a compile task. Returns the name of the last task in the
// generated chain of tasks, which the Job should add as a dependency.
2016-10-20 18:04:31 +00:00
func compile ( b * specs . TasksCfgBuilder , name string , parts map [ string ] string ) string {
2016-09-30 19:53:12 +00:00
// Collect the necessary CIPD packages.
pkgs := [ ] * specs . CipdPackage { }
// Android bots require a toolchain.
if strings . Contains ( name , "Android" ) {
if strings . Contains ( name , "Mac" ) {
2016-10-20 18:04:31 +00:00
pkgs = append ( pkgs , b . MustGetCipdPackageFromAsset ( "android_ndk_darwin" ) )
2016-11-02 17:13:16 +00:00
} else if strings . Contains ( name , "Win" ) {
2016-11-02 19:44:26 +00:00
pkg := b . MustGetCipdPackageFromAsset ( "android_ndk_windows" )
pkg . Path = "n"
pkgs = append ( pkgs , pkg )
2016-09-30 19:53:12 +00:00
} else {
2016-10-20 18:04:31 +00:00
pkgs = append ( pkgs , b . MustGetCipdPackageFromAsset ( "android_ndk_linux" ) )
2016-09-30 19:53:12 +00:00
}
2017-03-08 19:01:01 +00:00
} else if strings . Contains ( name , "Chromecast" ) {
pkgs = append ( pkgs , b . MustGetCipdPackageFromAsset ( "cast_toolchain" ) )
2017-04-05 11:32:45 +00:00
} else if strings . Contains ( name , "Chromebook" ) {
pkgs = append ( pkgs , b . MustGetCipdPackageFromAsset ( "clang_linux" ) )
pkgs = append ( pkgs , b . MustGetCipdPackageFromAsset ( "armhf_sysroot" ) )
if strings . Contains ( name , "Chromebook_C100p" ) {
pkgs = append ( pkgs , b . MustGetCipdPackageFromAsset ( "chromebook_c100p_lib" ) )
}
2017-01-18 14:24:56 +00:00
} else if strings . Contains ( name , "Ubuntu" ) {
if strings . Contains ( name , "Clang" ) {
pkgs = append ( pkgs , b . MustGetCipdPackageFromAsset ( "clang_linux" ) )
}
if strings . Contains ( name , "Vulkan" ) {
pkgs = append ( pkgs , b . MustGetCipdPackageFromAsset ( "linux_vulkan_sdk" ) )
}
2016-11-09 21:31:42 +00:00
} else if strings . Contains ( name , "Win" ) {
2016-10-20 18:04:31 +00:00
pkgs = append ( pkgs , b . MustGetCipdPackageFromAsset ( "win_toolchain" ) )
2016-09-30 19:53:12 +00:00
if strings . Contains ( name , "Vulkan" ) {
2016-10-20 18:04:31 +00:00
pkgs = append ( pkgs , b . MustGetCipdPackageFromAsset ( "win_vulkan_sdk" ) )
2016-09-30 19:53:12 +00:00
}
}
2017-03-20 17:38:45 +00:00
// TODO(stephana): Remove this once all Mac machines are on the same
// OS version again. Move the call to swarmDimensions back to the
// creation of the TaskSpec struct below.
dimensions := swarmDimensions ( parts )
if strings . Contains ( name , "Mac" ) {
for idx , dim := range dimensions {
if strings . HasPrefix ( dim , "os" ) {
dimensions [ idx ] = "os:Mac-10.12"
break
}
}
}
2016-09-30 19:53:12 +00:00
// Add the task.
2016-10-20 18:04:31 +00:00
b . MustAddTask ( name , & specs . TaskSpec {
2016-09-30 19:53:12 +00:00
CipdPackages : pkgs ,
2017-03-20 17:38:45 +00:00
Dimensions : dimensions ,
2016-09-30 19:53:12 +00:00
ExtraArgs : [ ] string {
"--workdir" , "../../.." , "swarm_compile" ,
2016-11-04 18:37:26 +00:00
fmt . Sprintf ( "repository=%s" , specs . PLACEHOLDER_REPO ) ,
2016-09-30 19:53:12 +00:00
fmt . Sprintf ( "buildername=%s" , name ) ,
"mastername=fake-master" ,
"buildnumber=2" ,
"slavename=fake-buildslave" ,
2016-10-13 13:23:45 +00:00
"nobuildbot=True" ,
2016-09-30 19:53:12 +00:00
fmt . Sprintf ( "swarm_out_dir=%s" , specs . PLACEHOLDER_ISOLATED_OUTDIR ) ,
fmt . Sprintf ( "revision=%s" , specs . PLACEHOLDER_REVISION ) ,
2016-10-13 13:23:45 +00:00
fmt . Sprintf ( "patch_storage=%s" , specs . PLACEHOLDER_PATCH_STORAGE ) ,
2016-11-04 18:37:26 +00:00
fmt . Sprintf ( "patch_issue=%s" , specs . PLACEHOLDER_ISSUE ) ,
fmt . Sprintf ( "patch_set=%s" , specs . PLACEHOLDER_PATCHSET ) ,
2016-09-30 19:53:12 +00:00
} ,
Isolate : "compile_skia.isolate" ,
Priority : 0.8 ,
2016-10-20 18:04:31 +00:00
} )
2016-12-12 19:30:12 +00:00
// All compile tasks are runnable as their own Job. Assert that the Job
// is listed in JOBS.
if ! util . In ( name , JOBS ) {
glog . Fatalf ( "Job %q is missing from the JOBS list!" , name )
}
2016-09-30 19:53:12 +00:00
return name
}
// recreateSKPs generates a RecreateSKPs task. Returns the name of the last
// task in the generated chain of tasks, which the Job should add as a
// dependency.
2016-10-20 18:04:31 +00:00
func recreateSKPs ( b * specs . TasksCfgBuilder , name string ) string {
2016-11-08 17:55:32 +00:00
b . MustAddTask ( name , & specs . TaskSpec {
2016-11-15 20:18:20 +00:00
CipdPackages : [ ] * specs . CipdPackage { } ,
2017-02-01 20:56:55 +00:00
Dimensions : linuxGceDimensions ( ) ,
2016-11-15 20:18:20 +00:00
ExecutionTimeout : 4 * time . Hour ,
2016-11-08 17:55:32 +00:00
ExtraArgs : [ ] string {
"--workdir" , "../../.." , "swarm_RecreateSKPs" ,
fmt . Sprintf ( "repository=%s" , specs . PLACEHOLDER_REPO ) ,
fmt . Sprintf ( "buildername=%s" , name ) ,
"mastername=fake-master" ,
"buildnumber=2" ,
"slavename=fake-buildslave" ,
"nobuildbot=True" ,
fmt . Sprintf ( "swarm_out_dir=%s" , specs . PLACEHOLDER_ISOLATED_OUTDIR ) ,
fmt . Sprintf ( "revision=%s" , specs . PLACEHOLDER_REVISION ) ,
fmt . Sprintf ( "patch_storage=%s" , specs . PLACEHOLDER_PATCH_STORAGE ) ,
fmt . Sprintf ( "patch_issue=%s" , specs . PLACEHOLDER_ISSUE ) ,
fmt . Sprintf ( "patch_set=%s" , specs . PLACEHOLDER_PATCHSET ) ,
} ,
2016-11-15 20:18:20 +00:00
IoTimeout : 40 * time . Minute ,
Isolate : "compile_skia.isolate" ,
Priority : 0.8 ,
2016-11-08 17:55:32 +00:00
} )
2016-09-30 19:53:12 +00:00
return name
}
// ctSKPs generates a CT SKPs task. Returns the name of the last task in the
// generated chain of tasks, which the Job should add as a dependency.
2016-10-20 18:04:31 +00:00
func ctSKPs ( b * specs . TasksCfgBuilder , name string ) string {
2016-11-08 17:55:32 +00:00
b . MustAddTask ( name , & specs . TaskSpec {
CipdPackages : [ ] * specs . CipdPackage { } ,
Dimensions : [ ] string { "pool:SkiaCT" } ,
ExecutionTimeout : 24 * time . Hour ,
ExtraArgs : [ ] string {
"--workdir" , "../../.." , "swarm_ct_skps" ,
fmt . Sprintf ( "repository=%s" , specs . PLACEHOLDER_REPO ) ,
fmt . Sprintf ( "buildername=%s" , name ) ,
"mastername=fake-master" ,
"buildnumber=2" ,
"slavename=fake-buildslave" ,
"nobuildbot=True" ,
fmt . Sprintf ( "swarm_out_dir=%s" , specs . PLACEHOLDER_ISOLATED_OUTDIR ) ,
fmt . Sprintf ( "revision=%s" , specs . PLACEHOLDER_REVISION ) ,
fmt . Sprintf ( "patch_storage=%s" , specs . PLACEHOLDER_PATCH_STORAGE ) ,
fmt . Sprintf ( "patch_issue=%s" , specs . PLACEHOLDER_ISSUE ) ,
fmt . Sprintf ( "patch_set=%s" , specs . PLACEHOLDER_PATCHSET ) ,
} ,
IoTimeout : time . Hour ,
Isolate : "ct_skps_skia.isolate" ,
Priority : 0.8 ,
} )
2016-09-30 19:53:12 +00:00
return name
}
// housekeeper generates a Housekeeper task. Returns the name of the last task
// in the generated chain of tasks, which the Job should add as a dependency.
2016-10-20 18:04:31 +00:00
func housekeeper ( b * specs . TasksCfgBuilder , name , compileTaskName string ) string {
2016-11-08 17:55:32 +00:00
b . MustAddTask ( name , & specs . TaskSpec {
2016-12-02 16:01:33 +00:00
CipdPackages : [ ] * specs . CipdPackage { b . MustGetCipdPackageFromAsset ( "go" ) } ,
2016-11-08 17:55:32 +00:00
Dependencies : [ ] string { compileTaskName } ,
2017-02-01 20:56:55 +00:00
Dimensions : linuxGceDimensions ( ) ,
2016-11-08 17:55:32 +00:00
ExtraArgs : [ ] string {
"--workdir" , "../../.." , "swarm_housekeeper" ,
fmt . Sprintf ( "repository=%s" , specs . PLACEHOLDER_REPO ) ,
fmt . Sprintf ( "buildername=%s" , name ) ,
"mastername=fake-master" ,
"buildnumber=2" ,
"slavename=fake-buildslave" ,
"nobuildbot=True" ,
fmt . Sprintf ( "swarm_out_dir=%s" , specs . PLACEHOLDER_ISOLATED_OUTDIR ) ,
fmt . Sprintf ( "revision=%s" , specs . PLACEHOLDER_REVISION ) ,
fmt . Sprintf ( "patch_storage=%s" , specs . PLACEHOLDER_PATCH_STORAGE ) ,
fmt . Sprintf ( "patch_issue=%s" , specs . PLACEHOLDER_ISSUE ) ,
fmt . Sprintf ( "patch_set=%s" , specs . PLACEHOLDER_PATCHSET ) ,
} ,
Isolate : "housekeeper_skia.isolate" ,
Priority : 0.8 ,
} )
2016-09-30 19:53:12 +00:00
return name
}
2016-10-14 13:32:09 +00:00
// infra generates an infra_tests task. Returns the name of the last task in the
// generated chain of tasks, which the Job should add as a dependency.
2016-10-20 18:04:31 +00:00
func infra ( b * specs . TasksCfgBuilder , name string ) string {
b . MustAddTask ( name , & specs . TaskSpec {
2016-10-14 13:32:09 +00:00
CipdPackages : [ ] * specs . CipdPackage { } ,
2017-02-01 20:56:55 +00:00
Dimensions : linuxGceDimensions ( ) ,
2016-10-14 13:32:09 +00:00
ExtraArgs : [ ] string {
"--workdir" , "../../.." , "swarm_infra" ,
2016-11-04 18:37:26 +00:00
fmt . Sprintf ( "repository=%s" , specs . PLACEHOLDER_REPO ) ,
2016-10-14 13:32:09 +00:00
fmt . Sprintf ( "buildername=%s" , name ) ,
"mastername=fake-master" ,
"buildnumber=2" ,
"slavename=fake-buildslave" ,
"nobuildbot=True" ,
fmt . Sprintf ( "swarm_out_dir=%s" , specs . PLACEHOLDER_ISOLATED_OUTDIR ) ,
fmt . Sprintf ( "revision=%s" , specs . PLACEHOLDER_REVISION ) ,
fmt . Sprintf ( "patch_storage=%s" , specs . PLACEHOLDER_PATCH_STORAGE ) ,
2016-11-04 18:37:26 +00:00
fmt . Sprintf ( "patch_issue=%s" , specs . PLACEHOLDER_ISSUE ) ,
fmt . Sprintf ( "patch_set=%s" , specs . PLACEHOLDER_PATCHSET ) ,
2016-10-14 13:32:09 +00:00
} ,
Isolate : "infra_skia.isolate" ,
Priority : 0.8 ,
2016-10-20 18:04:31 +00:00
} )
2016-10-14 13:32:09 +00:00
return name
}
2016-09-30 19:53:12 +00:00
// doUpload indicates whether the given Job should upload its results.
func doUpload ( name string ) bool {
2017-02-01 20:56:55 +00:00
for _ , s := range CONFIG . NoUpload {
m , err := regexp . MatchString ( s , name )
if err != nil {
glog . Fatal ( err )
}
if m {
2016-09-30 19:53:12 +00:00
return false
}
}
return true
}
// test generates a Test task. Returns the name of the last task in the
// generated chain of tasks, which the Job should add as a dependency.
2016-10-20 18:04:31 +00:00
func test ( b * specs . TasksCfgBuilder , name string , parts map [ string ] string , compileTaskName string , pkgs [ ] * specs . CipdPackage ) string {
2016-11-08 17:55:32 +00:00
s := & specs . TaskSpec {
2016-11-09 23:35:15 +00:00
CipdPackages : pkgs ,
Dependencies : [ ] string { compileTaskName } ,
Dimensions : swarmDimensions ( parts ) ,
ExecutionTimeout : 4 * time . Hour ,
Expiration : 20 * time . Hour ,
2016-09-30 19:53:12 +00:00
ExtraArgs : [ ] string {
"--workdir" , "../../.." , "swarm_test" ,
2016-11-04 18:37:26 +00:00
fmt . Sprintf ( "repository=%s" , specs . PLACEHOLDER_REPO ) ,
2016-09-30 19:53:12 +00:00
fmt . Sprintf ( "buildername=%s" , name ) ,
"mastername=fake-master" ,
"buildnumber=2" ,
"slavename=fake-buildslave" ,
2016-10-13 13:23:45 +00:00
"nobuildbot=True" ,
2016-09-30 19:53:12 +00:00
fmt . Sprintf ( "swarm_out_dir=%s" , specs . PLACEHOLDER_ISOLATED_OUTDIR ) ,
fmt . Sprintf ( "revision=%s" , specs . PLACEHOLDER_REVISION ) ,
2016-10-13 13:23:45 +00:00
fmt . Sprintf ( "patch_storage=%s" , specs . PLACEHOLDER_PATCH_STORAGE ) ,
2016-11-04 18:37:26 +00:00
fmt . Sprintf ( "patch_issue=%s" , specs . PLACEHOLDER_ISSUE ) ,
fmt . Sprintf ( "patch_set=%s" , specs . PLACEHOLDER_PATCHSET ) ,
2016-09-30 19:53:12 +00:00
} ,
2017-02-22 13:36:03 +00:00
IoTimeout : 40 * time . Minute ,
Isolate : "test_skia.isolate" ,
MaxAttempts : 1 ,
Priority : 0.8 ,
2016-11-08 17:55:32 +00:00
}
2017-04-06 12:53:31 +00:00
if parts [ "os" ] == "Android" {
2017-04-04 13:06:16 +00:00
s . Dependencies = append ( s . Dependencies , BUNDLE_RECIPES_NAME )
s . Isolate = "test_skia_bundled.isolate"
}
2016-11-08 17:55:32 +00:00
if strings . Contains ( parts [ "extra_config" ] , "Valgrind" ) {
s . ExecutionTimeout = 9 * time . Hour
s . Expiration = 48 * time . Hour
s . IoTimeout = time . Hour
} else if strings . Contains ( parts [ "extra_config" ] , "MSAN" ) {
s . ExecutionTimeout = 9 * time . Hour
}
b . MustAddTask ( name , s )
2016-09-30 19:53:12 +00:00
// Upload results if necessary.
if doUpload ( name ) {
uploadName := fmt . Sprintf ( "%s%s%s" , PREFIX_UPLOAD , jobNameSchema . Sep , name )
2016-10-20 18:04:31 +00:00
b . MustAddTask ( uploadName , & specs . TaskSpec {
2016-09-30 19:53:12 +00:00
Dependencies : [ ] string { name } ,
2017-02-01 20:56:55 +00:00
Dimensions : linuxGceDimensions ( ) ,
2016-09-30 19:53:12 +00:00
ExtraArgs : [ ] string {
"--workdir" , "../../.." , "upload_dm_results" ,
2016-11-04 18:37:26 +00:00
fmt . Sprintf ( "repository=%s" , specs . PLACEHOLDER_REPO ) ,
2016-09-30 19:53:12 +00:00
fmt . Sprintf ( "buildername=%s" , name ) ,
"mastername=fake-master" ,
"buildnumber=2" ,
"slavename=fake-buildslave" ,
2016-10-13 13:23:45 +00:00
"nobuildbot=True" ,
2016-09-30 19:53:12 +00:00
fmt . Sprintf ( "swarm_out_dir=%s" , specs . PLACEHOLDER_ISOLATED_OUTDIR ) ,
fmt . Sprintf ( "revision=%s" , specs . PLACEHOLDER_REVISION ) ,
2016-10-13 13:23:45 +00:00
fmt . Sprintf ( "patch_storage=%s" , specs . PLACEHOLDER_PATCH_STORAGE ) ,
2016-11-04 18:37:26 +00:00
fmt . Sprintf ( "patch_issue=%s" , specs . PLACEHOLDER_ISSUE ) ,
fmt . Sprintf ( "patch_set=%s" , specs . PLACEHOLDER_PATCHSET ) ,
2017-02-06 20:38:41 +00:00
fmt . Sprintf ( "gs_bucket=%s" , CONFIG . GsBucketGm ) ,
2016-09-30 19:53:12 +00:00
} ,
Isolate : "upload_dm_results.isolate" ,
Priority : 0.8 ,
2016-10-20 18:04:31 +00:00
} )
2016-09-30 19:53:12 +00:00
return uploadName
}
return name
}
// perf generates a Perf task. Returns the name of the last task in the
// generated chain of tasks, which the Job should add as a dependency.
2016-10-20 18:04:31 +00:00
func perf ( b * specs . TasksCfgBuilder , name string , parts map [ string ] string , compileTaskName string , pkgs [ ] * specs . CipdPackage ) string {
2016-11-14 18:42:27 +00:00
recipe := "swarm_perf"
isolate := "perf_skia.isolate"
if strings . Contains ( parts [ "extra_config" ] , "Skpbench" ) {
recipe = "swarm_skpbench"
isolate = "skpbench_skia.isolate"
2017-04-06 12:53:31 +00:00
if parts [ "os" ] == "Android" {
2017-04-04 13:06:16 +00:00
isolate = "skpbench_skia_bundled.isolate"
}
2017-04-06 12:53:31 +00:00
} else if parts [ "os" ] == "Android" {
2017-04-04 13:06:16 +00:00
isolate = "perf_skia_bundled.isolate"
2016-11-14 18:42:27 +00:00
}
2016-11-08 17:55:32 +00:00
s := & specs . TaskSpec {
2016-11-09 23:35:15 +00:00
CipdPackages : pkgs ,
Dependencies : [ ] string { compileTaskName } ,
Dimensions : swarmDimensions ( parts ) ,
ExecutionTimeout : 4 * time . Hour ,
Expiration : 20 * time . Hour ,
2016-09-30 19:53:12 +00:00
ExtraArgs : [ ] string {
2016-11-14 18:42:27 +00:00
"--workdir" , "../../.." , recipe ,
2016-11-04 18:37:26 +00:00
fmt . Sprintf ( "repository=%s" , specs . PLACEHOLDER_REPO ) ,
2016-09-30 19:53:12 +00:00
fmt . Sprintf ( "buildername=%s" , name ) ,
"mastername=fake-master" ,
"buildnumber=2" ,
"slavename=fake-buildslave" ,
2016-10-13 13:23:45 +00:00
"nobuildbot=True" ,
2016-09-30 19:53:12 +00:00
fmt . Sprintf ( "swarm_out_dir=%s" , specs . PLACEHOLDER_ISOLATED_OUTDIR ) ,
fmt . Sprintf ( "revision=%s" , specs . PLACEHOLDER_REVISION ) ,
2016-10-13 13:23:45 +00:00
fmt . Sprintf ( "patch_storage=%s" , specs . PLACEHOLDER_PATCH_STORAGE ) ,
2016-11-04 18:37:26 +00:00
fmt . Sprintf ( "patch_issue=%s" , specs . PLACEHOLDER_ISSUE ) ,
fmt . Sprintf ( "patch_set=%s" , specs . PLACEHOLDER_PATCHSET ) ,
2016-09-30 19:53:12 +00:00
} ,
2017-02-22 13:36:03 +00:00
IoTimeout : 40 * time . Minute ,
Isolate : isolate ,
MaxAttempts : 1 ,
Priority : 0.8 ,
2016-11-08 17:55:32 +00:00
}
2017-04-06 12:53:31 +00:00
if parts [ "os" ] == "Android" {
2017-04-04 13:06:16 +00:00
s . Dependencies = append ( s . Dependencies , BUNDLE_RECIPES_NAME )
}
2016-11-08 17:55:32 +00:00
if strings . Contains ( parts [ "extra_config" ] , "Valgrind" ) {
s . ExecutionTimeout = 9 * time . Hour
s . Expiration = 48 * time . Hour
s . IoTimeout = time . Hour
} else if strings . Contains ( parts [ "extra_config" ] , "MSAN" ) {
s . ExecutionTimeout = 9 * time . Hour
}
b . MustAddTask ( name , s )
2016-09-30 19:53:12 +00:00
// Upload results if necessary.
if strings . Contains ( name , "Release" ) && doUpload ( name ) {
uploadName := fmt . Sprintf ( "%s%s%s" , PREFIX_UPLOAD , jobNameSchema . Sep , name )
2016-10-20 18:04:31 +00:00
b . MustAddTask ( uploadName , & specs . TaskSpec {
2016-09-30 19:53:12 +00:00
Dependencies : [ ] string { name } ,
2017-02-01 20:56:55 +00:00
Dimensions : linuxGceDimensions ( ) ,
2016-09-30 19:53:12 +00:00
ExtraArgs : [ ] string {
"--workdir" , "../../.." , "upload_nano_results" ,
2016-11-04 18:37:26 +00:00
fmt . Sprintf ( "repository=%s" , specs . PLACEHOLDER_REPO ) ,
2016-09-30 19:53:12 +00:00
fmt . Sprintf ( "buildername=%s" , name ) ,
"mastername=fake-master" ,
"buildnumber=2" ,
"slavename=fake-buildslave" ,
2016-10-13 13:23:45 +00:00
"nobuildbot=True" ,
2016-09-30 19:53:12 +00:00
fmt . Sprintf ( "swarm_out_dir=%s" , specs . PLACEHOLDER_ISOLATED_OUTDIR ) ,
fmt . Sprintf ( "revision=%s" , specs . PLACEHOLDER_REVISION ) ,
2016-10-13 13:23:45 +00:00
fmt . Sprintf ( "patch_storage=%s" , specs . PLACEHOLDER_PATCH_STORAGE ) ,
2016-11-04 18:37:26 +00:00
fmt . Sprintf ( "patch_issue=%s" , specs . PLACEHOLDER_ISSUE ) ,
fmt . Sprintf ( "patch_set=%s" , specs . PLACEHOLDER_PATCHSET ) ,
2017-02-06 20:38:41 +00:00
fmt . Sprintf ( "gs_bucket=%s" , CONFIG . GsBucketNano ) ,
2016-09-30 19:53:12 +00:00
} ,
Isolate : "upload_nano_results.isolate" ,
Priority : 0.8 ,
2016-10-20 18:04:31 +00:00
} )
2016-09-30 19:53:12 +00:00
return uploadName
}
return name
}
// process generates tasks and jobs for the given job name.
2016-10-20 18:04:31 +00:00
func process ( b * specs . TasksCfgBuilder , name string ) {
2016-09-30 19:53:12 +00:00
deps := [ ] string { }
2017-04-04 13:06:16 +00:00
// Bundle Recipes.
if name == BUNDLE_RECIPES_NAME {
deps = append ( deps , bundleRecipes ( b ) )
}
2016-09-30 19:53:12 +00:00
parts , err := jobNameSchema . ParseJobName ( name )
if err != nil {
glog . Fatal ( err )
}
// RecreateSKPs.
if strings . Contains ( name , "RecreateSKPs" ) {
2016-10-20 18:04:31 +00:00
deps = append ( deps , recreateSKPs ( b , name ) )
2016-09-30 19:53:12 +00:00
}
// CT bots.
if strings . Contains ( name , "-CT_" ) {
2016-10-20 18:04:31 +00:00
deps = append ( deps , ctSKPs ( b , name ) )
2016-09-30 19:53:12 +00:00
}
2016-10-14 13:32:09 +00:00
// Infra tests.
if name == "Housekeeper-PerCommit-InfraTests" {
2016-10-20 18:04:31 +00:00
deps = append ( deps , infra ( b , name ) )
2016-10-14 13:32:09 +00:00
}
2016-09-30 19:53:12 +00:00
// Compile bots.
if parts [ "role" ] == "Build" {
2016-10-20 18:04:31 +00:00
deps = append ( deps , compile ( b , name , parts ) )
2016-09-30 19:53:12 +00:00
}
2016-11-15 20:18:20 +00:00
// Most remaining bots need a compile task.
2016-09-30 19:53:12 +00:00
compileTaskName := deriveCompileTaskName ( name , parts )
2016-10-17 17:17:53 +00:00
compileTaskParts , err := jobNameSchema . ParseJobName ( compileTaskName )
if err != nil {
glog . Fatal ( err )
}
2016-11-17 16:33:27 +00:00
// These bots do not need a compile task.
2016-11-15 20:18:20 +00:00
if parts [ "role" ] != "Build" &&
name != "Housekeeper-PerCommit-InfraTests" &&
2016-11-30 19:05:16 +00:00
! strings . Contains ( name , "RecreateSKPs" ) &&
! strings . Contains ( name , "-CT_" ) {
2016-10-20 18:04:31 +00:00
compile ( b , compileTaskName , compileTaskParts )
2016-10-17 17:17:53 +00:00
}
2016-09-30 19:53:12 +00:00
// Housekeeper.
2016-12-02 16:01:33 +00:00
if name == "Housekeeper-PerCommit" {
2016-10-20 18:04:31 +00:00
deps = append ( deps , housekeeper ( b , name , compileTaskName ) )
2016-09-30 19:53:12 +00:00
}
// Common assets needed by the remaining bots.
pkgs := [ ] * specs . CipdPackage {
2016-10-20 18:04:31 +00:00
b . MustGetCipdPackageFromAsset ( "skimage" ) ,
b . MustGetCipdPackageFromAsset ( "skp" ) ,
b . MustGetCipdPackageFromAsset ( "svg" ) ,
2016-09-30 19:53:12 +00:00
}
2017-03-21 13:25:34 +00:00
if strings . Contains ( name , "Chromecast" ) {
// Chromecasts don't have enough disk space to fit all of the content,
// so we do a subset of the skps.
pkgs = [ ] * specs . CipdPackage {
b . MustGetCipdPackageFromAsset ( "skp" ) ,
}
}
2016-11-08 17:55:32 +00:00
if strings . Contains ( name , "Ubuntu" ) && strings . Contains ( name , "SAN" ) {
pkgs = append ( pkgs , b . MustGetCipdPackageFromAsset ( "clang_linux" ) )
}
2017-02-17 15:25:34 +00:00
if strings . Contains ( name , "Ubuntu16" ) {
if strings . Contains ( name , "Vulkan" ) {
pkgs = append ( pkgs , b . MustGetCipdPackageFromAsset ( "linux_vulkan_sdk" ) )
}
2017-02-06 17:45:29 +00:00
if strings . Contains ( name , "Release" ) {
pkgs = append ( pkgs , b . MustGetCipdPackageFromAsset ( "linux_vulkan_intel_driver_release" ) )
} else {
pkgs = append ( pkgs , b . MustGetCipdPackageFromAsset ( "linux_vulkan_intel_driver_debug" ) )
}
}
2016-11-14 18:42:27 +00:00
// Skpbench only needs skps
if strings . Contains ( name , "Skpbench" ) {
pkgs = [ ] * specs . CipdPackage {
b . MustGetCipdPackageFromAsset ( "skp" ) ,
}
}
2016-09-30 19:53:12 +00:00
// Test bots.
2016-11-30 19:05:16 +00:00
if parts [ "role" ] == "Test" && ! strings . Contains ( name , "-CT_" ) {
2016-10-20 18:04:31 +00:00
deps = append ( deps , test ( b , name , parts , compileTaskName , pkgs ) )
2016-09-30 19:53:12 +00:00
}
// Perf bots.
2016-11-30 19:05:16 +00:00
if parts [ "role" ] == "Perf" && ! strings . Contains ( name , "-CT_" ) {
2016-10-20 18:04:31 +00:00
deps = append ( deps , perf ( b , name , parts , compileTaskName , pkgs ) )
2016-09-30 19:53:12 +00:00
}
// Add the Job spec.
2016-11-15 20:18:20 +00:00
j := & specs . JobSpec {
2016-09-30 19:53:12 +00:00
Priority : 0.8 ,
TaskSpecs : deps ,
2016-11-15 20:18:20 +00:00
}
if name == "Housekeeper-Nightly-RecreateSKPs_Canary" {
j . Trigger = "nightly"
}
if name == "Housekeeper-Weekly-RecreateSKPs" {
j . Trigger = "weekly"
}
2016-11-30 19:05:16 +00:00
if name == "Test-Ubuntu-GCC-GCE-CPU-AVX2-x86_64-Debug-CT_DM_1m_SKPs" {
j . Trigger = "weekly"
}
2016-12-12 19:30:12 +00:00
b . MustAddJob ( name , j )
2016-09-30 19:53:12 +00:00
}
2017-02-01 20:56:55 +00:00
func loadJson ( flag * string , defaultFlag string , val interface { } ) {
if * flag == "" {
* flag = defaultFlag
}
b , err := ioutil . ReadFile ( * flag )
if err != nil {
glog . Fatal ( err )
}
if err := json . Unmarshal ( b , val ) ; err != nil {
glog . Fatal ( err )
}
}
2016-09-30 19:53:12 +00:00
// Regenerate the tasks.json file.
func main ( ) {
2016-10-20 18:04:31 +00:00
b := specs . MustNewTasksCfgBuilder ( )
2017-02-01 20:56:55 +00:00
b . SetAssetsDir ( * assetsDir )
infraBots := path . Join ( b . CheckoutRoot ( ) , "infra" , "bots" )
// Load the jobs from a JSON file.
loadJson ( jobsFile , path . Join ( infraBots , "jobs.json" ) , & JOBS )
// Load the GPU mapping from a JSON file.
loadJson ( gpuMapFile , path . Join ( infraBots , "gpu_map.json" ) , & GPU_MAPPING )
// Load the Android device mapping from a JSON file.
loadJson ( androidMapFile , path . Join ( infraBots , "android_map.json" ) , & ANDROID_MAPPING )
// Load general config information from a JSON file.
loadJson ( cfgFile , path . Join ( infraBots , "cfg.json" ) , & CONFIG )
2016-09-30 19:53:12 +00:00
// Create the JobNameSchema.
2017-02-07 14:16:30 +00:00
if * builderNameSchemaFile == "" {
* builderNameSchemaFile = path . Join ( b . CheckoutRoot ( ) , "infra" , "bots" , "recipe_modules" , "builder_name_schema" , "builder_name_schema.json" )
}
schema , err := NewJobNameSchema ( * builderNameSchemaFile )
2016-09-30 19:53:12 +00:00
if err != nil {
glog . Fatal ( err )
}
jobNameSchema = schema
// Create Tasks and Jobs.
2016-10-20 18:04:31 +00:00
for _ , name := range JOBS {
process ( b , name )
2016-09-30 19:53:12 +00:00
}
2016-10-20 18:04:31 +00:00
b . MustFinish ( )
2016-09-30 19:53:12 +00:00
}
// TODO(borenet): The below really belongs in its own file, probably next to the
// builder_name_schema.json file.
// JobNameSchema is a struct used for (de)constructing Job names in a
// predictable format.
type JobNameSchema struct {
Schema map [ string ] [ ] string ` json:"builder_name_schema" `
Sep string ` json:"builder_name_sep" `
}
// NewJobNameSchema returns a JobNameSchema instance based on the given JSON
// file.
func NewJobNameSchema ( jsonFile string ) ( * JobNameSchema , error ) {
var rv JobNameSchema
f , err := os . Open ( jsonFile )
if err != nil {
return nil , err
}
defer util . Close ( f )
if err := json . NewDecoder ( f ) . Decode ( & rv ) ; err != nil {
return nil , err
}
return & rv , nil
}
// ParseJobName splits the given Job name into its component parts, according
// to the schema.
func ( s * JobNameSchema ) ParseJobName ( n string ) ( map [ string ] string , error ) {
split := strings . Split ( n , s . Sep )
if len ( split ) < 2 {
return nil , fmt . Errorf ( "Invalid job name: %q" , n )
}
role := split [ 0 ]
split = split [ 1 : ]
keys , ok := s . Schema [ role ]
if ! ok {
return nil , fmt . Errorf ( "Invalid job name; %q is not a valid role." , role )
}
extraConfig := ""
if len ( split ) == len ( keys ) + 1 {
extraConfig = split [ len ( split ) - 1 ]
split = split [ : len ( split ) - 1 ]
}
if len ( split ) != len ( keys ) {
return nil , fmt . Errorf ( "Invalid job name; %q has incorrect number of parts." , n )
}
rv := make ( map [ string ] string , len ( keys ) + 2 )
rv [ "role" ] = role
if extraConfig != "" {
rv [ "extra_config" ] = extraConfig
}
for i , k := range keys {
rv [ k ] = split [ i ]
}
return rv , nil
}
// MakeJobName assembles the given parts of a Job name, according to the schema.
func ( s * JobNameSchema ) MakeJobName ( parts map [ string ] string ) ( string , error ) {
role , ok := parts [ "role" ]
if ! ok {
return "" , fmt . Errorf ( "Invalid job parts; jobs must have a role." )
}
keys , ok := s . Schema [ role ]
if ! ok {
return "" , fmt . Errorf ( "Invalid job parts; unknown role %q" , role )
}
rvParts := make ( [ ] string , 0 , len ( parts ) )
rvParts = append ( rvParts , role )
for _ , k := range keys {
v , ok := parts [ k ]
if ! ok {
return "" , fmt . Errorf ( "Invalid job parts; missing %q" , k )
}
rvParts = append ( rvParts , v )
}
if _ , ok := parts [ "extra_config" ] ; ok {
rvParts = append ( rvParts , parts [ "extra_config" ] )
}
return strings . Join ( rvParts , s . Sep ) , nil
}