Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2)

Side by Side Diff: tools/android/loading/cloud/backend/trace_task_handler.py

Issue 2037073002: tools/android/loading Switch from multiprocessing Pool to Process (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Review comments Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « tools/android/loading/cloud/backend/multiprocessing_helper.py ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright 2016 The Chromium Authors. All rights reserved. 1 # Copyright 2016 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 import multiprocessing
6 import os 5 import os
7 import re 6 import re
8 import resource
9 import sys 7 import sys
10 import traceback 8 import traceback
11 9
12 import psutil
13
14 import common.clovis_paths 10 import common.clovis_paths
15 from common.clovis_task import ClovisTask 11 from common.clovis_task import ClovisTask
16 from common.loading_trace_database import LoadingTraceDatabase 12 from common.loading_trace_database import LoadingTraceDatabase
17 import controller 13 import controller
18 from failure_database import FailureDatabase 14 from failure_database import FailureDatabase
19 import loading_trace 15 import loading_trace
16 import multiprocessing_helper
20 import options 17 import options
21 import xvfb_helper 18 import xvfb_helper
22 19
23 20
24 def LimitMemory(memory_share):
25 """Limits the memory available to this process, to avoid OOM issues.
26
27 Args:
28 memory_share: (float) Share coefficient of the total physical memory that
29 the process can use.
30 """
31 total_memory = psutil.virtual_memory().total
32 memory_limit = memory_share * total_memory
33 resource.setrlimit(resource.RLIMIT_AS, (memory_limit, -1L))
34
35
36 def GenerateTrace(url, emulate_device, emulate_network, filename, log_filename): 21 def GenerateTrace(url, emulate_device, emulate_network, filename, log_filename):
37 """ Generates a trace. 22 """ Generates a trace.
38 23
39 Args: 24 Args:
40 url: URL as a string. 25 url: URL as a string.
41 emulate_device: Name of the device to emulate. Empty for no emulation. 26 emulate_device: Name of the device to emulate. Empty for no emulation.
42 emulate_network: Type of network emulation. Empty for no emulation. 27 emulate_network: Type of network emulation. Empty for no emulation.
43 filename: Name of the file where the trace is saved. 28 filename: Name of the file where the trace is saved.
44 log_filename: Name of the file where standard output and errors are 29 log_filename: Name of the file where standard output and errors are
45 logged. 30 logged.
(...skipping 11 matching lines...) Expand all
57 old_stderr = sys.stderr 42 old_stderr = sys.stderr
58 43
59 trace_metadata = { 'succeeded' : False, 'url' : url } 44 trace_metadata = { 'succeeded' : False, 'url' : url }
60 trace = None 45 trace = None
61 if not url.startswith('http') and not url.startswith('file'): 46 if not url.startswith('http') and not url.startswith('file'):
62 url = 'http://' + url 47 url = 'http://' + url
63 with open(log_filename, 'w') as sys.stdout: 48 with open(log_filename, 'w') as sys.stdout:
64 try: 49 try:
65 sys.stderr = sys.stdout 50 sys.stderr = sys.stdout
66 51
52 sys.stdout.write('Starting trace generation for: %s.\n' % url)
53
67 # Set up the controller. 54 # Set up the controller.
68 chrome_ctl = controller.LocalChromeController() 55 chrome_ctl = controller.LocalChromeController()
69 chrome_ctl.SetChromeEnvOverride(xvfb_helper.GetChromeEnvironment()) 56 chrome_ctl.SetChromeEnvOverride(xvfb_helper.GetChromeEnvironment())
70 if emulate_device: 57 if emulate_device:
71 chrome_ctl.SetDeviceEmulation(emulate_device) 58 chrome_ctl.SetDeviceEmulation(emulate_device)
72 if emulate_network: 59 if emulate_network:
73 chrome_ctl.SetNetworkEmulation(emulate_network) 60 chrome_ctl.SetNetworkEmulation(emulate_network)
74 61
75 # Record and write the trace. 62 # Record and write the trace.
76 with chrome_ctl.Open() as connection: 63 with chrome_ctl.Open() as connection:
77 connection.ClearCache() 64 connection.ClearCache()
78 trace = loading_trace.LoadingTrace.RecordUrlNavigation( 65 trace = loading_trace.LoadingTrace.RecordUrlNavigation(
79 url, connection, chrome_ctl.ChromeMetadata()) 66 url, connection, chrome_ctl.ChromeMetadata())
80 trace_metadata['succeeded'] = True 67 trace_metadata['succeeded'] = True
81 trace_metadata.update(trace.ToJsonDict()[trace._METADATA_KEY]) 68 trace_metadata.update(trace.ToJsonDict()[trace._METADATA_KEY])
69 sys.stdout.write('Trace generation success.\n')
82 except controller.ChromeControllerError as e: 70 except controller.ChromeControllerError as e:
83 e.Dump(sys.stderr) 71 e.Dump(sys.stderr)
84 except Exception as e: 72 except Exception as e:
85 sys.stderr.write('Unknown exception:\n' + str(e)) 73 sys.stderr.write('Unknown exception:\n' + str(e))
86 traceback.print_exc(file=sys.stderr) 74 traceback.print_exc(file=sys.stderr)
87 75
88 if trace: 76 if trace:
77 sys.stdout.write('Dumping trace to file.\n')
89 trace.ToJsonFile(filename) 78 trace.ToJsonFile(filename)
79 else:
80 sys.stderr.write('No trace generated.\n')
81
82 sys.stdout.write('Trace generation finished.\n')
90 83
91 sys.stdout = old_stdout 84 sys.stdout = old_stdout
92 sys.stderr = old_stderr 85 sys.stderr = old_stderr
93 86
94 return trace_metadata 87 return trace_metadata
95 88
96 89
97 class TraceTaskHandler(object): 90 class TraceTaskHandler(object):
98 """Handles 'trace' tasks.""" 91 """Handles 'trace' tasks."""
99 92
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
159 """ Generates a trace in a separate process by calling GenerateTrace(). 152 """ Generates a trace in a separate process by calling GenerateTrace().
160 153
161 The generation is done out of process to avoid issues where the system would 154 The generation is done out of process to avoid issues where the system would
162 run out of memory when the trace is very large. This ensures that the system 155 run out of memory when the trace is very large. This ensures that the system
163 can reclaim all the memory when the trace generation is done. 156 can reclaim all the memory when the trace generation is done.
164 157
165 See the GenerateTrace() documentation for a description of the parameters 158 See the GenerateTrace() documentation for a description of the parameters
166 and return values. 159 and return values.
167 """ 160 """
168 self._logger.info('Starting external process for trace generation.') 161 self._logger.info('Starting external process for trace generation.')
169 failed_metadata = {'succeeded':False, 'url':url} 162 result = multiprocessing_helper.RunInSeparateProcess(
170 failed = False 163 GenerateTrace,
171 pool = multiprocessing.Pool(1, initializer=LimitMemory, initargs=(0.9,)) 164 (url, emulate_device, emulate_network, filename, log_filename),
165 self._logger, timeout_seconds=180, memory_share=0.9)
172 166
173 apply_result = pool.apply_async( 167 self._logger.info('Cleaning up Chrome processes.')
174 GenerateTrace, 168 controller.LocalChromeController.KillChromeProcesses()
175 (url, emulate_device, emulate_network, filename, log_filename))
176 pool.close()
177 apply_result.wait(timeout=180)
178 169
179 if not apply_result.ready(): 170 if not result:
180 self._logger.error('Process timeout for trace generation of URL: ' + url)
181 self._failure_database.AddFailure('trace_process_timeout', url) 171 self._failure_database.AddFailure('trace_process_timeout', url)
182 # Explicitly kill Chrome now, or pool.terminate() will hang. 172 return {'succeeded':False, 'url':url}
183 controller.LocalChromeController.KillChromeProcesses() 173 return result
184 pool.terminate()
185 failed = True
186 elif not apply_result.successful():
187 # Try to reraise the exception that killed the subprocess and add it to
188 # the error log.
189 try:
190 apply_result.get()
191 except Exception as e:
192 with file(log_filename, 'w+') as error_log:
193 error_log.write('Unhandled exception caught by apply_result: {}'
194 .format(e))
195 traceback.print_exc(file=error_log)
196 else:
197 with file(log_filename, 'w+') as error_log:
198 error_log.write('No exception found for unsuccessful apply_result')
199 self._logger.error('Process failure for trace generation of URL: ' + url)
200 self._failure_database.AddFailure('trace_process_error', url)
201 failed = True
202 174
203 self._logger.info('Cleaning up external process.')
204 pool.join()
205
206 if failed:
207 return failed_metadata
208 return apply_result.get()
209 175
210 def _HandleTraceGenerationResults(self, local_filename, log_filename, 176 def _HandleTraceGenerationResults(self, local_filename, log_filename,
211 remote_filename, trace_metadata): 177 remote_filename, trace_metadata):
212 """Updates the trace database and the failure database after a trace 178 """Updates the trace database and the failure database after a trace
213 generation. Uploads the trace and the log. 179 generation. Uploads the trace and the log.
214 Results related to successful traces are uploaded in the 'traces' directory, 180 Results related to successful traces are uploaded in the 'traces' directory,
215 and failures are uploaded in the 'failures' directory. 181 and failures are uploaded in the 'failures' directory.
216 182
217 Args: 183 Args:
218 local_filename (str): Path to the local file containing the trace. 184 local_filename (str): Path to the local file containing the trace.
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
295 trace_metadata = self._GenerateTraceOutOfProcess( 261 trace_metadata = self._GenerateTraceOutOfProcess(
296 url, emulate_device, emulate_network, local_filename, log_filename) 262 url, emulate_device, emulate_network, local_filename, log_filename)
297 if trace_metadata['succeeded']: 263 if trace_metadata['succeeded']:
298 success_happened = True 264 success_happened = True
299 remote_filename = os.path.join(local_filename, str(repeat)) 265 remote_filename = os.path.join(local_filename, str(repeat))
300 self._HandleTraceGenerationResults( 266 self._HandleTraceGenerationResults(
301 local_filename, log_filename, remote_filename, trace_metadata) 267 local_filename, log_filename, remote_filename, trace_metadata)
302 268
303 if success_happened: 269 if success_happened:
304 self._UploadTraceDatabase() 270 self._UploadTraceDatabase()
OLDNEW
« no previous file with comments | « tools/android/loading/cloud/backend/multiprocessing_helper.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698