001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.activemq.store.kahadb.disk.util;
018
019 import java.io.File;
020 import java.io.IOException;
021 import java.io.RandomAccessFile;
022 import java.util.ArrayList;
023 import java.util.Arrays;
024
025 /**
026 * This class is used to get a benchmark the raw disk performance.
027 */
028 public class DiskBenchmark {
029
030 boolean verbose;
031 // reads and writes work with 4k of data at a time.
032 int bs=1024*4;
033 // Work with 100 meg file.
034 long size=1024*1024*500;
035 long sampleInterval = 10*1000;
036
037 public static void main(String[] args) {
038
039 DiskBenchmark benchmark = new DiskBenchmark();
040 args = CommandLineSupport.setOptions(benchmark, args);
041 ArrayList<String> files = new ArrayList<String>();
042 if (args.length == 0) {
043 files.add("disk-benchmark.dat");
044 } else {
045 files.addAll(Arrays.asList(args));
046 }
047
048 for (String f : files) {
049 try {
050 File file = new File(f);
051 if (file.exists()) {
052 System.out.println("File " + file + " allready exists, will not benchmark.");
053 } else {
054 System.out.println("Benchmarking: " + file.getCanonicalPath());
055 Report report = benchmark.benchmark(file);
056 file.delete();
057 System.out.println(report.toString());
058 }
059 } catch (Throwable e) {
060 if (benchmark.verbose) {
061 System.out.println("ERROR:");
062 e.printStackTrace(System.out);
063 } else {
064 System.out.println("ERROR: " + e);
065 }
066 }
067 }
068
069 }
070
071 public static class Report {
072
073 public int size;
074
075 public int writes;
076 public long writeDuration;
077
078 public int syncWrites;
079 public long syncWriteDuration;
080
081 public int reads;
082 public long readDuration;
083
084 @Override
085 public String toString() {
086 return
087 "Writes: \n" +
088 " "+writes+" writes of size "+size+" written in "+(writeDuration/1000.0)+" seconds.\n"+
089 " "+getWriteRate()+" writes/second.\n"+
090 " "+getWriteSizeRate()+" megs/second.\n"+
091 "\n"+
092 "Sync Writes: \n" +
093 " "+syncWrites+" writes of size "+size+" written in "+(syncWriteDuration/1000.0)+" seconds.\n"+
094 " "+getSyncWriteRate()+" writes/second.\n"+
095 " "+getSyncWriteSizeRate()+" megs/second.\n"+
096 "\n"+
097 "Reads: \n" +
098 " "+reads+" reads of size "+size+" read in "+(readDuration/1000.0)+" seconds.\n"+
099 " "+getReadRate()+" writes/second.\n"+
100 " "+getReadSizeRate()+" megs/second.\n"+
101 "\n"+
102 "";
103 }
104
105 private float getWriteSizeRate() {
106 float rc = writes;
107 rc *= size;
108 rc /= (1024*1024); // put it in megs
109 rc /= (writeDuration/1000.0); // get rate.
110 return rc;
111 }
112
113 private float getWriteRate() {
114 float rc = writes;
115 rc /= (writeDuration/1000.0); // get rate.
116 return rc;
117 }
118
119 private float getSyncWriteSizeRate() {
120 float rc = syncWrites;
121 rc *= size;
122 rc /= (1024*1024); // put it in megs
123 rc /= (syncWriteDuration/1000.0); // get rate.
124 return rc;
125 }
126
127 private float getSyncWriteRate() {
128 float rc = syncWrites;
129 rc /= (syncWriteDuration/1000.0); // get rate.
130 return rc;
131 }
132 private float getReadSizeRate() {
133 float rc = reads;
134 rc *= size;
135 rc /= (1024*1024); // put it in megs
136 rc /= (readDuration/1000.0); // get rate.
137 return rc;
138 }
139
140 private float getReadRate() {
141 float rc = reads;
142 rc /= (readDuration/1000.0); // get rate.
143 return rc;
144 }
145
146 public int getSize() {
147 return size;
148 }
149
150 public void setSize(int size) {
151 this.size = size;
152 }
153
154 public int getWrites() {
155 return writes;
156 }
157
158 public void setWrites(int writes) {
159 this.writes = writes;
160 }
161
162 public long getWriteDuration() {
163 return writeDuration;
164 }
165
166 public void setWriteDuration(long writeDuration) {
167 this.writeDuration = writeDuration;
168 }
169
170 public int getSyncWrites() {
171 return syncWrites;
172 }
173
174 public void setSyncWrites(int syncWrites) {
175 this.syncWrites = syncWrites;
176 }
177
178 public long getSyncWriteDuration() {
179 return syncWriteDuration;
180 }
181
182 public void setSyncWriteDuration(long syncWriteDuration) {
183 this.syncWriteDuration = syncWriteDuration;
184 }
185
186 public int getReads() {
187 return reads;
188 }
189
190 public void setReads(int reads) {
191 this.reads = reads;
192 }
193
194 public long getReadDuration() {
195 return readDuration;
196 }
197
198 public void setReadDuration(long readDuration) {
199 this.readDuration = readDuration;
200 }
201 }
202
203
204 public Report benchmark(File file) throws IOException {
205 Report rc = new Report();
206
207 // Initialize the block we will be writing to disk.
208 byte []data = new byte[bs];
209 for (int i = 0; i < data.length; i++) {
210 data[i] = (byte)('a'+(i%26));
211 }
212
213 rc.size = data.length;
214 RandomAccessFile raf = new RandomAccessFile(file, "rw");
215 raf.setLength(size);
216
217 // Figure out how many writes we can do in the sample interval.
218 long start = System.currentTimeMillis();
219 long now = System.currentTimeMillis();
220 int ioCount=0;
221 while( true ) {
222 if( (now-start)>sampleInterval ) {
223 break;
224 }
225 raf.seek(0);
226 for( long i=0; i+data.length < size; i+=data.length) {
227 raf.write(data);
228 ioCount++;
229 now = System.currentTimeMillis();
230 if( (now-start)>sampleInterval ) {
231 break;
232 }
233 }
234 // Sync to disk so that the we actually write the data to disk.. otherwise
235 // OS buffering might not really do the write.
236 raf.getFD().sync();
237 }
238 raf.getFD().sync();
239 raf.close();
240 now = System.currentTimeMillis();
241
242 rc.size = data.length;
243 rc.writes = ioCount;
244 rc.writeDuration = (now-start);
245
246 raf = new RandomAccessFile(file, "rw");
247 start = System.currentTimeMillis();
248 now = System.currentTimeMillis();
249 ioCount=0;
250 while( true ) {
251 if( (now-start)>sampleInterval ) {
252 break;
253 }
254 for( long i=0; i+data.length < size; i+=data.length) {
255 raf.seek(i);
256 raf.write(data);
257 raf.getFD().sync();
258 ioCount++;
259 now = System.currentTimeMillis();
260 if( (now-start)>sampleInterval ) {
261 break;
262 }
263 }
264 }
265 raf.close();
266 now = System.currentTimeMillis();
267 rc.syncWrites = ioCount;
268 rc.syncWriteDuration = (now-start);
269
270 raf = new RandomAccessFile(file, "rw");
271 start = System.currentTimeMillis();
272 now = System.currentTimeMillis();
273 ioCount=0;
274 while( true ) {
275 if( (now-start)>sampleInterval ) {
276 break;
277 }
278 raf.seek(0);
279 for( long i=0; i+data.length < size; i+=data.length) {
280 raf.seek(i);
281 raf.readFully(data);
282 ioCount++;
283 now = System.currentTimeMillis();
284 if( (now-start)>sampleInterval ) {
285 break;
286 }
287 }
288 }
289 raf.close();
290
291 rc.reads = ioCount;
292 rc.readDuration = (now-start);
293 return rc;
294 }
295
296
297 public boolean isVerbose() {
298 return verbose;
299 }
300
301
302 public void setVerbose(boolean verbose) {
303 this.verbose = verbose;
304 }
305
306
307 public int getBs() {
308 return bs;
309 }
310
311
312 public void setBs(int bs) {
313 this.bs = bs;
314 }
315
316
317 public long getSize() {
318 return size;
319 }
320
321
322 public void setSize(long size) {
323 this.size = size;
324 }
325
326
327 public long getSampleInterval() {
328 return sampleInterval;
329 }
330
331
332 public void setSampleInterval(long sampleInterval) {
333 this.sampleInterval = sampleInterval;
334 }
335
336 }