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