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.DownloadWorkerArtifacts(util.PAGESETS_DIR_NAME, *pageset Type, *workerNum); err != nil { | |
dogben
2016/05/19 16:48:41
nit: delete
rmistry
2016/05/19 17:01:25
Done.
| |
95 » if _, err := gs.DownloadSwarmingArtifacts(pathToPagesets, util.PAGESETS_ DIR_NAME, *pagesetType, *startRange, *num); err != nil { | |
100 glog.Error(err) | 96 glog.Error(err) |
101 return | 97 return |
102 } | 98 } |
103 » pathToPagesets := filepath.Join(util.PagesetsDir, *pagesetType) | 99 » defer skutil.RemoveAll(pathToPagesets) |
104 | 100 |
105 // Download archives if they do not exist locally. | 101 // Download archives if they do not exist locally. |
106 » if err := gs.DownloadWorkerArtifacts(util.WEB_ARCHIVES_DIR_NAME, *pagese tType, *workerNum); err != nil { | 102 » pathToArchives := filepath.Join(util.WebArchivesDir, *pagesetType) |
103 » archivesToIndex, err := gs.DownloadSwarmingArtifacts(pathToArchives, uti l.WEB_ARCHIVES_DIR_NAME, *pagesetType, *startRange, *num) | |
104 » if err != nil { | |
107 glog.Error(err) | 105 glog.Error(err) |
108 return | 106 return |
109 } | 107 } |
108 defer skutil.RemoveAll(pathToArchives) | |
110 | 109 |
111 // Create the dir that SKPs will be stored in. | 110 // Create the dir that SKPs will be stored in. |
112 pathToSkps := filepath.Join(util.SkpsDir, *pagesetType, *chromiumBuild) | 111 pathToSkps := filepath.Join(util.SkpsDir, *pagesetType, *chromiumBuild) |
113 // Delete and remake the local SKPs directory. | 112 // Delete and remake the local SKPs directory. |
114 skutil.RemoveAll(pathToSkps) | 113 skutil.RemoveAll(pathToSkps) |
115 skutil.MkdirAll(pathToSkps, 0700) | 114 skutil.MkdirAll(pathToSkps, 0700) |
116 | 115 » 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 | 116 |
123 // Construct path to the ct_run_benchmark python script. | 117 // Construct path to the ct_run_benchmark python script. |
124 » _, currentFile, _, _ := runtime.Caller(0) | 118 » pathToPyFiles := util.GetPathToPyFiles(!*worker_common.Local) |
125 » pathToPyFiles := filepath.Join( | |
126 » » filepath.Dir((filepath.Dir(filepath.Dir(filepath.Dir(currentFile ))))), | |
127 » » "py") | |
128 | 119 |
129 timeoutSecs := util.PagesetTypeToInfo[*pagesetType].CaptureSKPsTimeoutSe cs | 120 timeoutSecs := util.PagesetTypeToInfo[*pagesetType].CaptureSKPsTimeoutSe cs |
130 fileInfos, err := ioutil.ReadDir(pathToPagesets) | 121 fileInfos, err := ioutil.ReadDir(pathToPagesets) |
131 if err != nil { | 122 if err != nil { |
132 glog.Errorf("Unable to read the pagesets dir %s: %s", pathToPage sets, err) | 123 glog.Errorf("Unable to read the pagesets dir %s: %s", pathToPage sets, err) |
133 return | 124 return |
134 } | 125 } |
135 | 126 |
136 // Create channel that contains all pageset file names. This channel wil l | 127 // Create channel that contains all pageset file names. This channel wil l |
137 // be consumed by the worker pool. | 128 // be consumed by the worker pool. |
(...skipping 23 matching lines...) Expand all Loading... | |
161 pagesetPath := filepath.Join(pathToPagesets, pag esetName) | 152 pagesetPath := filepath.Join(pathToPagesets, pag esetName) |
162 decodedPageset, err := util.ReadPageset(pagesetP ath) | 153 decodedPageset, err := util.ReadPageset(pagesetP ath) |
163 if err != nil { | 154 if err != nil { |
164 glog.Errorf("Could not read %s: %s", pag esetPath, err) | 155 glog.Errorf("Could not read %s: %s", pag esetPath, err) |
165 continue | 156 continue |
166 } | 157 } |
167 | 158 |
168 glog.Infof("===== Processing %s =====", pagesetP ath) | 159 glog.Infof("===== Processing %s =====", pagesetP ath) |
169 | 160 |
170 skutil.LogErr(os.Chdir(pathToPyFiles)) | 161 skutil.LogErr(os.Chdir(pathToPyFiles)) |
162 index := archivesToIndex[decodedPageset.ArchiveD ataFile] | |
dogben
2016/05/19 16:48:41
paranoid: check that archivesToIndex contains an e
rmistry
2016/05/19 17:01:25
Done.
| |
171 args := []string{ | 163 args := []string{ |
172 filepath.Join(util.TelemetryBinariesDir, util.BINARY_RUN_BENCHMARK), | 164 filepath.Join(util.TelemetryBinariesDir, util.BINARY_RUN_BENCHMARK), |
173 util.BenchmarksToTelemetryName[util.BENC HMARK_SKPICTURE_PRINTER], | 165 util.BenchmarksToTelemetryName[util.BENC HMARK_SKPICTURE_PRINTER], |
174 "--also-run-disabled-tests", | 166 "--also-run-disabled-tests", |
175 "--page-repeat=1", // Only need one run for SKPs. | 167 "--page-repeat=1", // Only need one run for SKPs. |
176 » » » » » "--skp-outdir=" + pathToSkps, | 168 » » » » » "--skp-outdir=" + path.Join(pathToSkps, strconv.Itoa(index)), |
177 "--extra-browser-args=" + util.DEFAULT_B ROWSER_ARGS, | 169 "--extra-browser-args=" + util.DEFAULT_B ROWSER_ARGS, |
178 "--user-agent=" + decodedPageset.UserAge nt, | 170 "--user-agent=" + decodedPageset.UserAge nt, |
179 "--urls-list=" + decodedPageset.UrlsList , | 171 "--urls-list=" + decodedPageset.UrlsList , |
180 "--archive-data-file=" + decodedPageset. ArchiveDataFile, | 172 "--archive-data-file=" + decodedPageset. ArchiveDataFile, |
181 } | 173 } |
182 // Figure out which browser and device should be used. | 174 // Figure out which browser and device should be used. |
183 if *targetPlatform == util.PLATFORM_ANDROID { | 175 if *targetPlatform == util.PLATFORM_ANDROID { |
184 args = append(args, "--browser=android-c hromium") | 176 args = append(args, "--browser=android-c hromium") |
185 } else { | 177 } else { |
186 args = append(args, "--browser=exact", " --browser-executable="+chromiumBinary) | 178 args = append(args, "--browser=exact", " --browser-executable="+chromiumBinary) |
187 args = append(args, "--device=desktop") | 179 args = append(args, "--device=desktop") |
188 } | 180 } |
189 // Set the PYTHONPATH to the pagesets and the te lemetry dirs. | 181 // Set the PYTHONPATH to the pagesets and the te lemetry dirs. |
190 env := []string{ | 182 env := []string{ |
191 fmt.Sprintf("PYTHONPATH=%s:%s:%s:%s:$PYT HONPATH", pathToPagesets, util.TelemetryBinariesDir, util.TelemetrySrcDir, util. CatapultSrcDir), | 183 fmt.Sprintf("PYTHONPATH=%s:%s:%s:%s:$PYT HONPATH", pathToPagesets, util.TelemetryBinariesDir, util.TelemetrySrcDir, util. CatapultSrcDir), |
192 "DISPLAY=:0", | 184 "DISPLAY=:0", |
193 } | 185 } |
194 skutil.LogErr( | 186 skutil.LogErr( |
195 util.ExecuteCmd("python", args, env, tim e.Duration(timeoutSecs)*time.Second, nil, nil)) | 187 util.ExecuteCmd("python", args, env, tim e.Duration(timeoutSecs)*time.Second, nil, nil)) |
196 | 188 |
197 mutex.RUnlock() | 189 mutex.RUnlock() |
198 | |
199 } | 190 } |
200 }() | 191 }() |
201 } | 192 } |
202 | 193 |
203 if !*worker_common.Local { | 194 if !*worker_common.Local { |
204 // Start the cleaner. | 195 // Start the cleaner. |
205 go util.ChromeProcessesCleaner(&mutex, *chromeCleanerTimer) | 196 go util.ChromeProcessesCleaner(&mutex, *chromeCleanerTimer) |
206 } | 197 } |
207 | 198 |
208 // Wait for all spawned goroutines to complete. | 199 // Wait for all spawned goroutines to complete. |
209 wg.Wait() | 200 wg.Wait() |
210 | 201 |
211 // Move and validate all SKP files. | 202 // Move and validate all SKP files. |
212 » if err := util.ValidateSKPs(pathToSkps); err != nil { | 203 » if err := util.ValidateSKPs(pathToSkps, pathToPyFiles); err != nil { |
213 glog.Error(err) | 204 glog.Error(err) |
214 return | 205 return |
215 } | 206 } |
216 | 207 |
217 // Write timestamp to the SKPs dir. | |
218 skutil.LogErr(util.CreateTimestampFile(pathToSkps)) | |
219 | |
220 // Upload SKPs dir to Google Storage. | 208 // Upload SKPs dir to Google Storage. |
221 » if err := gs.UploadWorkerArtifacts(util.SKPS_DIR_NAME, filepath.Join(*pa gesetType, *chromiumBuild), *workerNum); err != nil { | 209 » if err := gs.UploadSwarmingArtifacts(util.SKPS_DIR_NAME, *pagesetType); err != nil { |
222 glog.Error(err) | 210 glog.Error(err) |
223 return | 211 return |
224 } | 212 } |
225 } | 213 } |
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 |