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 |