001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: // To run me:
043: // cd nb_all
044: // ant -f nbbuild/build.xml
045: // java -classpath core/netbeans/lib/ext/boot.jar:core/netbeans/lib/core.jar:openide/netbeans/lib/openide.jar:performance/src:junit/external/junit-3.7.jar:core/test/perf/src:core/external/xerces-2.0.2.jar:core/external/xml-apis-1.0b2.jar org.netbeans.core.modules.ModuleInitTest
046: package org.netbeans.core.modules;
047:
048: import java.io.*;
049: import java.lang.reflect.Method;
050: import java.text.DecimalFormat;
051: import java.util.*;
052: import java.util.zip.*;
053: import java.util.jar.*;
054:
055: import org.w3c.dom.*;
056: import org.apache.xml.serialize.*;
057:
058: import org.netbeans.core.NbTopManager;
059: import org.netbeans.performance.Benchmark;
060: import org.openide.xml.XMLUtil;
061:
062: // initial run (04-sep-02) with empty dummy modules under JDK 1.4.1rc:
063: // 0 - 0.92Mb, 2.75s
064: // 10 - 1.44Mb, 3.36s
065: // 100 - 1.71Mb, 4.5s
066: // 1000 - 7.21Mb, 9-12s
067:
068: // another run (04-sep-02) with module dependencies:
069: // 0 - 0.92Mb, 2.77s
070: // 10 - 1.41Mb, 3.37s
071: // 100 - 1.69Mb, 4.3s
072: // 1000 - 7.72Mb, 10-12s
073: // So dependencies only seem to have a small startup time impact
074: // for a lot of modules (hundreds, a second or so).
075:
076: // 7ms/module to read manifest & .xml file, plus .25ms/module to get file list from Modules/ (mostly file access?)
077: // .35ms/module to check dependency & orderings
078: // 2.4ms/module to open JAR & create classloader
079: // .2ms/m to look for nonexistent sections [already improving]
080: // .14ms/m to look for nonexistent module installs [how to improve?]
081:
082: // after some tweaks (05-sep-02), measured inside NB w/ term:
083: // 0 - 0.87Mb, 3.0s
084: // 10 - 1.32Mb, 3.7s
085: // 100 - 1.73Mb, 4.6s
086: // 1000 - 6.29Mb, 11.3s
087: // measured outside from a shell:
088: // 0 - 1.15Mb, 2.9s
089: // 10 - 0.82Mb, 3.1s
090: // 100 - 1.66Mb, around 4s
091: // 1000 - 5.74Mb, 10.5s
092: // after adding 1000 files to each module:
093: // 1000 - 6.82Mb, 13.2s
094: // after adding 0 - 250 files to each module:
095: // 1000 - 6.64Mb, around 12s
096: // after adding 23 files to each module's layer:
097: // 1000 - 19.00Mb, around 17s
098: // with some attributes too, 2 on 1/5 of folders and 1 on 1/3 of files:
099: // 1000 - 20.3Mb, around 17.5s
100:
101: // so about 5.5ms/m for layer parsing, <1ms/m for opening a bigger JAR
102:
103: // After ModuleList opt to not use Crimson to parse Modules/*.xml:
104: // 1000 - 21.1Mb, 16.4s
105: // detail timing: now only 3.8ms/m to load manifest + parse XML
106:
107: /**
108: * Benchmark measuring initialization of the module system.
109: * Covers parsing of module config XML files; opening JARs;
110: * reading their manifests; computing dependencies; loading XML layers;
111: * turning everything on.
112: * @author Jesse Glick
113: * @see "#26786"
114: */
115: public class ModuleInitTest extends Benchmark {
116:
117: public static void main(String[] args) {
118: simpleRun(ModuleInitTest.class);
119: }
120:
121: private static Map[] parseParams(String[] ps) {
122: Map[] m = new Map[ps.length];
123: for (int i = 0; i < ps.length; i++) {
124: m[i] = new HashMap(); // Map<String,String|Integer>
125: StringTokenizer tok = new StringTokenizer(ps[i], ",");
126: while (tok.hasMoreTokens()) {
127: String kv = tok.nextToken();
128: int x = kv.indexOf('=');
129: String k = kv.substring(0, x);
130: String v = kv.substring(x + 1);
131: try {
132: m[i].put(k, new Integer(v));
133: } catch (NumberFormatException nfe) {
134: m[i].put(k, v);
135: }
136: }
137: }
138: return m;
139: }
140:
141: public ModuleInitTest(String name) {
142: super (name, parseParams(new String[] {
143: // Simple scalability test:
144: "modules=0,jarSize=200,layerSize=23",
145: "modules=10,jarSize=200,layerSize=23",
146: "modules=100,jarSize=200,layerSize=23",
147: "modules=1000,jarSize=200,layerSize=23",
148: /* Test manifest caching:
149: "modules=100,jarSize=200,layerSize=0,-Dnetbeans.cache.manifests=false",
150: "modules=100,jarSize=200,layerSize=0,-Dnetbeans.cache.manifests=true",
151: "modules=1000,jarSize=200,layerSize=0,-Dnetbeans.cache.manifests=false",
152: "modules=1000,jarSize=200,layerSize=0,-Dnetbeans.cache.manifests=true",
153: */
154: }));
155: }
156:
157: private static File getTmpDir() {
158: File ramdisk = new File("/dev/shm");
159: if (ramdisk.isDirectory() && ramdisk.canWrite()) {
160: return ramdisk;
161: } else {
162: return new File(System.getProperty("java.io.tmpdir"));
163: }
164: }
165:
166: private File topdir = new File(getTmpDir(), "ModuleInitTest");
167: private File homedir = new File(topdir, "home");
168: private File skeldir = new File(topdir, "skeluser");
169: private File userdir = new File(topdir, "user");
170: private Map lastParams = null;
171:
172: protected void setUp() throws Exception {
173: Map params = (Map) getArgument();
174: if (!params.equals(lastParams)) {
175: //System.out.println("Setup: " + params);
176: if (homedir.exists()) {
177: deleteRec(homedir);
178: }
179: File mods = new File(homedir, "modules");
180: File amods = new File(mods, "autoload");
181: amods.mkdirs();
182: File emods = new File(mods, "eager");
183: emods.mkdirs();
184: createModules(params, mods, amods, emods);
185: new File(homedir, "system").mkdirs();
186: // Priming run to create system/Modules directory:
187: if (skeldir.exists()) {
188: deleteRec(skeldir);
189: }
190: runNB(homedir, skeldir, false, params);
191: lastParams = params;
192: }
193: // On every run, copy the primed skeleton user dir to the real location,
194: // then start NB with the copied user dir.
195: if (userdir.exists()) {
196: deleteRec(userdir);
197: }
198: copyRec(skeldir, userdir);
199: }
200:
201: protected void tearDown() throws Exception {
202: }
203:
204: private static void deleteRec(File x) throws IOException {
205: File[] kids = x.listFiles();
206: if (kids != null) {
207: for (int i = 0; i < kids.length; i++) {
208: deleteRec(kids[i]);
209: }
210: }
211: if (!x.delete())
212: throw new IOException("Could not delete: " + x);
213: }
214:
215: private static void copyStream(InputStream is, OutputStream os)
216: throws IOException {
217: try {
218: byte[] b = new byte[4096];
219: int i;
220: while ((i = is.read(b)) != -1) {
221: os.write(b, 0, i);
222: }
223: } finally {
224: is.close();
225: }
226: }
227:
228: private static void copyRec(File x, File y) throws IOException {
229: if (x.isDirectory()) {
230: if (!y.mkdirs())
231: throw new IOException("Could not mkdir: " + y);
232: String[] kids = x.list();
233: if (kids == null)
234: throw new IOException("Could not list: " + x);
235: for (int i = 0; i < kids.length; i++) {
236: copyRec(new File(x, kids[i]), new File(y, kids[i]));
237: }
238: } else {
239: y.getParentFile().mkdirs();
240: OutputStream os = new FileOutputStream(y);
241: try {
242: copyStream(new FileInputStream(x), os);
243: } finally {
244: os.close();
245: }
246: }
247: }
248:
249: // Sorry, I can't easily draw this dependency graph.
250: // It is complicated - that is the whole point.
251: private static final int cyclesize = 8;
252: // Base names of cyclic pattern of modules:
253: private static final String[] names = { "aut1", "prv1", "reg1",
254: "aut2", "reg2", "reg3", "dis1", "eag1" };
255: // Types: 0 = regular, 1 = autoload, 2 = eager
256: private static final int[] types = { 1, 1, 0, 1, 0, 0, 0, 2 };
257: // Intra-set dependencies (list of indices of other modules):
258: private static final int[][] intradeps = { {}, {}, { 0 }, {},
259: { 0, 3 }, { 3 }, { 3 }, { 4, 5 } };
260: // Inter-set dependencies (list of indices of analogous modules in the previous cycle):
261: private static final int[][] interdeps = { { 0 }, {}, { 2 }, {},
262: {}, {}, { 6 }, { 5 } };
263: // Whether the module should be permitted to be enabled or not:
264: private static final boolean[] enabled = { true, true, true, true,
265: true, true, false, true };
266: // Provided tokens from the module; freeform, but if ends in '#' that will get subst'd w/ cycle
267: private static final String[][] provides = { {}, { "tok#" }, {},
268: {}, {}, {}, {}, {} };
269: // Required tokens; same syntax as above.
270: private static final String[][] requires = { {}, {}, { "tok#" },
271: {}, {}, {}, {}, {} };
272: // E.g.: module #16 (0-indexed) is in the third cycle and is a reg1, thus named reg1_002.
273: // It depends on module #14, aut1_002 (from intradeps) and module #9, reg1_001 (from interdeps).
274: // It also depends on tok_002, provided only by module #15, prv1_002.
275: // All of these will be enabled, along with some other modules (indirectly).
276: static {
277: if (names.length != cyclesize || types.length != cyclesize
278: || intradeps.length != cyclesize
279: || interdeps.length != cyclesize
280: || enabled.length != cyclesize
281: || provides.length != cyclesize
282: || requires.length != cyclesize) {
283: throw new Error();
284: }
285: }
286:
287: private void createModules(Map params, File mods, File amods,
288: File emods) throws IOException {
289: int size = ((Integer) params.get("modules")).intValue();
290: int jarSize = ((Integer) params.get("jarSize")).intValue();
291: int layerSize = ((Integer) params.get("layerSize")).intValue();
292: File[] moddirs = { mods, amods, emods }; // indexed by types[n]
293: for (int i = 0; i < size; i++) {
294: int which = i % cyclesize;
295: int cycle = i / cyclesize;
296: String cycleS = Integer.toString(cycle);
297: // Enough for 1000*cyclesize modules to sort nicely:
298: while (cycleS.length() < 3)
299: cycleS = "0" + cycleS;
300: Manifest mani = new Manifest();
301: Attributes attr = mani.getMainAttributes();
302: attr.putValue("Manifest-Version", "1.0");
303: String nameBase = names[which] + "_" + cycleS;
304: String name = "com.testdomain." + nameBase;
305: String nameSlashes = name.replace('.', '/');
306: attr.putValue("OpenIDE-Module", name + "/1");
307: // Avoid requiring javahelp:
308: attr.putValue("OpenIDE-Module-IDE-Dependencies",
309: "IDE/1 > 2.2");
310: attr
311: .putValue("OpenIDE-Module-Specification-Version",
312: "1.0");
313: StringBuffer deps = null;
314: for (int j = 0; j < intradeps[which].length; j++) {
315: if (deps == null) {
316: deps = new StringBuffer(1000);
317: } else {
318: deps.append(", ");
319: }
320: deps.append("com.testdomain."
321: + names[intradeps[which][j]]);
322: deps.append('_');
323: deps.append(cycleS);
324: deps.append("/1 > 1.0");
325: }
326: if (cycle > 0) {
327: String oldCycleS = Integer.toString(cycle - 1);
328: while (oldCycleS.length() < 3)
329: oldCycleS = "0" + oldCycleS;
330: for (int j = 0; j < interdeps[which].length; j++) {
331: if (deps == null) {
332: deps = new StringBuffer(1000);
333: } else {
334: deps.append(", ");
335: }
336: deps.append("com.testdomain."
337: + names[interdeps[which][j]]);
338: deps.append('_');
339: deps.append(oldCycleS);
340: deps.append("/1 > 1.0");
341: }
342: }
343: if (!enabled[which]) {
344: if (deps == null) {
345: deps = new StringBuffer(1000);
346: } else {
347: deps.append(", ");
348: }
349: // An impossible dependency.
350: deps.append("honest.man.in.washington");
351: }
352: if (deps != null) {
353: attr.putValue("OpenIDE-Module-Module-Dependencies",
354: deps.toString());
355: }
356: if (provides[which].length > 0) {
357: StringBuffer buf = new StringBuffer(100);
358: for (int j = 0; j < provides[which].length; j++) {
359: if (j > 0) {
360: buf.append(", ");
361: }
362: String tok = provides[which][j];
363: if (tok.endsWith("#")) {
364: tok = tok.substring(0, tok.length() - 1) + "_"
365: + cycleS;
366: }
367: buf.append("com.testdomain." + tok);
368: }
369: attr
370: .putValue("OpenIDE-Module-Provides", buf
371: .toString());
372: }
373: if (requires[which].length > 0) {
374: StringBuffer buf = new StringBuffer(100);
375: for (int j = 0; j < requires[which].length; j++) {
376: if (j > 0) {
377: buf.append(", ");
378: }
379: String tok = requires[which][j];
380: if (tok.endsWith("#")) {
381: tok = tok.substring(0, tok.length() - 1) + "_"
382: + cycleS;
383: }
384: buf.append("com.testdomain." + tok);
385: }
386: attr
387: .putValue("OpenIDE-Module-Requires", buf
388: .toString());
389: }
390: // Files in JAR other than manifest:
391: Map contents = new TreeMap(); // Map<String,byte[]>
392: String locb = nameSlashes + "/Bundle.properties";
393: contents.put(locb,
394: ("OpenIDE-Module-Name=Module #" + i + "\n")
395: .getBytes());
396: attr.putValue("OpenIDE-Module-Localizing-Bundle", locb);
397: contents.put(nameSlashes + "/foo", "stuff here\n"
398: .getBytes());
399: contents.put(nameSlashes + "/subdir/foo",
400: "more stuff here\n".getBytes());
401: for (int j = 0; j < jarSize; j++) {
402: contents.put(nameSlashes + "/sub/subdir/file" + j,
403: new byte[j]);
404: }
405: // XML layer:
406: Map layer = new TreeMap(); // Map<String,byte[]|null>
407: // Construct a binomial tree, module #i contributing the next layerSize files (leaves):
408: int start = i * layerSize;
409: int end = (i + 1) * layerSize;
410: for (int j = start; j < end; j++) {
411: String filename = "file" + j + ".txt";
412: int bit = 0;
413: int x = j;
414: while (x > 0) {
415: if (x % 2 == 1) {
416: filename = "dir" + bit + "/" + filename;
417: }
418: bit++;
419: x /= 2;
420: }
421: layer.put(filename,
422: (j % 2 == 0) ? ("Contents #" + j + "\n")
423: .getBytes() : null);
424: }
425: ByteArrayOutputStream baos = new ByteArrayOutputStream(
426: layer.size() * 100 + 1);
427: Document doc = XMLUtil.createDocument("filesystem", null,
428: "-//NetBeans//DTD Filesystem 1.1//EN",
429: "http://www.netbeans.org/dtds/filesystem-1_1.dtd");
430: doc.getDocumentElement().appendChild(
431: doc.createComment(" Layer filenames for module #"
432: + i + ": " + layer.keySet() + " "));
433: Iterator it = layer.entrySet().iterator();
434: while (it.hasNext()) {
435: Map.Entry e = (Map.Entry) it.next();
436: String filename = (String) e.getKey();
437: byte[] filebytes = (byte[]) e.getValue();
438: Element el = doc.getDocumentElement();
439: StringTokenizer tok = new StringTokenizer(filename, "/");
440: while (tok.hasMoreTokens()) {
441: String piece = tok.nextToken();
442: if (tok.hasMoreTokens()) {
443: // A dir. Look for it...
444: Element child = null;
445: NodeList kids = el.getChildNodes();
446: for (int j = 0; j < kids.getLength(); j++) {
447: Node n = kids.item(j);
448: if (!(n instanceof Element))
449: continue;
450: Element kid = (Element) n;
451: if (!kid.getNodeName().equals("folder"))
452: continue;
453: if (kid.getAttribute("name").equals(piece)) {
454: child = kid;
455: break;
456: }
457: }
458: if (child == null) {
459: child = doc.createElement("folder");
460: child.setAttribute("name", piece);
461: // Attributes, on every fifth folder:
462: if (Math.abs(filename.hashCode()) % 5 == 0) {
463: Element a = doc.createElement("attr");
464: a
465: .setAttribute("name",
466: "SystemFileSystem.localizingBundle");
467: a.setAttribute("stringvalue", name
468: + ".Bundle");
469: child.appendChild(a);
470: a = doc.createElement("attr");
471: a.setAttribute("name",
472: "SystemFileSystem.icon");
473: a.setAttribute("urlvalue", "nbresloc:/"
474: + nameSlashes + "/resources/"
475: + piece + ".gif");
476: child.appendChild(a);
477: }
478: el.appendChild(child);
479: }
480: el = child;
481: } else {
482: // This is a file. It is not already in the doc - because
483: // of the map.
484: Element child = doc.createElement("file");
485: child.setAttribute("name", piece);
486: if (filebytes != null) {
487: String contentsName = "resources/layerfile"
488: + Integer.toHexString(filename
489: .hashCode());
490: contents.put(nameSlashes + "/"
491: + contentsName, filebytes);
492: child.setAttribute("url", contentsName);
493: }
494: // Attributes, on every third file:
495: if (Math.abs(filename.hashCode()) % 3 == 0) {
496: Element a = doc.createElement("attr");
497: a.setAttribute("name", "instanceOf");
498: a.setAttribute("stringvalue", name
499: + ".Whatever");
500: child.appendChild(a);
501: }
502: el.appendChild(child);
503: }
504: }
505: }
506: XMLSerializer ser = new XMLSerializer(baos,
507: new OutputFormat(doc, "UTF-8", true));
508: ser.serialize(doc);
509: String layerName = nameSlashes + "/layer.xml";
510: contents.put(layerName, baos.toByteArray());
511: attr.putValue("OpenIDE-Module-Layer", layerName);
512: OutputStream os = new FileOutputStream(new File(
513: moddirs[types[which]], nameBase + ".jar"));
514: try {
515: JarOutputStream jos = new JarOutputStream(os, mani);
516: Set addedDirs = new HashSet(1000); // Set<String>
517: it = contents.entrySet().iterator();
518: while (it.hasNext()) {
519: Map.Entry e = (Map.Entry) it.next();
520: String filename = (String) e.getKey();
521: byte[] filebytes = (byte[]) e.getValue();
522: String dircheck = filename;
523: while (true) {
524: int idx = dircheck.lastIndexOf('/');
525: if (idx == -1)
526: break;
527: dircheck = dircheck.substring(0, idx);
528: if (!addedDirs.add(dircheck))
529: break;
530: JarEntry je = new JarEntry(dircheck + "/");
531: je.setMethod(ZipEntry.STORED);
532: je.setSize(0);
533: je.setCompressedSize(0);
534: je.setCrc(0);
535: jos.putNextEntry(je);
536: }
537: JarEntry je = new JarEntry(filename);
538: je.setMethod(ZipEntry.DEFLATED);
539: //je.setSize(filebytes.length);
540: jos.putNextEntry(je);
541: jos.write(filebytes);
542: }
543: jos.close();
544: } finally {
545: os.close();
546: }
547: }
548: }
549:
550: public void testInitModuleSystem() throws Exception {
551: int count = getIterationCount();
552: for (int i = 0; i < count; i++) {
553: runNB(homedir, userdir, true, (Map) getArgument());
554: }
555: }
556:
557: private String cp = refinecp(System.getProperty("java.class.path"));
558:
559: private void runNB(File homedir, File userdir, boolean log,
560: Map params) throws IOException {
561: List cmd = new ArrayList(
562: Arrays
563: .asList(new String[] {
564: "java",
565: "-Xms24m",
566: "-Xmx96m",
567: "-Dorg.openide.TopManager=org.netbeans.core.NonGuiMain",
568: "-Dnetbeans.security.nocheck=true",
569: "-Dnetbeans.home="
570: + homedir.getAbsolutePath(),
571: "-Dnetbeans.user="
572: + userdir.getAbsolutePath(),
573: "-Dnetbeans.modules.quiet=true",
574: "-Dlog=" + log, "-classpath", cp, }));
575: Iterator it = params.entrySet().iterator();
576: while (it.hasNext()) {
577: Map.Entry e = (Map.Entry) it.next();
578: String key = (String) e.getKey();
579: if (key.startsWith("-D")) {
580: cmd.add(key + "=" + e.getValue());
581: }
582: }
583: //if (log) cmd.add("-Dorg.netbeans.log.startup=print");
584: cmd.add("org.netbeans.core.modules.ModuleInitTest$Main");
585: //System.out.println("Running: " + cmd);
586: Process p = Runtime.getRuntime().exec(
587: (String[]) cmd.toArray(new String[cmd.size()]));
588: new Copier(p.getInputStream(), System.out).start();
589: new Copier(p.getErrorStream(), System.err).start();
590: try {
591: int stat = p.waitFor();
592: if (stat != 0) {
593: throw new IOException("Command failed (status " + stat
594: + "): " + cmd);
595: }
596: } catch (InterruptedException ie) {
597: throw new IOException(ie.toString());
598: }
599: }
600:
601: /** Remove openide/test/perf/src/ if present since it overrides ErrorManager badly.
602: */
603: private static String refinecp(String cp) {
604: StringBuffer b = new StringBuffer(cp.length());
605: StringTokenizer t = new StringTokenizer(cp, File.pathSeparator);
606: while (t.hasMoreTokens()) {
607: File f = new File(t.nextToken());
608: if (f.isDirectory()) {
609: if (new File(new File(new File(f, "org"), "openide"),
610: "ErrorManagerTest.java").exists()
611: || new File(new File(new File(f, "org"),
612: "openide"), "ErrorManagerTest.class")
613: .exists()) {
614: //System.err.println("Removing " + f + " from classpath");
615: continue;
616: }
617: }
618: if (b.length() != 0) {
619: b.append(File.pathSeparatorChar);
620: }
621: b.append(f);
622: }
623: return b.toString();
624: }
625:
626: private static final class Copier extends Thread {
627: private final InputStream is;
628: private final PrintStream ps;
629:
630: public Copier(InputStream is, PrintStream ps) {
631: this .is = is;
632: this .ps = ps;
633: }
634:
635: public void run() {
636: try {
637: copyStream(is, ps);
638: } catch (IOException ioe) {
639: ioe.printStackTrace();
640: }
641: }
642: }
643:
644: public static final class Main {
645: public static void main(String[] x) {
646: NbTopManager.get();
647: if (Boolean.getBoolean("log")) {
648: Runtime r = Runtime.getRuntime();
649: r.gc();
650: double megs = (r.totalMemory() - r.freeMemory()) / 1024.0 / 1024.0;
651: System.err.println("Used memory: "
652: + new DecimalFormat("0.00 Mb").format(megs));
653: }
654: }
655: }
656:
657: }
|