13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package com.sun.tools.sjavac;
27
28 import java.io.File;
29 import java.io.PrintStream;
30 import java.net.URI;
31 import java.util.Arrays;
32 import java.util.Collections;
33 import java.util.Set;
34 import java.util.Map;
35
36 import com.sun.tools.sjavac.options.Options;
37 import com.sun.tools.sjavac.server.CompilationResult;
38 import com.sun.tools.sjavac.server.Sjavac;
39 import com.sun.tools.sjavac.server.SysInfo;
40
41 /**
42 * This transform compiles a set of packages containing Java sources.
43 * The compile request is divided into separate sets of source files.
44 * For each set a separate request thread is dispatched to a javac server
45 * and the meta data is accumulated. The number of sets correspond more or
46 * less to the number of cores. Less so now, than it will in the future.
47 *
48 * <p><b>This is NOT part of any supported API.
49 * If you write code that depends on this, you do so at your own
50 * risk. This code and its internal interfaces are subject to change
51 * or deletion without notice.</b></p>
52 */
53 public class CompileJavaPackages implements Transformer {
54
55 // The current limited sharing of data between concurrent JavaCompilers
56 // in the server will not give speedups above 3 cores. Thus this limit.
57 // We hope to improve this in the future.
58 final static int limitOnConcurrency = 3;
59
60 Options args;
61
62 public void setExtra(String e) {
63 }
64
65 public void setExtra(Options a) {
66 args = a;
67 }
68
69 public boolean transform(final Sjavac sjavac,
70 Map<String,Set<URI>> pkgSrcs,
71 final Set<URI> visibleSources,
72 final Map<URI,Set<String>> visibleClasses,
73 Map<String,Set<String>> oldPackageDependents,
74 URI destRoot,
75 final Map<String,Set<URI>> packageArtifacts,
76 final Map<String,Set<String>> packageDependencies,
77 final Map<String,String> packagePubapis,
78 int debugLevel,
79 boolean incremental,
80 int numCores,
81 final PrintStream out,
82 final PrintStream err)
83 {
84 boolean rc = true;
85 boolean concurrentCompiles = true;
86
87 // Fetch the id.
88 final String id = Util.extractStringOption("id", sjavac.serverSettings());
89 // Only keep portfile and sjavac settings..
90 String psServerSettings = Util.cleanSubOptions(Util.set("portfile","sjavac","background","keepalive"), sjavac.serverSettings());
91
92 // Get maximum heap size from the server!
93 SysInfo sysinfo = sjavac.getSysInfo();
94 if (sysinfo == null) {
95 Log.error("Could not query server for sysinfo!");
96 return false;
97 }
98 int numMBytes = (int)(sysinfo.maxMemory / ((long)(1024*1024)));
99 Log.debug("Server reports "+numMBytes+"MiB of memory and "+sysinfo.numCores+" cores");
100
101 if (numCores <= 0) {
102 // Set the requested number of cores to the number of cores on the server.
103 numCores = sysinfo.numCores;
104 Log.debug("Number of jobs not explicitly set, defaulting to "+sysinfo.numCores);
105 } else if (sysinfo.numCores < numCores) {
106 // Set the requested number of cores to the number of cores on the server.
107 Log.debug("Limiting jobs from explicitly set "+numCores+" to cores available on server: "+sysinfo.numCores);
108 numCores = sysinfo.numCores;
109 } else {
110 Log.debug("Number of jobs explicitly set to "+numCores);
193 Log.debug("Chunk "+cn+" for "+id+" ---------------");
194 cn++;
195 for (URI u : cc.srcs) {
196 Log.debug(""+u);
197 }
198 }
199 }
200
201 // The return values for each chunked compile.
202 final CompilationResult[] rn = new CompilationResult[numCompiles];
203 // The requets, might or might not run as a background thread.
204 final Thread[] requests = new Thread[numCompiles];
205
206 long start = System.currentTimeMillis();
207
208 for (int i=0; i<numCompiles; ++i) {
209 final int ii = i;
210 final CompileChunk cc = compileChunks[i];
211
212 // Pass the num_cores and the id (appended with the chunk number) to the server.
213 final String cleanedServerSettings = psServerSettings+",poolsize="+numCores+",id="+id+"-"+i;
214
215 requests[i] = new Thread() {
216 @Override
217 public void run() {
218 rn[ii] = sjavac.compile("n/a",
219 id + "-" + ii,
220 args.prepJavacArgs(),
221 Collections.<File>emptyList(),
222 cc.srcs,
223 visibleSources);
224 packageArtifacts.putAll(rn[ii].packageArtifacts);
225 packageDependencies.putAll(rn[ii].packageDependencies);
226 packagePubapis.putAll(rn[ii].packagePubapis);
227 }
228 };
229
230 if (cc.srcs.size() > 0) {
231 String numdeps = "";
232 if (cc.numDependents > 0) numdeps = "(with "+cc.numDependents+" dependents) ";
233 if (!incremental || cc.numPackages > 16) {
234 String info = "("+cc.pkgFromTos+")";
235 if (info.equals("( to )")) {
236 info = "";
237 }
238 Log.info("Compiling "+cc.srcs.size()+" files "+numdeps+"in "+cc.numPackages+" packages "+info);
239 } else {
240 Log.info("Compiling "+cc.pkgNames+numdeps);
241 }
242 if (concurrentCompiles) {
243 requests[ii].start();
244 }
245 else {
246 requests[ii].run();
261 }
262
263 // Check the return values.
264 for (int i=0; i<numCompiles; ++i) {
265 if (compileChunks[i].srcs.size() > 0) {
266 if (rn[i].returnCode != 0) {
267 Log.info(rn[i].stdout);
268 Log.error(rn[i].stderr);
269 rc = false;
270 }
271 }
272 }
273 long duration = System.currentTimeMillis() - start;
274 long minutes = duration/60000;
275 long seconds = (duration-minutes*60000)/1000;
276 Log.debug("Compilation of "+numSources+" source files took "+minutes+"m "+seconds+"s");
277
278 return rc;
279 }
280
281
282 /**
283 * Split up the sources into compile chunks. If old package dependents information
284 * is available, sort the order of the chunks into the most dependent first!
285 * (Typically that chunk contains the java.lang package.) In the future
286 * we could perhaps improve the heuristics to put the sources into even more sensible chunks.
287 * Now the package are simple sorted in alphabetical order and chunked, then the chunks
288 * are sorted on how dependent they are.
289 *
290 * @param pkgSrcs The sources to compile.
291 * @param oldPackageDependents Old package dependents, if non-empty, used to sort the chunks.
292 * @param numCompiles The number of chunks.
293 * @param sourcesPerCompile The number of sources per chunk.
294 * @return
295 */
296 CompileChunk[] createCompileChunks(Map<String,Set<URI>> pkgSrcs,
297 Map<String,Set<String>> oldPackageDependents,
298 int numCompiles,
299 int sourcesPerCompile) {
300
301 CompileChunk[] compileChunks = new CompileChunk[numCompiles];
|
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package com.sun.tools.sjavac;
27
28 import java.io.File;
29 import java.io.PrintStream;
30 import java.net.URI;
31 import java.util.Arrays;
32 import java.util.Collections;
33 import java.util.HashMap;
34 import java.util.Map;
35 import java.util.Set;
36
37 import com.sun.tools.sjavac.options.Options;
38 import com.sun.tools.sjavac.pubapi.PubApi;
39 import com.sun.tools.sjavac.server.CompilationResult;
40 import com.sun.tools.sjavac.server.Sjavac;
41 import com.sun.tools.sjavac.server.SysInfo;
42
43 /**
44 * This transform compiles a set of packages containing Java sources.
45 * The compile request is divided into separate sets of source files.
46 * For each set a separate request thread is dispatched to a javac server
47 * and the meta data is accumulated. The number of sets correspond more or
48 * less to the number of cores. Less so now, than it will in the future.
49 *
50 * <p><b>This is NOT part of any supported API.
51 * If you write code that depends on this, you do so at your own
52 * risk. This code and its internal interfaces are subject to change
53 * or deletion without notice.</b></p>
54 */
55 public class CompileJavaPackages implements Transformer {
56
57 // The current limited sharing of data between concurrent JavaCompilers
58 // in the server will not give speedups above 3 cores. Thus this limit.
59 // We hope to improve this in the future.
60 final static int limitOnConcurrency = 3;
61
62 Options args;
63
64 public void setExtra(String e) {
65 }
66
67 public void setExtra(Options a) {
68 args = a;
69 }
70
71 public boolean transform(final Sjavac sjavac,
72 Map<String,Set<URI>> pkgSrcs,
73 final Set<URI> visibleSources,
74 final Map<URI,Set<String>> visibleClasses,
75 Map<String,Set<String>> oldPackageDependents,
76 URI destRoot,
77 final Map<String,Set<URI>> packageArtifacts,
78 final Map<String,Map<String, Set<String>>> packageDependencies,
79 final Map<String,Map<String, Set<String>>> packageCpDependencies,
80 final Map<String, PubApi> packagePubapis,
81 final Map<String, PubApi> dependencyPubapis,
82 int debugLevel,
83 boolean incremental,
84 int numCores,
85 final PrintStream out,
86 final PrintStream err) {
87
88 Log.debug("Performing CompileJavaPackages transform...");
89
90 boolean rc = true;
91 boolean concurrentCompiles = true;
92
93 // Fetch the id.
94 final String id = Util.extractStringOption("id", sjavac.serverSettings());
95 // Only keep portfile and sjavac settings..
96 //String psServerSettings = Util.cleanSubOptions(Util.set("portfile","sjavac","background","keepalive"), sjavac.serverSettings());
97
98 // Get maximum heap size from the server!
99 SysInfo sysinfo = sjavac.getSysInfo();
100 if (sysinfo == null) {
101 Log.error("Could not query server for sysinfo!");
102 return false;
103 }
104 int numMBytes = (int)(sysinfo.maxMemory / ((long)(1024*1024)));
105 Log.debug("Server reports "+numMBytes+"MiB of memory and "+sysinfo.numCores+" cores");
106
107 if (numCores <= 0) {
108 // Set the requested number of cores to the number of cores on the server.
109 numCores = sysinfo.numCores;
110 Log.debug("Number of jobs not explicitly set, defaulting to "+sysinfo.numCores);
111 } else if (sysinfo.numCores < numCores) {
112 // Set the requested number of cores to the number of cores on the server.
113 Log.debug("Limiting jobs from explicitly set "+numCores+" to cores available on server: "+sysinfo.numCores);
114 numCores = sysinfo.numCores;
115 } else {
116 Log.debug("Number of jobs explicitly set to "+numCores);
199 Log.debug("Chunk "+cn+" for "+id+" ---------------");
200 cn++;
201 for (URI u : cc.srcs) {
202 Log.debug(""+u);
203 }
204 }
205 }
206
207 // The return values for each chunked compile.
208 final CompilationResult[] rn = new CompilationResult[numCompiles];
209 // The requets, might or might not run as a background thread.
210 final Thread[] requests = new Thread[numCompiles];
211
212 long start = System.currentTimeMillis();
213
214 for (int i=0; i<numCompiles; ++i) {
215 final int ii = i;
216 final CompileChunk cc = compileChunks[i];
217
218 // Pass the num_cores and the id (appended with the chunk number) to the server.
219 Object lock = new Object();
220 requests[i] = new Thread() {
221 @Override
222 public void run() {
223 rn[ii] = sjavac.compile("n/a",
224 id + "-" + ii,
225 args.prepJavacArgs(),
226 Collections.<File>emptyList(),
227 cc.srcs,
228 visibleSources);
229 // In the code below we have to keep in mind that two
230 // different compilation results may include results for
231 // the same package.
232 synchronized (lock) {
233
234 for (String pkg : rn[ii].packageArtifacts.keySet()) {
235 Set<URI> pkgArtifacts = rn[ii].packageArtifacts.get(pkg);
236 packageArtifacts.merge(pkg, pkgArtifacts, Util::union);
237 }
238
239 for (String pkg : rn[ii].packageDependencies.keySet()) {
240 packageDependencies.putIfAbsent(pkg, new HashMap<>());
241 packageDependencies.get(pkg).putAll(rn[ii].packageDependencies.get(pkg));
242 }
243
244 for (String pkg : rn[ii].packageCpDependencies.keySet()) {
245 packageCpDependencies.putIfAbsent(pkg, new HashMap<>());
246 packageCpDependencies.get(pkg).putAll(rn[ii].packageCpDependencies.get(pkg));
247 }
248
249 for (String pkg : rn[ii].packagePubapis.keySet()) {
250 packagePubapis.merge(pkg, rn[ii].packagePubapis.get(pkg), PubApi::mergeTypes);
251 }
252
253 for (String pkg : rn[ii].dependencyPubapis.keySet()) {
254 dependencyPubapis.merge(pkg, rn[ii].dependencyPubapis.get(pkg), PubApi::mergeTypes);
255 }
256 }
257 }
258 };
259
260 if (cc.srcs.size() > 0) {
261 String numdeps = "";
262 if (cc.numDependents > 0) numdeps = "(with "+cc.numDependents+" dependents) ";
263 if (!incremental || cc.numPackages > 16) {
264 String info = "("+cc.pkgFromTos+")";
265 if (info.equals("( to )")) {
266 info = "";
267 }
268 Log.info("Compiling "+cc.srcs.size()+" files "+numdeps+"in "+cc.numPackages+" packages "+info);
269 } else {
270 Log.info("Compiling "+cc.pkgNames+numdeps);
271 }
272 if (concurrentCompiles) {
273 requests[ii].start();
274 }
275 else {
276 requests[ii].run();
291 }
292
293 // Check the return values.
294 for (int i=0; i<numCompiles; ++i) {
295 if (compileChunks[i].srcs.size() > 0) {
296 if (rn[i].returnCode != 0) {
297 Log.info(rn[i].stdout);
298 Log.error(rn[i].stderr);
299 rc = false;
300 }
301 }
302 }
303 long duration = System.currentTimeMillis() - start;
304 long minutes = duration/60000;
305 long seconds = (duration-minutes*60000)/1000;
306 Log.debug("Compilation of "+numSources+" source files took "+minutes+"m "+seconds+"s");
307
308 return rc;
309 }
310
311 /**
312 * Split up the sources into compile chunks. If old package dependents information
313 * is available, sort the order of the chunks into the most dependent first!
314 * (Typically that chunk contains the java.lang package.) In the future
315 * we could perhaps improve the heuristics to put the sources into even more sensible chunks.
316 * Now the package are simple sorted in alphabetical order and chunked, then the chunks
317 * are sorted on how dependent they are.
318 *
319 * @param pkgSrcs The sources to compile.
320 * @param oldPackageDependents Old package dependents, if non-empty, used to sort the chunks.
321 * @param numCompiles The number of chunks.
322 * @param sourcesPerCompile The number of sources per chunk.
323 * @return
324 */
325 CompileChunk[] createCompileChunks(Map<String,Set<URI>> pkgSrcs,
326 Map<String,Set<String>> oldPackageDependents,
327 int numCompiles,
328 int sourcesPerCompile) {
329
330 CompileChunk[] compileChunks = new CompileChunk[numCompiles];
|