001: /*
002: * <copyright>
003: *
004: * Copyright 2002-2007 BBNT Solutions, LLC
005: * under sponsorship of the Defense Advanced Research Projects
006: * Agency (DARPA).
007: *
008: * You can redistribute this software and/or modify it under the
009: * terms of the Cougaar Open Source License as published on the
010: * Cougaar Open Source Website (www.cougaar.org).
011: *
012: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
013: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
014: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
015: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
016: * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
017: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
018: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
019: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
020: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
021: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
022: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
023: *
024: * </copyright>
025: */
026:
027: package org.cougaar.qos.qrs.sysstat;
028:
029: import java.util.Arrays;
030: import java.util.Map;
031:
032: import org.cougaar.qos.qrs.DataValue;
033:
034: /**
035: *
036: * This is a JVM+Host microbenchmark facility designed to determine the CAPACITY
037: * of a specific Java Virtual machine running on a specific host. We have found
038: * that the version of JVM makes a big difference in the application
039: * performance, orders of magnitudes, as well as the MIPS of the host. This
040: * benchmark tries to unify the hosts BogoMIPS measures and JVM version.
041: * Obviously to be valid the benchmark must be run under the same JAVA VM as the
042: * application.
043: *
044: * The goal is to measure JVM+host Capacity. We need to remove all the possible
045: * sources of latency variation, such as clock granularity, OS scheduling,
046: * memory swapping, and garbage collection. Given Java's clock granularity of 1
047: * msec, we should run the test for at least 100ms to get 1% accuracy.
048: * Unfortunately 100ms is longer than the OS scheduling increment, such as a
049: * Linux Jiffy which is 10ms. NOTE RUNNING FOR A LONGER TIME DOES NOT HELP,
050: * because OS scheduling other tasks, and garbage collection will then be
051: * "averaged" into the measurements.
052: *
053: * The scheme is:
054: *
055: * 1) Estimate the number of benchmark iterations that will run a test for
056: * around 100ms.
057: *
058: * 2) Run COUNT tests with a SLEEP of msec between the tests. The sleep is to
059: * help the benchmark process from being marked as greedy by the OS. Hence
060: * sleeping reduces the probability of being preempted during the test by some
061: * other job.
062: *
063: * 3) Pick the fastest time as best estimator for the maximum Capacity. Used to
064: * pick the second fastest because the fastest might be a bad measurement (the
065: * best seems fine)
066: *
067: * 4) Return JIPS (Java Instructions Per Second) Jips = (benchmarkIterations /
068: * BestTime) * INST_PER_ITER
069: *
070: * We have run benchmark on hosts with a load average of 10 and have got the
071: * same Jips as when run with a unloaded host. This work despite an under
072: * estimate of the number of iterations for 100ms.
073: *
074: * Jips comes with with 3 built in benchmarks, You are encouraged to experiment
075: * with others: 0 measures the overhead of the loop. 1 measures time to add two
076: * integers (Default) 2 measures time to add two floats
077: *
078: * Problems:
079: *
080: * What if the application excapes to C code, such as array copy, sockets, or
081: * compression?
082: *
083: *
084: */
085:
086: public class Jips extends SysStatHandler implements Runnable
087:
088: {
089: public static final double PERIOD = 0.1;
090: public static final int COUNT = 5;
091: public static final int TYPE = 3;
092: public static final int SLEEP = 100;
093: public static final int MEM_SIZE = 1000000;
094: public static final int MEM_SIZE_MINUS_1 = MEM_SIZE - 1;
095:
096: // estimate the number of "instructions per iteration"
097: public static final int[] INST_PER_ITER = { 19, 20, 20, 91, 148 };
098: private double fieldD = 0.0;
099: private int fieldI = 0;
100: private int[] fieldM = null;
101: private final int type;
102: private String key;
103: private DataValue theValue;
104:
105: private double iterationsPerSecond;
106:
107: public Jips(int type) {
108: this .type = type;
109: }
110:
111: public Jips() {
112: type = TYPE;
113: }
114:
115: public void initialize(String host, int pid) {
116: if (type >= 3) {
117: fieldM = new int[MEM_SIZE];
118: }
119: // cache value here
120: iterationsPerSecond = runTests(PERIOD, COUNT, SLEEP);
121: fieldM = null; // let memory be garbage collected
122: key = "Host" + KEY_SEPR + host + KEY_SEPR + "CPU" + KEY_SEPR
123: + "Jips";
124: theValue = new DataValue(iterationsPerSecond,
125: HOURLY_MEAS_CREDIBILITY, "", PROVENANCE);
126: }
127:
128: // backward compatibility
129: DataValue getData() {
130: return theValue;
131: }
132:
133: public void getData(Map<String, DataValue> map) {
134: map.put(key, theValue);
135: }
136:
137: public void printResults(double[] results) {
138: for (int i = 0; i < results.length; i++) {
139: System.out.println(i + " " + results[i]);
140: }
141: }
142:
143: public void run() {
144: switch (type) {
145: case 0:
146: break;
147: case 1:
148: incI(1);
149: break;
150: case 2:
151: incD(1.0);
152: break;
153: case 3:
154: incM(1);
155: break;
156: // Need better Cougaar benchmark, memory good enough for now.
157: case 4:
158: incM(1);
159: incI(1);
160: incI(1);
161: incI(1);
162: break;
163: }
164: }
165:
166: // Base Benchmarks
167: // Interger overflow will happen when processors are about 10Ghz
168: // (i.e. in the year 2006)
169: // Floating Point Add
170: public void incD(double value) {
171: fieldD = fieldD + value;
172: }
173:
174: // Interger Add
175: public void incI(int value) {
176: fieldI = fieldI + value;
177: }
178:
179: // Memory Add
180: public void incM(int value) {
181: // sweep memory from both sides
182: fieldI = fieldI + value;
183: int dst = fieldI % MEM_SIZE;
184: int src = MEM_SIZE_MINUS_1 - dst;
185: fieldM[dst] = fieldM[src] + fieldI;
186: }
187:
188: // time Benchmark over n iterations
189: public double time(int n) {
190: fieldI = 0;
191: fieldD = 0.0;
192: // fieldM just keeps old values
193: long start = System.currentTimeMillis();
194: while (n-- > 0) {
195: run();
196: }
197: // return time in Seconds
198: return (System.currentTimeMillis() - start) / 1000.0;
199: }
200:
201: // estimate the number of iterations to get the target period
202: public int estimateN(int n, double target) {
203: // exponentially increase n until time is above target
204: double time;
205: while ((time = Math.min(time(n), time(n))) < target) {
206: n = n * 2;
207: // sleep between tests
208: snooze(SLEEP + SLEEP);
209: }
210: return (int) (target / (time / n));
211: }
212:
213: // Sequence a number of tests and pick the second best time
214: public double runTests(double target, int count, int sleepMsec) {
215: // How many iterations to get about targetPeriod
216: int n = estimateN(1, target);
217: // Test results array
218: double[] results = new double[count];
219: for (int i = 0; i < count; i++) {
220: // run test
221: results[i] = time(n);
222: // sleep between tests
223: snooze(sleepMsec);
224: }
225: // sort results
226: Arrays.sort(results);
227: // Debug Dump array
228: // printResults(results);
229: // return the second fastest time
230: // Seconds per iteration
231: return n / results[0] * INST_PER_ITER[type];
232:
233: }
234:
235: private void snooze(int msec) {
236: // sleep between tests
237: try {
238: if (msec > 0) {
239: Thread.sleep(msec);
240: }
241: } catch (InterruptedException e) {
242: e.printStackTrace();
243: }
244: }
245:
246: public static void main(String args[]) {
247: Jips benchmark = null;
248:
249: benchmark = new Jips(0);
250: benchmark.initialize("localhost", 0);
251: System.out.println("Loop MJIPS = "
252: + benchmark.getData().getDoubleValue() / 1000000.0);
253:
254: benchmark = new Jips(1);
255: benchmark.initialize("localhost", 0);
256: System.out.println("Int MJIPS = "
257: + benchmark.getData().getDoubleValue() / 1000000.0);
258:
259: benchmark = new Jips(2);
260: benchmark.initialize("localhost", 0);
261: System.out.println("Double MJIPS = "
262: + benchmark.getData().getDoubleValue() / 1000000.0);
263:
264: benchmark = new Jips(3);
265: benchmark.initialize("localhost", 0);
266: System.out.println("Memory MJIPS = "
267: + benchmark.getData().getDoubleValue() / 1000000.0);
268:
269: benchmark = new Jips(4);
270: benchmark.initialize("localhost", 0);
271: System.out.println("Cougaar MJIPS = "
272: + benchmark.getData().getDoubleValue() / 1000000.0);
273:
274: }
275:
276: }
|