diff options
author | Jesse Wilson <jessewilson@google.com> | 2009-12-08 13:45:25 -0800 |
---|---|---|
committer | Jesse Wilson <jessewilson@google.com> | 2009-12-08 13:46:46 -0800 |
commit | 109c128644fdd598b9e71301424ff4fa11f4bcd2 (patch) | |
tree | 91cf4b7cb921337c8af3f332f5963ba91d9de72f | |
parent | 81df03cdd027342e7a6e6d8a10c56a4ba71b1dad (diff) | |
download | caliper-109c128644fdd598b9e71301424ff4fa11f4bcd2.tar.gz |
Updating caliper to current SVN as of 20091208
A test
A test/com
A test/com/google
A test/com/google/caliper
A test/com/google/caliper/DefaultBenchmarkSuiteTest.java
A test/com/google/caliper/AllTests.java
A test/com/google/caliper/examples
A test/com/google/caliper/examples/DoubleToStringBenchmarkSuite.java
A test/com/google/caliper/examples/SortBenchmarkSuite.java
A lib
A lib/junit.jar
A lib/google-collect-1.0-rc4.jar
A src
A src/com
A src/com/google
A src/com/google/caliper
A src/com/google/caliper/Caliper.java
A src/com/google/caliper/Param.java
A src/com/google/caliper/Parameter.java
A src/com/google/caliper/ExecutionException.java
A src/com/google/caliper/BenchmarkSuite.java
A src/com/google/caliper/Run.java
A src/com/google/caliper/ConfigurationException.java
A src/com/google/caliper/DefaultBenchmarkSuite.java
A src/com/google/caliper/Runner.java
A src/com/google/caliper/TypeConverter.java
A src/com/google/caliper/Benchmark.java
A src/com/google/caliper/ConsoleReport.java
A src/com/google/caliper/Result.java
A caliper.ipr
A core.iml
A COPYING
A build.xml
Checked out revision 14.
24 files changed, 2379 insertions, 0 deletions
diff --git a/Android.mk b/Android.mk new file mode 100644 index 0000000..5974b90 --- /dev/null +++ b/Android.mk @@ -0,0 +1,31 @@ +# Copyright (C) 2009 The Android Open Source Project +# +# Licensed 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. +# +# + +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := $(call all-java-files-under, src) + +LOCAL_MODULE := caliper + +LOCAL_STATIC_JAVA_LIBRARIES := google-collect + +include $(BUILD_HOST_JAVA_LIBRARY) + +# prebuilt google-collect-1.0-rc4.jar +include $(CLEAR_VARS) +LOCAL_PREBUILT_JAVA_LIBRARIES := google-collect:lib/google-collect-1.0-rc4.jar +include $(BUILD_HOST_PREBUILT) @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed 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. diff --git a/build.xml b/build.xml new file mode 100644 index 0000000..a1584b0 --- /dev/null +++ b/build.xml @@ -0,0 +1,114 @@ +<?xml version="1.0"?> + +<project name="caliper" default="compile"> + + <property environment="env"/> + + <!-- can be overridden at the command line with -Dversion= + or in IDEA, in the ant properties dialog --> + <property name="version" value="snapshot"/> + + <path id="compile.classpath"> + <pathelement location="lib/google-collect-1.0-rc4.jar"/> + </path> + + <target name="compile" description="Compile Java source."> + <mkdir dir="build/classes"/> + <javac srcdir="src" + debug="on" + destdir="build/classes" + source="1.5" + target="1.5"> + <classpath refid="compile.classpath"/> + </javac> + <copy toDir="build/classes"> + <fileset dir="src" excludes="**/*.java"/> + </copy> + </target> + + <target name="test.compile" + depends="compile" + description="Compile test source."> + <mkdir dir="build/test"/> + <javac srcdir="test" + debug="on" + destdir="build/test" + source="1.5" + target="1.5"> + <classpath> + <pathelement location="build/classes"/> + <pathelement location="lib/google-collect-1.0-rc4.jar"/> + <pathelement location="lib/junit.jar"/> + </classpath> + </javac> + <copy toDir="build/test"> + <fileset dir="test" excludes="**/*.java"/> + </copy> + </target> + + <target name="test" + depends="test.compile" + description="Execute JUnit tests."> + <java fork="true" + classname="junit.textui.TestRunner" + failonerror="true" + taskname="junit"> + <classpath> + <pathelement location="build/test"/> + <pathelement location="build/classes"/> + <pathelement location="lib/junit.jar"/> + <pathelement location="lib/google-collect-1.0-rc4.jar"/> + </classpath> + <arg value="com.google.caliper.AllTests" /> + </java> + </target> + + <target name="clean" + description="Remove generated files."> + <delete dir="build"/> + </target> + + <target name="jar" depends="compile" description="Build jars."> + <mkdir dir="build/dist"/> + <mkdir dir="build/dist/caliper-${version}"/> + <jar jarfile="build/dist/caliper-${version}/caliper-${version}.jar"> + <fileset dir="build/classes"/> + </jar> + </target> + + <target name="jarsrc" description="Build jar of source."> + <jar jarfile="build/dist/caliper-${version}/src-${version}.zip"> + <fileset dir="src"/> + </jar> + </target> + + <target name="dist" depends="jar, jarsrc, javadoc" + description="Build entire distribution."> + <copy toDir="build/dist/caliper-${version}" file="COPYING"/> + <copy toDir="build/dist/caliper-${version}"> + <fileset dir="build" includes="javadoc/**/*"/> + </copy> + + <zip destfile="build/caliper-${version}.zip" + basedir="build/dist"/> + </target> + + <target name="javadoc" + description="Generate Javadocs."> + <delete dir="build/javadoc"/> + <mkdir dir="build/javadoc"/> + <javadoc packagenames="com.google.caliper" + destdir="build/javadoc" + use="true" + author="true" + protected="true" + windowtitle="Caliper ${version}"> + <sourcepath> + <pathelement location="src"/> + </sourcepath> + <classpath refid="compile.classpath"/> + <link href="http://google-collections.googlecode.com/svn/trunk/javadoc/"/> + <link href="http://java.sun.com/javase/6/docs/api"/> + </javadoc> + </target> +</project> diff --git a/caliper.ipr b/caliper.ipr new file mode 100644 index 0000000..f4e0208 --- /dev/null +++ b/caliper.ipr @@ -0,0 +1,342 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project relativePaths="false" version="4"> + <component name="AntConfiguration"> + <defaultAnt bundledAnt="true" /> + </component> + <component name="BuildJarProjectSettings"> + <option name="BUILD_JARS_ON_MAKE" value="false" /> + </component> + <component name="CodeStyleSettingsManager"> + <option name="PER_PROJECT_SETTINGS"> + <value> + <ADDITIONAL_INDENT_OPTIONS fileType="java"> + <option name="INDENT_SIZE" value="4" /> + <option name="CONTINUATION_INDENT_SIZE" value="8" /> + <option name="TAB_SIZE" value="4" /> + <option name="USE_TAB_CHARACTER" value="false" /> + <option name="SMART_TABS" value="false" /> + <option name="LABEL_INDENT_SIZE" value="0" /> + <option name="LABEL_INDENT_ABSOLUTE" value="false" /> + </ADDITIONAL_INDENT_OPTIONS> + <ADDITIONAL_INDENT_OPTIONS fileType="jsp"> + <option name="INDENT_SIZE" value="4" /> + <option name="CONTINUATION_INDENT_SIZE" value="8" /> + <option name="TAB_SIZE" value="4" /> + <option name="USE_TAB_CHARACTER" value="false" /> + <option name="SMART_TABS" value="false" /> + <option name="LABEL_INDENT_SIZE" value="0" /> + <option name="LABEL_INDENT_ABSOLUTE" value="false" /> + </ADDITIONAL_INDENT_OPTIONS> + <ADDITIONAL_INDENT_OPTIONS fileType="xml"> + <option name="INDENT_SIZE" value="4" /> + <option name="CONTINUATION_INDENT_SIZE" value="8" /> + <option name="TAB_SIZE" value="4" /> + <option name="USE_TAB_CHARACTER" value="false" /> + <option name="SMART_TABS" value="false" /> + <option name="LABEL_INDENT_SIZE" value="0" /> + <option name="LABEL_INDENT_ABSOLUTE" value="false" /> + </ADDITIONAL_INDENT_OPTIONS> + </value> + </option> + <option name="USE_PER_PROJECT_SETTINGS" value="false" /> + </component> + <component name="CompilerConfiguration"> + <option name="DEFAULT_COMPILER" value="Javac" /> + <option name="DEPLOY_AFTER_MAKE" value="0" /> + <resourceExtensions> + <entry name=".+\.(properties|xml|html|dtd|tld)" /> + <entry name=".+\.(gif|png|jpeg|jpg)" /> + </resourceExtensions> + <wildcardResourcePatterns> + <entry name="?*.properties" /> + <entry name="?*.xml" /> + <entry name="?*.gif" /> + <entry name="?*.png" /> + <entry name="?*.jpeg" /> + <entry name="?*.jpg" /> + <entry name="?*.html" /> + <entry name="?*.dtd" /> + <entry name="?*.tld" /> + <entry name="?*.ftl" /> + </wildcardResourcePatterns> + </component> + <component name="CopyrightManager" default=""> + <module2copyright /> + </component> + <component name="DependencyValidationManager"> + <option name="SKIP_IMPORT_STATEMENTS" value="false" /> + </component> + <component name="EclipseCompilerSettings"> + <option name="DEBUGGING_INFO" value="true" /> + <option name="GENERATE_NO_WARNINGS" value="true" /> + <option name="DEPRECATION" value="false" /> + <option name="ADDITIONAL_OPTIONS_STRING" value="" /> + <option name="MAXIMUM_HEAP_SIZE" value="128" /> + </component> + <component name="Encoding" useUTFGuessing="true" native2AsciiForPropertiesFiles="false" /> + <component name="InspectionProjectProfileManager"> + <option name="PROJECT_PROFILE" value="Project Default" /> + <option name="USE_PROJECT_LEVEL_SETTINGS" value="false" /> + <scopes /> + <profiles> + <profile version="1.0" is_locked="false"> + <option name="myName" value="Project Default" /> + <option name="myLocal" value="false" /> + <inspection_tool class="CloneDeclaresCloneNotSupported" level="WARNING" enabled="false" /> + <inspection_tool class="JavaDoc" level="WARNING" enabled="false"> + <option name="TOP_LEVEL_CLASS_OPTIONS"> + <value> + <option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" /> + <option name="REQUIRED_TAGS" value="" /> + </value> + </option> + <option name="INNER_CLASS_OPTIONS"> + <value> + <option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" /> + <option name="REQUIRED_TAGS" value="" /> + </value> + </option> + <option name="METHOD_OPTIONS"> + <value> + <option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" /> + <option name="REQUIRED_TAGS" value="@return@param@throws or @exception" /> + </value> + </option> + <option name="FIELD_OPTIONS"> + <value> + <option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" /> + <option name="REQUIRED_TAGS" value="" /> + </value> + </option> + <option name="IGNORE_DEPRECATED" value="false" /> + <option name="IGNORE_JAVADOC_PERIOD" value="true" /> + <option name="myAdditionalJavadocTags" value="" /> + </inspection_tool> + </profile> + </profiles> + <list size="0" /> + </component> + <component name="JavacSettings"> + <option name="DEBUGGING_INFO" value="true" /> + <option name="GENERATE_NO_WARNINGS" value="false" /> + <option name="DEPRECATION" value="true" /> + <option name="ADDITIONAL_OPTIONS_STRING" value="" /> + <option name="MAXIMUM_HEAP_SIZE" value="128" /> + </component> + <component name="JavadocGenerationManager"> + <option name="OUTPUT_DIRECTORY" /> + <option name="OPTION_SCOPE" value="protected" /> + <option name="OPTION_HIERARCHY" value="true" /> + <option name="OPTION_NAVIGATOR" value="true" /> + <option name="OPTION_INDEX" value="true" /> + <option name="OPTION_SEPARATE_INDEX" value="true" /> + <option name="OPTION_DOCUMENT_TAG_USE" value="false" /> + <option name="OPTION_DOCUMENT_TAG_AUTHOR" value="false" /> + <option name="OPTION_DOCUMENT_TAG_VERSION" value="false" /> + <option name="OPTION_DOCUMENT_TAG_DEPRECATED" value="true" /> + <option name="OPTION_DEPRECATED_LIST" value="true" /> + <option name="OTHER_OPTIONS" value="" /> + <option name="HEAP_SIZE" /> + <option name="LOCALE" /> + <option name="OPEN_IN_BROWSER" value="true" /> + </component> + <component name="JikesSettings"> + <option name="JIKES_PATH" value="" /> + <option name="DEBUGGING_INFO" value="true" /> + <option name="DEPRECATION" value="true" /> + <option name="GENERATE_NO_WARNINGS" value="false" /> + <option name="IS_EMACS_ERRORS_MODE" value="true" /> + <option name="ADDITIONAL_OPTIONS_STRING" value="" /> + </component> + <component name="Palette2"> + <group name="Swing"> + <item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.png" removable="false" auto-create-binding="false" can-attach-label="false"> + <default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" /> + </item> + <item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.png" removable="false" auto-create-binding="false" can-attach-label="false"> + <default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" /> + </item> + <item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.png" removable="false" auto-create-binding="false" can-attach-label="false"> + <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" /> + </item> + <item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.png" removable="false" auto-create-binding="false" can-attach-label="true"> + <default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" /> + </item> + <item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.png" removable="false" auto-create-binding="true" can-attach-label="false"> + <default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" /> + <initial-values> + <property name="text" value="Button" /> + </initial-values> + </item> + <item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.png" removable="false" auto-create-binding="true" can-attach-label="false"> + <default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" /> + <initial-values> + <property name="text" value="RadioButton" /> + </initial-values> + </item> + <item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.png" removable="false" auto-create-binding="true" can-attach-label="false"> + <default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" /> + <initial-values> + <property name="text" value="CheckBox" /> + </initial-values> + </item> + <item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.png" removable="false" auto-create-binding="false" can-attach-label="false"> + <default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" /> + <initial-values> + <property name="text" value="Label" /> + </initial-values> + </item> + <item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.png" removable="false" auto-create-binding="true" can-attach-label="true"> + <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1"> + <preferred-size width="150" height="-1" /> + </default-constraints> + </item> + <item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.png" removable="false" auto-create-binding="true" can-attach-label="true"> + <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1"> + <preferred-size width="150" height="-1" /> + </default-constraints> + </item> + <item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.png" removable="false" auto-create-binding="true" can-attach-label="true"> + <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1"> + <preferred-size width="150" height="-1" /> + </default-constraints> + </item> + <item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.png" removable="false" auto-create-binding="true" can-attach-label="true"> + <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3"> + <preferred-size width="150" height="50" /> + </default-constraints> + </item> + <item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.png" removable="false" auto-create-binding="true" can-attach-label="true"> + <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3"> + <preferred-size width="150" height="50" /> + </default-constraints> + </item> + <item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.png" removable="false" auto-create-binding="true" can-attach-label="true"> + <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3"> + <preferred-size width="150" height="50" /> + </default-constraints> + </item> + <item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.png" removable="false" auto-create-binding="true" can-attach-label="true"> + <default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" /> + </item> + <item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.png" removable="false" auto-create-binding="true" can-attach-label="false"> + <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3"> + <preferred-size width="150" height="50" /> + </default-constraints> + </item> + <item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.png" removable="false" auto-create-binding="true" can-attach-label="false"> + <default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3"> + <preferred-size width="150" height="50" /> + </default-constraints> + </item> + <item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.png" removable="false" auto-create-binding="true" can-attach-label="false"> + <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3"> + <preferred-size width="150" height="50" /> + </default-constraints> + </item> + <item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.png" removable="false" auto-create-binding="true" can-attach-label="false"> + <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3"> + <preferred-size width="200" height="200" /> + </default-constraints> + </item> + <item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.png" removable="false" auto-create-binding="false" can-attach-label="false"> + <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3"> + <preferred-size width="200" height="200" /> + </default-constraints> + </item> + <item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.png" removable="false" auto-create-binding="true" can-attach-label="true"> + <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" /> + </item> + <item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.png" removable="false" auto-create-binding="true" can-attach-label="false"> + <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" /> + </item> + <item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.png" removable="false" auto-create-binding="false" can-attach-label="false"> + <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" /> + </item> + <item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.png" removable="false" auto-create-binding="true" can-attach-label="false"> + <default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" /> + </item> + <item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.png" removable="false" auto-create-binding="false" can-attach-label="false"> + <default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1"> + <preferred-size width="-1" height="20" /> + </default-constraints> + </item> + <item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.png" removable="false" auto-create-binding="false" can-attach-label="false"> + <default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" /> + </item> + <item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.png" removable="false" auto-create-binding="true" can-attach-label="false"> + <default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" /> + </item> + </group> + </component> + <component name="ProjectDetails"> + <option name="projectName" value="caliper" /> + </component> + <component name="ProjectFileVersion" converted="true" /> + <component name="ProjectKey"> + <option name="state" value="https://caliper.googlecode.com/svn/trunk/caliper.ipr" /> + </component> + <component name="ProjectModuleManager"> + <modules> + <module fileurl="file://$PROJECT_DIR$/core.iml" filepath="$PROJECT_DIR$/core.iml" /> + </modules> + </component> + <component name="ProjectRootManager" version="2" languageLevel="JDK_1_5" assert-keyword="true" jdk-15="true" project-jdk-name="1.5" project-jdk-type="JavaSDK"> + <output url="file://$PROJECT_DIR$/out" /> + </component> + <component name="ResourceManagerContainer"> + <option name="myResourceBundles"> + <value> + <list size="0" /> + </value> + </option> + </component> + <component name="RmicSettings"> + <option name="IS_EANABLED" value="false" /> + <option name="DEBUGGING_INFO" value="true" /> + <option name="GENERATE_NO_WARNINGS" value="false" /> + <option name="GENERATE_IIOP_STUBS" value="false" /> + <option name="ADDITIONAL_OPTIONS_STRING" value="" /> + </component> + <component name="SvnBranchConfigurationManager"> + <option name="myConfigurationMap"> + <map> + <entry key="$PROJECT_DIR$"> + <value> + <SvnBranchConfiguration> + <option name="branchUrls"> + <list> + <option value="https://caliper.googlecode.com/svn/branches" /> + <option value="https://caliper.googlecode.com/svn/tags" /> + </list> + </option> + <option name="trunkUrl" value="https://caliper.googlecode.com/svn/trunk" /> + </SvnBranchConfiguration> + </value> + </entry> + </map> + </option> + <option name="myVersion" value="124" /> + <option name="mySupportsUserInfoFilter" value="true" /> + </component> + <component name="VcsDirectoryMappings"> + <mapping directory="" vcs="svn" /> + </component> + <component name="libraryTable"> + <library name="Google Collections"> + <CLASSES> + <root url="jar://$PROJECT_DIR$/lib/google-collect-1.0-rc4.jar!/" /> + </CLASSES> + <JAVADOC /> + <SOURCES /> + </library> + <library name="JUnit"> + <CLASSES> + <root url="jar://$PROJECT_DIR$/lib/junit.jar!/" /> + </CLASSES> + <JAVADOC /> + <SOURCES /> + </library> + </component> +</project> + diff --git a/core.iml b/core.iml new file mode 100644 index 0000000..09f6e96 --- /dev/null +++ b/core.iml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<module relativePaths="false" type="JAVA_MODULE" version="4"> + <component name="NewModuleRootManager" inherit-compiler-output="true"> + <exclude-output /> + <content url="file://$MODULE_DIR$"> + <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" /> + <sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" /> + </content> + <orderEntry type="inheritedJdk" /> + <orderEntry type="sourceFolder" forTests="false" /> + <orderEntry type="library" name="Google Collections" level="project" /> + <orderEntry type="library" name="JUnit" level="project" /> + </component> +</module> + diff --git a/lib/google-collect-1.0-rc4.jar b/lib/google-collect-1.0-rc4.jar Binary files differnew file mode 100644 index 0000000..6e69f8a --- /dev/null +++ b/lib/google-collect-1.0-rc4.jar diff --git a/lib/junit.jar b/lib/junit.jar Binary files differnew file mode 100644 index 0000000..674d71e --- /dev/null +++ b/lib/junit.jar diff --git a/src/com/google/caliper/Benchmark.java b/src/com/google/caliper/Benchmark.java new file mode 100644 index 0000000..bd60b45 --- /dev/null +++ b/src/com/google/caliper/Benchmark.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2009 Google Inc. + * + * Licensed 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. + */ + +package com.google.caliper; + +public abstract class Benchmark { + + /** + * Runs the benchmark through {@code trials} iterations. + * + * @return any object or null. Benchmark implementors may keep an accumulating + * value to prevent the runtime from optimizing away the code under test. + * Such an accumulator value can be returned here. + */ + public abstract Object run(int trials) throws Exception; + + @Override public String toString() { + return getClass().getSimpleName(); + } +} diff --git a/src/com/google/caliper/BenchmarkSuite.java b/src/com/google/caliper/BenchmarkSuite.java new file mode 100644 index 0000000..40106a0 --- /dev/null +++ b/src/com/google/caliper/BenchmarkSuite.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2009 Google Inc. + * + * Licensed 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. + */ + +package com.google.caliper; + +import java.util.Map; +import java.util.Set; + +/** + * A collection of benchmarks that share a set of configuration parameters. + */ +public abstract class BenchmarkSuite { + + protected abstract Set<Class<? extends Benchmark>> benchmarkClasses(); + + protected abstract Set<String> parameterNames(); + + protected abstract Set<String> parameterValues(String parameterName); + + protected abstract Benchmark createBenchmark( + Class<? extends Benchmark> benchmark, Map<String, String> parameterValues); +}
\ No newline at end of file diff --git a/src/com/google/caliper/Caliper.java b/src/com/google/caliper/Caliper.java new file mode 100644 index 0000000..855101e --- /dev/null +++ b/src/com/google/caliper/Caliper.java @@ -0,0 +1,65 @@ +/** + * Copyright (C) 2009 Google Inc. + * + * Licensed 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. + */ + +package com.google.caliper; + +import static com.google.common.base.Preconditions.checkArgument; + +/** + * Measure's the benchmark's per-trial execution time. + */ +class Caliper { + + private final long warmupNanos; + private final long runNanos; + + public Caliper(long warmupMillis, long runMillis) { + checkArgument(warmupMillis > 50); + checkArgument(runMillis > 50); + + this.warmupNanos = warmupMillis * 1000000; + this.runNanos = runMillis * 1000000; + } + + public double warmUp(Benchmark benchmark) throws Exception { + long startNanos = System.nanoTime(); + long endNanos = startNanos + warmupNanos; + int trials = 0; + long currentNanos; + while ((currentNanos = System.nanoTime()) < endNanos) { + benchmark.run(1); + trials++; + } + double nanosPerExecution = (currentNanos - startNanos) / trials; + if (nanosPerExecution > 1000000000 || nanosPerExecution < 2) { + throw new ConfigurationException("Runtime out of range"); + } + return nanosPerExecution; + } + + /** + * In the run proper, we predict how extrapolate based on warmup how many + * runs we're going to need, and run them all in a single batch. + */ + public double run(Benchmark test, double estimatedNanosPerTrial) throws Exception { + int trials = (int) (runNanos / estimatedNanosPerTrial); + long startNanos = System.nanoTime(); + test.run(trials); + long endNanos = System.nanoTime(); + estimatedNanosPerTrial = (endNanos - startNanos) / trials; + return estimatedNanosPerTrial; + } +}
\ No newline at end of file diff --git a/src/com/google/caliper/ConfigurationException.java b/src/com/google/caliper/ConfigurationException.java new file mode 100644 index 0000000..5ad7bde --- /dev/null +++ b/src/com/google/caliper/ConfigurationException.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2009 Google Inc. + * + * Licensed 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. + */ + +package com.google.caliper; + +/** + * Thrown upon occurrence of a configuration error. + */ +public final class ConfigurationException extends RuntimeException { + + public ConfigurationException(String s) { + super(s); + } + + public ConfigurationException(Throwable cause) { + super(cause); + } +} diff --git a/src/com/google/caliper/ConsoleReport.java b/src/com/google/caliper/ConsoleReport.java new file mode 100644 index 0000000..537d56a --- /dev/null +++ b/src/com/google/caliper/ConsoleReport.java @@ -0,0 +1,254 @@ +/** + * Copyright (C) 2009 Google Inc. + * + * Licensed 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. + */ + +package com.google.caliper; + +import com.google.common.collect.*; + +import java.util.*; + +/** + * Prints a report containing the tested values and the corresponding + * measurements. Measurements are grouped by variable using indentation. + * Alongside numeric values, quick-glance ascii art bar charts are printed. + * Sample output: + * <pre> + * benchmark d ns logarithmic runtime + * ConcatenationBenchmark 3.141592653589793 4397 |||||||||||||||||||||||| + * ConcatenationBenchmark -0.0 223 ||||||||||||||| + * FormatterBenchmark 3.141592653589793 33999 |||||||||||||||||||||||||||||| + * FormatterBenchmark -0.0 26399 ||||||||||||||||||||||||||||| + * </pre> + */ +final class ConsoleReport { + + private static final int bargraphWidth = 30; + private static final String benchmarkKey = "benchmark"; + private static final String vmKey = "vm"; + + private final List<Parameter> parameters; + private final Result result; + private final List<Run> runs; + + private final double logMaxValue; + private final int decimalDigits; + private final double divideBy; + private final String units; + private final int measurementColumnLength; + + public ConsoleReport(Result result) { + this.result = result; + + double minValue = Double.POSITIVE_INFINITY; + double maxValue = 0; + + Multimap<String, String> nameToValues = LinkedHashMultimap.create(); + List<Parameter> parametersBuilder = new ArrayList<Parameter>(); + for (Map.Entry<Run, Double> entry : result.getMeasurements().entrySet()) { + Run run = entry.getKey(); + double d = entry.getValue(); + + minValue = minValue < d ? minValue : d; + maxValue = maxValue > d ? maxValue : d; + + for (Map.Entry<String, String> parameter : run.getParameters().entrySet()) { + String name = parameter.getKey(); + nameToValues.put(name, parameter.getValue()); + } + + nameToValues.put(benchmarkKey, run.getBenchmarkClass().getSimpleName()); + nameToValues.put(vmKey, run.getVm()); + } + + for (Map.Entry<String, Collection<String>> entry : nameToValues.asMap().entrySet()) { + Parameter parameter = new Parameter(entry.getKey(), entry.getValue()); + parametersBuilder.add(parameter); + } + + /* + * Figure out how much influence each parameter has on the measured value. + * We sum the measurements taken with each value of each parameter. For + * parameters that have influence on the measurement, the sums will differ + * by value. If the parameter has little influence, the sums will be similar + * to one another and close to the overall average. We take the standard + * deviation across each parameters collection of sums. Higher standard + * deviation implies higher influence on the measured result. + */ + double sumOfAllMeasurements = 0; + for (double measurement : result.getMeasurements().values()) { + sumOfAllMeasurements += measurement; + } + for (Parameter parameter : parametersBuilder) { + int numValues = parameter.values.size(); + double[] sumForValue = new double[numValues]; + for (Map.Entry<Run, Double> entry : result.getMeasurements().entrySet()) { + Run run = entry.getKey(); + sumForValue[parameter.index(run)] += entry.getValue(); + } + double mean = sumOfAllMeasurements / sumForValue.length; + double stdDeviationSquared = 0; + for (double value : sumForValue) { + double distance = value - mean; + stdDeviationSquared += distance * distance; + } + parameter.stdDeviation = Math.sqrt(stdDeviationSquared / numValues); + } + + this.parameters = new StandardDeviationOrdering().reverse().sortedCopy(parametersBuilder); + this.runs = new ByParametersOrdering().sortedCopy(result.getMeasurements().keySet()); + this.logMaxValue = Math.log(maxValue); + + int numDigitsInMin = (int) Math.ceil(Math.log10(minValue)); + if (numDigitsInMin > 9) { + divideBy = 1000000000; + decimalDigits = Math.max(0, 9 + 3 - numDigitsInMin); + units = "s"; + } else if (numDigitsInMin > 6) { + divideBy = 1000000; + decimalDigits = Math.max(0, 6 + 3 - numDigitsInMin); + units = "ms"; + } else if (numDigitsInMin > 3) { + divideBy = 1000; + decimalDigits = Math.max(0, 3 + 3 - numDigitsInMin); + units = "us"; + } else { + divideBy = 1; + decimalDigits = 0; + units = "ns"; + } + measurementColumnLength = (int) Math.ceil(Math.log10(maxValue / divideBy)) + decimalDigits + 1; + } + + /** + * A parameter plus all of its values. + */ + static class Parameter { + final String name; + final ImmutableList<String> values; + final int maxLength; + double stdDeviation; + + public Parameter(String name, Collection<String> values) { + this.name = name; + this.values = ImmutableList.copyOf(values); + + int maxLength = name.length(); + for (String value : values) { + maxLength = Math.max(maxLength, value.length()); + } + this.maxLength = maxLength; + } + + String get(Run run) { + if (benchmarkKey.equals(name)) { + return run.getBenchmarkClass().getSimpleName(); + } else if (vmKey.equals(name)) { + return run.getVm(); + } else { + return run.getParameters().get(name); + } + } + + int index(Run run) { + return values.indexOf(get(run)); + } + + boolean isInteresting() { + return values.size() > 1; + } + } + + /** + * Orders the different parameters by their standard deviation. This results + * in an appropriate grouping of output values. + */ + static class StandardDeviationOrdering extends Ordering<Parameter> { + public int compare(Parameter a, Parameter b) { + return Double.compare(a.stdDeviation, b.stdDeviation); + } + } + + /** + * Orders runs by the parameters. + */ + class ByParametersOrdering extends Ordering<Run> { + public int compare(Run a, Run b) { + for (Parameter parameter : parameters) { + int aValue = parameter.values.indexOf(parameter.get(a)); + int bValue = parameter.values.indexOf(parameter.get(b)); + int diff = aValue - bValue; + if (diff != 0) { + return diff; + } + } + return 0; + } + } + + void displayResults() { + printValues(); + System.out.println(); + printUninterestingParameters(); + } + + /** + * Prints a table of values. + */ + private void printValues() { + for (Parameter parameter : parameters) { + if (parameter.isInteresting()) { + System.out.printf("%" + parameter.maxLength + "s ", parameter.name); + } + } + System.out.printf("%" + measurementColumnLength + "s logarithmic runtime%n", units); + + String numbersFormat = "%" + measurementColumnLength + "." + decimalDigits + "f %s%n"; + for (Run run : runs) { + for (Parameter parameter : parameters) { + if (parameter.isInteresting()) { + System.out.printf("%" + parameter.maxLength + "s ", parameter.get(run)); + } + } + double measurement = result.getMeasurements().get(run); + System.out.printf(numbersFormat, measurement / divideBy, bargraph(measurement)); + } + } + + /** + * Prints parameters with only one unique value. + */ + private void printUninterestingParameters() { + for (Parameter parameter : parameters) { + if (!parameter.isInteresting()) { + System.out.println(parameter.name + ": " + Iterables.getOnlyElement(parameter.values)); + } + } + } + + /** + * Returns a string containing a bar of proportional width to the specified + * value. + */ + private String bargraph(double value) { + double logValue = Math.log(value); + int numChars = (int) ((logValue / logMaxValue) * bargraphWidth); + StringBuilder result = new StringBuilder(numChars); + for (int i = 0; i < numChars; i++) { + result.append("|"); + } + return result.toString(); + } +} diff --git a/src/com/google/caliper/DefaultBenchmarkSuite.java b/src/com/google/caliper/DefaultBenchmarkSuite.java new file mode 100644 index 0000000..0e197f6 --- /dev/null +++ b/src/com/google/caliper/DefaultBenchmarkSuite.java @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2009 Google Inc. + * + * Licensed 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. + */ + +package com.google.caliper; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Type; +import java.util.*; + +/** + * A convenience class for implementing benchmark suites in plain code. + * Implementing classes must have a no-arguments constructor. + * + * <h3>Benchmarks</h3> + * The benchmarks of a suite are defined by inner classes within the suite. + * These inner classes implement the {@link Benchmark} interface. They may be + * static. They are not permitted to take parameters in their constructors. + * + * <h3>Parameters</h3> + * Implementing classes may be configured using parameters. Each parameter is a + * property of a benchmark, plus the default values that fulfill it. Parameters + * are specified by annotated fields: + * <pre> + * {@literal @}Param int length; + * </pre> + * The available values for a parameter are specified by another field with the + * same name plus the {@code Values} suffix. The type of this field must be an + * {@code Iterable} of the parameter's type. + * <pre> + * Iterable<Integer> lengthValues = Arrays.asList(10, 100, 1000, 10000); + * </pre> + * Alternatively, the available values may be specified with a method. The + * method's name follows the same naming convention and returns the same type. + * Such methods may not accept parameters of their own. + * <pre> + * Iterable<Integer> lengthValues() { + * return Arrays.asList(10, 100, 1000, 10000); + * } + * </pre> + */ +public abstract class DefaultBenchmarkSuite extends BenchmarkSuite { + + private final Map<String, Parameter<?>> parameters; + private final Map<Class<? extends Benchmark>, BenchmarkFactory> benchmarkFactories; + + protected void setUp() throws Exception {} + + protected DefaultBenchmarkSuite() { + parameters = Parameter.forClass(getClass()); + benchmarkFactories = createBenchmarkFactories(); + + if (benchmarkFactories.isEmpty()) { + throw new ConfigurationException( + "No benchmarks defined in " + getClass().getName()); + } + } + + protected Set<Class<? extends Benchmark>> benchmarkClasses() { + return benchmarkFactories.keySet(); + } + + protected Set<String> parameterNames() { + return parameters.keySet(); + } + + protected Set<String> parameterValues(String parameterName) { + try { + TypeConverter typeConverter = new TypeConverter(); + Parameter<?> parameter = parameters.get(parameterName); + if (parameter == null) { + throw new IllegalArgumentException(); + } + Collection<?> values = parameter.values(); + Type type = parameter.getType(); + Set<String> result = new LinkedHashSet<String>(); + for (Object value : values) { + result.add(typeConverter.toString(value, type)); + } + return result; + } catch (Exception e) { + throw new ExecutionException(e); + } + } + + protected Benchmark createBenchmark(Class<? extends Benchmark> benchmarkClass, + Map<String, String> parameterValues) { + TypeConverter typeConverter = new TypeConverter(); + + BenchmarkFactory benchmarkFactory = benchmarkFactories.get(benchmarkClass); + if (benchmarkFactory == null) { + throw new IllegalArgumentException(); + } + + if (!parameters.keySet().equals(parameterValues.keySet())) { + throw new IllegalArgumentException("Invalid parameters specified. Expected " + + parameters.keySet() + " but was " + parameterValues.keySet()); + } + + try { + DefaultBenchmarkSuite copyOfSelf = getClass().newInstance(); + Benchmark benchmark = benchmarkFactory.create(copyOfSelf); + for (Map.Entry<String, String> entry : parameterValues.entrySet()) { + Parameter parameter = parameters.get(entry.getKey()); + Object value = typeConverter.fromString(entry.getValue(), parameter.getType()); + parameter.set(copyOfSelf, value); + } + + copyOfSelf.setUp(); + return benchmark; + + } catch (Exception e) { + throw new ExecutionException(e); + } + } + + /** + * Returns a spec for each benchmark defined in the specified class. The + * returned specs have no parameter values; those must be added separately. + */ + private Map<Class<? extends Benchmark>, BenchmarkFactory> createBenchmarkFactories() { + Map<Class<? extends Benchmark>, BenchmarkFactory> result + = new LinkedHashMap<Class<? extends Benchmark>, BenchmarkFactory>(); + for (Class<?> c : getClass().getDeclaredClasses()) { + if (!Benchmark.class.isAssignableFrom(c) || c.isInterface()) { + continue; + } + + @SuppressWarnings("unchecked") // guarded by isAssignableFrom + Class<? extends Benchmark> benchmarkClass = (Class<? extends Benchmark>) c; + + try { + final Constructor<? extends Benchmark> constructor + = benchmarkClass.getDeclaredConstructor(); + constructor.setAccessible(true); + result.put(benchmarkClass, new BenchmarkFactory() { + public Benchmark create(BenchmarkSuite suite) throws Exception { + return constructor.newInstance(); + } + }); + continue; + } catch (NoSuchMethodException ignored) { + } + + try { + final Constructor<? extends Benchmark> constructor + = benchmarkClass.getDeclaredConstructor(getClass()); + constructor.setAccessible(true); + result.put(benchmarkClass, new BenchmarkFactory() { + public Benchmark create(BenchmarkSuite suite) throws Exception { + return constructor.newInstance(suite); + } + }); + continue; + } catch (NoSuchMethodException ignored) { + } + + throw new ConfigurationException("No usable constructor for " + + benchmarkClass.getName() + "\n Benchmarks may only use no arguments constructors."); + } + + return result; + } + + interface BenchmarkFactory { + Benchmark create(BenchmarkSuite suite) throws Exception; + } +}
\ No newline at end of file diff --git a/src/com/google/caliper/ExecutionException.java b/src/com/google/caliper/ExecutionException.java new file mode 100644 index 0000000..7d8a592 --- /dev/null +++ b/src/com/google/caliper/ExecutionException.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2009 Google Inc. + * + * Licensed 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. + */ + +package com.google.caliper; + +/** + * Thrown upon occurrence of a runtime failure during test construction or + * execution. + */ +public final class ExecutionException extends RuntimeException { + + public ExecutionException(Throwable throwable) { + super(throwable); + } +} diff --git a/src/com/google/caliper/Param.java b/src/com/google/caliper/Param.java new file mode 100644 index 0000000..0a9b203 --- /dev/null +++ b/src/com/google/caliper/Param.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2009 Google Inc. + * + * Licensed 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. + */ + +package com.google.caliper; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotates the field accepting a parameter in a {@link DefaultBenchmarkSuite}. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface Param {} diff --git a/src/com/google/caliper/Parameter.java b/src/com/google/caliper/Parameter.java new file mode 100644 index 0000000..a5ab6c8 --- /dev/null +++ b/src/com/google/caliper/Parameter.java @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2009 Google Inc. + * + * Licensed 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. + */ + +package com.google.caliper; + +import java.lang.reflect.*; +import java.util.*; + +/** + * A parameter in a {@link DefaultBenchmarkSuite}. + */ +abstract class Parameter<T> { + + private final Field field; + + private Parameter(Field field) { + this.field = field; + } + + /** + * Returns all properties for the given class. + */ + public static Map<String, Parameter<?>> forClass(Class<? extends BenchmarkSuite> suiteClass) { + Map<String, Parameter<?>> parameters = new TreeMap<String, Parameter<?>>(); + for (final Field field : suiteClass.getDeclaredFields()) { + if (field.isAnnotationPresent(Param.class)) { + field.setAccessible(true); + Parameter parameter = Parameter.forField(suiteClass, field); + parameters.put(parameter.getName(), parameter); + } + } + return parameters; + } + + public static Parameter forField( + Class<? extends BenchmarkSuite> suiteClass, final Field field) { + Parameter result = null; + Type returnType = null; + Member member = null; + + try { + final Method valuesMethod = suiteClass.getDeclaredMethod(field.getName() + "Values"); + valuesMethod.setAccessible(true); + member = valuesMethod; + returnType = valuesMethod.getGenericReturnType(); + result = new Parameter<Object>(field) { + @SuppressWarnings("unchecked") // guarded below + public Collection<Object> values() throws Exception { + return (Collection<Object>) valuesMethod.invoke(null); + } + }; + } catch (NoSuchMethodException ignored) { + } + + try { + final Field valuesField = suiteClass.getDeclaredField(field.getName() + "Values"); + valuesField.setAccessible(true); + member = valuesField; + if (result != null) { + throw new ConfigurationException("Two values members defined for " + field); + } + returnType = valuesField.getGenericType(); + result = new Parameter<Object>(field) { + @SuppressWarnings("unchecked") // guarded below + public Collection<Object> values() throws Exception { + return (Collection<Object>) valuesField.get(null); + } + }; + } catch (NoSuchFieldException ignored) { + } + + if (result == null) { + throw new ConfigurationException("No values member defined for " + field); + } + + if (!Modifier.isStatic(member.getModifiers())) { + throw new ConfigurationException("Values member must be static " + member); + } + + // validate return type + boolean valid = false; + if (returnType instanceof ParameterizedType) { + ParameterizedType type = (ParameterizedType) returnType; + if (type.getRawType() == Collection.class) { + valid = true; + } + } + + if (!valid) { + throw new ConfigurationException("Invalid return type " + returnType + + " for values member " + member + "; must be Collection"); + } + + return result; + } + + /** + * Sets the value of this property to the specified value for the given suite. + */ + public void set(BenchmarkSuite suite, Object value) throws Exception { + field.set(suite, value); + } + + /** + * Returns the available values of the property as specified by the suite. + */ + public abstract Collection<T> values() throws Exception; + + /** + * Returns the parameter's type, such as double.class. + */ + public Type getType() { + return field.getGenericType(); + } + + /** + * Returns the field's name. + */ + public String getName() { + return field.getName(); + } +}
\ No newline at end of file diff --git a/src/com/google/caliper/Result.java b/src/com/google/caliper/Result.java new file mode 100644 index 0000000..888a9f4 --- /dev/null +++ b/src/com/google/caliper/Result.java @@ -0,0 +1,37 @@ +/** + * Copyright (C) 2009 Google Inc. + * + * Licensed 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. + */ + +package com.google.caliper; + +import com.google.common.collect.ImmutableMap; + +import java.util.Map; + +/** + * The complete result of a benchmark suite run. + */ +final class Result { + + private final ImmutableMap<Run, Double> measurements; + + public Result(Map<Run, Double> measurements) { + this.measurements = ImmutableMap.copyOf(measurements); + } + + public ImmutableMap<Run, Double> getMeasurements() { + return measurements; + } +} diff --git a/src/com/google/caliper/Run.java b/src/com/google/caliper/Run.java new file mode 100644 index 0000000..5ab8856 --- /dev/null +++ b/src/com/google/caliper/Run.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2009 Google Inc. + * + * Licensed 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. + */ + +package com.google.caliper; + +import com.google.common.collect.ImmutableMap; + +import java.util.Map; + +/** + * A configured benchmark. + */ +final class Run { + + private final ImmutableMap<String, String> parameters; + private final Class<? extends Benchmark> benchmarkClass; + private final String vm; + + public Run(Map<String, String> parameters, + Class<? extends Benchmark> benchmarkClass, + String vm) { + this.benchmarkClass = benchmarkClass; + this.parameters = ImmutableMap.copyOf(parameters); + this.vm = vm; + } + + public ImmutableMap<String, String> getParameters() { + return parameters; + } + + public Class<? extends Benchmark> getBenchmarkClass() { + return benchmarkClass; + } + + public String getVm() { + return vm; + } + + @Override public String toString() { + return benchmarkClass.getSimpleName() + " " + parameters; + } +} diff --git a/src/com/google/caliper/Runner.java b/src/com/google/caliper/Runner.java new file mode 100644 index 0000000..c575af1 --- /dev/null +++ b/src/com/google/caliper/Runner.java @@ -0,0 +1,425 @@ +/* + * Copyright (C) 2009 Google Inc. + * + * Licensed 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. + */ + +package com.google.caliper; + +import com.google.common.collect.LinkedHashMultimap; +import com.google.common.collect.Multimap; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.*; + +/** + * Creates, executes and reports benchmark runs. + */ +public final class Runner { + + private String suiteClassName; + private BenchmarkSuite suite; + + /** Effective parameters to run in the benchmark. */ + private Multimap<String, String> parameters = LinkedHashMultimap.create(); + + /** JVMs to run in the benchmark */ + private Set<String> userVms = new LinkedHashSet<String>(); + + /** + * Parameter values specified by the user on the command line. Parameters with + * no value in this multimap will get their values from the benchmark suite. + */ + private Multimap<String, String> userParameters = LinkedHashMultimap.create(); + + /** + * Benchmark class specified by the user on the command line; or null to run + * the complete set of benchmark classes. + */ + private Class<? extends Benchmark> userBenchmarkClass; + + /** + * True if each benchmark should run in process. + */ + private boolean inProcess; + + private long warmupMillis = 5000; + private long runMillis = 5000; + + /** + * Sets the named parameter to the specified value. This value will replace + * the benchmark suite's default values for the parameter. Multiple calls to + * this method will cause benchmarks for each value to be run. + */ + void setParameter(String name, String value) { + userParameters.put(name, value); + } + + private void prepareSuite() { + try { + @SuppressWarnings("unchecked") // guarded by the if statement that follows + Class<? extends BenchmarkSuite> suiteClass + = (Class<? extends BenchmarkSuite>) Class.forName(suiteClassName); + if (!BenchmarkSuite.class.isAssignableFrom(suiteClass)) { + throw new ConfigurationException(suiteClass + " is not a benchmark suite."); + } + + Constructor<? extends BenchmarkSuite> constructor = suiteClass.getDeclaredConstructor(); + suite = constructor.newInstance(); + } catch (InvocationTargetException e) { + throw new ExecutionException(e.getCause()); + } catch (Exception e) { + throw new ConfigurationException(e); + } + } + + private void prepareParameters() { + for (String key : suite.parameterNames()) { + // first check if the user has specified values + Collection<String> userValues = userParameters.get(key); + if (!userValues.isEmpty()) { + parameters.putAll(key, userValues); + // TODO: type convert 'em to validate? + + } else { // otherwise use the default values from the suite + Set<String> values = suite.parameterValues(key); + if (values.isEmpty()) { + throw new ConfigurationException(key + " has no values"); + } + parameters.putAll(key, values); + } + } + } + + /** + * Returns a complete set of runs with every combination of values and + * benchmark classes. + */ + private List<Run> createRuns() throws Exception { + List<RunBuilder> builders = new ArrayList<RunBuilder>(); + + // create runs for each benchmark class + Set<Class<? extends Benchmark>> benchmarkClasses = (userBenchmarkClass != null) + ? ImmutableSet.<Class<? extends Benchmark>>of(userBenchmarkClass) + : suite.benchmarkClasses(); + for (Class<? extends Benchmark> benchmarkClass : benchmarkClasses) { + RunBuilder builder = new RunBuilder(); + builder.benchmarkClass = benchmarkClass; + builders.add(builder); + } + + // multiply the runs by the number of VMs + Set<String> vms = userVms.isEmpty() + ? ImmutableSet.of("java") + : userVms; + Iterator<String> vmIterator = vms.iterator(); + String firstVm = vmIterator.next(); + for (RunBuilder builder : builders) { + builder.vm = firstVm; + } + int length = builders.size(); + while (vmIterator.hasNext()) { + String alternateVm = vmIterator.next(); + for (int s = 0; s < length; s++) { + RunBuilder copy = builders.get(s).copy(); + copy.vm = alternateVm; + builders.add(copy); + } + } + + for (Map.Entry<String, Collection<String>> parameter : parameters.asMap().entrySet()) { + Iterator<String> values = parameter.getValue().iterator(); + if (!values.hasNext()) { + throw new ConfigurationException("Not enough values for " + parameter); + } + + String key = parameter.getKey(); + + String firstValue = values.next(); + for (RunBuilder builder : builders) { + builder.parameters.put(key, firstValue); + } + + // multiply the size of the specs by the number of alternate values + length = builders.size(); + while (values.hasNext()) { + String alternate = values.next(); + for (int s = 0; s < length; s++) { + RunBuilder copy = builders.get(s).copy(); + copy.parameters.put(key, alternate); + builders.add(copy); + } + } + } + + List<Run> result = new ArrayList<Run>(); + for (RunBuilder builder : builders) { + result.add(builder.build()); + } + + return result; + } + + static class RunBuilder { + Map<String, String> parameters = new LinkedHashMap<String, String>(); + Class<? extends Benchmark> benchmarkClass; + String vm; + + RunBuilder copy() { + RunBuilder result = new RunBuilder(); + result.parameters.putAll(parameters); + result.benchmarkClass = benchmarkClass; + result.vm = vm; + return result; + } + + public Run build() { + return new Run(parameters, benchmarkClass, vm); + } + } + + private double executeForked(Run run) { + ProcessBuilder builder = new ProcessBuilder(); + List<String> command = builder.command(); + command.addAll(Arrays.asList(run.getVm().split("\\s+"))); + command.add("-cp"); + command.add(System.getProperty("java.class.path")); + command.add(Runner.class.getName()); + command.add("--warmupMillis"); + command.add(String.valueOf(warmupMillis)); + command.add("--runMillis"); + command.add(String.valueOf(runMillis)); + command.add("--inProcess"); + command.add("--benchmark"); + command.add(run.getBenchmarkClass().getName()); + for (Map.Entry<String, String> entry : run.getParameters().entrySet()) { + command.add("-D" + entry.getKey() + "=" + entry.getValue()); + } + command.add(suiteClassName); + + BufferedReader reader = null; + try { + builder.redirectErrorStream(true); + builder.directory(new File(System.getProperty("user.dir"))); + Process process = builder.start(); + + reader = new BufferedReader(new InputStreamReader(process.getInputStream())); + String firstLine = reader.readLine(); + Double nanosPerTrial = null; + try { + nanosPerTrial = Double.valueOf(firstLine); + } catch (NumberFormatException e) { + } + + String anotherLine = reader.readLine(); + if (nanosPerTrial != null && anotherLine == null) { + return nanosPerTrial; + } + + String message = "Failed to execute " + command; + System.err.println(message); + System.err.println(" " + firstLine); + do { + System.err.println(" " + anotherLine); + } while ((anotherLine = reader.readLine()) != null); + throw new ConfigurationException(message); + } catch (IOException e) { + throw new ConfigurationException(e); + } finally { + if (reader != null) { + try { + reader.close(); + } catch (IOException ignored) { + } + } + } + } + + private Result runOutOfProcess() { + ImmutableMap.Builder<Run, Double> resultsBuilder = ImmutableMap.builder(); + + try { + List<Run> runs = createRuns(); + int i = 0; + for (Run run : runs) { + beforeRun(i++, runs.size(), run); + double nanosPerTrial = executeForked(run); + afterRun(nanosPerTrial); + resultsBuilder.put(run, nanosPerTrial); + } + return new Result(resultsBuilder.build()); + } catch (Exception e) { + throw new ExecutionException(e); + } + } + + private void beforeRun(int index, int total, Run run) { + double percentDone = (double) index / total; + int runStringLength = 63; // so the total line length is 80 + String runString = String.valueOf(run); + if (runString.length() > runStringLength) { + runString = runString.substring(0, runStringLength); + } + System.out.printf("%2.0f%% %-" + runStringLength + "s", + percentDone * 100, runString); + } + + private void afterRun(double nanosPerTrial) { + System.out.printf(" %10.0fns%n", nanosPerTrial); + } + + private void runInProcess() { + try { + Caliper caliper = new Caliper(warmupMillis, runMillis); + + for (Run run : createRuns()) { + double result; + Benchmark benchmark = suite.createBenchmark( + run.getBenchmarkClass(), run.getParameters()); + double warmupNanosPerTrial = caliper.warmUp(benchmark); + result = caliper.run(benchmark, warmupNanosPerTrial); + double nanosPerTrial = result; + System.out.println(nanosPerTrial); + } + } catch (Exception e) { + throw new ExecutionException(e); + } + } + + private boolean parseArgs(String[] args) { + for (int i = 0; i < args.length; i++) { + if ("--help".equals(args[i])) { + return false; + + } else if ("--benchmark".equals(args[i])) { + try { + @SuppressWarnings("unchecked") // guarded immediately afterwards! + Class<? extends Benchmark> c = (Class<? extends Benchmark>) Class.forName(args[++i]); + if (!Benchmark.class.isAssignableFrom(c)) { + System.out.println("Not a benchmark class: " + c); + return false; + } + userBenchmarkClass = c; + } catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } + + } else if ("--inProcess".equals(args[i])) { + inProcess = true; + + } else if (args[i].startsWith("-D")) { + int equalsSign = args[i].indexOf('='); + if (equalsSign == -1) { + System.out.println("Malformed parameter " + args[i]); + return false; + } + String name = args[i].substring(2, equalsSign); + String value = args[i].substring(equalsSign + 1); + setParameter(name, value); + + } else if ("--warmupMillis".equals(args[i])) { + warmupMillis = Long.parseLong(args[++i]); + + } else if ("--runMillis".equals(args[i])) { + runMillis = Long.parseLong(args[++i]); + + } else if ("--vm".equals(args[i])) { + userVms.add(args[++i]); + + } else if (args[i].startsWith("-")) { + System.out.println("Unrecognized option: " + args[i]); + return false; + + } else { + if (suiteClassName != null) { + System.out.println("Too many benchmark classes!"); + return false; + } + + suiteClassName = args[i]; + + } + } + + if (inProcess && !userVms.isEmpty()) { + System.out.println("Cannot customize VM when running in process"); + return false; + } + + if (suiteClassName == null) { + System.out.println("No benchmark class provided."); + return false; + } + + return true; + } + + private void printUsage() { + System.out.println("Usage: Runner [OPTIONS...] <benchmark>"); + System.out.println(); + System.out.println(" <benchmark>: a benchmark class or suite"); + System.out.println(); + System.out.println("OPTIONS"); + System.out.println(); + System.out.println(" --D<param>=<value>: fix a benchmark parameter to a given value."); + System.out.println(" When multiple values for the same parameter are given (via"); + System.out.println(" multiple --Dx=y args), all supplied values are used."); + System.out.println(); + System.out.println(" --benchmark <class>: fix a benchmark executable to the named class"); + System.out.println(); + System.out.println(" --inProcess: run the benchmark in the same JVM rather than spawning"); + System.out.println(" another with the same classpath. By default each benchmark is"); + System.out.println(" run in a separate VM"); + System.out.println(); + System.out.println(" --warmupMillis <millis>: duration to warmup each benchmark"); + System.out.println(); + System.out.println(" --runMillis <millis>: duration to execute each benchmark"); + System.out.println(); + System.out.println(" --vm <vm>: executable to test benchmark on"); + + // adding new options? don't forget to update executeForked() + } + + public static void main(String... args) { + Runner runner = new Runner(); + if (!runner.parseArgs(args)) { + runner.printUsage(); + return; + } + + runner.prepareSuite(); + runner.prepareParameters(); + if (runner.inProcess) { + runner.runInProcess(); + return; + } + + Result result = runner.runOutOfProcess(); + System.out.println(); + new ConsoleReport(result).displayResults(); + } + + public static void main(Class<? extends BenchmarkSuite> suite, String... args) { + String[] argsWithSuiteName = new String[args.length + 1]; + System.arraycopy(args, 0, argsWithSuiteName, 0, args.length); + argsWithSuiteName[args.length] = suite.getName(); + main(argsWithSuiteName); + } +} diff --git a/src/com/google/caliper/TypeConverter.java b/src/com/google/caliper/TypeConverter.java new file mode 100644 index 0000000..73300ec --- /dev/null +++ b/src/com/google/caliper/TypeConverter.java @@ -0,0 +1,57 @@ +/** + * Copyright (C) 2009 Google Inc. + * + * Licensed 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. + */ + +package com.google.caliper; + +import java.lang.reflect.Type; + +/** + * Convert objects to and from Strings. + */ +class TypeConverter { + + // the enum to strings conversion is manually checked + @SuppressWarnings("unchecked") + public Object fromString(String value, Type type) { + if (type instanceof Class) { + Class<?> c = (Class<?>) type; + if (c.isEnum()) { + return Enum.valueOf((Class) c, value); + } else if (type == Double.class || type == double.class) { + return Double.valueOf(value); + } else if (type == Integer.class || type == int.class) { + return Integer.valueOf(value); + } + } + throw new UnsupportedOperationException( + "Cannot convert " + value + " of type " + type); + } + + public String toString(Object value, Type type) { + if (type instanceof Class) { + Class<?> c = (Class<?>) type; + if (c.isEnum()) { + return value.toString(); + } else if (type == Double.class || type == double.class) { + return value.toString(); + } else if (type == Integer.class || type == int.class) { + return value.toString(); + } + } + throw new UnsupportedOperationException( + "Cannot convert " + value + " of type " + type); + } +} diff --git a/test/com/google/caliper/AllTests.java b/test/com/google/caliper/AllTests.java new file mode 100644 index 0000000..55f620a --- /dev/null +++ b/test/com/google/caliper/AllTests.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2009 Google Inc. + * + * Licensed 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. + */ + +package com.google.caliper; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public final class AllTests { + public static Test suite() { + TestSuite suite = new TestSuite(); + suite.addTestSuite(DefaultBenchmarkSuiteTest.class); + return suite; + } +} diff --git a/test/com/google/caliper/DefaultBenchmarkSuiteTest.java b/test/com/google/caliper/DefaultBenchmarkSuiteTest.java new file mode 100644 index 0000000..232cb4c --- /dev/null +++ b/test/com/google/caliper/DefaultBenchmarkSuiteTest.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2009 Google Inc. + * + * Licensed 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. + */ + +package com.google.caliper; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; + +import junit.framework.TestCase; + +import java.util.Arrays; +import java.util.Collection; + +public class DefaultBenchmarkSuiteTest extends TestCase { + + public void testIntrospection() { + SampleBenchmarkSuite suite = new SampleBenchmarkSuite(); + assertEquals(ImmutableSet.of("a", "b"), suite.parameterNames()); + assertEquals(ImmutableSet.of("1", "2", "3"), suite.parameterValues("a")); + assertEquals(ImmutableSet.of("4"), suite.parameterValues("b")); + assertEquals(ImmutableSet.of( + SampleBenchmarkSuite.MultiplyBenchmark.class, + SampleBenchmarkSuite.DivideBenchmark.class), + suite.benchmarkClasses()); + + } + + public void testCreateBenchmark() { + SampleBenchmarkSuite originalSuite = new SampleBenchmarkSuite(); + Benchmark benchmark = originalSuite.createBenchmark( + SampleBenchmarkSuite.MultiplyBenchmark.class, + ImmutableMap.of("a", "2", "b", "4")); + + SampleBenchmarkSuite.MultiplyBenchmark multiplyBenchmark + = (SampleBenchmarkSuite.MultiplyBenchmark) benchmark; + + SampleBenchmarkSuite multiplySuite = multiplyBenchmark.suite(); + assertNotSame(originalSuite, multiplySuite); + assertEquals(2, multiplySuite.a); + assertEquals(4, multiplySuite.b); + } + + static class SampleBenchmarkSuite extends DefaultBenchmarkSuite { + @Param int a; + + private static Collection<Integer> aValues = Arrays.asList(1, 2, 3); + + @Param int b; + + private static Collection<Integer> bValues() { + return Arrays.asList(4); + } + + class MultiplyBenchmark extends Benchmark { + @Override public Object run(int trials) throws Exception { + int result = 0; + for (int i = 0; i < trials; i++) { + result ^= a * b; + } + return result; + } + + SampleBenchmarkSuite suite() { + return SampleBenchmarkSuite.this; + } + } + + class DivideBenchmark extends Benchmark { + @Override public Object run(int trials) throws Exception { + int result = 0; + for (int i = 0; i < trials; i++) { + result ^= a / b; + } + return result; + } + } + } +} diff --git a/test/com/google/caliper/examples/DoubleToStringBenchmarkSuite.java b/test/com/google/caliper/examples/DoubleToStringBenchmarkSuite.java new file mode 100644 index 0000000..a5d5234 --- /dev/null +++ b/test/com/google/caliper/examples/DoubleToStringBenchmarkSuite.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2009 Google Inc. + * + * Licensed 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. + */ + +package com.google.caliper.examples; + +import com.google.caliper.Benchmark; +import com.google.caliper.DefaultBenchmarkSuite; +import com.google.caliper.Param; +import com.google.caliper.Runner; + +import java.util.Arrays; +import java.util.Collection; + +/** + * Measures the various ways the JDK converts doubles to Strings. + */ +public class DoubleToStringBenchmarkSuite extends DefaultBenchmarkSuite { + + @Param private Double d; + + private static Collection<Double> dValues = Arrays.asList( + Math.PI, + -0.0d, + Double.NEGATIVE_INFINITY, + Double.NaN + ); + + class FormatterBenchmark extends Benchmark { + public Object run(int trials) { + Double value = d; + String result = null; + for (int i = 0; i < trials; i++) { + result = String.format("%f", value); + } + return result; + } + } + + class ToStringBenchmark extends Benchmark { + public Object run(int trials) { + Double value = d; + String result = null; + for (int i = 0; i < trials; i++) { + result = value.toString(); + } + return result; + } + } + + class ConcatenationBenchmark extends Benchmark { + public Object run(int trials) { + Double value = d; + String result = null; + for (int i = 0; i < trials; i++) { + result = "" + value; + } + return result; + } + } + + public static void main(String[] args) { + Runner.main(DoubleToStringBenchmarkSuite.class, args); + } +} diff --git a/test/com/google/caliper/examples/SortBenchmarkSuite.java b/test/com/google/caliper/examples/SortBenchmarkSuite.java new file mode 100644 index 0000000..e92fc10 --- /dev/null +++ b/test/com/google/caliper/examples/SortBenchmarkSuite.java @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2009 Google Inc. + * + * Licensed 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. + */ + +package com.google.caliper.examples; + +import com.google.caliper.Benchmark; +import com.google.caliper.DefaultBenchmarkSuite; +import com.google.caliper.Param; +import com.google.caliper.Runner; + +import java.util.Arrays; +import java.util.EnumSet; +import java.util.Random; +import java.util.Collection; + +/** + * Measures sorting on different distributions of integers. + */ +public class SortBenchmarkSuite extends DefaultBenchmarkSuite { + + @Param int length; + + static Collection<Integer> lengthValues = Arrays.asList(10, 100, 1000, 10000); + + @Param Distribution distribution; + + static Collection<Distribution> distributionValues = EnumSet.allOf(Distribution.class); + + int[] values; + int[] copy; + + @Override protected void setUp() throws Exception { + values = distribution.create(length); + copy = new int[length]; + } + + class ArraysSortBenchmark extends Benchmark { + public Object run(int trials) throws Exception { + int result = 0; + for (int i = 0; i < trials; i++) { + System.arraycopy(values, 0, copy, 0, values.length); + Arrays.sort(copy); + result ^= copy[0]; + } + return result; + } + } + + enum Distribution { + SAWTOOTH { + @Override + int[] create(int length) { + int[] result = new int[length]; + for (int i = 0; i < length; i += 5) { + result[i] = 0; + result[i + 1] = 1; + result[i + 2] = 2; + result[i + 3] = 3; + result[i + 4] = 4; + } + return result; + } + }, + INCREASING { + @Override + int[] create(int length) { + int[] result = new int[length]; + for (int i = 0; i < length; i++) { + result[i] = i; + } + return result; + } + }, + DECREASING { + @Override + int[] create(int length) { + int[] result = new int[length]; + for (int i = 0; i < length; i++) { + result[i] = length - i; + } + return result; + } + }, + RANDOM { + @Override + int[] create(int length) { + Random random = new Random(); + int[] result = new int[length]; + for (int i = 0; i < length; i++) { + result[i] = random.nextInt(); + } + return result; + } + }; + + abstract int[] create(int length); + } + + public static void main(String[] args) { + Runner.main(SortBenchmarkSuite.class, args); + } +} |