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    }