Author: chirino
Date: Mon Jan 16 17:25:28 2012
New Revision: 1232066

URL: http://svn.apache.org/viewvc?rev=1232066&view=rev
Log:
Moving the disk benchmark so that it's accessible via the apollo CLI.  Improved 
the memory property editor so it supports both SI and IEC units up to exbibyte 
and exabytes. You can now also format a long memory value.

Added:
    
activemq/activemq-apollo/trunk/apollo-cli/src/main/scala/org/apache/activemq/apollo/cli/commands/DiskBenchmark.scala
Removed:
    
activemq/activemq-apollo/trunk/apollo-util/src/main/scala/org/apache/activemq/apollo/util/DiskBenchmark.java
Modified:
    
activemq/activemq-apollo/trunk/apollo-cli/src/main/resources/META-INF/services/org.apache.activemq.apollo/apollo-broker-commands.index
    
activemq/activemq-apollo/trunk/apollo-cli/src/main/resources/META-INF/services/org.apache.activemq.apollo/apollo-commands.index
    
activemq/activemq-apollo/trunk/apollo-util/src/main/scala/org/apache/activemq/apollo/util/MemoryPropertyEditor.java

Modified: 
activemq/activemq-apollo/trunk/apollo-cli/src/main/resources/META-INF/services/org.apache.activemq.apollo/apollo-broker-commands.index
URL: 
http://svn.apache.org/viewvc/activemq/activemq-apollo/trunk/apollo-cli/src/main/resources/META-INF/services/org.apache.activemq.apollo/apollo-broker-commands.index?rev=1232066&r1=1232065&r2=1232066&view=diff
==============================================================================
--- 
activemq/activemq-apollo/trunk/apollo-cli/src/main/resources/META-INF/services/org.apache.activemq.apollo/apollo-broker-commands.index
 (original)
+++ 
activemq/activemq-apollo/trunk/apollo-cli/src/main/resources/META-INF/services/org.apache.activemq.apollo/apollo-broker-commands.index
 Mon Jan 16 17:25:28 2012
@@ -22,4 +22,5 @@ org.apache.activemq.apollo.cli.commands.
 org.apache.activemq.apollo.cli.commands.StoreExport
 org.apache.activemq.apollo.cli.commands.StoreImport
 org.apache.activemq.apollo.cli.commands.DashHelp
-org.apache.activemq.apollo.cli.commands.Version
\ No newline at end of file
+org.apache.activemq.apollo.cli.commands.Version
+org.apache.activemq.apollo.cli.commands.DiskBenchmark
\ No newline at end of file

Modified: 
activemq/activemq-apollo/trunk/apollo-cli/src/main/resources/META-INF/services/org.apache.activemq.apollo/apollo-commands.index
URL: 
http://svn.apache.org/viewvc/activemq/activemq-apollo/trunk/apollo-cli/src/main/resources/META-INF/services/org.apache.activemq.apollo/apollo-commands.index?rev=1232066&r1=1232065&r2=1232066&view=diff
==============================================================================
--- 
activemq/activemq-apollo/trunk/apollo-cli/src/main/resources/META-INF/services/org.apache.activemq.apollo/apollo-commands.index
 (original)
+++ 
activemq/activemq-apollo/trunk/apollo-cli/src/main/resources/META-INF/services/org.apache.activemq.apollo/apollo-commands.index
 Mon Jan 16 17:25:28 2012
@@ -19,3 +19,4 @@ org.apache.activemq.apollo.cli.commands.
 org.apache.activemq.apollo.cli.commands.Help
 org.apache.activemq.apollo.cli.commands.DashHelp
 org.apache.activemq.apollo.cli.commands.Version
+org.apache.activemq.apollo.cli.commands.DiskBenchmark
\ No newline at end of file

Added: 
activemq/activemq-apollo/trunk/apollo-cli/src/main/scala/org/apache/activemq/apollo/cli/commands/DiskBenchmark.scala
URL: 
http://svn.apache.org/viewvc/activemq/activemq-apollo/trunk/apollo-cli/src/main/scala/org/apache/activemq/apollo/cli/commands/DiskBenchmark.scala?rev=1232066&view=auto
==============================================================================
--- 
activemq/activemq-apollo/trunk/apollo-cli/src/main/scala/org/apache/activemq/apollo/cli/commands/DiskBenchmark.scala
 (added)
+++ 
activemq/activemq-apollo/trunk/apollo-cli/src/main/scala/org/apache/activemq/apollo/cli/commands/DiskBenchmark.scala
 Mon Jan 16 17:25:28 2012
