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();
+ }
}