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: package memory;
043:
044: import java.io.BufferedReader;
045: import java.io.File;
046: import java.io.FileReader;
047: import java.io.IOException;
048: import java.io.InputStreamReader;
049: import java.io.LineNumberReader;
050:
051: import java.util.StringTokenizer;
052:
053: /**
054: * Measure memory footprint, by checking size of memory occupied by runide process.
055: * On Windows platform used <b>pslist.exe</b>, on Unix platform used <b>ps</b>.
056: * Output of these commands is parsed and measured memory size
057: * (windows - "MEM", unix - "RES", "RSS") presents as measured memory footprint.
058: *
059: * @author mmirilovic@netbeans.org
060: */
061: public class MeasureBaselineMemoryFootprint extends
062: org.netbeans.junit.NbPerformanceTestCase {
063:
064: /** Used platform. */
065: private static String platform;
066:
067: /** IDE process PID. */
068: private static long pid;
069:
070: /** Ouput file where is logged ouput from ps command. */
071: private static String PS_OUTPUT_FILENAME = "psOutput.txt";
072:
073: private static final String UNIX = "unix";
074: private static final String WINDOWS = "windows";
075: private static final String UNKNOWN = "unknown";
076:
077: private static final String[][] SUPPORTED_PLATFORMS = {
078: { "Linux,i386", UNIX }, { "SunOS,sparc", UNIX },
079: { "Windows_NT,x86", WINDOWS },
080: { "Windows_2000,x86", WINDOWS },
081: { "Windows_XP,x86", WINDOWS },
082: { "Windows_95,x86", WINDOWS },
083: { "Windows_98,x86", WINDOWS },
084: { "Windows_Me,x86", WINDOWS } };
085:
086: /** Define testcase
087: * @param testName name of the testcase
088: */
089: public MeasureBaselineMemoryFootprint(String testName) {
090: super (testName);
091: }
092:
093: /** Measure baseline memory footprint */
094: public void testMemoryFootprintAfterStart() {
095: long memory;
096: try {
097: memory = getMemoryConsumption();
098:
099: if (memory > 0) {
100: reportPerformance("Memory Consumption After Start",
101: memory, "kB", 1);
102: } else
103: fail("Measured value = " + memory
104: + "kB - it's wrong value!");
105:
106: } catch (Exception exc) {
107: exc.printStackTrace(getLog());
108: fail("Exception rises during measurement : "
109: + exc.toString());
110: }
111: }
112:
113: /**
114: * Measure memory footprint. Looks for file [xtest.tmpdir]/ide.pid
115: * to IDE process PID which is used by utils to measure memory.
116: * @throws IOException if [xtest.tmpdir]/ide.pid file doesn't exist
117: * @return return measured memory footprint
118: */
119: private long getMemoryConsumption() throws IOException {
120: String workdir = System.getProperty("xtest.tmpdir");
121:
122: File ideRunning;
123: log("Start");
124:
125: if (workdir != null) {
126: log("Workdir {" + workdir + "}.");
127: workdir = workdir.substring(0, workdir
128: .lastIndexOf(File.separator));
129:
130: // create flag file indicating running tests
131: ideRunning = new File(workdir, "ide.pid");
132: log("Looking for file {" + ideRunning.getAbsolutePath()
133: + "}.");
134:
135: if (ideRunning.exists()) {
136: log("PID file exists.");
137: try {
138: LineNumberReader reader = new LineNumberReader(
139: new FileReader(ideRunning));
140: String line = reader.readLine();
141: if (line != null) {
142: try {
143: pid = Long.parseLong(line);
144: log("Measure memory footprint of process with PID="
145: + pid);
146: long measuredMemory = measureMemory();
147: Thread.sleep(2000);
148: return measuredMemory;
149: } catch (NumberFormatException nfe) {
150: nfe.printStackTrace(getLog());
151: fail("Cannot parse PID written in the ide.pid file: "
152: + line + "- cannot measure.");
153: }
154: }
155: } catch (IOException ioe) {
156: ioe.printStackTrace(getLog());
157: fail("IOException when reading PID from ide.pid file - cannot measure");
158: } catch (Exception e) {
159: e.printStackTrace(getLog());
160: fail("Exception when trying to measure IDE's used memory");
161: }
162: } else {
163: fail("Cannot find file containing PID of running IDE ("
164: + ideRunning.getAbsolutePath()
165: + ") - cannot measure");
166: }
167: } else {
168: fail("xtest.workdir property is not specified - cannot measure");
169: }
170: fail("Wrong state");
171: return 0;
172: }
173:
174: /**
175: * Run appropriate command against used platform.
176: * @return return measured memory footprint
177: */
178: private long measureMemory() {
179: platform = getPlatform();
180:
181: log("Platform=" + platform);
182:
183: if (platform.equals(UNIX))
184: return psOnUnix();
185: else if (platform.equals(WINDOWS))
186: return psOnWindows();
187: else
188: fail("Unsupported platform!");
189:
190: return 0;
191: }
192:
193: /**
194: * Execute appropriate command and save output as file psOutput.txt.
195: * @param psCommand command to be runned (using platform dependent util)
196: */
197: private void executePsCommand(String psCommand) {
198: log("Ecexute command: [" + psCommand + "].");
199:
200: try {
201: Process ps = Runtime.getRuntime().exec(psCommand);
202:
203: StringBuffer buffer = new StringBuffer();
204: BufferedReader dataInput = new BufferedReader(
205: new InputStreamReader(ps.getInputStream()));
206: String line;
207:
208: while ((line = dataInput.readLine()) != null) {
209: buffer.append(line);
210: buffer.append('\n');
211: }
212:
213: getLog(PS_OUTPUT_FILENAME).print(buffer.toString());
214: ps.waitFor();
215:
216: log("ps command exit value = " + ps.exitValue());
217: } catch (InterruptedException ie) {
218: ie.printStackTrace(getLog());
219: log("InterruptedException when ps :" + ie.toString());
220: } catch (IOException ioe) {
221: ioe.printStackTrace(getLog());
222: log("None output from command ps, exception arise "
223: + ioe.toString());
224: }
225: }
226:
227: /**
228: * Execute commands :
229: * <pre>
230: * ps -A -o pid,comm,rss
231: * </pre>
232: * and save output as file psOutput.txt.
233: * @param psCommand command to be runned (using platform depend util)
234: */
235: private long psOnUnix() {
236: long returnValue = 0;
237:
238: executePsCommand("ps -A -o pid,comm,rss");
239: returnValue = parsePsFile();
240:
241: return returnValue;
242: }
243:
244: /**
245: * Execute commands :
246: * <pre>
247: * pslist.exe
248: * </pre>
249: * and save output as file psOutput.txt.
250: * @param psCommand command to be runned (using platform depend util)
251: */
252: private long psOnWindows() {
253: String xtestHome = System.getProperty("xtest.tmpdir");
254: if (xtestHome != null) {
255: File psFile = new File(xtestHome, "pslist.exe");
256: String psPath = psFile.getAbsolutePath();
257: String psCommand = psPath;
258: executePsCommand(psCommand);
259: return parsePsFile();
260: } else {
261: fail("xtest.home system property not set - cannot find ps distributed with XTest on windows");
262: }
263: return 0;
264: }
265:
266: /**
267: * Parse file (created as output from ps command) and looks for line with appropriate pid.
268: * File can be found (if exists) after test run in working directory. If file has not been created
269: * return 0. If work dir doesn't exist or output file exists but line with appropriate PID doens't
270: * exists there -> test fails.
271: * @return measured memory - parsed output from command ps
272: */
273: private long parsePsFile() {
274: String workDirPath = "";
275:
276: try {
277: workDirPath = getWorkDir().getAbsolutePath();
278: } catch (IOException ioe) {
279: ioe.printStackTrace(getLog());
280: fail("It isn't possible to get work directory, arise exception :"
281: + ioe.toString());
282: }
283:
284: try {
285: File psOutput = new File(workDirPath, PS_OUTPUT_FILENAME);
286: log("Parse file " + psOutput.getAbsolutePath());
287:
288: BufferedReader reader = new BufferedReader(new FileReader(
289: psOutput));
290: String line;
291:
292: while ((line = reader.readLine()) != null) {
293: log("\t Line=[" + line + "]");
294: long memory = getMemory(line);
295: if (memory != 0)
296: return memory;
297: }
298:
299: // fail("Cannot find line with PID in output from ps command!");
300:
301: } catch (IOException ioe) {
302: ioe.printStackTrace(getLog());
303: log("None output from ps command, arise exception :"
304: + ioe.toString());
305: }
306:
307: return 0;
308: }
309:
310: /** Get used memory size parsed from one line of output from command ps .
311: * Transform memory size to [kB]. Type of parser depends on used platform.
312: * @param line line from command ps's output file
313: * @return measured memory
314: */
315: private long getMemory(String line) {
316: StringTokenizer st = new StringTokenizer(line);
317: String line_pid, line_mem;
318: long memory = 0;
319: long ppid;
320:
321: if (line.length() > 0) {
322: if (platform.equals(UNIX)) {
323: line_pid = st.nextToken();
324: try {
325: ppid = Long.parseLong(line_pid);
326: } catch (NumberFormatException exc) {
327: return 0;
328: }
329:
330: log("\t proces pid=" + ppid + " looking for pid=" + pid);
331:
332: if (pid == ppid) {
333: st.nextToken();
334: line_mem = st.nextToken();
335: memory = Long.parseLong(line_mem);
336: }
337:
338: } else if (platform.equals(WINDOWS)) {
339: st.nextToken();
340: line_pid = st.nextToken();
341: try {
342: ppid = Long.parseLong(line_pid);
343: } catch (NumberFormatException exc) {
344: return 0;
345: }
346:
347: log("\t proces pid=" + ppid + " looking for pid=" + pid);
348: if (pid == ppid) {
349: for (int i = 0; i < 3; i++)
350: st.nextToken();
351: line_mem = st.nextToken();
352:
353: memory = Long.parseLong(line_mem);
354: }
355: } else {
356: fail("Unsupported platform!");
357: }
358:
359: }
360: log("Memory=" + memory);
361: return memory;
362: }
363:
364: /**
365: * Get platform on which the code is executed.
366: * @return platform identification string
367: */
368: private static String getPlatform() {
369:
370: String platformString = (System.getProperty("os.name", "")
371: + "," +
372: /*
373: System.getProperty("os.version","")+","+
374: */
375: System.getProperty("os.arch", "")).replace(' ', '_');
376: for (int i = 0; i < SUPPORTED_PLATFORMS.length; i++) {
377: if (platformString
378: .equalsIgnoreCase(SUPPORTED_PLATFORMS[i][0])) {
379: return SUPPORTED_PLATFORMS[i][1];
380: }
381: }
382: return UNKNOWN;
383: }
384:
385: }
|