@@ -0,0 +1,256 @@
+package org.apache.activemq.apollo.cli.commands
+
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import org.apache.felix.gogo.commands.{Action, Option => option, Argument => 
argument, Command => command}
+import org.apache.felix.service.command.CommandSession
+import java.io.{RandomAccessFile, File}
+import java.util.concurrent.TimeUnit
+import javax.management.ObjectName
+import management.ManagementFactory
+import org.apache.activemq.apollo.util.{MemoryPropertyEditor, IOHelper}
+
+
+class Report {
+  
+  var block_size: Int = 0
+  var async_writes: Int = 0
+  var async_write_duration: Long = 0L
+  var sync_writes: Int = 0
+  var sync_write_duration: Long = 0L
+  var reads: Int = 0
+  var read_duration: Long = 0L
+
+  def async_write_size_rate: Float = {
+    var rc: Float = async_writes
+    rc *= block_size
+    rc /= (1024 * 1024)
+    rc /= (async_write_duration / 1000.0f)
+    return rc
+  }
+
+  def async_write_rate: Float = {
+    var rc: Float = async_writes
+    rc /= (async_write_duration / 1000.0f)
+    return rc
+  }
+
+  def sync_write_size_rate: Float = {
+    var rc: Float = sync_writes
+    rc *= block_size
+    rc /= (1024 * 1024)
+    rc /= (sync_write_duration / 1000.0f)
+    return rc
+  }
+
+  def sync_write_rate: Float = {
+    var rc: Float = sync_writes
+    rc /= (sync_write_duration / 1000.0f)
+    return rc
+  }
+
+  def read_size_rate: Float = {
+    var rc: Float = reads
+    rc *= block_size
+    rc /= (1024 * 1024)
+    rc /= (read_duration / 1000.0f)
+    return rc
+  }
+
+  def read_rate: Float = {
+    var rc: Float = reads
+    rc /= (read_duration / 1000.0f)
+    return rc
+  }
+  
+  override def toString: String = {
+    return "Async writes: \n" + "  " + async_writes + " writes of size " + 
block_size + " written in " + (async_write_duration / 1000.0) + " seconds.\n" +
+            "  " + async_write_rate + " writes/second.\n" +
+            "  " + async_write_size_rate + " megs/second.\n" +
+            "\n" +
+            "Sync writes: \n" + "  " + sync_writes + " writes of size " + 
block_size + " written in " + (sync_write_duration / 1000.0) + " seconds.\n" +
+            "  " + sync_write_rate + " writes/second.\n" +
+            "  " + sync_write_size_rate + " megs/second.\n" +
+            "\n" +
+            "Reads: \n" + "  " + reads + " reads of size " + block_size + " 
read in " + (read_duration / 1000.0) + " seconds.\n" +
+            "  " + read_rate + " writes/second.\n" +
+            "  " + read_size_rate + " megs/second.\n" +
+            "\n" + ""
+  }
+
+}
+
+object DiskBenchmark {
+  
+  final val PHYSICAL_MEM_SIZE = MemoryPropertyEditor.format((try {
+    val mbean_server = ManagementFactory.getPlatformMBeanServer()
+    mbean_server.getAttribute(new 
ObjectName("java.lang:type=OperatingSystem"), "TotalPhysicalMemorySize") match {
+      case x:java.lang.Long=> Some(x.longValue)
+      case _ => None
+    }
+  } catch {
+    case _ => None
+  }).getOrElse(1024*1024*500L))
+
+}
+
+
+/**
+ * The apollo encrypt command
+ */
+@command(scope="apollo", name = "disk-benchmark", description = "Benchmarks 
your disk's speed")
+class DiskBenchmark extends Action {
+  import DiskBenchmark._
+
+  @option(name = "--verbose", description = "Enable verbose output")
+  var verbose: Boolean = false
+  @option(name = "--sample-interval", description = "The number of 
milliseconds to spend mesuring perfomance.")
+  var sampleInterval: Long = 10 * 1000
+  @argument(name="file", description="The file that will be used to benchmark 
your disk (must NOT exist)")
+  var file = new File("disk-benchmark.dat")
+  
+  @option(name = "--block-size", description = "The size of each IO 
operation.")
+  var block_size_txt = "4k"
+  def block_size = MemoryPropertyEditor.parse(block_size_txt).toInt
+
+  @option(name = "--file-size", description = "The size of the data file to 
use, this should be big enough to flush the OS write cache.")
+  var file_size_txt = PHYSICAL_MEM_SIZE
+  def file_size = MemoryPropertyEditor.parse(file_size_txt)
+
+  @option(name = "--warm-up-size", description = "The amount of data we should 
initial write before measuring performance samples (used to flush the OS write 
cache).")
+  var warm_up_size_txt = PHYSICAL_MEM_SIZE
+  def warm_up_size = MemoryPropertyEditor.parse(warm_up_size_txt)
+
+  def execute(session: CommandSession):AnyRef = {
+    def out = session.getConsole
+    try {
+      if (file.exists) {
+        out.println("File " + file + " allready exists, will not benchmark.")
+      } else {
+        out.println("Benchmark using data file: " + file.getCanonicalPath)
+
+        // Initialize the block /w data..
+        var data = new Array[Byte](block_size)
+        var i: Int = 0
+        while (i < data.length) {
+          data(i) = ('a' + (i % 26)).asInstanceOf[Byte]
+          i += 1
+        }
+
+        val report = new Report
+        report.block_size = block_size
+
+        // Pre-allocate the file size..
+        var raf = new RandomAccessFile(file, "rw")
+        try {
+
+          out.println("Pre-allocating data file of size: "+file_size_txt)
+          raf.setLength(file_size)
+          raf.seek(file_size-1)
+          raf.writeByte(0);
+          IOHelper.sync(raf.getFD)
+
+          if( warm_up_size > 0 ) {
+            val max = warm_up_size
+            out.println("Warming up... writing async "+warm_up_size_txt+" so 
that async writes don't have that much of an advantage due to the OS write 
cache.")
+            write(raf, data, (count)=>{
+              count > max
+            })
+          }
+
+
+          out.println("Benchmarking async writes")
+          var start = System.nanoTime()
+          var end = start
+          report.async_writes = write(raf, data, (count)=>{
+            end = System.nanoTime
+            TimeUnit.NANOSECONDS.toMillis(end-start) >  sampleInterval
+          })
+          report.async_write_duration = 
TimeUnit.NANOSECONDS.toMillis(end-start)
+
+          out.println("Syncing previous writes before measuring sync write 
performance.. (might take a while if your OS has a big write cache)")
+          IOHelper.sync(raf.getFD)
+
+          out.println("Benchmarking sync writes")
+          start = System.nanoTime()
+          end = start
+          report.sync_writes = write(raf, data, (count)=>{
+            IOHelper.sync(raf.getFD)
+            end = System.nanoTime
+            TimeUnit.NANOSECONDS.toMillis(end-start) >  sampleInterval
+          })
+          report.sync_write_duration = TimeUnit.NANOSECONDS.toMillis(end-start)
+
+          out.println("Benchmarking reads")
+          start = System.nanoTime()
+          end = start
+          report.reads = read(raf, data, (count)=>{
+            end = System.nanoTime
+            TimeUnit.NANOSECONDS.toMillis(end-start) >  sampleInterval
+          })
+          report.read_duration = TimeUnit.NANOSECONDS.toMillis(end-start)
+
+        } finally {
+          raf.close
+        }
+        file.delete
+        out.println(report)
+      }
+    } catch {
+      case x:Helper.Failure=> error(x.getMessage)
+      case e: Throwable =>
+        if (verbose) {
+          out.println("ERROR:")
+          e.printStackTrace(System.out)
+        } else {
+          out.println("ERROR: " + e)
+        }
+    }
+    null
+  }
+
+  private def write(raf: RandomAccessFile, data: Array[Byte], until: 
(Long)=>Boolean) = {
+    var file_position = raf.getFilePointer
+    var counter = 0
+    while (!until(counter * data.length)) {
+      if(  file_position + data.length >= file_size ) {
+        file_position = 0;
+        raf.seek(file_position)
+      }
+      raf.write(data)
+      counter += 1;
+      file_position += data.length
+    }
+    counter
+  }
+
+  private def read(raf: RandomAccessFile, data: Array[Byte], until: 
(Long)=>Boolean) = {
+    var file_position = raf.getFilePointer
+    var counter = 0
+    while (!until(counter * data.length)) {
+      if( file_position + data.length >= file_size ) {
+        file_position = 0;
+        raf.seek(file_position)
+      }
+      raf.readFully(data)
+      counter += 1;
+      file_position += data.length
+    }
+    counter
+  }
+
+}
\ No newline at end of file

Modified: 
activemq/activemq-apollo/trunk/apollo-util/src/main/scala/org/apache/activemq/apollo/util/MemoryPropertyEditor.java
URL: 
http://svn.apache.org/viewvc/activemq/activemq-apollo/trunk/apollo-util/src/main/scala/org/apache/activemq/apollo/util/MemoryPropertyEditor.java?rev=1232066&r1=1232065&r2=1232066&view=diff
==============================================================================
--- 
activemq/activemq-apollo/trunk/apollo-util/src/main/scala/org/apache/activemq/apollo/util/MemoryPropertyEditor.java
 (original)
+++ 
activemq/activemq-apollo/trunk/apollo-util/src/main/scala/org/apache/activemq/apollo/util/MemoryPropertyEditor.java
 Mon Jan 16 17:25:28 2012
@@ -21,46 +21,165 @@ import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
 /**
- * Converts string values like "20 Mb", "1024kb", and "1g" to long values in
- * bytes.
+ * Converts string values like "20 Mib", "1024kb", and "1g" to long values in 
bytes.
  */
 public class MemoryPropertyEditor extends PropertyEditorSupport {
+
+    private static final Pattern BYTE_PATTERN = 
Pattern.compile("^\\s*(\\d+)\\s*b?\\s*$", Pattern.CASE_INSENSITIVE);
+
+    private static final Pattern KIB_PATTERN = 
Pattern.compile("^\\s*(\\d+)\\s*k(ib)?\\s*$", Pattern.CASE_INSENSITIVE);
+    private static final Pattern MIB_PATTERN = 
Pattern.compile("^\\s*(\\d+)\\s*m(ib)?\\s*$", Pattern.CASE_INSENSITIVE);
+    private static final Pattern GIB_PATTERN = 
Pattern.compile("^\\s*(\\d+)\\s*g(ib)?\\s*$", Pattern.CASE_INSENSITIVE);
+    private static final Pattern TIB_PATTERN = 
Pattern.compile("^\\s*(\\d+)\\s*t(ib)?\\s*$", Pattern.CASE_INSENSITIVE);
+    private static final Pattern PIB_PATTERN = 
Pattern.compile("^\\s*(\\d+)\\s*p(ib)?\\s*$", Pattern.CASE_INSENSITIVE);
+    private static final Pattern EIB_PATTERN = 
Pattern.compile("^\\s*(\\d+)\\s*e(ib)?\\s*$", Pattern.CASE_INSENSITIVE);
+
+    private static final Pattern KB_PATTERN = 
Pattern.compile("^\\s*(\\d+)\\s*kb?\\s*$", Pattern.CASE_INSENSITIVE);
+    private static final Pattern MB_PATTERN = 
Pattern.compile("^\\s*(\\d+)\\s*mb?\\s*$", Pattern.CASE_INSENSITIVE);
+    private static final Pattern GB_PATTERN = 
Pattern.compile("^\\s*(\\d+)\\s*gb?\\s*$", Pattern.CASE_INSENSITIVE);
+    private static final Pattern TB_PATTERN = 
Pattern.compile("^\\s*(\\d+)\\s*tb?\\s*$", Pattern.CASE_INSENSITIVE);
+    private static final Pattern PB_PATTERN = 
Pattern.compile("^\\s*(\\d+)\\s*pb?\\s*$", Pattern.CASE_INSENSITIVE);
+    private static final Pattern EB_PATTERN = 
Pattern.compile("^\\s*(\\d+)\\s*eb?\\s*$", Pattern.CASE_INSENSITIVE);
+
     public void setAsText(String text) throws IllegalArgumentException {
 
-        Pattern p = Pattern.compile("^\\s*(\\d+)\\s*(b)?\\s*$", 
Pattern.CASE_INSENSITIVE);
-        Matcher m = p.matcher(text);
+        Matcher m = BYTE_PATTERN.matcher(text);
         if (m.matches()) {
             setValue(Long.valueOf(Long.parseLong(m.group(1))));
             return;
         }
-
-        p = Pattern.compile("^\\s*(\\d+)\\s*k(b)?\\s*$", 
Pattern.CASE_INSENSITIVE);
-        m = p.matcher(text);
+        m = KIB_PATTERN.matcher(text);
         if (m.matches()) {
             setValue(Long.valueOf(Long.parseLong(m.group(1)) * 1024));
             return;
         }
-
-        p = Pattern.compile("^\\s*(\\d+)\\s*m(b)?\\s*$", 
Pattern.CASE_INSENSITIVE);
-        m = p.matcher(text);
+        m = MIB_PATTERN.matcher(text);
         if (m.matches()) {
             setValue(Long.valueOf(Long.parseLong(m.group(1)) * 1024 * 1024));
             return;
         }
-
-        p = Pattern.compile("^\\s*(\\d+)\\s*g(b)?\\s*$", 
Pattern.CASE_INSENSITIVE);
-        m = p.matcher(text);
+        m = GIB_PATTERN.matcher(text);
         if (m.matches()) {
             setValue(Long.valueOf(Long.parseLong(m.group(1)) * 1024 * 1024 * 
1024));
             return;
         }
+        m = TIB_PATTERN.matcher(text);
+        if (m.matches()) {
+            setValue(Long.valueOf(Long.parseLong(m.group(1)) * 1024 * 1024 * 
1024 * 1024));
+            return;
+        }
+        m = PIB_PATTERN.matcher(text);
+        if (m.matches()) {
+            setValue(Long.valueOf(Long.parseLong(m.group(1)) * 1024 * 1024 * 
1024 * 1024 * 1024));
+            return;
+        }
+        m = EIB_PATTERN.matcher(text);
+        if (m.matches()) {
+            setValue(Long.valueOf(Long.parseLong(m.group(1)) * 1024 * 1024 * 
1024 * 1024 * 1024 * 1024));
+            return;
+        }
+
+        m = KB_PATTERN.matcher(text);
+        if (m.matches()) {
+            setValue(Long.valueOf(Long.parseLong(m.group(1)) * 1000));
+            return;
+        }
+        m = MB_PATTERN.matcher(text);
+        if (m.matches()) {
+            setValue(Long.valueOf(Long.parseLong(m.group(1)) * 1000 * 1000));
+            return;
+        }
+        m = GB_PATTERN.matcher(text);
+        if (m.matches()) {
+            setValue(Long.valueOf(Long.parseLong(m.group(1)) * 1000 * 1000 * 
1000));
+            return;
+        }
+        m = TB_PATTERN.matcher(text);
+        if (m.matches()) {
+            setValue(Long.valueOf(Long.parseLong(m.group(1)) * 1000 * 1000 * 
1000 * 1000));
+            return;
+        }
+        m = PB_PATTERN.matcher(text);
+        if (m.matches()) {
+            setValue(Long.valueOf(Long.parseLong(m.group(1)) * 1000 * 1000 * 
1000 * 1000 * 1000));
+            return;
+        }
+        m = EB_PATTERN.matcher(text);
+        if (m.matches()) {
+            setValue(Long.valueOf(Long.parseLong(m.group(1)) * 1000 * 1000 * 
1000 * 1000 * 1000 * 1000));
+            return;
+        }
 
         throw new IllegalArgumentException("Could convert not to a memory 
size: " + text);
     }
 
     public String getAsText() {
         Long value = (Long)getValue();
-        return value != null ? value.toString() : "";
+        if( value == null ) 
+            return "";
+        long v = value.longValue();
+        
+        if( (v % 1024) != 0) {
+            if( (v % 1000) != 0) {
+                return Long.toString(v);
+            } else {
+                v = v/1000;
+                if( (v % 1000) != 0) {
+                    return v+"kB";
+                } else {
+                    v = v/1000;
+                    if( (v % 1000) != 0) {
+                        return v+"MB";
+                    } else {
+                        v = v/1000;
+                        if( (v % 1000) != 0) {
+                            return v+"GB";
+                        } else {
+                            v = v/1000;
+                            if( (v % 1000) != 0) {
+                                return v+"TB";
+                            } else {
+                                v = v/1000;
+                                if( (v % 1000) != 0) {
+                                    return v+"PB";
+                                } else {
+                                    v = v/1000;
+                                    return v+"EB";
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        } else {
+            v = v/1024;
+            if( (v % 1024) != 0) {
+                return v+"KiB";
+            } else {
+                v = v/1024;
+                if( (v % 1024) != 0) {
+                    return v+"MiB";
+                } else {
+                    v = v/1024;
+                    if( (v % 1024) != 0) {
+                        return v+"GiB";
+                    } else {
+                        v = v/1024;
+                        if( (v % 1024) != 0) {
+                            return v+"TiB";
+                        } else {
+                            v = v/1024;
+                            if( (v % 1024) != 0) {
+                                return v+"PiB";
+                            } else {
+                                v = v/1024;
+                                return v+"EiB";
+                            }
+                        }
+                    }
+                }
+            }
+        }
     }
 
     public static long parse(String value) {
@@ -68,4 +187,10 @@ public class MemoryPropertyEditor extend
         pe.setAsText(value);
         return (Long)pe.getValue();
     }
+    
+    public static String format(long value) {
+        MemoryPropertyEditor pe = new MemoryPropertyEditor();
+        pe.setValue(value);
+        return pe.getAsText();
+    }
 }


Reply via email to