|
37 | 37 | from Queue import Queue, Empty
|
38 | 38 | from os.path import join, exists, basename, relpath
|
39 | 39 | from threading import Thread, Lock
|
| 40 | +from multiprocessing import Pool, cpu_count |
40 | 41 | from subprocess import Popen, PIPE
|
41 | 42 |
|
42 | 43 | # Imports related to mbed build api
|
@@ -2068,6 +2069,27 @@ def norm_relative_path(path, start):
|
2068 | 2069 | path = path.replace("\\", "/")
|
2069 | 2070 | return path
|
2070 | 2071 |
|
| 2072 | + |
| 2073 | +def build_test_worker(*args, **kwargs): |
| 2074 | + bin_file = None |
| 2075 | + ret = { |
| 2076 | + 'result': False, |
| 2077 | + 'args': args, |
| 2078 | + 'kwargs': kwargs |
| 2079 | + } |
| 2080 | + |
| 2081 | + try: |
| 2082 | + bin_file = build_project(*args, **kwargs) |
| 2083 | + ret['result'] = True |
| 2084 | + ret['bin_file'] = bin_file |
| 2085 | + ret['kwargs'] = kwargs |
| 2086 | + |
| 2087 | + except: |
| 2088 | + ret['reason'] = sys.exc_info()[1] |
| 2089 | + |
| 2090 | + return ret |
| 2091 | + |
| 2092 | + |
2071 | 2093 | def build_tests(tests, base_source_paths, build_path, target, toolchain_name,
|
2072 | 2094 | clean=False, notify=None, verbose=False, jobs=1, macros=None,
|
2073 | 2095 | silent=False, report=None, properties=None,
|
@@ -2095,58 +2117,86 @@ def build_tests(tests, base_source_paths, build_path, target, toolchain_name,
|
2095 | 2117 |
|
2096 | 2118 | result = True
|
2097 | 2119 |
|
2098 |
| - map_outputs_total = list() |
| 2120 | + jobs_count = int(jobs if jobs else cpu_count()) |
| 2121 | + p = Pool(processes=jobs_count) |
| 2122 | + |
| 2123 | + results = [] |
2099 | 2124 | for test_name, test_path in tests.iteritems():
|
2100 | 2125 | test_build_path = os.path.join(build_path, test_path)
|
2101 | 2126 | src_path = base_source_paths + [test_path]
|
2102 | 2127 | bin_file = None
|
2103 | 2128 | test_case_folder_name = os.path.basename(test_path)
|
2104 | 2129 |
|
| 2130 | + args = (src_path, test_build_path, target, toolchain_name) |
| 2131 | + kwargs = { |
| 2132 | + 'jobs': jobs, |
| 2133 | + 'clean': clean, |
| 2134 | + 'macros': macros, |
| 2135 | + 'name': test_case_folder_name, |
| 2136 | + 'project_id': test_name, |
| 2137 | + 'report': report, |
| 2138 | + 'properties': properties, |
| 2139 | + 'verbose': verbose, |
| 2140 | + 'app_config': app_config, |
| 2141 | + 'build_profile': build_profile |
| 2142 | + } |
2105 | 2143 |
|
2106 |
| - try: |
2107 |
| - bin_file = build_project(src_path, test_build_path, target, toolchain_name, |
2108 |
| - jobs=jobs, |
2109 |
| - clean=clean, |
2110 |
| - macros=macros, |
2111 |
| - name=test_case_folder_name, |
2112 |
| - project_id=test_name, |
2113 |
| - report=report, |
2114 |
| - properties=properties, |
2115 |
| - verbose=verbose, |
2116 |
| - app_config=app_config, |
2117 |
| - build_profile=build_profile) |
2118 |
| - |
2119 |
| - except NotSupportedException: |
2120 |
| - pass |
2121 |
| - except ToolException: |
2122 |
| - result = False |
2123 |
| - if continue_on_build_fail: |
2124 |
| - continue |
2125 |
| - else: |
2126 |
| - break |
| 2144 | + results.append(p.apply_async(build_test_worker, args, kwargs)) |
2127 | 2145 |
|
2128 |
| - # If a clean build was carried out last time, disable it for the next build. |
2129 |
| - # Otherwise the previously built test will be deleted. |
2130 |
| - if clean: |
2131 |
| - clean = False |
2132 |
| - |
2133 |
| - # Normalize the path |
2134 |
| - if bin_file: |
2135 |
| - bin_file = norm_relative_path(bin_file, execution_directory) |
2136 |
| - |
2137 |
| - test_build['tests'][test_name] = { |
2138 |
| - "binaries": [ |
2139 |
| - { |
2140 |
| - "path": bin_file |
2141 |
| - } |
2142 |
| - ] |
2143 |
| - } |
| 2146 | + p.close() |
| 2147 | + result = True |
| 2148 | + itr = 0 |
| 2149 | + while len(results): |
| 2150 | + itr += 1 |
| 2151 | + if itr > 360000: |
| 2152 | + p.terminate() |
| 2153 | + p.join() |
| 2154 | + raise ToolException("Compile did not finish in 10 minutes") |
| 2155 | + |
| 2156 | + sleep(0.01) |
| 2157 | + pending = 0 |
| 2158 | + for r in results: |
| 2159 | + if r.ready() is True: |
| 2160 | + try: |
| 2161 | + worker_result = r.get() |
| 2162 | + results.remove(r) |
| 2163 | + |
| 2164 | + |
| 2165 | + for test_key in worker_result['kwargs']['report'][target_name][toolchain_name].keys(): |
| 2166 | + report[target_name][toolchain_name][test_key] = worker_result['kwargs']['report'][target_name][toolchain_name][test_key] |
| 2167 | + |
| 2168 | + if not worker_result['result'] and not isinstance(worker_result['reason'], NotSupportedException): |
| 2169 | + result = False |
| 2170 | + |
| 2171 | + if worker_result['result'] and 'bin_file' in worker_result: |
| 2172 | + bin_file = norm_relative_path(worker_result['bin_file'], execution_directory) |
| 2173 | + |
| 2174 | + test_build['tests'][worker_result['kwargs']['project_id']] = { |
| 2175 | + "binaries": [ |
| 2176 | + { |
| 2177 | + "path": bin_file |
| 2178 | + } |
| 2179 | + ] |
| 2180 | + } |
| 2181 | + |
| 2182 | + # TODO: add 'Image: bin_file' print statement here |
| 2183 | + |
| 2184 | + except ToolException, err: |
| 2185 | + if p._taskqueue.queue: |
| 2186 | + p._taskqueue.queue.clear() |
| 2187 | + sleep(0.5) |
| 2188 | + p.terminate() |
| 2189 | + p.join() |
| 2190 | + raise ToolException(err) |
| 2191 | + else: |
| 2192 | + pending += 1 |
| 2193 | + if pending >= jobs_count: |
| 2194 | + break |
2144 | 2195 |
|
2145 |
| - print 'Image: %s'% bin_file |
| 2196 | + p.join() |
2146 | 2197 |
|
2147 | 2198 | test_builds = {}
|
2148 | 2199 | test_builds["%s-%s" % (target_name, toolchain_name)] = test_build
|
2149 |
| - |
2150 | 2200 |
|
2151 | 2201 | return result, test_builds
|
2152 | 2202 |
|
|
0 commit comments