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