| OLD | NEW |
| 1 // Application that captures SKPs from CT's webpage archives. | 1 // Application that captures SKPs from CT's webpage archives. |
| 2 package main | 2 package main |
| 3 | 3 |
| 4 import ( | 4 import ( |
| 5 "encoding/csv" | |
| 6 "flag" | 5 "flag" |
| 7 "fmt" | 6 "fmt" |
| 8 "io/ioutil" | 7 "io/ioutil" |
| 9 "os" | 8 "os" |
| 9 "path" |
| 10 "path/filepath" | 10 "path/filepath" |
| 11 » "runtime" | 11 » "strconv" |
| 12 "sync" | 12 "sync" |
| 13 "time" | 13 "time" |
| 14 | 14 |
| 15 "github.com/skia-dev/glog" | 15 "github.com/skia-dev/glog" |
| 16 | 16 |
| 17 "go.skia.org/infra/ct/go/util" | 17 "go.skia.org/infra/ct/go/util" |
| 18 "go.skia.org/infra/ct/go/worker_scripts/worker_common" | 18 "go.skia.org/infra/ct/go/worker_scripts/worker_common" |
| 19 "go.skia.org/infra/go/common" | 19 "go.skia.org/infra/go/common" |
| 20 skutil "go.skia.org/infra/go/util" | 20 skutil "go.skia.org/infra/go/util" |
| 21 ) | 21 ) |
| 22 | 22 |
| 23 const ( | 23 const ( |
| 24 // The number of goroutines that will run in parallel to capture SKPs. | 24 // The number of goroutines that will run in parallel to capture SKPs. |
| 25 WORKER_POOL_SIZE = 10 | 25 WORKER_POOL_SIZE = 10 |
| 26 ) | 26 ) |
| 27 | 27 |
| 28 var ( | 28 var ( |
| 29 » workerNum = flag.Int("worker_num", 1, "The number of this CT wo
rker. It will be in the {1..100} range.") | 29 » startRange = flag.Int("start_range", 1, "The number this worker
will capture SKPs from.") |
| 30 » num = flag.Int("num", 100, "The total number of SKPs to c
apture starting from the start_range.") |
| 30 pagesetType = flag.String("pageset_type", util.PAGESET_TYPE_MOBIL
E_10k, "The type of pagesets to create SKPs from. Eg: 10k, Mobile10k, All.") | 31 pagesetType = flag.String("pageset_type", util.PAGESET_TYPE_MOBIL
E_10k, "The type of pagesets to create SKPs from. Eg: 10k, Mobile10k, All.") |
| 31 chromiumBuild = flag.String("chromium_build", "", "The chromium bui
ld that will be used to create the SKPs.") | 32 chromiumBuild = flag.String("chromium_build", "", "The chromium bui
ld that will be used to create the SKPs.") |
| 32 runID = flag.String("run_id", "", "The unique run id (typic
ally requester + timestamp).") | 33 runID = flag.String("run_id", "", "The unique run id (typic
ally requester + timestamp).") |
| 33 targetPlatform = flag.String("target_platform", util.PLATFORM_LINUX,
"The platform the benchmark will run on (Android / Linux).") | 34 targetPlatform = flag.String("target_platform", util.PLATFORM_LINUX,
"The platform the benchmark will run on (Android / Linux).") |
| 34 chromeCleanerTimer = flag.Duration("cleaner_timer", 30*time.Minute, "How
often all chrome processes will be killed on this slave.") | 35 chromeCleanerTimer = flag.Duration("cleaner_timer", 30*time.Minute, "How
often all chrome processes will be killed on this slave.") |
| 35 ) | 36 ) |
| 36 | 37 |
| 37 func main() { | 38 func main() { |
| 38 defer common.LogPanic() | 39 defer common.LogPanic() |
| 39 worker_common.Init() | 40 worker_common.Init() |
| 40 if !*worker_common.Local { | |
| 41 defer util.CleanTmpDir() | |
| 42 } | |
| 43 defer util.TimeTrack(time.Now(), "Capturing SKPs") | 41 defer util.TimeTrack(time.Now(), "Capturing SKPs") |
| 44 defer glog.Flush() | 42 defer glog.Flush() |
| 45 | 43 |
| 46 // Validate required arguments. | 44 // Validate required arguments. |
| 47 if *chromiumBuild == "" { | 45 if *chromiumBuild == "" { |
| 48 glog.Error("Must specify --chromium_build") | 46 glog.Error("Must specify --chromium_build") |
| 49 return | 47 return |
| 50 } | 48 } |
| 51 if *runID == "" { | 49 if *runID == "" { |
| 52 glog.Error("Must specify --run_id") | 50 glog.Error("Must specify --run_id") |
| 53 return | 51 return |
| 54 } | 52 } |
| 55 if *targetPlatform == util.PLATFORM_ANDROID { | 53 if *targetPlatform == util.PLATFORM_ANDROID { |
| 56 glog.Error("Android is not yet supported for capturing SKPs.") | 54 glog.Error("Android is not yet supported for capturing SKPs.") |
| 57 return | 55 return |
| 58 } | 56 } |
| 59 | 57 |
| 60 // Reset the local chromium checkout. | 58 // Reset the local chromium checkout. |
| 61 if err := util.ResetCheckout(util.ChromiumSrcDir); err != nil { | 59 if err := util.ResetCheckout(util.ChromiumSrcDir); err != nil { |
| 62 glog.Errorf("Could not reset %s: %s", util.ChromiumSrcDir, err) | 60 glog.Errorf("Could not reset %s: %s", util.ChromiumSrcDir, err) |
| 63 return | 61 return |
| 64 } | 62 } |
| 65 // Sync the local chromium checkout. | 63 // Sync the local chromium checkout. |
| 66 if err := util.SyncDir(util.ChromiumSrcDir); err != nil { | 64 if err := util.SyncDir(util.ChromiumSrcDir); err != nil { |
| 67 glog.Errorf("Could not gclient sync %s: %s", util.ChromiumSrcDir
, err) | 65 glog.Errorf("Could not gclient sync %s: %s", util.ChromiumSrcDir
, err) |
| 68 return | 66 return |
| 69 } | 67 } |
| 70 | 68 |
| 71 // Create the task file so that the master knows this worker is still bu
sy. | |
| 72 skutil.LogErr(util.CreateTaskFile(util.ACTIVITY_CAPTURING_SKPS)) | |
| 73 defer util.DeleteTaskFile(util.ACTIVITY_CAPTURING_SKPS) | |
| 74 | |
| 75 // Instantiate GsUtil object. | 69 // Instantiate GsUtil object. |
| 76 gs, err := util.NewGsUtil(nil) | 70 gs, err := util.NewGsUtil(nil) |
| 77 if err != nil { | 71 if err != nil { |
| 78 glog.Error(err) | 72 glog.Error(err) |
| 79 return | 73 return |
| 80 } | 74 } |
| 81 | 75 |
| 82 // Download the specified chromium build. | 76 // Download the specified chromium build. |
| 83 if err := gs.DownloadChromiumBuild(*chromiumBuild); err != nil { | 77 if err := gs.DownloadChromiumBuild(*chromiumBuild); err != nil { |
| 84 glog.Error(err) | 78 glog.Error(err) |
| 85 return | 79 return |
| 86 } | 80 } |
| 87 // Delete the chromium build to save space when we are done. | 81 // Delete the chromium build to save space when we are done. |
| 88 defer skutil.RemoveAll(filepath.Join(util.ChromiumBuildsDir, *chromiumBu
ild)) | 82 defer skutil.RemoveAll(filepath.Join(util.ChromiumBuildsDir, *chromiumBu
ild)) |
| 89 chromiumBinary := filepath.Join(util.ChromiumBuildsDir, *chromiumBuild,
util.BINARY_CHROME) | 83 chromiumBinary := filepath.Join(util.ChromiumBuildsDir, *chromiumBuild,
util.BINARY_CHROME) |
| 90 if *targetPlatform == util.PLATFORM_ANDROID { | 84 if *targetPlatform == util.PLATFORM_ANDROID { |
| 91 // Install the APK on the Android device. | 85 // Install the APK on the Android device. |
| 92 if err := util.InstallChromeAPK(*chromiumBuild); err != nil { | 86 if err := util.InstallChromeAPK(*chromiumBuild); err != nil { |
| 93 glog.Errorf("Could not install the chromium APK: %s", er
r) | 87 glog.Errorf("Could not install the chromium APK: %s", er
r) |
| 94 return | 88 return |
| 95 } | 89 } |
| 96 } | 90 } |
| 97 | 91 |
| 98 // Download pagesets if they do not exist locally. | 92 // Download pagesets if they do not exist locally. |
| 99 » if err := gs.DownloadWorkerArtifacts(util.PAGESETS_DIR_NAME, *pagesetTyp
e, *workerNum); err != nil { | 93 » pathToPagesets := filepath.Join(util.PagesetsDir, *pagesetType) |
| 94 » if _, err := gs.DownloadSwarmingArtifacts(pathToPagesets, util.PAGESETS_
DIR_NAME, *pagesetType, *startRange, *num); err != nil { |
| 100 glog.Error(err) | 95 glog.Error(err) |
| 101 return | 96 return |
| 102 } | 97 } |
| 103 » pathToPagesets := filepath.Join(util.PagesetsDir, *pagesetType) | 98 » defer skutil.RemoveAll(pathToPagesets) |
| 104 | 99 |
| 105 // Download archives if they do not exist locally. | 100 // Download archives if they do not exist locally. |
| 106 » if err := gs.DownloadWorkerArtifacts(util.WEB_ARCHIVES_DIR_NAME, *pagese
tType, *workerNum); err != nil { | 101 » pathToArchives := filepath.Join(util.WebArchivesDir, *pagesetType) |
| 102 » archivesToIndex, err := gs.DownloadSwarmingArtifacts(pathToArchives, uti
l.WEB_ARCHIVES_DIR_NAME, *pagesetType, *startRange, *num) |
| 103 » if err != nil { |
| 107 glog.Error(err) | 104 glog.Error(err) |
| 108 return | 105 return |
| 109 } | 106 } |
| 107 defer skutil.RemoveAll(pathToArchives) |
| 110 | 108 |
| 111 // Create the dir that SKPs will be stored in. | 109 // Create the dir that SKPs will be stored in. |
| 112 pathToSkps := filepath.Join(util.SkpsDir, *pagesetType, *chromiumBuild) | 110 pathToSkps := filepath.Join(util.SkpsDir, *pagesetType, *chromiumBuild) |
| 113 // Delete and remake the local SKPs directory. | 111 // Delete and remake the local SKPs directory. |
| 114 skutil.RemoveAll(pathToSkps) | 112 skutil.RemoveAll(pathToSkps) |
| 115 skutil.MkdirAll(pathToSkps, 0700) | 113 skutil.MkdirAll(pathToSkps, 0700) |
| 116 | 114 » defer skutil.RemoveAll(pathToSkps) |
| 117 » // Establish output paths. | |
| 118 » localOutputDir := filepath.Join(util.StorageDir, util.BenchmarkRunsDir,
*runID) | |
| 119 » skutil.RemoveAll(localOutputDir) | |
| 120 » skutil.MkdirAll(localOutputDir, 0700) | |
| 121 » defer skutil.RemoveAll(localOutputDir) | |
| 122 | 115 |
| 123 // Construct path to the ct_run_benchmark python script. | 116 // Construct path to the ct_run_benchmark python script. |
| 124 » _, currentFile, _, _ := runtime.Caller(0) | 117 » pathToPyFiles := util.GetPathToPyFiles(!*worker_common.Local) |
| 125 » pathToPyFiles := filepath.Join( | |
| 126 » » filepath.Dir((filepath.Dir(filepath.Dir(filepath.Dir(currentFile
))))), | |
| 127 » » "py") | |
| 128 | 118 |
| 129 timeoutSecs := util.PagesetTypeToInfo[*pagesetType].CaptureSKPsTimeoutSe
cs | 119 timeoutSecs := util.PagesetTypeToInfo[*pagesetType].CaptureSKPsTimeoutSe
cs |
| 130 fileInfos, err := ioutil.ReadDir(pathToPagesets) | 120 fileInfos, err := ioutil.ReadDir(pathToPagesets) |
| 131 if err != nil { | 121 if err != nil { |
| 132 glog.Errorf("Unable to read the pagesets dir %s: %s", pathToPage
sets, err) | 122 glog.Errorf("Unable to read the pagesets dir %s: %s", pathToPage
sets, err) |
| 133 return | 123 return |
| 134 } | 124 } |
| 135 | 125 |
| 136 // Create channel that contains all pageset file names. This channel wil
l | 126 // Create channel that contains all pageset file names. This channel wil
l |
| 137 // be consumed by the worker pool. | 127 // be consumed by the worker pool. |
| (...skipping 23 matching lines...) Expand all Loading... |
| 161 pagesetPath := filepath.Join(pathToPagesets, pag
esetName) | 151 pagesetPath := filepath.Join(pathToPagesets, pag
esetName) |
| 162 decodedPageset, err := util.ReadPageset(pagesetP
ath) | 152 decodedPageset, err := util.ReadPageset(pagesetP
ath) |
| 163 if err != nil { | 153 if err != nil { |
| 164 glog.Errorf("Could not read %s: %s", pag
esetPath, err) | 154 glog.Errorf("Could not read %s: %s", pag
esetPath, err) |
| 165 continue | 155 continue |
| 166 } | 156 } |
| 167 | 157 |
| 168 glog.Infof("===== Processing %s =====", pagesetP
ath) | 158 glog.Infof("===== Processing %s =====", pagesetP
ath) |
| 169 | 159 |
| 170 skutil.LogErr(os.Chdir(pathToPyFiles)) | 160 skutil.LogErr(os.Chdir(pathToPyFiles)) |
| 161 index, ok := archivesToIndex[decodedPageset.Arch
iveDataFile] |
| 162 if !ok { |
| 163 glog.Errorf("%s not found in the archive
sToIndex map", decodedPageset.ArchiveDataFile) |
| 164 continue |
| 165 } |
| 171 args := []string{ | 166 args := []string{ |
| 172 filepath.Join(util.TelemetryBinariesDir,
util.BINARY_RUN_BENCHMARK), | 167 filepath.Join(util.TelemetryBinariesDir,
util.BINARY_RUN_BENCHMARK), |
| 173 util.BenchmarksToTelemetryName[util.BENC
HMARK_SKPICTURE_PRINTER], | 168 util.BenchmarksToTelemetryName[util.BENC
HMARK_SKPICTURE_PRINTER], |
| 174 "--also-run-disabled-tests", | 169 "--also-run-disabled-tests", |
| 175 "--page-repeat=1", // Only need one run
for SKPs. | 170 "--page-repeat=1", // Only need one run
for SKPs. |
| 176 » » » » » "--skp-outdir=" + pathToSkps, | 171 » » » » » "--skp-outdir=" + path.Join(pathToSkps,
strconv.Itoa(index)), |
| 177 "--extra-browser-args=" + util.DEFAULT_B
ROWSER_ARGS, | 172 "--extra-browser-args=" + util.DEFAULT_B
ROWSER_ARGS, |
| 178 "--user-agent=" + decodedPageset.UserAge
nt, | 173 "--user-agent=" + decodedPageset.UserAge
nt, |
| 179 "--urls-list=" + decodedPageset.UrlsList
, | 174 "--urls-list=" + decodedPageset.UrlsList
, |
| 180 "--archive-data-file=" + decodedPageset.
ArchiveDataFile, | 175 "--archive-data-file=" + decodedPageset.
ArchiveDataFile, |
| 181 } | 176 } |
| 182 // Figure out which browser and device should be
used. | 177 // Figure out which browser and device should be
used. |
| 183 if *targetPlatform == util.PLATFORM_ANDROID { | 178 if *targetPlatform == util.PLATFORM_ANDROID { |
| 184 args = append(args, "--browser=android-c
hromium") | 179 args = append(args, "--browser=android-c
hromium") |
| 185 } else { | 180 } else { |
| 186 args = append(args, "--browser=exact", "
--browser-executable="+chromiumBinary) | 181 args = append(args, "--browser=exact", "
--browser-executable="+chromiumBinary) |
| 187 args = append(args, "--device=desktop") | 182 args = append(args, "--device=desktop") |
| 188 } | 183 } |
| 189 // Set the PYTHONPATH to the pagesets and the te
lemetry dirs. | 184 // Set the PYTHONPATH to the pagesets and the te
lemetry dirs. |
| 190 env := []string{ | 185 env := []string{ |
| 191 fmt.Sprintf("PYTHONPATH=%s:%s:%s:%s:$PYT
HONPATH", pathToPagesets, util.TelemetryBinariesDir, util.TelemetrySrcDir, util.
CatapultSrcDir), | 186 fmt.Sprintf("PYTHONPATH=%s:%s:%s:%s:$PYT
HONPATH", pathToPagesets, util.TelemetryBinariesDir, util.TelemetrySrcDir, util.
CatapultSrcDir), |
| 192 "DISPLAY=:0", | 187 "DISPLAY=:0", |
| 193 } | 188 } |
| 194 skutil.LogErr( | 189 skutil.LogErr( |
| 195 util.ExecuteCmd("python", args, env, tim
e.Duration(timeoutSecs)*time.Second, nil, nil)) | 190 util.ExecuteCmd("python", args, env, tim
e.Duration(timeoutSecs)*time.Second, nil, nil)) |
| 196 | 191 |
| 197 mutex.RUnlock() | 192 mutex.RUnlock() |
| 198 | |
| 199 } | 193 } |
| 200 }() | 194 }() |
| 201 } | 195 } |
| 202 | 196 |
| 203 if !*worker_common.Local { | 197 if !*worker_common.Local { |
| 204 // Start the cleaner. | 198 // Start the cleaner. |
| 205 go util.ChromeProcessesCleaner(&mutex, *chromeCleanerTimer) | 199 go util.ChromeProcessesCleaner(&mutex, *chromeCleanerTimer) |
| 206 } | 200 } |
| 207 | 201 |
| 208 // Wait for all spawned goroutines to complete. | 202 // Wait for all spawned goroutines to complete. |
| 209 wg.Wait() | 203 wg.Wait() |
| 210 | 204 |
| 211 // Move and validate all SKP files. | 205 // Move and validate all SKP files. |
| 212 » if err := util.ValidateSKPs(pathToSkps); err != nil { | 206 » if err := util.ValidateSKPs(pathToSkps, pathToPyFiles); err != nil { |
| 213 glog.Error(err) | 207 glog.Error(err) |
| 214 return | 208 return |
| 215 } | 209 } |
| 216 | 210 |
| 217 // Write timestamp to the SKPs dir. | |
| 218 skutil.LogErr(util.CreateTimestampFile(pathToSkps)) | |
| 219 | |
| 220 // Upload SKPs dir to Google Storage. | 211 // Upload SKPs dir to Google Storage. |
| 221 » if err := gs.UploadWorkerArtifacts(util.SKPS_DIR_NAME, filepath.Join(*pa
gesetType, *chromiumBuild), *workerNum); err != nil { | 212 » if err := gs.UploadSwarmingArtifacts(util.SKPS_DIR_NAME, *pagesetType);
err != nil { |
| 222 glog.Error(err) | 213 glog.Error(err) |
| 223 return | 214 return |
| 224 } | 215 } |
| 225 } | 216 } |
| 226 | |
| 227 func getRowsFromCSV(csvPath string) ([]string, []string, error) { | |
| 228 csvFile, err := os.Open(csvPath) | |
| 229 defer skutil.Close(csvFile) | |
| 230 if err != nil { | |
| 231 return nil, nil, fmt.Errorf("Could not open %s: %s", csvPath, er
r) | |
| 232 } | |
| 233 reader := csv.NewReader(csvFile) | |
| 234 reader.FieldsPerRecord = -1 | |
| 235 rawCSVdata, err := reader.ReadAll() | |
| 236 if err != nil { | |
| 237 return nil, nil, fmt.Errorf("Could not read %s: %s", csvPath, er
r) | |
| 238 } | |
| 239 if len(rawCSVdata) != 2 { | |
| 240 return nil, nil, fmt.Errorf("No data in %s", csvPath) | |
| 241 } | |
| 242 return rawCSVdata[0], rawCSVdata[1], nil | |
| 243 } | |
| 244 | |
| 245 func writeRowsToCSV(csvPath string, headers, values []string) error { | |
| 246 csvFile, err := os.OpenFile(csvPath, os.O_WRONLY, 666) | |
| 247 defer skutil.Close(csvFile) | |
| 248 if err != nil { | |
| 249 return fmt.Errorf("Could not open %s: %s", csvPath, err) | |
| 250 } | |
| 251 writer := csv.NewWriter(csvFile) | |
| 252 defer writer.Flush() | |
| 253 for _, row := range [][]string{headers, values} { | |
| 254 if err := writer.Write(row); err != nil { | |
| 255 return fmt.Errorf("Could not write to %s: %s", csvPath,
err) | |
| 256 } | |
| 257 } | |
| 258 return nil | |
| 259 } | |
| OLD | NEW |