diff options
44 files changed, 3116 insertions, 902 deletions
@@ -1,104 +1,103 @@ <?xml version="1.0"?> -<project name="caliper" default="compile"> - - <property environment="env"/> - +<project name="caliper" default="install"> <!-- can be overridden at the command line with -Dversion= or in IDEA, in the ant properties dialog --> - <property name="version" value="snapshot"/> + <property name="version" value="0.0"/> <!-- subversion revision? --> + + <property name="frameworkclasses" value="build/classes/framework"/> + <property name="otherclasses" value="build/classes/other"/> + <property name="installroot" value="build/caliper-${version}"/> + <property name="javadocroot" value="${installroot}/docs/api"/> + <property name="collections" value="lib/google-collect-1.0-rc4.jar"/> + + <path id="dependencies"> + <pathelement location="${collections}"/> + </path> - <path id="compile.classpath"> - <pathelement location="lib/google-collect-1.0-rc4.jar"/> + <path id="testdependencies"> + <path refid="dependencies"/> + <pathelement location="${frameworkclasses}"/> + <pathelement location="lib/junit.jar"/> </path> - <target name="compile" description="Compile Java source."> - <mkdir dir="build/classes"/> + <target name="compile" + description="Compile all Java source code"> + <mkdir dir="${frameworkclasses}"/> <javac srcdir="src" + includes="com/**" + destdir="${frameworkclasses}" debug="on" - destdir="build/classes" source="1.5" - target="1.5"> - <classpath refid="compile.classpath"/> + target="1.5" + classpathref="dependencies"> + <compilerarg value="-Xlint"/> + <!--compilerarg value="-Werror"/--> </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" + <mkdir dir="${otherclasses}"/> + <javac srcdir="src" + excludes="com/**" debug="on" - destdir="build/test" + destdir="${otherclasses}" source="1.5" target="1.5"> + <compilerarg value="-Xlint"/> + <!--compilerarg value="-Werror"/--> <classpath> - <pathelement location="build/classes"/> - <pathelement location="lib/google-collect-1.0-rc4.jar"/> - <pathelement location="lib/junit.jar"/> + <path refid="testdependencies"/> </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"> + depends="compile" + description="Run unit tests"> + <junit fork="true" + haltonfailure="true"> <classpath> - <pathelement location="build/test"/> - <pathelement location="build/classes"/> - <pathelement location="lib/junit.jar"/> - <pathelement location="lib/google-collect-1.0-rc4.jar"/> + <pathelement location="${otherclasses}"/> + <path refid="testdependencies"/> </classpath> - <arg value="com.google.caliper.AllTests" /> - </java> - </target> + <batchtest> + <fileset dir="src"> + <include name="test/*Test.java"/> + </fileset> + </batchtest> - <target name="clean" - description="Remove generated files."> - <delete dir="build"/> + </junit> </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="buildjar" + depends="compile" + description="Build JAR archive of caliper framework"> + <mkdir dir="${installroot}/lib"/> - <target name="jarsrc" description="Build jar of source."> - <jar jarfile="build/dist/caliper-${version}/src-${version}.zip"> - <fileset dir="src"/> - </jar> - </target> + <taskdef name="jarjar" + classname="com.tonicsystems.jarjar.JarJarTask" + classpath="lib/jarjar-1.0rc8.jar"/> - <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> + <jarjar jarfile="${installroot}/lib/caliper-${version}.jar"> + <fileset dir="${frameworkclasses}"/> + <zipfileset src="${collections}"/> + <rule pattern="com.google.common.**" result="com.google.caliper.internal.guava.@1"/> + <keep pattern="com.google.caliper.**"/> - <zip destfile="build/caliper-${version}.zip" - basedir="build/dist"/> + <!-- include some files for GWT's benefit --> + <zipfileset dir="src"> + <include name="com/google/caliper/Run.java"/> + <include name="com/google/caliper/Scenario.java"/> + <include name="CaliperCore.gwt.xml" /> + </zipfileset> + </jarjar> </target> <target name="javadoc" - description="Generate Javadocs."> - <delete dir="build/javadoc"/> - <mkdir dir="build/javadoc"/> + description="Generate API documentation to ${javadocroot}"> + <delete dir="${javadocroot}"/> <!-- TODO: figure out how to make this more incremental --> + <mkdir dir="${javadocroot}"/> <javadoc packagenames="com.google.caliper" - destdir="build/javadoc" + destdir="${javadocroot}" use="true" author="true" protected="true" @@ -106,9 +105,44 @@ <sourcepath> <pathelement location="src"/> </sourcepath> - <classpath refid="compile.classpath"/> + <classpath refid="dependencies"/> <link href="http://google-collections.googlecode.com/svn/trunk/javadoc/"/> <link href="http://java.sun.com/javase/6/docs/api"/> </javadoc> </target> + + <target name="install" depends="buildjar, javadoc" + description="Create a complete installation tree in ./build/caliper-*"> + <mkdir dir="${installroot}"/> + <zip zipfile="${installroot}/src-${version}.zip"> + <fileset dir="src"/> + </zip> + + <copy toDir="${installroot}" file="COPYING"/> + <copy toDir="${installroot}" file="src/scripts/caliper"> + <filterset> + <filter token="VERSION" value="${version}"/> + </filterset> + </copy> + <chmod perm="ugo=rx" file="${installroot}/caliper"/> + </target> + + <target name="dist" + depends="install" + description="Create a zipped distribution for upload to Google Code"> + <zip destfile="build/caliper-${version}.zip"> + <zipfileset dir="build/caliper-${version}" + excludes="caliper" + prefix="caliper-${version}"/> + <zipfileset file="build/caliper-${version}/caliper" + prefix="caliper-${version}" + filemode="555"/> + </zip> + </target> + + <target name="clean" + description="Remove all generated files."> + <delete dir="build"/> + </target> + </project> diff --git a/caliper.iml b/caliper.iml new file mode 100644 index 0000000..70039aa --- /dev/null +++ b/caliper.iml @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="UTF-8"?> +<module type="JAVA_MODULE" version="4"> + <component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_5" inherit-compiler-output="false"> + <output url="file://$MODULE_DIR$/ideabuild/framework" /> + <output-test url="file://$MODULE_DIR$/ideabuild/other" /> + <exclude-output /> + <content url="file://$MODULE_DIR$"> + <sourceFolder url="file://$MODULE_DIR$/src/com" isTestSource="false" packagePrefix="com" /> + <sourceFolder url="file://$MODULE_DIR$/src/examples" isTestSource="true" packagePrefix="examples" /> + <sourceFolder url="file://$MODULE_DIR$/src/test" isTestSource="true" packagePrefix="test" /> + <sourceFolder url="file://$MODULE_DIR$/src/tutorial" isTestSource="true" packagePrefix="tutorial" /> + <excludeFolder url="file://$MODULE_DIR$/build" /> + </content> + <orderEntry type="inheritedJdk" /> + <orderEntry type="sourceFolder" forTests="false" /> + <orderEntry type="module-library"> + <library> + <CLASSES> + <root url="jar://$MODULE_DIR$/lib/google-collect-1.0-rc4.jar!/" /> + </CLASSES> + <JAVADOC /> + <SOURCES /> + </library> + </orderEntry> + <orderEntry type="module-library" scope="TEST"> + <library> + <CLASSES> + <root url="jar://$MODULE_DIR$/lib/junit.jar!/" /> + </CLASSES> + <JAVADOC /> + <SOURCES /> + </library> + </orderEntry> + </component> +</module> + diff --git a/caliper.ipr b/caliper.ipr index f4e0208..80e7392 100644 --- a/caliper.ipr +++ b/caliper.ipr @@ -1,15 +1,79 @@ <?xml version="1.0" encoding="UTF-8"?> -<project relativePaths="false" version="4"> +<project version="4"> <component name="AntConfiguration"> <defaultAnt bundledAnt="true" /> - </component> - <component name="BuildJarProjectSettings"> - <option name="BUILD_JARS_ON_MAKE" value="false" /> + <buildFile url="file://$PROJECT_DIR$/build.xml"> + <additionalClassPath /> + <antReference projectDefault="true" /> + <customJdkName value="" /> + <maximumHeapSize value="128" /> + <maximumStackSize value="2" /> + <properties /> + </buildFile> </component> <component name="CodeStyleSettingsManager"> <option name="PER_PROJECT_SETTINGS"> <value> - <ADDITIONAL_INDENT_OPTIONS fileType="java"> + <option name="KEEP_CONTROL_STATEMENT_IN_ONE_LINE" value="false" /> + <option name="ALIGN_MULTILINE_PARAMETERS" value="false" /> + <option name="ALIGN_MULTILINE_FOR" value="false" /> + <option name="KEEP_BLANK_LINES_IN_DECLARATIONS" value="1" /> + <option name="KEEP_BLANK_LINES_IN_CODE" value="1" /> + <option name="KEEP_BLANK_LINES_BEFORE_RBRACE" value="0" /> + <option name="BLANK_LINES_BEFORE_PACKAGE" value="1" /> + <option name="BLANK_LINES_AROUND_CLASS" value="0" /> + <option name="SPACE_BEFORE_ARRAY_INITIALIZER_LBRACE" value="true" /> + <option name="USE_FQ_CLASS_NAMES_IN_JAVADOC" value="false" /> + <option name="INSERT_INNER_CLASS_IMPORTS" value="true" /> + <option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99" /> + <option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99" /> + <option name="PACKAGES_TO_USE_IMPORT_ON_DEMAND"> + <value /> + </option> + <option name="IMPORT_LAYOUT_TABLE"> + <value> + <package name="" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="" withSubpackages="true" static="true" /> + </value> + </option> + <option name="RIGHT_MARGIN" value="100" /> + <option name="CALL_PARAMETERS_WRAP" value="1" /> + <option name="METHOD_PARAMETERS_WRAP" value="1" /> + <option name="EXTENDS_LIST_WRAP" value="1" /> + <option name="THROWS_LIST_WRAP" value="1" /> + <option name="EXTENDS_KEYWORD_WRAP" value="1" /> + <option name="THROWS_KEYWORD_WRAP" value="1" /> + <option name="METHOD_CALL_CHAIN_WRAP" value="1" /> + <option name="BINARY_OPERATION_WRAP" value="1" /> + <option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true" /> + <option name="TERNARY_OPERATION_WRAP" value="1" /> + <option name="TERNARY_OPERATION_SIGNS_ON_NEXT_LINE" value="true" /> + <option name="KEEP_SIMPLE_BLOCKS_IN_ONE_LINE" value="true" /> + <option name="FOR_STATEMENT_WRAP" value="1" /> + <option name="ARRAY_INITIALIZER_WRAP" value="1" /> + <option name="ASSIGNMENT_WRAP" value="1" /> + <option name="PLACE_ASSIGNMENT_SIGN_ON_NEXT_LINE" value="true" /> + <option name="LABELED_STATEMENT_WRAP" value="1" /> + <option name="WRAP_COMMENTS" value="true" /> + <option name="ASSERT_STATEMENT_WRAP" value="1" /> + <option name="IF_BRACE_FORCE" value="3" /> + <option name="DOWHILE_BRACE_FORCE" value="3" /> + <option name="WHILE_BRACE_FORCE" value="3" /> + <option name="FOR_BRACE_FORCE" value="3" /> + <option name="JD_ALIGN_PARAM_COMMENTS" value="false" /> + <option name="JD_ALIGN_EXCEPTION_COMMENTS" value="false" /> + <option name="JD_P_AT_EMPTY_LINES" value="false" /> + <option name="JD_KEEP_EMPTY_PARAMETER" value="false" /> + <option name="JD_KEEP_EMPTY_EXCEPTION" value="false" /> + <option name="JD_KEEP_EMPTY_RETURN" value="false" /> + <option name="METHOD_ANNOTATION_WRAP" value="5" /> + <option name="CLASS_ANNOTATION_WRAP" value="5" /> + <option name="FIELD_ANNOTATION_WRAP" value="5" /> + <option name="PARAMETER_ANNOTATION_WRAP" value="1" /> + <option name="VARIABLE_ANNOTATION_WRAP" value="1" /> + <option name="ENUM_CONSTANTS_WRAP" value="2" /> + <ADDITIONAL_INDENT_OPTIONS fileType=""> <option name="INDENT_SIZE" value="4" /> <option name="CONTINUATION_INDENT_SIZE" value="8" /> <option name="TAB_SIZE" value="4" /> @@ -18,8 +82,8 @@ <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" /> + <ADDITIONAL_INDENT_OPTIONS fileType="groovy"> + <option name="INDENT_SIZE" value="2" /> <option name="CONTINUATION_INDENT_SIZE" value="8" /> <option name="TAB_SIZE" value="4" /> <option name="USE_TAB_CHARACTER" value="false" /> @@ -27,6 +91,15 @@ <option name="LABEL_INDENT_SIZE" value="0" /> <option name="LABEL_INDENT_ABSOLUTE" value="false" /> </ADDITIONAL_INDENT_OPTIONS> + <ADDITIONAL_INDENT_OPTIONS fileType="java"> + <option name="INDENT_SIZE" value="2" /> + <option name="CONTINUATION_INDENT_SIZE" value="4" /> + <option name="TAB_SIZE" value="2" /> + <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" /> @@ -38,90 +111,590 @@ </ADDITIONAL_INDENT_OPTIONS> </value> </option> - <option name="USE_PER_PROJECT_SETTINGS" value="false" /> + <option name="USE_PER_PROJECT_SETTINGS" value="true" /> </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> + <wildcardResourcePatterns /> + <annotationProcessing enabled="false" useClasspath="true" /> </component> - <component name="CopyrightManager" default=""> + <component name="CopyrightManager" default="Apache 2.0/Google"> + <copyright> + <option name="notice" value="Copyright (C) &#36;today.year 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." /> + <option name="keyword" value="Copyright" /> + <option name="allowReplaceKeyword" value="Copyright" /> + <option name="myName" value="Apache 2.0/Google" /> + <option name="myLocal" value="true" /> + </copyright> <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 name="Encoding" useUTFGuessing="true" native2AsciiForPropertiesFiles="false" defaultCharsetForPropertiesFiles="UTF-8"> + <file url="file://$PROJECT_DIR$" charset="UTF-8" /> + <file url="PROJECT" charset="UTF-8" /> + </component> + <component name="EntryPointsManager"> + <entry_points version="2.0" /> </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"> + <inspection_tool class="AbstractMethodCallInConstructor" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="AbstractMethodOverridesAbstractMethod" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="AccessToNonThreadSafeStaticFieldFromInstance" enabled="true" level="WARNING" enabled_by_default="true"> + <option name="nonThreadSafeTypes" value="java.text.DateFormat,java.util.Calendar" /> + </inspection_tool> + <inspection_tool class="AccessToStaticFieldLockedOnInstance" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="AmbiguousMethodCall" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="AnonymousClassVariableHidesContainingMethodVariable" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="ArchaicSystemPropertyAccess" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="ArithmeticOnVolatileField" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="AssertEqualsMayBeAssertSame" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="AssertStatement" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="AssignmentToCatchBlockParameter" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="AssignmentToCollectionFieldFromParameter" enabled="true" level="WARNING" enabled_by_default="true"> + <option name="ignorePrivateMethods" value="true" /> + </inspection_tool> + <inspection_tool class="AssignmentToDateFieldFromParameter" enabled="true" level="WARNING" enabled_by_default="true"> + <option name="ignorePrivateMethods" value="true" /> + </inspection_tool> + <inspection_tool class="AssignmentToForLoopParameter" enabled="true" level="WARNING" enabled_by_default="true"> + <option name="m_checkForeachParameters" value="false" /> + </inspection_tool> + <inspection_tool class="AssignmentToMethodParameter" enabled="true" level="WARNING" enabled_by_default="true"> + <option name="ignoreTransformationOfOriginalParameter" value="false" /> + </inspection_tool> + <inspection_tool class="AssignmentToStaticFieldFromInstanceMethod" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="AssignmentUsedAsCondition" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="AwaitNotInLoop" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="AwaitWithoutCorrespondingSignal" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="BadOddness" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="BeforeClassOrAfterClassIsPublicStaticVoidNoArg" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="BeforeOrAfterIsPublicVoidNoArg" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="BigDecimalEquals" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="BooleanMethodIsAlwaysInverted" enabled="false" level="WARNING" enabled_by_default="false" /> + <inspection_tool class="BusyWait" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="CStyleArrayDeclaration" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="CachedNumberConstructorCall" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="CallToNativeMethodWhileLocked" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="CallToStringConcatCanBeReplacedByOperator" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="CastConflictsWithInstanceof" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="CastThatLosesPrecision" enabled="true" level="WARNING" enabled_by_default="true"> + <option name="ignoreIntegerCharCasts" value="false" /> + </inspection_tool> + <inspection_tool class="CastToIncompatibleInterface" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="ChainedEquality" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="CheckEmptyScriptTag" enabled="false" level="WARNING" enabled_by_default="false" /> + <inspection_tool class="CheckValidXmlInScriptTagBody" enabled="false" level="ERROR" enabled_by_default="false" /> + <inspection_tool class="ClassEscapesItsScope" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="ClassInTopLevelPackage" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="ClassInitializer" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="ClassNameDiffersFromFileName" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="ClassNewInstance" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="ClassWithMultipleLoggers" enabled="true" level="WARNING" enabled_by_default="true"> + <option name="loggerClassName" value="java.util.logging.Logger" /> + </inspection_tool> + <inspection_tool class="CloneCallsSuperClone" enabled="false" level="WARNING" enabled_by_default="false" /> + <inspection_tool class="CloneDeclaresCloneNotSupported" enabled="false" level="WARNING" enabled_by_default="false" /> + <inspection_tool class="CollectionAddedToSelf" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="CollectionsFieldAccessReplaceableByMethodCall" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="ComparableImplementedButEqualsNotOverridden" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="ComparatorNotSerializable" enabled="true" level="INFO" enabled_by_default="true" /> + <inspection_tool class="CompareToUsesNonFinalVariable" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="ComparisonOfShortAndChar" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="ComparisonToNaN" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="ConditionSignal" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="ConditionalExpressionWithIdenticalBranches" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="ConfusingElse" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="ConfusingFloatingPointLiteral" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="ConfusingOctalEscape" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="ConstantAssertCondition" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="ConstantJUnitAssertArgument" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="ConstantMathCall" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="ConstantOnLHSOfComparison" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="ConstantStringIntern" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="ConstantValueVariableUse" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="ControlFlowStatementWithoutBraces" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="CovariantEquals" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="DefaultNotLastCaseInSwitch" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="DivideByZero" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="DoubleCheckedLocking" enabled="true" level="WARNING" enabled_by_default="true"> + <option name="ignoreOnVolatileVariables" value="false" /> + </inspection_tool> + <inspection_tool class="DoubleNegation" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="DuplicateBooleanBranch" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="DuplicateCondition" enabled="true" level="WARNING" enabled_by_default="true"> + <option name="ignoreMethodCalls" value="false" /> + </inspection_tool> + <inspection_tool class="DynamicRegexReplaceableByCompiledPattern" enabled="true" level="INFO" enabled_by_default="true" /> + <inspection_tool class="EmptyInitializer" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="EmptySynchronizedStatement" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="EnumerationCanBeIteration" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="EqualsAndHashcode" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="EqualsHashCodeCalledOnUrl" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="EqualsUsesNonFinalVariable" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="ExceptionFromCatchWhichDoesntWrap" enabled="false" level="WARNING" enabled_by_default="false"> + <option name="ignoreGetMessage" value="true" /> + </inspection_tool> + <inspection_tool class="ExtendsThread" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="ExtendsUtilityClass" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="ExternalizableWithSerializationMethods" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="FallthruInSwitchStatement" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="FieldAccessedSynchronizedAndUnsynchronized" enabled="true" level="WARNING" enabled_by_default="true"> + <option name="countGettersAndSetters" value="false" /> + </inspection_tool> + <inspection_tool class="FieldHidesSuperclassField" enabled="true" level="WARNING" enabled_by_default="true"> + <option name="m_ignoreInvisibleFields" value="true" /> + </inspection_tool> + <inspection_tool class="FieldMayBeFinal" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="FinalMethodInFinalClass" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="FinalStaticMethod" enabled="false" level="WARNING" enabled_by_default="false" /> + <inspection_tool class="Finalize" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="FinalizeNotProtected" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="FloatingPointEquality" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="ForLoopReplaceableByWhile" enabled="true" level="WARNING" enabled_by_default="true"> + <option name="m_ignoreLoopsWithoutConditions" value="false" /> + </inspection_tool> + <inspection_tool class="ForLoopThatDoesntUseLoopVariable" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="HardcodedLineSeparators" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="HashCodeUsesNonFinalVariable" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="HtmlExtraClosingTag" enabled="false" level="ERROR" enabled_by_default="false" /> + <inspection_tool class="HtmlUnknownAttribute" enabled="false" level="WARNING" enabled_by_default="false"> + <option name="myValues"> + <value> + <list size="0" /> + </value> + </option> + <option name="myCustomValuesEnabled" value="true" /> + </inspection_tool> + <inspection_tool class="HtmlUnknownTag" enabled="false" level="WARNING" enabled_by_default="false"> + <option name="myValues"> + <value> + <list size="4"> + <item index="0" class="java.lang.String" itemvalue="nobr" /> + <item index="1" class="java.lang.String" itemvalue="noembed" /> + <item index="2" class="java.lang.String" itemvalue="comment" /> + <item index="3" class="java.lang.String" itemvalue="noscript" /> + </list> + </value> + </option> + <option name="myCustomValuesEnabled" value="true" /> + </inspection_tool> + <inspection_tool class="IOResource" enabled="true" level="INFO" enabled_by_default="true" /> + <inspection_tool class="IfMayBeConditional" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="IfStatementWithIdenticalBranches" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="ImplicitNumericConversion" enabled="true" level="WARNING" enabled_by_default="true"> + <option name="ignoreWideningConversions" value="true" /> + <option name="ignoreCharConversions" value="false" /> + <option name="ignoreConstantConversions" value="false" /> + </inspection_tool> + <inspection_tool class="InconsistentLanguageLevel" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="IndexOfReplaceableByContains" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="InnerClassVariableHidesOuterClassVariable" enabled="true" level="WARNING" enabled_by_default="true"> + <option name="m_ignoreInvisibleFields" value="true" /> + </inspection_tool> + <inspection_tool class="InstanceVariableUninitializedUse" enabled="true" level="WARNING" enabled_by_default="true"> + <option name="m_ignorePrimitives" value="false" /> + </inspection_tool> + <inspection_tool class="InstanceofCatchParameter" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="InstanceofIncompatibleInterface" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="InstanceofThis" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="InstantiationOfUtilityClass" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="IntLiteralMayBeLongLiteral" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="IntegerDivisionInFloatingPointContext" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="IntegerMultiplicationImplicitCastToLong" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="IteratorHasNextCallsIteratorNext" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="IteratorNextDoesNotThrowNoSuchElementException" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="JUnit4AnnotatedMethodInJUnit3TestCase" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="JUnitAbstractTestClassNamingConvention" enabled="true" level="WARNING" enabled_by_default="true"> + <option name="m_regex" value="[A-Z][A-Za-z\d]*TestCase" /> + <option name="m_minLength" value="12" /> + <option name="m_maxLength" value="64" /> + </inspection_tool> + <inspection_tool class="JUnitTestClassNamingConvention" enabled="true" level="WARNING" enabled_by_default="true"> + <option name="m_regex" value="[A-Z][A-Za-z\d]*Test" /> + <option name="m_minLength" value="8" /> + <option name="m_maxLength" value="64" /> + </inspection_tool> + <inspection_tool class="JavaDoc" enabled="false" level="WARNING" enabled_by_default="false"> <option name="TOP_LEVEL_CLASS_OPTIONS"> <value> - <option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" /> + <option name="ACCESS_JAVADOC_REQUIRED_FOR" value="public" /> <option name="REQUIRED_TAGS" value="" /> </value> </option> <option name="INNER_CLASS_OPTIONS"> <value> - <option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" /> + <option name="ACCESS_JAVADOC_REQUIRED_FOR" value="protected" /> <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" /> + <option name="ACCESS_JAVADOC_REQUIRED_FOR" value="protected" /> + <option name="REQUIRED_TAGS" value="@throws or @exception" /> </value> </option> <option name="FIELD_OPTIONS"> <value> - <option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" /> + <option name="ACCESS_JAVADOC_REQUIRED_FOR" value="protected" /> <option name="REQUIRED_TAGS" value="" /> </value> </option> - <option name="IGNORE_DEPRECATED" value="false" /> - <option name="IGNORE_JAVADOC_PERIOD" value="true" /> + <option name="IGNORE_DEPRECATED" value="true" /> + <option name="IGNORE_JAVADOC_PERIOD" value="false" /> + <option name="IGNORE_DUPLICATED_THROWS" value="false" /> <option name="myAdditionalJavadocTags" value="" /> </inspection_tool> + <inspection_tool class="JavaLangImport" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="LengthOneStringInIndexOf" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="ListIndexOfReplaceableByContains" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="LocalVariableHidingMemberVariable" enabled="true" level="WARNING" enabled_by_default="true"> + <option name="m_ignoreInvisibleFields" value="true" /> + <option name="m_ignoreStaticMethods" value="true" /> + </inspection_tool> + <inspection_tool class="LoggerInitializedWithForeignClass" enabled="true" level="WARNING" enabled_by_default="true"> + <option name="loggerClassName" value="org.apache.log4j.Logger" /> + <option name="loggerFactoryMethodName" value="getLogger" /> + </inspection_tool> + <inspection_tool class="LoggingConditionDisagreesWithLogStatement" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="LongLiteralsEndingWithLowercaseL" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="LoopConditionNotUpdatedInsideLoop" enabled="true" level="WARNING" enabled_by_default="true"> + <option name="ignoreIterators" value="false" /> + </inspection_tool> + <inspection_tool class="LoopWithImplicitTerminationCondition" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="MapReplaceableByEnumMap" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="MavenModelInspection" enabled="false" level="ERROR" enabled_by_default="false" /> + <inspection_tool class="MethodMayBeSynchronized" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="MethodNameSameAsClassName" enabled="false" level="WARNING" enabled_by_default="false" /> + <inspection_tool class="MethodOverloadsParentMethod" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="MethodOverridesPackageLocalMethod" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="MethodOverridesPrivateMethod" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="MethodOverridesStaticMethod" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="MethodReturnAlwaysConstant" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="MismatchedArrayReadWrite" enabled="false" level="WARNING" enabled_by_default="false" /> + <inspection_tool class="MisorderedAssertEqualsParameters" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="MissingDeprecatedAnnotation" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="MissingOverrideAnnotation" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="MissortedModifiers" enabled="true" level="WARNING" enabled_by_default="true"> + <option name="m_requireAnnotationsFirst" value="true" /> + </inspection_tool> + <inspection_tool class="MisspelledCompareTo" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="MisspelledEquals" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="MisspelledHashcode" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="MisspelledSetUp" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="MisspelledTearDown" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="MisspelledToString" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="MultipleDeclaration" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="MultipleExceptionsDeclaredOnTestMethod" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="MultipleTopLevelClassesInFile" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="MultipleTypedDeclaration" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="NakedNotify" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="NativeMethods" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="NegatedConditional" enabled="true" level="WARNING" enabled_by_default="true"> + <option name="m_ignoreNegatedNullComparison" value="true" /> + </inspection_tool> + <inspection_tool class="NestedConditionalExpression" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="NestedSynchronizedStatement" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="NonFinalFieldOfException" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="NonFinalStaticVariableUsedInClassInitialization" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="NonProtectedConstructorInAbstractClass" enabled="true" level="WARNING" enabled_by_default="true"> + <option name="m_ignoreNonPublicClasses" value="false" /> + </inspection_tool> + <inspection_tool class="NonSerializableFieldInSerializableClass" enabled="true" level="WARNING" enabled_by_default="true"> + <option name="superClassString" value="java.awt.Component" /> + </inspection_tool> + <inspection_tool class="NonSerializableObjectBoundToHttpSession" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="NonSerializableObjectPassedToObjectStream" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="NonSerializableWithSerialVersionUIDField" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="NonSerializableWithSerializationMethods" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="NonShortCircuitBoolean" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="NonStaticFinalLogger" enabled="true" level="WARNING" enabled_by_default="true"> + <option name="loggerClassName" value="java.util.logging.Logger" /> + </inspection_tool> + <inspection_tool class="NonSynchronizedMethodOverridesSynchronizedMethod" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="NonThreadSafeLazyInitialization" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="NotifyCalledOnCondition" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="NotifyNotInSynchronizedContext" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="NotifyWithoutCorrespondingWait" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="NullableProblems" enabled="false" level="WARNING" enabled_by_default="false"> + <option name="REPORT_NULLABLE_METHOD_OVERRIDES_NOTNULL" value="true" /> + <option name="REPORT_NOT_ANNOTATED_METHOD_OVERRIDES_NOTNULL" value="true" /> + <option name="REPORT_NOTNULL_PARAMETER_OVERRIDES_NULLABLE" value="true" /> + <option name="REPORT_NOT_ANNOTATED_PARAMETER_OVERRIDES_NOTNULL" value="true" /> + <option name="REPORT_NOT_ANNOTATED_GETTER" value="true" /> + <option name="REPORT_NOT_ANNOTATED_SETTER_PARAMETER" value="true" /> + <option name="REPORT_ANNOTATION_NOT_PROPAGATED_TO_OVERRIDERS" value="true" /> + </inspection_tool> + <inspection_tool class="ObjectEquality" enabled="true" level="WARNING" enabled_by_default="true"> + <option name="m_ignoreEnums" value="true" /> + <option name="m_ignoreClassObjects" value="true" /> + <option name="m_ignorePrivateConstructors" value="false" /> + </inspection_tool> + <inspection_tool class="ObjectNotify" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="ObjectToString" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="ObsoleteCollection" enabled="true" level="WARNING" enabled_by_default="true"> + <option name="ignoreLibraryArguments" value="false" /> + </inspection_tool> + <inspection_tool class="OctalAndDecimalIntegersMixed" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="OnDemandImport" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="OverlyComplexArithmeticExpression" enabled="true" level="WARNING" enabled_by_default="true"> + <option name="m_limit" value="6" /> + </inspection_tool> + <inspection_tool class="OverlyStrongTypeCast" enabled="true" level="WARNING" enabled_by_default="true"> + <option name="ignoreInMatchingInstanceof" value="false" /> + </inspection_tool> + <inspection_tool class="OverridableMethodCallDuringObjectConstruction" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="OverriddenMethodCallDuringObjectConstruction" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="ParameterHidingMemberVariable" enabled="true" level="WARNING" enabled_by_default="true"> + <option name="m_ignoreInvisibleFields" value="true" /> + <option name="m_ignoreStaticMethodParametersHidingInstanceFields" value="true" /> + <option name="m_ignoreForConstructors" value="true" /> + <option name="m_ignoreForPropertySetters" value="true" /> + <option name="m_ignoreForAbstractMethods" value="false" /> + </inspection_tool> + <inspection_tool class="ParameterizedParametersStaticCollection" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="PatternNotApplicable" enabled="false" level="ERROR" enabled_by_default="false" /> + <inspection_tool class="PatternOverriddenByNonAnnotatedMethod" enabled="false" level="WARNING" enabled_by_default="false" /> + <inspection_tool class="PatternValidation" enabled="false" level="WARNING" enabled_by_default="false"> + <option name="CHECK_NON_CONSTANT_VALUES" value="true" /> + </inspection_tool> + <inspection_tool class="PointlessIndexOfComparison" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="ProtectedMemberInFinalClass" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="PublicConstructorInNonPublicClass" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="PublicField" enabled="true" level="WARNING" enabled_by_default="true"> + <option name="ignoreEnums" value="false" /> + </inspection_tool> + <inspection_tool class="PublicFieldAccessedInSynchronizedContext" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="PublicStaticArrayField" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="RawUseOfParameterizedType" enabled="true" level="WARNING" enabled_by_default="true"> + <option name="ignoreObjectConstruction" value="true" /> + <option name="ignoreTypeCasts" value="false" /> + </inspection_tool> + <inspection_tool class="ReadObjectAndWriteObjectPrivate" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="ReadObjectInitialization" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="ReadResolveAndWriteReplaceProtected" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="RedundantFieldInitialization" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="RedundantImplements" enabled="true" level="WARNING" enabled_by_default="true"> + <option name="ignoreSerializable" value="false" /> + <option name="ignoreCloneable" value="false" /> + </inspection_tool> + <inspection_tool class="RedundantImport" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="RedundantMethodOverride" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="RedundantStringFormatCall" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="RedundantSuppression" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="RedundantThrowsDeclaration" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="ReplaceAllDot" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="ReplaceAssignmentWithOperatorAssignment" enabled="true" level="WARNING" enabled_by_default="true"> + <option name="ignoreLazyOperators" value="true" /> + <option name="ignoreObscureOperators" value="false" /> + </inspection_tool> + <inspection_tool class="RequiredAttributes" enabled="false" level="WARNING" enabled_by_default="false"> + <option name="myAdditionalRequiredHtmlAttributes" value="" /> + </inspection_tool> + <inspection_tool class="ResultOfObjectAllocationIgnored" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="ReturnOfDateField" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="ReuseOfLocalVariable" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="RuntimeExec" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="SafeLock" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="SamePackageImport" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="SerialPersistentFieldsWithWrongSignature" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="SerialVersionUIDNotStaticFinal" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="SerializableHasSerialVersionUIDField" enabled="true" level="WARNING" enabled_by_default="true"> + <option name="superClassString" value="java.awt.Component" /> + </inspection_tool> + <inspection_tool class="SerializableInnerClassHasSerialVersionUIDField" enabled="true" level="WARNING" enabled_by_default="true"> + <option name="superClassString" value="java.awt.Component" /> + </inspection_tool> + <inspection_tool class="SerializableInnerClassWithNonSerializableOuterClass" enabled="true" level="WARNING" enabled_by_default="true"> + <option name="superClassString" value="java.awt.Component" /> + </inspection_tool> + <inspection_tool class="SerializableWithUnconstructableAncestor" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="SetReplaceableByEnumSet" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="SetupCallsSuperSetup" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="SetupIsPublicVoidNoArg" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="SignalWithoutCorrespondingAwait" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="SimplifiableIfStatement" enabled="false" level="WARNING" enabled_by_default="false" /> + <inspection_tool class="SimplifiableJUnitAssertion" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="Since15" enabled="true" level="ERROR" enabled_by_default="true"> + <option name="FORBID_15_API" value="false" /> + <option name="FORBID_16_API" value="true" /> + </inspection_tool> + <inspection_tool class="SizeReplaceableByIsEmpty" enabled="true" level="WARNING" enabled_by_default="true"> + <option name="ignoreNegations" value="false" /> + </inspection_tool> + <inspection_tool class="SleepWhileHoldingLock" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="SocketResource" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false"> + <option name="processCode" value="true" /> + <option name="processLiterals" value="true" /> + <option name="processComments" value="true" /> + </inspection_tool> + <inspection_tool class="StaticCallOnSubclass" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="StaticFieldReferenceOnSubclass" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="StaticInheritance" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="StaticNonFinalField" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="StaticSuite" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="StaticVariableInitialization" enabled="true" level="WARNING" enabled_by_default="true"> + <option name="m_ignorePrimitives" value="false" /> + </inspection_tool> + <inspection_tool class="StaticVariableUninitializedUse" enabled="true" level="WARNING" enabled_by_default="true"> + <option name="m_ignorePrimitives" value="false" /> + </inspection_tool> + <inspection_tool class="StringBufferReplaceableByStringBuilder" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="StringEqualsEmptyString" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="SubtractionInCompareTo" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="SuspiciousIndentAfterControlStatement" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="SwitchStatementWithConfusingDeclaration" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="SynchronizeOnLock" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="SynchronizeOnThis" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="SynchronizedMethod" enabled="true" level="WARNING" enabled_by_default="true"> + <option name="m_includeNativeMethods" value="true" /> + </inspection_tool> + <inspection_tool class="SynchronizedOnLiteralObject" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="SystemRunFinalizersOnExit" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="TailRecursion" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="TeardownCallsSuperTeardown" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="TeardownIsPublicVoidNoArg" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="TestCaseInProductCode" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="TestCaseWithConstructor" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="TestCaseWithNoTestMethods" enabled="true" level="WARNING" enabled_by_default="true"> + <option name="ignoreSupers" value="false" /> + </inspection_tool> + <inspection_tool class="TestMethodInProductCode" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="TestMethodIsPublicVoidNoArg" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="TestMethodWithoutAssertion" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="TestOnlyProblems" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="TextLabelInSwitchStatement" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="ThisEscapedInConstructor" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="ThreadDumpStack" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="ThreadLocalNotStaticFinal" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="ThreadPriority" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="ThreadRun" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="ThreadStartInConstruction" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="ThreadStopSuspendResume" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="ThreadWithDefaultRunMethod" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="ThreadYield" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="ThrowCaughtLocally" enabled="true" level="WARNING" enabled_by_default="true"> + <option name="ignoreRethrownExceptions" value="false" /> + </inspection_tool> + <inspection_tool class="ThrowablePrintStackTrace" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="TooBroadScope" enabled="true" level="WARNING" enabled_by_default="true"> + <option name="m_allowConstructorAsInitializer" value="false" /> + <option name="m_onlyLookAtBlocks" value="false" /> + </inspection_tool> + <inspection_tool class="TransientFieldInNonSerializableClass" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="TransientFieldNotInitialized" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="TypeParameterExtendsFinalClass" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="TypeParameterHidesVisibleType" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="UNUSED_SYMBOL" enabled="true" level="WARNING" enabled_by_default="true"> + <option name="LOCAL_VARIABLE" value="true" /> + <option name="FIELD" value="true" /> + <option name="METHOD" value="true" /> + <option name="CLASS" value="true" /> + <option name="PARAMETER" value="true" /> + <option name="REPORT_PARAMETER_FOR_PUBLIC_METHODS" value="true" /> + <option name="INJECTION_ANNOS"> + <value> + <list size="1"> + <item index="0" class="java.lang.String" itemvalue="com.google.caliper.Param" /> + </list> + </value> + </option> + </inspection_tool> + <inspection_tool class="UnaryPlus" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="UnconditionalWait" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="UnconstructableTestCase" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="UnnecessarilyQualifiedStaticUsage" enabled="true" level="WARNING" enabled_by_default="true"> + <option name="m_ignoreStaticFieldAccesses" value="false" /> + <option name="m_ignoreStaticMethodCalls" value="false" /> + <option name="m_ignoreStaticAccessFromStaticContext" value="false" /> + </inspection_tool> + <inspection_tool class="UnnecessaryAnnotationParentheses" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="UnnecessaryBlockStatement" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="UnnecessaryCallToStringValueOf" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="UnnecessaryConstantArrayCreationExpression" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="UnnecessaryConstructor" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="UnnecessaryEnumModifier" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="UnnecessaryFinalOnLocalVariable" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="UnnecessaryFinalOnParameter" enabled="true" level="WARNING" enabled_by_default="true"> + <option name="onlyWarnOnAbstractMethods" value="false" /> + </inspection_tool> + <inspection_tool class="UnnecessaryFullyQualifiedName" enabled="true" level="WARNING" enabled_by_default="true"> + <option name="m_ignoreJavadoc" value="false" /> + </inspection_tool> + <inspection_tool class="UnnecessaryInheritDoc" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="UnnecessaryInterfaceModifier" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="UnnecessaryJavaDocLink" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="UnnecessaryParentheses" enabled="true" level="INFO" enabled_by_default="true"> + <option name="ignoreClarifyingParentheses" value="true" /> + <option name="ignoreParenthesesOnConditionals" value="true" /> + </inspection_tool> + <inspection_tool class="UnnecessaryQualifierForThis" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="UnnecessarySuperConstructor" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="UnnecessarySuperQualifier" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="UnnecessaryUnaryMinus" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="UnpredictableBigDecimalConstructorCall" enabled="true" level="WARNING" enabled_by_default="true"> + <option name="ignoreReferences" value="true" /> + <option name="ignoreComplexLiterals" value="false" /> + </inspection_tool> + <inspection_tool class="UnusedCatchParameter" enabled="true" level="WARNING" enabled_by_default="true"> + <option name="m_ignoreCatchBlocksWithComments" value="true" /> + <option name="m_ignoreTestCases" value="true" /> + </inspection_tool> + <inspection_tool class="UnusedDeclaration" enabled="false" level="WARNING" enabled_by_default="false"> + <option name="ADD_MAINS_TO_ENTRIES" value="true" /> + <option name="ADD_APPLET_TO_ENTRIES" value="true" /> + <option name="ADD_SERVLET_TO_ENTRIES" value="true" /> + <option name="ADD_NONJAVA_TO_ENTRIES" value="true" /> + <option name="ADDITIONAL_ANNOTATIONS"> + <value> + <list size="1"> + <item index="0" class="java.lang.String" itemvalue="javax.ws.rs.*" /> + </list> + </value> + </option> + <option name="ADD_JUNIT_TO_ENTRIES" value="true" /> + </inspection_tool> + <inspection_tool class="UnusedImport" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="UnusedLibrary" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="UseOfAnotherObjectsPrivateField" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="UseOfPropertiesAsHashtable" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="UseOfSunClasses" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="UtilityClassWithPublicConstructor" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="UtilityClassWithoutPrivateConstructor" enabled="true" level="WARNING" enabled_by_default="true"> + <option name="ignoreClassesWithOnlyMain" value="false" /> + </inspection_tool> + <inspection_tool class="VariableNotUsedInsideIf" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="VolatileArrayField" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="VolatileLongOrDoubleField" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="WaitCalledOnCondition" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="WaitNotInLoop" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="WaitNotInSynchronizedContext" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="WaitOrAwaitWithoutTimeout" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="WaitWhileHoldingTwoLocks" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="WaitWithoutCorrespondingNotify" enabled="true" level="WARNING" enabled_by_default="true" /> + <inspection_tool class="WeakerAccess" enabled="true" level="WARNING" enabled_by_default="true"> + <option name="SUGGEST_PACKAGE_LOCAL_FOR_MEMBERS" value="true" /> + <option name="SUGGEST_PACKAGE_LOCAL_FOR_TOP_CLASSES" value="false" /> + <option name="SUGGEST_PRIVATE_FOR_INNERS" value="false" /> + </inspection_tool> + <inspection_tool class="WhileLoopSpinsOnField" enabled="true" level="WARNING" enabled_by_default="true"> + <option name="ignoreNonEmtpyLoops" value="false" /> + </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" /> + <option name="PROJECT_PROFILE" value="Project Default" /> + <option name="USE_PROJECT_PROFILE" value="true" /> + <version value="1.0" /> </component> <component name="JavadocGenerationManager"> <option name="OUTPUT_DIRECTORY" /> @@ -140,14 +713,6 @@ <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"> @@ -272,31 +837,17 @@ <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 name="ProjectDictionaryState"> + <dictionary name="kevinb" /> </component> <component name="ProjectModuleManager"> <modules> - <module fileurl="file://$PROJECT_DIR$/core.iml" filepath="$PROJECT_DIR$/core.iml" /> + <module fileurl="file://$PROJECT_DIR$/caliper.iml" filepath="$PROJECT_DIR$/caliper.iml" /> + <module fileurl="file://$PROJECT_DIR$/ideaplugin/ideaplugin.iml" filepath="$PROJECT_DIR$/ideaplugin/ideaplugin.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 name="ProjectRootManager" version="2" languageLevel="JDK_1_5" assert-keyword="true" jdk-15="true" project-jdk-name="1.6" project-jdk-type="JavaSDK"> + <output url="file://$PROJECT_DIR$/ideabuild" /> </component> <component name="SvnBranchConfigurationManager"> <option name="myConfigurationMap"> @@ -304,9 +855,35 @@ <entry key="$PROJECT_DIR$"> <value> <SvnBranchConfiguration> + <option name="branchMap"> + <map> + <entry key="https://caliper.googlecode.com/svn/branches"> + <value> + <list /> + </value> + </entry> + <entry key="https://caliper.googlecode.com/svn/cloud"> + <value> + <list /> + </value> + </entry> + <entry key="https://caliper.googlecode.com/svn/static"> + <value> + <list /> + </value> + </entry> + <entry key="https://caliper.googlecode.com/svn/tags"> + <value> + <list /> + </value> + </entry> + </map> + </option> <option name="branchUrls"> <list> <option value="https://caliper.googlecode.com/svn/branches" /> + <option value="https://caliper.googlecode.com/svn/cloud" /> + <option value="https://caliper.googlecode.com/svn/static" /> <option value="https://caliper.googlecode.com/svn/tags" /> </list> </option> @@ -316,27 +893,10 @@ </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 deleted file mode 100644 index 09f6e96..0000000 --- a/core.iml +++ /dev/null @@ -1,15 +0,0 @@ -<?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/jarjar-1.0rc8.jar b/lib/jarjar-1.0rc8.jar Binary files differnew file mode 100644 index 0000000..89390bf --- /dev/null +++ b/lib/jarjar-1.0rc8.jar diff --git a/src/CaliperCore.gwt.xml b/src/CaliperCore.gwt.xml new file mode 100644 index 0000000..161ac57 --- /dev/null +++ b/src/CaliperCore.gwt.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<module> + <inherits name='com.google.gwt.user.User'/> + <source path="com/google/caliper"> + <include name="**/Run.java"/> + <include name="**/Scenario.java"/> + </source> +</module>
\ No newline at end of file diff --git a/src/com/google/caliper/Arguments.java b/src/com/google/caliper/Arguments.java new file mode 100644 index 0000000..e5ff0f7 --- /dev/null +++ b/src/com/google/caliper/Arguments.java @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2010 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.caliper.UserException.DisplayUsageException; +import com.google.caliper.UserException.MalformedParameterException; +import com.google.caliper.UserException.MultipleBenchmarkClassesException; +import com.google.caliper.UserException.NoBenchmarkClassException; +import com.google.caliper.UserException.UnrecognizedOptionException; +import com.google.common.collect.Iterators; +import com.google.common.collect.LinkedHashMultimap; +import com.google.common.collect.Multimap; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.Set; + +/** + * Parse command line arguments for the runner and in-process runner. + */ +public final class Arguments { + private String suiteClassName; + + /** JVMs to run in the benchmark */ + private final 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 final Multimap<String, String> userParameters = LinkedHashMultimap.create(); + + private long warmupMillis = 5000; + private long runMillis = 5000; + + /** The URL to post benchmark results to. */ + private String postHost = "http://microbenchmarks.appspot.com/run/"; + + public String getSuiteClassName() { + return suiteClassName; + } + + public Set<String> getUserVms() { + return userVms; + } + + public Multimap<String, String> getUserParameters() { + return userParameters; + } + + public long getWarmupMillis() { + return warmupMillis; + } + + public long getRunMillis() { + return runMillis; + } + + public String getPostHost() { + return postHost; + } + + public static Arguments parse(String[] argsArray) { + Arguments result = new Arguments(); + + Iterator<String> args = Iterators.forArray(argsArray); + while (args.hasNext()) { + String arg = args.next(); + + if ("--help".equals(arg)) { + throw new DisplayUsageException(); + } + + if ("--postHost".equals(arg)) { + result.postHost = args.next(); + + } else if (arg.startsWith("-D")) { + int equalsSign = arg.indexOf('='); + if (equalsSign == -1) { + throw new MalformedParameterException(arg); + } + String name = arg.substring(2, equalsSign); + String value = arg.substring(equalsSign + 1); + result.userParameters.put(name, value); + + } else if ("--warmupMillis".equals(arg)) { + result.warmupMillis = Long.parseLong(args.next()); + + } else if ("--runMillis".equals(arg)) { + result.runMillis = Long.parseLong(args.next()); + + } else if ("--vm".equals(arg)) { + result.userVms.add(args.next()); + + } else if (arg.startsWith("-")) { + throw new UnrecognizedOptionException(arg); + + } else { + if (result.suiteClassName != null) { + throw new MultipleBenchmarkClassesException(result.suiteClassName, arg); + } + result.suiteClassName = arg; + } + } + + if (result.suiteClassName == null) { + throw new NoBenchmarkClassException(); + } + + return result; + } + + public static void printUsage() { + Arguments defaults = new Arguments(); + + System.out.println(); + 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(" --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(" --postHost <host>: the URL to post benchmark results to, or \"none\""); + System.out.println(" to skip posting results to the web."); + System.out.println(" default value: " + defaults.postHost); + 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() + } +} diff --git a/src/com/google/caliper/Benchmark.java b/src/com/google/caliper/Benchmark.java index 19426e6..b5d35f9 100644 --- a/src/com/google/caliper/Benchmark.java +++ b/src/com/google/caliper/Benchmark.java @@ -16,7 +16,6 @@ package com.google.caliper; -import java.lang.reflect.Method; import java.util.Map; import java.util.Set; diff --git a/src/com/google/caliper/Caliper.java b/src/com/google/caliper/Caliper.java index 315431f..6c9d625 100644 --- a/src/com/google/caliper/Caliper.java +++ b/src/com/google/caliper/Caliper.java @@ -26,7 +26,7 @@ class Caliper { private final long warmupNanos; private final long runNanos; - public Caliper(long warmupMillis, long runMillis) { + Caliper(long warmupMillis, long runMillis) { checkArgument(warmupMillis > 50); checkArgument(runMillis > 50); @@ -37,15 +37,24 @@ class Caliper { public double warmUp(TimedRunnable timedRunnable) throws Exception { long startNanos = System.nanoTime(); long endNanos = startNanos + warmupNanos; - int trials = 0; long currentNanos; + int netReps = 0; + int reps = 1; + + /* + * Run progressively more reps at a time until we cross our warmup + * threshold. This way any just-in-time compiler will be comfortable running + * multiple iterations of our measurement method. + */ while ((currentNanos = System.nanoTime()) < endNanos) { - timedRunnable.run(1); - trials++; + timedRunnable.run(reps); + netReps += reps; + reps *= 2; } - double nanosPerExecution = (currentNanos - startNanos) / trials; + + double nanosPerExecution = (currentNanos - startNanos) / (double) netReps; if (nanosPerExecution > 1000000000 || nanosPerExecution < 2) { - throw new ConfigurationException("Runtime out of range"); + throw new ConfigurationException("Runtime " + nanosPerExecution + " out of range"); } return nanosPerExecution; } @@ -54,15 +63,51 @@ class Caliper { * 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(TimedRunnable test, double estimatedNanosPerTrial) throws Exception { + public double run(TimedRunnable test, double estimatedNanosPerTrial) + throws Exception { + @SuppressWarnings("NumericCastThatLosesPrecision") int trials = (int) (runNanos / estimatedNanosPerTrial); if (trials == 0) { trials = 1; } + + double nanosPerTrial = measure(test, trials); + + // if the runtime was in the expected range, return it. We're good. + if (isPlausible(estimatedNanosPerTrial, nanosPerTrial)) { + return nanosPerTrial; + } + + // The runtime was outside of the expected range. Perhaps the VM is inlining + // things too aggressively? We'll run more rounds to confirm that the + // runtime scales with the number of trials. + double nanosPerTrial2 = measure(test, trials * 4); + if (isPlausible(nanosPerTrial, nanosPerTrial2)) { + return nanosPerTrial; + } + + throw new ConfigurationException("Measurement error: " + + "runtime isn't proportional to the number of repetitions!"); + } + + /** + * Returns true if the given measurement is consistent with the expected + * measurement. + */ + private boolean isPlausible(double expected, double measurement) { + double ratio = measurement / expected; + return ratio > 0.5 && ratio < 2.0; + } + + private double measure(TimedRunnable test, int trials) throws Exception { + prepareForTest(); long startNanos = System.nanoTime(); test.run(trials); - long endNanos = System.nanoTime(); - estimatedNanosPerTrial = (endNanos - startNanos) / trials; - return estimatedNanosPerTrial; + return (System.nanoTime() - startNanos) / (double) trials; + } + + private void prepareForTest() { + System.gc(); + System.gc(); } }
\ No newline at end of file diff --git a/src/com/google/caliper/ConfigurationException.java b/src/com/google/caliper/ConfigurationException.java index 5ad7bde..c4a35ec 100644 --- a/src/com/google/caliper/ConfigurationException.java +++ b/src/com/google/caliper/ConfigurationException.java @@ -19,13 +19,15 @@ package com.google.caliper; /** * Thrown upon occurrence of a configuration error. */ -public final class ConfigurationException extends RuntimeException { +final class ConfigurationException extends RuntimeException { - public ConfigurationException(String s) { + ConfigurationException(String s) { super(s); } - public ConfigurationException(Throwable cause) { + ConfigurationException(Throwable cause) { super(cause); } + + private static final long serialVersionUID = 0; } diff --git a/src/com/google/caliper/ConsoleReport.java b/src/com/google/caliper/ConsoleReport.java index b367ec4..e59ceb6 100644 --- a/src/com/google/caliper/ConsoleReport.java +++ b/src/com/google/caliper/ConsoleReport.java @@ -16,8 +16,11 @@ package com.google.caliper; -import com.google.common.collect.*; - +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterables; +import com.google.common.collect.LinkedHashMultimap; +import com.google.common.collect.Multimap; +import com.google.common.collect.Ordering; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -39,13 +42,11 @@ import java.util.Map; final class ConsoleReport { private static final int bargraphWidth = 30; - private static final String vmKey = "vm"; - private final List<Parameter> parameters; - private final Result result; - private final List<Run> runs; + private final List<Variable> variables; + private final Run run; + private final List<Scenario> scenarios; - private final double minValue; private final double maxValue; private final double logMaxValue; private final int decimalDigits; @@ -53,53 +54,51 @@ final class ConsoleReport { private final String units; private final int measurementColumnLength; - public ConsoleReport(Result result) { - this.result = result; + ConsoleReport(Run run) { + this.run = run; - double minValue = Double.POSITIVE_INFINITY; - double maxValue = 0; + double min = Double.POSITIVE_INFINITY; + double max = 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(); + List<Variable> variablesBuilder = new ArrayList<Variable>(); + for (Map.Entry<Scenario, Double> entry : run.getMeasurements().entrySet()) { + Scenario scenario = entry.getKey(); double d = entry.getValue(); - minValue = Math.min(minValue, d); - maxValue = Math.max(maxValue, d); + min = Math.min(min, d); + max = Math.max(max, d); - for (Map.Entry<String, String> parameter : run.getParameters().entrySet()) { - String name = parameter.getKey(); - nameToValues.put(name, parameter.getValue()); + for (Map.Entry<String, String> variable : scenario.getVariables().entrySet()) { + String name = variable.getKey(); + nameToValues.put(name, variable.getValue()); } - - 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); + Variable variable = new Variable(entry.getKey(), entry.getValue()); + variablesBuilder.add(variable); } /* - * 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 + * Figure out how much influence each variable has on the measured value. + * We sum the measurements taken with each value of each variable. For + * variable that have influence on the measurement, the sums will differ + * by value. If the variable 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 across each variable's collection of sums. Higher standard * deviation implies higher influence on the measured result. */ double sumOfAllMeasurements = 0; - for (double measurement : result.getMeasurements().values()) { + for (double measurement : run.getMeasurements().values()) { sumOfAllMeasurements += measurement; } - for (Parameter parameter : parametersBuilder) { - int numValues = parameter.values.size(); + for (Variable variable : variablesBuilder) { + int numValues = variable.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(); + for (Map.Entry<Scenario, Double> entry : run.getMeasurements().entrySet()) { + Scenario scenario = entry.getKey(); + sumForValue[variable.index(scenario)] += entry.getValue(); } double mean = sumOfAllMeasurements / sumForValue.length; double stdDeviationSquared = 0; @@ -107,16 +106,15 @@ final class ConsoleReport { double distance = value - mean; stdDeviationSquared += distance * distance; } - parameter.stdDeviation = Math.sqrt(stdDeviationSquared / numValues); + variable.stdDeviation = Math.sqrt(stdDeviationSquared / numValues); } - this.parameters = new StandardDeviationOrdering().reverse().sortedCopy(parametersBuilder); - this.runs = new ByParametersOrdering().sortedCopy(result.getMeasurements().keySet()); - this.minValue = minValue; - this.maxValue = maxValue; - this.logMaxValue = Math.log(maxValue); + this.variables = new StandardDeviationOrdering().reverse().sortedCopy(variablesBuilder); + this.scenarios = new ByVariablesOrdering().sortedCopy(run.getMeasurements().keySet()); + this.maxValue = max; + this.logMaxValue = Math.log(max); - int numDigitsInMin = (int) Math.ceil(Math.log10(minValue)); + int numDigitsInMin = ceil(Math.log10(min)); if (numDigitsInMin > 9) { divideBy = 1000000000; decimalDigits = Math.max(0, 9 + 3 - numDigitsInMin); @@ -134,41 +132,37 @@ final class ConsoleReport { decimalDigits = 0; units = "ns"; } - measurementColumnLength = maxValue > 0 - ? (int) Math.ceil(Math.log10(maxValue / divideBy)) + decimalDigits + 1 + measurementColumnLength = max > 0 + ? ceil(Math.log10(max / divideBy)) + decimalDigits + 1 : 1; } /** - * A parameter plus all of its values. + * A variable and the set of values to which it has been assigned. */ - static class Parameter { + private static class Variable { final String name; final ImmutableList<String> values; final int maxLength; double stdDeviation; - public Parameter(String name, Collection<String> values) { + Variable(String name, Collection<String> values) { this.name = name; this.values = ImmutableList.copyOf(values); - int maxLength = name.length(); + int maxLen = name.length(); for (String value : values) { - maxLength = Math.max(maxLength, value.length()); + maxLen = Math.max(maxLen, value.length()); } - this.maxLength = maxLength; + this.maxLength = maxLen; } - String get(Run run) { - if (vmKey.equals(name)) { - return run.getVm(); - } else { - return run.getParameters().get(name); - } + String get(Scenario scenario) { + return scenario.getVariables().get(name); } - int index(Run run) { - return values.indexOf(get(run)); + int index(Scenario scenario) { + return values.indexOf(get(scenario)); } boolean isInteresting() { @@ -177,23 +171,23 @@ final class ConsoleReport { } /** - * Orders the different parameters by their standard deviation. This results + * Orders the different variables 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) { + private static class StandardDeviationOrdering extends Ordering<Variable> { + public int compare(Variable a, Variable b) { return Double.compare(a.stdDeviation, b.stdDeviation); } } /** - * Orders runs by the parameters. + * Orders scenarios by the variables. */ - 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)); + private class ByVariablesOrdering extends Ordering<Scenario> { + public int compare(Scenario a, Scenario b) { + for (Variable variable : variables) { + int aValue = variable.values.indexOf(variable.get(a)); + int bValue = variable.values.indexOf(variable.get(b)); int diff = aValue - bValue; if (diff != 0) { return diff; @@ -206,7 +200,7 @@ final class ConsoleReport { void displayResults() { printValues(); System.out.println(); - printUninterestingParameters(); + printUninterestingVariables(); } /** @@ -214,33 +208,33 @@ final class ConsoleReport { */ private void printValues() { // header - for (Parameter parameter : parameters) { - if (parameter.isInteresting()) { - System.out.printf("%" + parameter.maxLength + "s ", parameter.name); + for (Variable variable : variables) { + if (variable.isInteresting()) { + System.out.printf("%" + variable.maxLength + "s ", variable.name); } } System.out.printf("%" + measurementColumnLength + "s logarithmic runtime%n", units); // rows 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)); + for (Scenario scenario : scenarios) { + for (Variable variable : variables) { + if (variable.isInteresting()) { + System.out.printf("%" + variable.maxLength + "s ", variable.get(scenario)); } } - double measurement = result.getMeasurements().get(run); + double measurement = run.getMeasurements().get(scenario); System.out.printf(numbersFormat, measurement / divideBy, bargraph(measurement)); } } /** - * Prints parameters with only one unique value. + * Prints variables with only one unique value. */ - private void printUninterestingParameters() { - for (Parameter parameter : parameters) { - if (!parameter.isInteresting()) { - System.out.println(parameter.name + ": " + Iterables.getOnlyElement(parameter.values)); + private void printUninterestingVariables() { + for (Variable variable : variables) { + if (!variable.isInteresting()) { + System.out.println(variable.name + ": " + Iterables.getOnlyElement(variable.values)); } } } @@ -250,17 +244,27 @@ final class ConsoleReport { * value. */ private String bargraph(double value) { - int numLinearChars = (int) ((value / maxValue) * bargraphWidth); + int numLinearChars = floor(value / maxValue * bargraphWidth); double logValue = Math.log(value); - int numChars = (int) ((logValue / logMaxValue) * bargraphWidth); - StringBuilder result = new StringBuilder(numChars); + int numChars = floor(logValue / logMaxValue * bargraphWidth); + StringBuilder sb = new StringBuilder(numChars); for (int i = 0; i < numLinearChars; i++) { - result.append("X"); + sb.append("X"); } for (int i = numLinearChars; i < numChars; i++) { - result.append("|"); + sb.append("|"); } - return result.toString(); + return sb.toString(); + } + + @SuppressWarnings("NumericCastThatLosesPrecision") + private static int floor(double d) { + return (int) d; + } + + @SuppressWarnings("NumericCastThatLosesPrecision") + private static int ceil(double d) { + return (int) Math.ceil(d); } } diff --git a/src/com/google/caliper/InProcessRunner.java b/src/com/google/caliper/InProcessRunner.java new file mode 100644 index 0000000..33e9e00 --- /dev/null +++ b/src/com/google/caliper/InProcessRunner.java @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2010 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.caliper.UserException.CantCustomizeInProcessVmException; +import com.google.caliper.UserException.ExceptionFromUserCodeException; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintStream; + +/** + * Executes a benchmark in the current VM. + */ +final class InProcessRunner { + + public void run(String... args) { + Arguments arguments = Arguments.parse(args); + + if (!arguments.getUserVms().isEmpty()) { + throw new CantCustomizeInProcessVmException(); + } + + ScenarioSelection scenarioSelection = new ScenarioSelection(arguments); + + PrintStream resultStream = System.out; + System.setOut(nullPrintStream()); + System.setErr(nullPrintStream()); + + try { + Caliper caliper = new Caliper(arguments.getWarmupMillis(), arguments.getRunMillis()); + + for (Scenario scenario : scenarioSelection.select()) { + TimedRunnable timedRunnable = scenarioSelection.createBenchmark(scenario); + double warmupNanosPerTrial = caliper.warmUp(timedRunnable); + double nanosPerTrial = caliper.run(timedRunnable, warmupNanosPerTrial); + resultStream.println(nanosPerTrial); + } + } catch (Exception e) { + throw new ExceptionFromUserCodeException(e); + } + } + + public static void main(String... args) { + try { + new InProcessRunner().run(args); + } catch (UserException e) { + e.display(); // TODO: send this to the host process + System.exit(1); + } + } + + public PrintStream nullPrintStream() { + return new PrintStream(new OutputStream() { + public void write(int b) throws IOException {} + }); + } +} diff --git a/src/com/google/caliper/Param.java b/src/com/google/caliper/Param.java index 28d3588..bea0269 100644 --- a/src/com/google/caliper/Param.java +++ b/src/com/google/caliper/Param.java @@ -26,4 +26,11 @@ import java.lang.annotation.Target; */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) -public @interface Param {} +public @interface Param { + /** + * One or more default values, as strings, that this parameter should be given if none are + * specified on the command line. If values are specified on the command line, the defaults given + * here are all ignored. + */ + String[] value() default {}; +} diff --git a/src/com/google/caliper/Parameter.java b/src/com/google/caliper/Parameter.java index 1ba77b5..caca252 100644 --- a/src/com/google/caliper/Parameter.java +++ b/src/com/google/caliper/Parameter.java @@ -16,8 +16,19 @@ package com.google.caliper; -import java.lang.reflect.*; -import java.util.*; +import java.lang.reflect.Field; +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.EnumSet; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; /** * A parameter in a {@link SimpleBenchmark}. @@ -35,22 +46,35 @@ abstract class Parameter<T> { */ public static Map<String, Parameter<?>> forClass(Class<? extends Benchmark> suiteClass) { Map<String, Parameter<?>> parameters = new TreeMap<String, Parameter<?>>(); - for (final Field field : suiteClass.getDeclaredFields()) { + for (Field field : suiteClass.getDeclaredFields()) { if (field.isAnnotationPresent(Param.class)) { field.setAccessible(true); - Parameter parameter = Parameter.forField(suiteClass, field); + Parameter<?> parameter = forField(suiteClass, field); parameters.put(parameter.getName(), parameter); } } return parameters; } - public static Parameter forField( + private static Parameter<?> forField( Class<? extends Benchmark> suiteClass, final Field field) { - Parameter result = null; + // First check for String values on the annotation itself + final Object[] defaults = field.getAnnotation(Param.class).value(); + if (defaults.length > 0) { + return new Parameter<Object>(field) { + @Override public Collection<Object> values() throws Exception { + return Arrays.asList(defaults); + } + }; + // TODO: or should we continue so we can give an error/warning if params are also give in a + // method or field? + } + + Parameter<?> result = null; Type returnType = null; Member member = null; + // Now check for a fooValues() method try { final Method valuesMethod = suiteClass.getDeclaredMethod(field.getName() + "Values"); valuesMethod.setAccessible(true); @@ -58,13 +82,14 @@ abstract class Parameter<T> { returnType = valuesMethod.getGenericReturnType(); result = new Parameter<Object>(field) { @SuppressWarnings("unchecked") // guarded below - public Collection<Object> values() throws Exception { + @Override public Collection<Object> values() throws Exception { return (Collection<Object>) valuesMethod.invoke(null); } }; } catch (NoSuchMethodException ignored) { } + // Now check for a fooValues field try { final Field valuesField = suiteClass.getDeclaredField(field.getName() + "Values"); valuesField.setAccessible(true); @@ -75,36 +100,58 @@ abstract class Parameter<T> { returnType = valuesField.getGenericType(); result = new Parameter<Object>(field) { @SuppressWarnings("unchecked") // guarded below - public Collection<Object> values() throws Exception { + @Override 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 (member != null && !Modifier.isStatic(member.getModifiers())) { + throw new ConfigurationException("Values member must be static " + member); + } + + // If there isn't a values member but the parameter is an enum, we default + // to EnumSet.allOf. + if (member == null && field.getType().isEnum()) { + returnType = Collection.class; + result = new Parameter<Object>(field) { + // TODO: figure out the simplest way to make this compile and be green in IDEA too + @SuppressWarnings({"unchecked", "RawUseOfParameterizedType", "RedundantCast"}) + // guarded above + @Override public Collection<Object> values() throws Exception { + Set<Enum> set = EnumSet.allOf((Class<Enum>) field.getType()); + return (Collection) set; + } + }; } - if (!Modifier.isStatic(member.getModifiers())) { - throw new ConfigurationException("Values member must be static " + member); + if (result == null) { + return new Parameter<Object>(field) { + @Override public Collection<Object> values() { + // TODO: need tests to make sure this fails properly when no cmdline params given and + // works properly when they are given + return Collections.emptySet(); + } + }; + } else if (!isValidReturnType(returnType)) { + throw new ConfigurationException("Invalid return type " + returnType + + " for values member " + member + "; must be Collection"); } + return result; + } - // validate return type - boolean valid = false; + private static boolean isValidReturnType(Type returnType) { + if (returnType == Collection.class) { + return true; + } if (returnType instanceof ParameterizedType) { ParameterizedType type = (ParameterizedType) returnType; if (type.getRawType() == Collection.class) { - valid = true; + return true; } } - - if (!valid) { - throw new ConfigurationException("Invalid return type " + returnType - + " for values member " + member + "; must be Collection"); - } - - return result; + return false; } /** @@ -129,7 +176,7 @@ abstract class Parameter<T> { /** * Returns the field's name. */ - public String getName() { + String getName() { return field.getName(); } -}
\ No newline at end of file +} diff --git a/src/com/google/caliper/Run.java b/src/com/google/caliper/Run.java index a9109de..f2e71de 100644 --- a/src/com/google/caliper/Run.java +++ b/src/com/google/caliper/Run.java @@ -1,4 +1,4 @@ -/* +/** * Copyright (C) 2009 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,33 +16,77 @@ package com.google.caliper; -import com.google.common.collect.ImmutableMap; - -import java.lang.reflect.Method; +import java.io.Serializable; +import java.util.Date; +import java.util.LinkedHashMap; import java.util.Map; /** - * A configured benchmark. + * The complete result of a benchmark suite run. + * + * <p>Gwt-safe. */ -final class Run { +public final class Run + implements Serializable /* for GWT Serialization */ { + + private /*final*/ Map<Scenario, Double> measurements; + private /*final*/ String benchmarkName; + private /*final*/ String executedByUuid; + private /*final*/ long executedTimestamp; - private final ImmutableMap<String, String> parameters; - private final String vm; + // TODO: add more run properites such as checksums of the executed code - public Run(Map<String, String> parameters, String vm) { - this.parameters = ImmutableMap.copyOf(parameters); - this.vm = vm; + public Run(Map<Scenario, Double> measurements, + String benchmarkName, String executedByUuid, Date executedTimestamp) { + if (benchmarkName == null || executedByUuid == null || executedTimestamp == null) { + throw new NullPointerException(); + } + + this.measurements = new LinkedHashMap<Scenario, Double>(measurements); + this.benchmarkName = benchmarkName; + this.executedByUuid = executedByUuid; + this.executedTimestamp = executedTimestamp.getTime(); + } + + public Map<Scenario, Double> getMeasurements() { + return measurements; } - public ImmutableMap<String, String> getParameters() { - return parameters; + public String getBenchmarkName() { + return benchmarkName; } - public String getVm() { - return vm; + public String getExecutedByUuid() { + return executedByUuid; + } + + public Date getExecutedTimestamp() { + return new Date(executedTimestamp); + } + + @Override public boolean equals(Object o) { + if (o instanceof Run) { + Run that = (Run) o; + return measurements.equals(that.measurements) + && benchmarkName.equals(that.benchmarkName) + && executedByUuid.equals(that.executedByUuid) + && executedTimestamp == that.executedTimestamp; + } + + return false; + } + + @Override public int hashCode() { + int result = measurements.hashCode(); + result = result * 37 + benchmarkName.hashCode(); + result = result * 37 + executedByUuid.hashCode(); + result = result * 37 + (int) ((executedTimestamp >> 32) ^ executedTimestamp); + return result; } @Override public String toString() { - return "Run" + parameters; + return measurements.toString(); } + + private Run() {} // for GWT Serialization } diff --git a/src/com/google/caliper/Runner.java b/src/com/google/caliper/Runner.java index 72442db..e359df8 100644 --- a/src/com/google/caliper/Runner.java +++ b/src/com/google/caliper/Runner.java @@ -16,180 +16,113 @@ package com.google.caliper; +import com.google.caliper.UserException.ExceptionFromUserCodeException; import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.LinkedHashMultimap; -import com.google.common.collect.Multimap; - +import com.google.common.collect.ImmutableMap.Builder; +import com.google.common.collect.ObjectArrays; import java.io.BufferedReader; import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.util.*; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.Arrays; +import java.util.Date; +import java.util.List; +import java.util.Map.Entry; +import java.util.Properties; +import java.util.UUID; /** * Creates, executes and reports benchmark runs. */ public final class Runner { - private String suiteClassName; - private Benchmark 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(); - - /** - * True if each benchmark should run in process. - */ - private boolean inProcess; - - private long warmupMillis = 5000; - private long runMillis = 5000; + /** Command line arguments to the process */ + private Arguments arguments; + private ScenarioSelection scenarioSelection; /** - * 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. + * Returns the UUID of the executing host. Multiple runs by the same user on + * the same machine should yield the same result. */ - void setParameter(String name, String value) { - userParameters.put(name, value); - } - - private void prepareSuite() { + private String getExecutedByUuid() { try { - @SuppressWarnings("unchecked") // guarded by the if statement that follows - Class<? extends Benchmark> suiteClass - = (Class<? extends Benchmark>) Class.forName(suiteClassName); - if (!Benchmark.class.isAssignableFrom(suiteClass)) { - throw new ConfigurationException(suiteClass + " is not a benchmark suite."); + File dotCaliperRc = new File(System.getProperty("user.home"), ".caliperrc"); + Properties properties = new Properties(); + if (dotCaliperRc.exists()) { + properties.load(new FileInputStream(dotCaliperRc)); } - Constructor<? extends Benchmark> 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); + String userUuid = properties.getProperty("userUuid"); + if (userUuid == null) { + userUuid = UUID.randomUUID().toString(); + properties.setProperty("userUuid", userUuid); + properties.store(new FileOutputStream(dotCaliperRc), ""); } + + return userUuid; + } catch (IOException e) { + throw new RuntimeException(e); } } - private ImmutableSet<String> defaultVms() { - return "Dalvik".equals(System.getProperty("java.vm.name")) - ? ImmutableSet.of("dalvikvm") - : ImmutableSet.of("java"); + public void run(String... args) { + this.arguments = Arguments.parse(args); + this.scenarioSelection = new ScenarioSelection(arguments); + Run run = runOutOfProcess(); + new ConsoleReport(run).displayResults(); + postResults(run); } - /** - * 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 VMs - Set<String> vms = userVms.isEmpty() - ? defaultVms() - : userVms; - for (String vm : vms) { - RunBuilder runBuilder = new RunBuilder(); - runBuilder.vm = vm; - builders.add(runBuilder); + private void postResults(Run run) { + String postHost = arguments.getPostHost(); + if ("none".equals(postHost)) { + return; } - 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); + try { + URL url = new URL(postHost + run.getExecutedByUuid() + "/" + run.getBenchmarkName()); + HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection(); + urlConnection.setDoOutput(true); + Xml.runToXml(run, urlConnection.getOutputStream()); + if (urlConnection.getResponseCode() == 200) { + System.out.println(""); + System.out.println("View current and previous benchmark results online:"); + System.out.println(" " + url); + return; } - // multiply the size of the specs by the number of alternate values - int size = builders.size(); - while (values.hasNext()) { - String alternate = values.next(); - for (int s = 0; s < size; s++) { - RunBuilder copy = builders.get(s).copy(); - copy.parameters.put(key, alternate); - builders.add(copy); - } + System.out.println("Posting to " + postHost + " failed: " + + urlConnection.getResponseMessage()); + BufferedReader reader = new BufferedReader( + new InputStreamReader(urlConnection.getInputStream())); + String line; + while ((line = reader.readLine()) != null) { + System.out.println(line); } - } - - 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>(); - String vm; - - RunBuilder copy() { - RunBuilder result = new RunBuilder(); - result.parameters.putAll(parameters); - result.vm = vm; - return result; - } - - public Run build() { - return new Run(parameters, vm); + } catch (IOException e) { + throw new RuntimeException(e); } } - private double executeForked(Run run) { + private double executeForked(Scenario scenario) { ProcessBuilder builder = new ProcessBuilder(); List<String> command = builder.command(); - command.addAll(Arrays.asList(run.getVm().split("\\s+"))); + command.addAll(Arrays.asList(scenario.getVariables().get(Scenario.VM_KEY).split("\\s+"))); command.add("-cp"); command.add(System.getProperty("java.class.path")); - command.add(Runner.class.getName()); + command.add(InProcessRunner.class.getName()); command.add("--warmupMillis"); - command.add(String.valueOf(warmupMillis)); + command.add(String.valueOf(arguments.getWarmupMillis())); command.add("--runMillis"); - command.add(String.valueOf(runMillis)); - command.add("--inProcess"); - for (Map.Entry<String, String> entry : run.getParameters().entrySet()) { + command.add(String.valueOf(arguments.getRunMillis())); + for (Entry<String, String> entry : scenario.getParameters().entrySet()) { command.add("-D" + entry.getKey() + "=" + entry.getValue()); } - command.add(suiteClassName); + command.add(arguments.getSuiteClassName()); BufferedReader reader = null; try { @@ -202,7 +135,7 @@ public final class Runner { Double nanosPerTrial = null; try { nanosPerTrial = Double.valueOf(firstLine); - } catch (NumberFormatException e) { + } catch (NumberFormatException ignore) { } String anotherLine = reader.readLine(); @@ -229,163 +162,63 @@ public final class Runner { } } - private Result runOutOfProcess() { - ImmutableMap.Builder<Run, Double> resultsBuilder = ImmutableMap.builder(); + // TODO: check if this is platform-independent + @SuppressWarnings("HardcodedLineSeparator") + private static final String RETURN = "\r"; + + private Run runOutOfProcess() { + String executedByUuid = getExecutedByUuid(); + Date executedDate = new Date(); + Builder<Scenario, Double> resultsBuilder = ImmutableMap.builder(); try { - List<Run> runs = createRuns(); + List<Scenario> scenarios = scenarioSelection.select(); int i = 0; - for (Run run : runs) { - beforeRun(i++, runs.size(), run); - double nanosPerTrial = executeForked(run); - afterRun(nanosPerTrial); - resultsBuilder.put(run, nanosPerTrial); + for (Scenario scenario : scenarios) { + beforeMeasurement(i++, scenarios.size(), scenario); + double nanosPerTrial = executeForked(scenario); + afterMeasurement(nanosPerTrial); + resultsBuilder.put(scenario, nanosPerTrial); } // blat out our progress bar - System.out.print("\r"); + System.out.print(RETURN); for (int j = 0; j < 80; j++) { System.out.print(" "); } - System.out.print("\r"); + System.out.print(RETURN); - return new Result(resultsBuilder.build()); + return new Run(resultsBuilder.build(), arguments.getSuiteClassName(), executedByUuid, executedDate); } catch (Exception e) { - throw new ExecutionException(e); + throw new ExceptionFromUserCodeException(e); } } - private void beforeRun(int index, int total, Run run) { + private void beforeMeasurement(int index, int total, Scenario scenario) { double percentDone = (double) index / total; int runStringLength = 63; // so the total line length is 80 - String runString = String.valueOf(run); + String runString = String.valueOf(scenario); if (runString.length() > runStringLength) { runString = runString.substring(0, runStringLength); } - System.out.printf("\r%2.0f%% %-" + runStringLength + "s", + System.out.printf(RETURN + "%2.0f%% %-" + runStringLength + "s", percentDone * 100, runString); } - private void afterRun(double nanosPerTrial) { + private void afterMeasurement(double nanosPerTrial) { System.out.printf(" %10.0fns", nanosPerTrial); } - private void runInProcess() { + public static void main(String... args) { try { - Caliper caliper = new Caliper(warmupMillis, runMillis); - - for (Run run : createRuns()) { - double result; - TimedRunnable timedRunnable = suite.createBenchmark(run.getParameters()); - double warmupNanosPerTrial = caliper.warmUp(timedRunnable); - result = caliper.run(timedRunnable, warmupNanosPerTrial); - double nanosPerTrial = result; - System.out.println(nanosPerTrial); - } - } catch (Exception e) { - throw new ExecutionException(e); - } - } - - private boolean parseArgs(String[] args) throws Exception { - for (int i = 0; i < args.length; i++) { - if ("--help".equals(args[i])) { - return false; - - } 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(" --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) throws Exception { // TODO: cleaner error reporting - Runner runner = new Runner(); - if (!runner.parseArgs(args)) { - runner.printUsage(); - return; + new Runner().run(args); + } catch (UserException e) { + e.display(); + System.exit(1); } - - runner.prepareSuite(); - runner.prepareParameters(); - if (runner.inProcess) { - runner.runInProcess(); - return; - } - - Result result = runner.runOutOfProcess(); - new ConsoleReport(result).displayResults(); } - public static void main(Class<? extends Benchmark> suite, String... args) throws Exception { - String[] argsWithSuiteName = new String[args.length + 1]; - System.arraycopy(args, 0, argsWithSuiteName, 0, args.length); - argsWithSuiteName[args.length] = suite.getName(); - main(argsWithSuiteName); + public static void main(Class<? extends Benchmark> suite, String... args) { + main(ObjectArrays.concat(args, suite.getName())); } } diff --git a/src/com/google/caliper/Scenario.java b/src/com/google/caliper/Scenario.java new file mode 100644 index 0000000..3fd06e4 --- /dev/null +++ b/src/com/google/caliper/Scenario.java @@ -0,0 +1,81 @@ +/* + * 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.io.Serializable; +import java.util.Arrays; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; + +/** + * A configured benchmark. + * + * <p>Gwt-safe. + */ +public final class Scenario + implements Serializable /* for GWT */ { + + static final String VM_KEY = "vm"; + + /** + * The subset of variable names that are managed by the system. It is an error + * to create a parameter with the same name as one of these variables. + */ + static final Set<String> SYSTEM_VARIABLES = new HashSet<String>(Arrays.asList(VM_KEY)); + + private /*final*/ Map<String, String> variables; + + public Scenario(Map<String, String> variables) { + this.variables = new LinkedHashMap<String, String>(variables); + } + + public Map<String, String> getVariables() { + return variables; + } + + /** + * Returns the user-specified parameters. This is the (possibly-empty) set of + * variables that may be varied from scenario to scenario in the same + * environment. + */ + public Map<String, String> getParameters() { + Map<String, String> result = new LinkedHashMap<String, String>(); + for (Map.Entry<String, String> entry : variables.entrySet()) { + if (!SYSTEM_VARIABLES.contains(entry.getKey())) { + result.put(entry.getKey(), entry.getValue()); + } + } + return result; + } + + @Override public boolean equals(Object o) { + return o instanceof Scenario + && ((Scenario) o).getVariables().equals(variables); + } + + @Override public int hashCode() { + return variables.hashCode(); + } + + @Override public String toString() { + return "Scenario" + variables; + } + + private Scenario() {} // for GWT +} diff --git a/src/com/google/caliper/ScenarioSelection.java b/src/com/google/caliper/ScenarioSelection.java new file mode 100644 index 0000000..7814818 --- /dev/null +++ b/src/com/google/caliper/ScenarioSelection.java @@ -0,0 +1,208 @@ +/* + * Copyright (C) 2010 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.caliper.UserException.AbstractBenchmarkException; +import com.google.caliper.UserException.DoesntImplementBenchmarkException; +import com.google.caliper.UserException.ExceptionFromUserCodeException; +import com.google.caliper.UserException.NoParameterlessConstructorException; +import com.google.caliper.UserException.NoSuchClassException; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.LinkedHashMultimap; +import com.google.common.collect.Multimap; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +/** + * Figures out which scenarios to benchmark given a benchmark suite, set of user + * parameters, and set of user VMs. + */ +public final class ScenarioSelection { + + private final String suiteClassName; + private final Multimap<String, String> userParameters; + private final Set<String> userVms; + + private Benchmark suite; + + /** Effective parameters to run in the benchmark. */ + private final Multimap<String, String> parameters = LinkedHashMultimap.create(); + + public ScenarioSelection(Arguments arguments) { + this(arguments.getSuiteClassName(), arguments.getUserParameters(), arguments.getUserVms()); + } + + public ScenarioSelection(String suiteClassName, + Multimap<String, String> userParameters, Set<String> userVms) { + this.suiteClassName = suiteClassName; + this.userParameters = userParameters; + this.userVms = userVms; + } + + /** + * Returns the selected scenarios for this benchmark. + */ + public List<Scenario> select() { + prepareSuite(); + prepareParameters(); + return createScenarios(); + } + + public TimedRunnable createBenchmark(Scenario scenario) { + return suite.createBenchmark(scenario.getParameters()); + } + + private void prepareSuite() { + Class<?> benchmarkClass; + try { + benchmarkClass = getClassByName(suiteClassName); + } catch (ExceptionInInitializerError e) { + throw new ExceptionFromUserCodeException(e.getCause()); + } catch (ClassNotFoundException ignored) { + throw new NoSuchClassException(suiteClassName); + } + + Object s; + try { + Constructor<?> constructor = benchmarkClass.getDeclaredConstructor(); + constructor.setAccessible(true); + s = constructor.newInstance(); + } catch (InstantiationException ignore) { + throw new AbstractBenchmarkException(benchmarkClass); + } catch (NoSuchMethodException ignore) { + throw new NoParameterlessConstructorException(benchmarkClass); + } catch (IllegalAccessException impossible) { + throw new AssertionError(impossible); // shouldn't happen since we setAccessible(true) + } catch (InvocationTargetException e) { + throw new ExceptionFromUserCodeException(e.getCause()); + } + + if (s instanceof Benchmark) { + this.suite = (Benchmark) s; + } else { + throw new DoesntImplementBenchmarkException(benchmarkClass); + } + } + + private static Class<?> getClassByName(String className) throws ClassNotFoundException { + try { + return Class.forName(className); + } catch (ClassNotFoundException ignored) { + // try replacing the last dot with a $, in case that helps + // example: tutorial.Tutorial.Benchmark1 becomes tutorial.Tutorial$Benchmark1 + // amusingly, the $ character means three different things in this one line alone + String newName = className.replaceFirst("\\.([^.]+)$", "\\$$1"); + return Class.forName(newName); + } + } + + 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); + } + } + } + + private ImmutableSet<String> defaultVms() { + return "Dalvik".equals(System.getProperty("java.vm.name")) + ? ImmutableSet.of("dalvikvm") + : ImmutableSet.of("java"); + } + + /** + * Returns a complete set of scenarios with every combination of values and + * benchmark classes. + */ + private List<Scenario> createScenarios() { + List<ScenarioBuilder> builders = new ArrayList<ScenarioBuilder>(); + + // create scenarios for each VM + Set<String> vms = userVms.isEmpty() + ? defaultVms() + : userVms; + for (String vm : vms) { + ScenarioBuilder scenarioBuilder = new ScenarioBuilder(); + scenarioBuilder.parameters.put(Scenario.VM_KEY, vm); + builders.add(scenarioBuilder); + } + + for (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 (ScenarioBuilder builder : builders) { + builder.parameters.put(key, firstValue); + } + + // multiply the size of the specs by the number of alternate values + int size = builders.size(); + while (values.hasNext()) { + String alternate = values.next(); + for (int s = 0; s < size; s++) { + ScenarioBuilder copy = builders.get(s).copy(); + copy.parameters.put(key, alternate); + builders.add(copy); + } + } + } + + List<Scenario> result = new ArrayList<Scenario>(); + for (ScenarioBuilder builder : builders) { + result.add(builder.build()); + } + + return result; + } + + private static class ScenarioBuilder { + final Map<String, String> parameters = new LinkedHashMap<String, String>(); + + ScenarioBuilder copy() { + ScenarioBuilder result = new ScenarioBuilder(); + result.parameters.putAll(parameters); + return result; + } + + public Scenario build() { + return new Scenario(parameters); + } + } +} diff --git a/src/com/google/caliper/SimpleBenchmark.java b/src/com/google/caliper/SimpleBenchmark.java index 8d2d4b1..31ff6c9 100644 --- a/src/com/google/caliper/SimpleBenchmark.java +++ b/src/com/google/caliper/SimpleBenchmark.java @@ -16,12 +16,11 @@ package com.google.caliper; +import com.google.caliper.UserException.ExceptionFromUserCodeException; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; - import java.lang.reflect.Method; import java.lang.reflect.Modifier; -import java.lang.reflect.Type; import java.util.Arrays; import java.util.Collection; import java.util.Map; @@ -88,34 +87,31 @@ public abstract class SimpleBenchmark implements Benchmark { return methods.keySet(); } + Parameter<?> parameter = parameters.get(parameterName); + if (parameter == null) { + throw new IllegalArgumentException(); + } try { - TypeConverter typeConverter = new TypeConverter(); - Parameter<?> parameter = parameters.get(parameterName); - if (parameter == null) { - throw new IllegalArgumentException(); - } Collection<?> values = parameter.values(); - Type type = parameter.getType(); ImmutableSet.Builder<String> result = ImmutableSet.builder(); for (Object value : values) { - result.add(typeConverter.toString(value, type)); + result.add(String.valueOf(value)); } return result.build(); } catch (Exception e) { - throw new ExecutionException(e); + throw new ExceptionFromUserCodeException(e); } } public TimedRunnable createBenchmark(Map<String, String> parameterValues) { - TypeConverter typeConverter = new TypeConverter(); - if (!parameterNames().equals(parameterValues.keySet())) { throw new IllegalArgumentException("Invalid parameters specified. Expected " + parameterNames() + " but was " + parameterValues.keySet()); } try { + @SuppressWarnings({"ClassNewInstance"}) // can throw any Exception, so we catch all Exceptions final SimpleBenchmark copyOfSelf = getClass().newInstance(); final Method method = methods.get(parameterValues.get("benchmark")); @@ -125,8 +121,8 @@ public abstract class SimpleBenchmark implements Benchmark { continue; } - Parameter parameter = parameters.get(parameterName); - Object value = typeConverter.fromString(entry.getValue(), parameter.getType()); + Parameter<?> parameter = parameters.get(parameterName); + Object value = TypeConverter.fromString(entry.getValue(), parameter.getType()); parameter.set(copyOfSelf, value); } copyOfSelf.setUp(); @@ -138,7 +134,7 @@ public abstract class SimpleBenchmark implements Benchmark { }; } catch (Exception e) { - throw new ExecutionException(e); + throw new ExceptionFromUserCodeException(e); } } @@ -148,7 +144,7 @@ public abstract class SimpleBenchmark implements Benchmark { */ private Map<String, Method> createTimedMethods() { ImmutableMap.Builder<String, Method> result = ImmutableMap.builder(); - for (final Method method : getClass().getDeclaredMethods()) { + for (Method method : getClass().getDeclaredMethods()) { int modifiers = method.getModifiers(); if (!method.getName().startsWith("time")) { continue; diff --git a/src/com/google/caliper/TypeConverter.java b/src/com/google/caliper/TypeConverter.java index 73300ec..29d00ea 100644 --- a/src/com/google/caliper/TypeConverter.java +++ b/src/com/google/caliper/TypeConverter.java @@ -16,42 +16,44 @@ package com.google.caliper; +import com.google.common.collect.ImmutableMap; +import java.lang.reflect.Method; import java.lang.reflect.Type; +import java.util.Map; /** * Convert objects to and from Strings. */ -class TypeConverter { +final class TypeConverter { + private 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); - } + public static Object fromString(String value, Type type) { + Class<?> c = wrap((Class<?>) type); + try { + Method m = c.getMethod("valueOf", String.class); + return m.invoke(null, value); + } catch (Exception e) { + throw new UnsupportedOperationException( + "Cannot convert " + value + " of type " + type, e); } - 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); + // safe because both Long.class and long.class are of type Class<Long> + @SuppressWarnings("unchecked") + private static <T> Class<T> wrap(Class<T> c) { + return c.isPrimitive() ? (Class<T>) PRIMITIVES_TO_WRAPPERS.get(c) : c; } + + private static final Map<Class<?>, Class<?>> PRIMITIVES_TO_WRAPPERS + = new ImmutableMap.Builder<Class<?>, Class<?>>() + .put(boolean.class, Boolean.class) + .put(byte.class, Byte.class) + .put(char.class, Character.class) + .put(double.class, Double.class) + .put(float.class, Float.class) + .put(int.class, Integer.class) + .put(long.class, Long.class) + .put(short.class, Short.class) + .put(void.class, Void.class) + .build(); } diff --git a/src/com/google/caliper/UserException.java b/src/com/google/caliper/UserException.java new file mode 100644 index 0000000..66fb8e3 --- /dev/null +++ b/src/com/google/caliper/UserException.java @@ -0,0 +1,141 @@ +/* + * 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.Arrays; + +/** + * Signifies a problem that should be explained in user-friendly terms on the command line, without + * a confusing stack trace, and optionally followed by a usage summary. + */ +@SuppressWarnings("serial") // never going to serialize these... right? +public abstract class UserException extends RuntimeException { + protected final String error; + + protected UserException(String error) { + this.error = error; + } + + public abstract void display(); + + // - - - - + + public abstract static class ErrorInUsageException extends UserException { + protected ErrorInUsageException(String error) { + super(error); + } + + @Override public void display() { + if (error != null) { + System.err.println("Error: " + error); + } + Arguments.printUsage(); + } + } + + public abstract static class ErrorInUserCodeException extends UserException { + private final String remedy; + + protected ErrorInUserCodeException(String error, String remedy) { + super(error); + this.remedy = remedy; + } + + @Override public void display() { + System.err.println("Error: " + error); + System.err.println("Typical Remedy: " + remedy); + } + } + + // - - - - + + // Not technically an error, but works nicely this way anyway + public static class DisplayUsageException extends ErrorInUsageException { + public DisplayUsageException() { + super(null); + } + } + + public static class UnrecognizedOptionException extends ErrorInUsageException { + public UnrecognizedOptionException(String arg) { + super("Argument not recognized: " + arg); + } + } + + public static class NoBenchmarkClassException extends ErrorInUsageException { + public NoBenchmarkClassException() { + super("No benchmark class specified."); + } + } + + public static class MultipleBenchmarkClassesException extends ErrorInUsageException { + public MultipleBenchmarkClassesException(String a, String b) { + super("Multiple benchmark classes specified: " + Arrays.asList(a, b)); + } + } + + public static class MalformedParameterException extends ErrorInUsageException { + public MalformedParameterException(String arg) { + super("Malformed parameter: " + arg); + } + } + + public static class CantCustomizeInProcessVmException extends ErrorInUsageException { + public CantCustomizeInProcessVmException() { + super("Can't customize VM when running in process."); + } + } + + public static class NoSuchClassException extends ErrorInUsageException { + public NoSuchClassException(String name) { + super("No class named [" + name + "] was found (check CLASSPATH)."); + } + } + + + public static class AbstractBenchmarkException extends ErrorInUserCodeException { + public AbstractBenchmarkException(Class<?> specifiedClass) { + super("Class [" + specifiedClass.getName() + "] is abstract.", "Specify a concrete class."); + } + } + + public static class NoParameterlessConstructorException extends ErrorInUserCodeException { + public NoParameterlessConstructorException(Class<?> specifiedClass) { + super("Class [" + specifiedClass.getName() + "] has no parameterless constructor.", + "Remove all constructors or add a parameterless constructor."); + } + } + + public static class DoesntImplementBenchmarkException extends ErrorInUserCodeException { + public DoesntImplementBenchmarkException(Class<?> specifiedClass) { + super("Class [" + specifiedClass + "] does not implement the " + Benchmark.class.getName() + + " interface.", "Add 'extends " + SimpleBenchmark.class + "' to the class declaration."); + } + } + + // TODO: should remove the caliper stack frames.... + public static class ExceptionFromUserCodeException extends UserException { + public ExceptionFromUserCodeException(Throwable t) { + super("An exception was thrown from the benchmark code."); + initCause(t); + } + @Override public void display() { + System.err.println(error); + getCause().printStackTrace(System.err); + } + } +} diff --git a/src/com/google/caliper/Xml.java b/src/com/google/caliper/Xml.java new file mode 100644 index 0000000..f7cfafc --- /dev/null +++ b/src/com/google/caliper/Xml.java @@ -0,0 +1,108 @@ +/** + * 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.ImmutableList; +import com.google.common.collect.ImmutableMap; +import java.io.InputStream; +import java.io.OutputStream; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Map; + +public final class Xml { + private static final String DATE_FORMAT_STRING = "yyyy-MM-dd'T'HH:mm:ssz"; + + /** + * Encodes this result as XML to the specified stream. This XML can be parsed + * with {@link #runFromXml(InputStream)}. Sample output: + * <pre>{@code + * <result benchmark="examples.FooBenchmark" + * executedBy="A0:1F:CAFE:BABE" + * executedTimestamp="2010-01-05T11:08:15PST"> + * <scenario bar="15" foo="A" vm="dalvikvm">1200.1</scenario> + * <scenario bar="15" foo="B" vm="dalvikvm">1100.2</scenario> + * </result> + * }</pre> + */ + public static void runToXml(Run run, OutputStream out) { + // BEGIN android-removed + // we don't have DOM level 3 on Android yet + // try { + // Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); + // Element result = doc.createElement("result"); + // doc.appendChild(result); + // + // result.setAttribute("benchmark", run.getBenchmarkName()); + // result.setAttribute("executedBy", run.getExecutedByUuid()); + // String executedTimestampString = new SimpleDateFormat(DATE_FORMAT_STRING) + // .format(run.getExecutedTimestamp()); + // result.setAttribute("executedTimestamp", executedTimestampString); + // + // for (Map.Entry<Scenario, Double> entry : run.getMeasurements().entrySet()) { + // Element runElement = doc.createElement("scenario"); + // result.appendChild(runElement); + // + // Scenario scenario = entry.getKey(); + // for (Map.Entry<String, String> parameter : scenario.getVariables().entrySet()) { + // runElement.setAttribute(parameter.getKey(), parameter.getValue()); + // } + // runElement.setTextContent(String.valueOf(entry.getValue())); + // } + // + // TransformerFactory.newInstance().newTransformer() + // .transform(new DOMSource(doc), new StreamResult(out)); + // } catch (Exception e) { + // throw new IllegalStateException("Malformed XML document", e); + // } + // END android-removed + } + + /** + * Creates a result by decoding XML from the specified stream. The XML should + * be consistent with the format emitted by {@link #runToXml(Run, OutputStream)}. + */ + public static Run runFromXml(InputStream in) { + // BEGIN android-removed + // we don't have DOM level 3 on Android yet + throw new UnsupportedOperationException(); + // try { + // Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(in); + // Element result = document.getDocumentElement(); + // + // String benchmarkName = result.getAttribute("benchmark"); + // String executedByUuid = result.getAttribute("executedBy"); + // String executedDateString = result.getAttribute("executedTimestamp"); + // Date executedDate = new SimpleDateFormat(DATE_FORMAT_STRING).parse(executedDateString); + // + // ImmutableMap.Builder<Scenario, Double> measurementsBuilder = ImmutableMap.builder(); + // for (Node node : childrenOf(result)) { + // Element scenarioElement = (Element) node; + // Scenario scenario = new Scenario(attributesOf(scenarioElement)); + // double measurement = Double.parseDouble(scenarioElement.getTextContent()); + // measurementsBuilder.put(scenario, measurement); + // } + // + // return new Run(measurementsBuilder.build(), benchmarkName, executedByUuid, executedDate); + // } catch (Exception e) { + // throw new IllegalStateException("Malformed XML document", e); + // } + // END android-removed + } + + private Xml() {} +} diff --git a/test/com/google/caliper/examples/ArraySortBenchmark.java b/src/examples/ArraySortBenchmark.java index 2978fa2..f42390f 100644 --- a/test/com/google/caliper/examples/ArraySortBenchmark.java +++ b/src/examples/ArraySortBenchmark.java @@ -14,15 +14,12 @@ * limitations under the License. */ -package com.google.caliper.examples; +package examples; import com.google.caliper.Param; import com.google.caliper.Runner; import com.google.caliper.SimpleBenchmark; - import java.util.Arrays; -import java.util.Collection; -import java.util.EnumSet; import java.util.Random; /** @@ -30,33 +27,26 @@ import java.util.Random; */ public class ArraySortBenchmark extends SimpleBenchmark { - @Param int length; - - static Collection<Integer> lengthValues = Arrays.asList(10, 100, 1000, 10000); - - @Param Distribution distribution; + @Param({"10", "100", "1000", "10000"}) private int length; - static final Collection<Distribution> distributionValues = EnumSet.allOf(Distribution.class); + @Param private Distribution distribution; - int[] values; - int[] copy; + private int[] values; + private int[] copy; @Override protected void setUp() throws Exception { values = distribution.create(length); copy = new int[length]; } - public int timeSort(int reps) { - int dummy = 0; + public void timeSort(int reps) { for (int i = 0; i < reps; i++) { System.arraycopy(values, 0, copy, 0, values.length); Arrays.sort(copy); - dummy ^= copy[0]; } - return dummy; } - enum Distribution { + public enum Distribution { SAWTOOTH { @Override int[] create(int length) { diff --git a/test/com/google/caliper/examples/BoxedDoubleToStringBenchmark.java b/src/examples/BoxedDoubleToStringBenchmark.java index 5e6cbfa..22cb28e 100644 --- a/test/com/google/caliper/examples/BoxedDoubleToStringBenchmark.java +++ b/src/examples/BoxedDoubleToStringBenchmark.java @@ -14,13 +14,12 @@ * limitations under the License. */ -package com.google.caliper.examples; +package examples; -import com.google.caliper.SimpleBenchmark; import com.google.caliper.Param; import com.google.caliper.Runner; - -import java.util.Arrays; +import com.google.caliper.SimpleBenchmark; +import com.google.common.collect.ImmutableList; import java.util.Collection; /** @@ -30,7 +29,9 @@ public class BoxedDoubleToStringBenchmark extends SimpleBenchmark { @Param private Double d; - private static final Collection<Double> dValues = Arrays.asList( + // Expressing these as strings in the annotation parameter would be annoying + // (and maybe not possible?) + public static final Collection<Double> dValues = ImmutableList.of( Math.PI, -0.0d, Double.NEGATIVE_INFINITY, @@ -68,7 +69,7 @@ public class BoxedDoubleToStringBenchmark extends SimpleBenchmark { Double value = d; int dummy = 0; for (int i = 0; i < reps; i++) { - dummy = ("" + value).length(); + dummy += ("" + value).length(); } return dummy; } diff --git a/src/examples/CharacterBenchmark.java b/src/examples/CharacterBenchmark.java new file mode 100644 index 0000000..1e013af --- /dev/null +++ b/src/examples/CharacterBenchmark.java @@ -0,0 +1,300 @@ +/* + * 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 examples; + +import com.google.caliper.Param; +import com.google.caliper.Runner; +import com.google.caliper.SimpleBenchmark; + +/** + * Tests various Character methods, intended for testing multiple + * implementations against each other. + */ +public class CharacterBenchmark extends SimpleBenchmark { + + @Param private CharacterSet characterSet; + + @Param private Overload overload; + + private char[] chars; + + @Override protected void setUp() throws Exception { + this.chars = characterSet.chars; + } + + public enum Overload { CHAR, INT } + + public enum CharacterSet { + ASCII(128), + UNICODE(65536); + final char[] chars; + CharacterSet(int size) { + this.chars = new char[65536]; + for (int i = 0; i < 65536; ++i) { + chars[i] = (char) (i % size); + } + } + } + + // A fake benchmark to give us a baseline. + public boolean timeIsSpace(int reps) { + boolean dummy = false; + if (overload == Overload.CHAR) { + for (int i = 0; i < reps; ++i) { + for (int ch = 0; ch < 65536; ++ch) { + dummy ^= ((char) ch == ' '); + } + } + } else { + for (int i = 0; i < reps; ++i) { + for (int ch = 0; ch < 65536; ++ch) { + dummy ^= (ch == ' '); + } + } + } + return dummy; + } + + public void timeDigit(int reps) { + if (overload == Overload.CHAR) { + for (int i = 0; i < reps; ++i) { + for (int ch = 0; ch < 65536; ++ch) { + Character.digit(chars[ch], 10); + } + } + } else { + for (int i = 0; i < reps; ++i) { + for (int ch = 0; ch < 65536; ++ch) { + Character.digit((int) chars[ch], 10); + } + } + } + } + + public void timeGetNumericValue(int reps) { + if (overload == Overload.CHAR) { + for (int i = 0; i < reps; ++i) { + for (int ch = 0; ch < 65536; ++ch) { + Character.getNumericValue(chars[ch]); + } + } + } else { + for (int i = 0; i < reps; ++i) { + for (int ch = 0; ch < 65536; ++ch) { + Character.getNumericValue((int) chars[ch]); + } + } + } + } + + public void timeIsDigit(int reps) { + if (overload == Overload.CHAR) { + for (int i = 0; i < reps; ++i) { + for (int ch = 0; ch < 65536; ++ch) { + Character.isDigit(chars[ch]); + } + } + } else { + for (int i = 0; i < reps; ++i) { + for (int ch = 0; ch < 65536; ++ch) { + Character.isDigit((int) chars[ch]); + } + } + } + } + + public void timeIsIdentifierIgnorable(int reps) { + if (overload == Overload.CHAR) { + for (int i = 0; i < reps; ++i) { + for (int ch = 0; ch < 65536; ++ch) { + Character.isIdentifierIgnorable(chars[ch]); + } + } + } else { + for (int i = 0; i < reps; ++i) { + for (int ch = 0; ch < 65536; ++ch) { + Character.isIdentifierIgnorable((int) chars[ch]); + } + } + } + } + + public void timeIsJavaIdentifierPart(int reps) { + if (overload == Overload.CHAR) { + for (int i = 0; i < reps; ++i) { + for (int ch = 0; ch < 65536; ++ch) { + Character.isJavaIdentifierPart(chars[ch]); + } + } + } else { + for (int i = 0; i < reps; ++i) { + for (int ch = 0; ch < 65536; ++ch) { + Character.isJavaIdentifierPart((int) chars[ch]); + } + } + } + } + + public void timeIsJavaIdentifierStart(int reps) { + if (overload == Overload.CHAR) { + for (int i = 0; i < reps; ++i) { + for (int ch = 0; ch < 65536; ++ch) { + Character.isJavaIdentifierStart(chars[ch]); + } + } + } else { + for (int i = 0; i < reps; ++i) { + for (int ch = 0; ch < 65536; ++ch) { + Character.isJavaIdentifierStart((int) chars[ch]); + } + } + } + } + + public void timeIsLetter(int reps) { + if (overload == Overload.CHAR) { + for (int i = 0; i < reps; ++i) { + for (int ch = 0; ch < 65536; ++ch) { + Character.isLetter(chars[ch]); + } + } + } else { + for (int i = 0; i < reps; ++i) { + for (int ch = 0; ch < 65536; ++ch) { + Character.isLetter((int) chars[ch]); + } + } + } + } + + public void timeIsLetterOrDigit(int reps) { + if (overload == Overload.CHAR) { + for (int i = 0; i < reps; ++i) { + for (int ch = 0; ch < 65536; ++ch) { + Character.isLetterOrDigit(chars[ch]); + } + } + } else { + for (int i = 0; i < reps; ++i) { + for (int ch = 0; ch < 65536; ++ch) { + Character.isLetterOrDigit((int) chars[ch]); + } + } + } + } + + public void timeIsLowerCase(int reps) { + if (overload == Overload.CHAR) { + for (int i = 0; i < reps; ++i) { + for (int ch = 0; ch < 65536; ++ch) { + Character.isLowerCase(chars[ch]); + } + } + } else { + for (int i = 0; i < reps; ++i) { + for (int ch = 0; ch < 65536; ++ch) { + Character.isLowerCase((int) chars[ch]); + } + } + } + } + + public void timeIsSpaceChar(int reps) { + if (overload == Overload.CHAR) { + for (int i = 0; i < reps; ++i) { + for (int ch = 0; ch < 65536; ++ch) { + Character.isSpaceChar(chars[ch]); + } + } + } else { + for (int i = 0; i < reps; ++i) { + for (int ch = 0; ch < 65536; ++ch) { + Character.isSpaceChar((int) chars[ch]); + } + } + } + } + + public void timeIsUpperCase(int reps) { + if (overload == Overload.CHAR) { + for (int i = 0; i < reps; ++i) { + for (int ch = 0; ch < 65536; ++ch) { + Character.isUpperCase(chars[ch]); + } + } + } else { + for (int i = 0; i < reps; ++i) { + for (int ch = 0; ch < 65536; ++ch) { + Character.isUpperCase((int) chars[ch]); + } + } + } + } + + public void timeIsWhitespace(int reps) { + if (overload == Overload.CHAR) { + for (int i = 0; i < reps; ++i) { + for (int ch = 0; ch < 65536; ++ch) { + Character.isWhitespace(chars[ch]); + } + } + } else { + for (int i = 0; i < reps; ++i) { + for (int ch = 0; ch < 65536; ++ch) { + Character.isWhitespace((int) chars[ch]); + } + } + } + } + + public void timeToLowerCase(int reps) { + if (overload == Overload.CHAR) { + for (int i = 0; i < reps; ++i) { + for (int ch = 0; ch < 65536; ++ch) { + Character.toLowerCase(chars[ch]); + } + } + } else { + for (int i = 0; i < reps; ++i) { + for (int ch = 0; ch < 65536; ++ch) { + Character.toLowerCase((int) chars[ch]); + } + } + } + } + + public void timeToUpperCase(int reps) { + if (overload == Overload.CHAR) { + for (int i = 0; i < reps; ++i) { + for (int ch = 0; ch < 65536; ++ch) { + Character.toUpperCase(chars[ch]); + } + } + } else { + for (int i = 0; i < reps; ++i) { + for (int ch = 0; ch < 65536; ++ch) { + Character.toUpperCase((int) chars[ch]); + } + } + } + } + + // TODO: remove this from all examples when IDE plugins are ready + public static void main(String[] args) throws Exception { + Runner.main(CharacterBenchmark.class, args); + } +} diff --git a/test/com/google/caliper/examples/EnumSetContainsBenchmark.java b/src/examples/EnumSetContainsBenchmark.java index a9f6f2f..b232514 100644 --- a/test/com/google/caliper/examples/EnumSetContainsBenchmark.java +++ b/src/examples/EnumSetContainsBenchmark.java @@ -14,13 +14,11 @@ * limitations under the License. */ -package com.google.caliper.examples; +package examples; import com.google.caliper.Param; import com.google.caliper.Runner; import com.google.caliper.SimpleBenchmark; - -import java.util.Collection; import java.util.EnumSet; import java.util.Set; @@ -31,9 +29,7 @@ public class EnumSetContainsBenchmark extends SimpleBenchmark { @Param private SetMaker setMaker; - private static final Collection<SetMaker> setMakerValues = EnumSet.allOf(SetMaker.class); - - enum SetMaker { + public enum SetMaker { ENUM_SET { @Override Set<?> newSet() { return EnumSet.allOf(RegularSize.class); @@ -57,13 +53,13 @@ public class EnumSetContainsBenchmark extends SimpleBenchmark { abstract Object[] testValues(); } - enum RegularSize { + private enum RegularSize { E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E13, E14, E15, E16, E17, E18, E19, E20, E21, E22, E23, E24, E25, E26, E27, E28, E29, E30, E31, E32, E33, E34, E35, E36, E37, E38, E39, E40, } - enum LargeSize { + private enum LargeSize { E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E13, E14, E15, E16, E17, E18, E19, E20, E21, E22, E23, E24, E25, E26, E27, E28, E29, E30, E31, E32, E33, E34, E35, E36, E37, E38, E39, E40, E41, E42, E43, E44, E45, E46, E47, @@ -79,20 +75,18 @@ public class EnumSetContainsBenchmark extends SimpleBenchmark { private Set<?> set; private Object[] testValues; - @Override protected void setUp() throws Exception { + @Override protected void setUp() { this.set = setMaker.newSet(); this.testValues = setMaker.testValues(); } - public int timeContains(int reps) throws Exception { - int dummy = 0; + public void timeContains(int reps) { for (int i = 0; i < reps; i++) { - dummy ^= (set.contains(testValues[i % testValues.length]) ? i : 0); + set.contains(testValues[i % testValues.length]); } - return dummy; } public static void main(String[] args) throws Exception { Runner.main(EnumSetContainsBenchmark.class, args); } -}
\ No newline at end of file +} diff --git a/test/com/google/caliper/examples/ExpensiveObjectsBenchmark.java b/src/examples/ExpensiveObjectsBenchmark.java index 2dbcf58..ebff8e6 100644 --- a/test/com/google/caliper/examples/ExpensiveObjectsBenchmark.java +++ b/src/examples/ExpensiveObjectsBenchmark.java @@ -14,13 +14,10 @@ * limitations under the License. */ -package com.google.caliper.examples; +package examples; -import com.google.caliper.Benchmark; -import com.google.caliper.Param; import com.google.caliper.Runner; import com.google.caliper.SimpleBenchmark; - import java.text.DecimalFormatSymbols; import java.text.NumberFormat; import java.text.SimpleDateFormat; @@ -29,6 +26,7 @@ import java.util.Locale; /** * Benchmarks creation and cloning various expensive objects. */ +@SuppressWarnings({"ResultOfObjectAllocationIgnored"}) // TODO: should fix! public class ExpensiveObjectsBenchmark extends SimpleBenchmark { public void timeNewDecimalFormatSymbols(int reps) { for (int i = 0; i < reps; ++i) { @@ -68,4 +66,9 @@ public class ExpensiveObjectsBenchmark extends SimpleBenchmark { sdf.clone(); } } + + // TODO: remove this from all examples when IDE plugins are ready + public static void main(String[] args) throws Exception { + Runner.main(ExpensiveObjectsBenchmark.class, args); + } } diff --git a/test/com/google/caliper/examples/FormatterBenchmark.java b/src/examples/FormatterBenchmark.java index f61f111..b4a0541 100644 --- a/test/com/google/caliper/examples/FormatterBenchmark.java +++ b/src/examples/FormatterBenchmark.java @@ -14,11 +14,10 @@ * limitations under the License. */ -package com.google.caliper.examples; +package examples; import com.google.caliper.Runner; import com.google.caliper.SimpleBenchmark; - import java.util.Formatter; /** diff --git a/test/com/google/caliper/examples/IntModBenchmark.java b/src/examples/IntModBenchmark.java index 86e85e7..55a119c 100644 --- a/test/com/google/caliper/examples/IntModBenchmark.java +++ b/src/examples/IntModBenchmark.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.google.caliper.examples; +package examples; import com.google.caliper.Runner; import com.google.caliper.SimpleBenchmark; @@ -22,6 +22,7 @@ import com.google.caliper.SimpleBenchmark; /** * Measures several candidate implementations for mod(). */ +@SuppressWarnings("SameParameterValue") public class IntModBenchmark extends SimpleBenchmark { private static final int M = (1 << 16) - 1; @@ -46,8 +47,9 @@ public class IntModBenchmark extends SimpleBenchmark { return dummy; } + @SuppressWarnings("NumericCastThatLosesPrecision") // result of % by an int must be in int range private static int doubleRemainderMod(int a, int m) { - return (int) (((a % m) + (long) m) % m); + return (int) ((a % m + (long) m) % m); } public int timeRightShiftingMod(int reps) { @@ -58,9 +60,10 @@ public class IntModBenchmark extends SimpleBenchmark { return dummy; } + @SuppressWarnings("NumericCastThatLosesPrecision") // must be in int range private static int rightShiftingMod(int a, int m) { long r = a % m; - return (int) (r + ((r >> 63) & m)); + return (int) (r + (r >> 63 & m)); } public int timeLeftShiftingMod(int reps) { @@ -71,8 +74,9 @@ public class IntModBenchmark extends SimpleBenchmark { return dummy; } + @SuppressWarnings("NumericCastThatLosesPrecision") // result of % by an int must be in int range private static int leftShiftingMod(int a, int m) { - return (int) ((a + (((long) m) << 32)) % m); + return (int) ((a + ((long) m << 32)) % m); } public int timeWrongMod(int reps) { diff --git a/test/com/google/caliper/examples/ListIterationBenchmark.java b/src/examples/ListIterationBenchmark.java index 53bcdf8..a8cfb05 100644 --- a/test/com/google/caliper/examples/ListIterationBenchmark.java +++ b/src/examples/ListIterationBenchmark.java @@ -14,24 +14,21 @@ * limitations under the License. */ -package com.google.caliper.examples; +package examples; import com.google.caliper.Param; import com.google.caliper.Runner; import com.google.caliper.SimpleBenchmark; - import java.util.AbstractList; -import java.util.Arrays; -import java.util.Collection; import java.util.List; /** * Measures iterating through list elements. */ public class ListIterationBenchmark extends SimpleBenchmark { - @Param private int length; - private static final Collection<Integer> lengthValues = Arrays.asList(0, 10, 100, 1000); + @Param({"0", "10", "100", "1000"}) + private int length; private List<Object> list; private Object[] array; @@ -53,24 +50,20 @@ public class ListIterationBenchmark extends SimpleBenchmark { }; } - public int timeListIteration(int reps) { - int count = 0; + @SuppressWarnings({"UnusedDeclaration"}) // TODO: fix + public void timeListIteration(int reps) { for (int i = 0; i < reps; i++) { for (Object value : list) { - count ^= value.hashCode(); // prevent overoptimization } } - return count; // ignored } - public int timeArrayIteration(int reps) { - int count = 0; + @SuppressWarnings({"UnusedDeclaration"}) // TODO: fix + public void timeArrayIteration(int reps) { for (int i = 0; i < reps; i++) { for (Object value : array) { - count ^= value.hashCode(); // prevent overoptimization } } - return count; // ignored } // TODO: remove this from all examples when IDE plugins are ready diff --git a/src/examples/LoopingBackwardsBenchmark.java b/src/examples/LoopingBackwardsBenchmark.java new file mode 100644 index 0000000..e98e5fc --- /dev/null +++ b/src/examples/LoopingBackwardsBenchmark.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2010 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 examples; + +import com.google.caliper.Param; +import com.google.caliper.Runner; +import com.google.caliper.SimpleBenchmark; + +/** + * Testing the old canard that looping backwards is faster. + * + * @author Kevin Bourrillion + */ +public class LoopingBackwardsBenchmark extends SimpleBenchmark { + @Param({"2", "20", "2000", "20000000"}) int max; + + public int timeForwards(int reps) { + int dummy = 0; + for (int i = 0; i < reps; i++) { + for (int j = 0; j < max; j++) { + dummy += j; + } + } + return dummy; + } + + public int timeBackwards(int reps) { + int dummy = 0; + for (int i = 0; i < reps; i++) { + for (int j = max - 1; j >= 0; j--) { + dummy += j; + } + } + return dummy; + } + + public static void main(String[] args) throws Exception { + Runner.main(LoopingBackwardsBenchmark.class, args); + } +} diff --git a/test/com/google/caliper/examples/PrimitiveDoubleToStringBenchmark.java b/src/examples/PrimitiveDoubleToStringBenchmark.java index 592acdc..d49a53d 100644 --- a/test/com/google/caliper/examples/PrimitiveDoubleToStringBenchmark.java +++ b/src/examples/PrimitiveDoubleToStringBenchmark.java @@ -14,13 +14,12 @@ * limitations under the License. */ -package com.google.caliper.examples; +package examples; -import com.google.caliper.SimpleBenchmark; import com.google.caliper.Param; import com.google.caliper.Runner; - -import java.util.Arrays; +import com.google.caliper.SimpleBenchmark; +import com.google.common.collect.ImmutableList; import java.util.Collection; /** @@ -30,7 +29,7 @@ public class PrimitiveDoubleToStringBenchmark extends SimpleBenchmark { @Param private double d; - private static final Collection<Double> dValues = Arrays.asList( + public static final Collection<Double> dValues = ImmutableList.of( Math.PI, -0.0d, Double.NEGATIVE_INFINITY, diff --git a/src/examples/SetContainsBenchmark.java b/src/examples/SetContainsBenchmark.java new file mode 100644 index 0000000..4185d55 --- /dev/null +++ b/src/examples/SetContainsBenchmark.java @@ -0,0 +1,171 @@ +/* + * 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 examples; + +import com.google.caliper.Param; +import com.google.caliper.Runner; +import com.google.caliper.SimpleBenchmark; +import com.google.common.collect.ImmutableSet; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.Random; +import java.util.Set; + +/** + * A microbenchmark that tests the performance of contains() on various Set + * implementations. + * + * @author Kevin Bourrillion + */ +public class SetContainsBenchmark extends SimpleBenchmark { + @Param private Impl impl; + + // So far, this is the best way to test various implementations + public enum Impl { + Hash { + @Override Set<Integer> create(Collection<Integer> contents) { + return new HashSet<Integer>(contents); + } + }, + LinkedHash { + @Override Set<Integer> create(Collection<Integer> contents) { + return new LinkedHashSet<Integer>(contents); + } + }, + UnmodHS { + @Override Set<Integer> create(Collection<Integer> contents) { + return Collections.unmodifiableSet(new HashSet<Integer>(contents)); + } + }, + SyncHS { + @Override Set<Integer> create(Collection<Integer> contents) { + return Collections.synchronizedSet(new HashSet<Integer>(contents)); + } + }, + + // Kind of cheating here -- Caliper just happens to bundle Google Collections so I'm testing + // this from it; this might not work at the command line since GC are jarjar'd for caliper.jar + Immutable { + @Override Set<Integer> create(Collection<Integer> contents) { + return ImmutableSet.copyOf(contents); + } + }; + + abstract Set<Integer> create(Collection<Integer> contents); + } + + @Param private int size; + public static final Collection<Integer> sizeValues = Arrays.asList( + (1<<2) - 1, + (1<<2), + (1<<6) - 1, + (1<<6), + (1<<10) - 1, + (1<<10), + (1<<14) - 1, + (1<<14), + (1<<18) - 1, + (1<<18) + ); + + // "" means no fixed seed + @Param("") private SpecialRandom random; + + // the following must be set during setUp + private Integer[] queries; + private Set<Integer> setToTest; + + // Queries are just sequential integers. Since the contents of the set were + // chosen randomly, this shouldn't cause any undue bias. + @Override public void setUp() { + this.queries = new Integer[size * 2]; + for (int i = 0; i < size * 2; i++) { + queries[i] = i; + } + Collections.shuffle(Arrays.asList(queries), random); + + setToTest = impl.create(createData()); + } + + private Collection<Integer> createData() { + Set<Integer> tempSet = new HashSet<Integer>(size * 3 / 2); + + // Choose 50% of the numbers between 0 and max to be in the set; thus we + // are measuring performance of contains() when there is a 50% hit rate + int max = size * 2; + while (tempSet.size() < size) { + tempSet.add(random.nextInt(max)); + } + return tempSet; + } + + public boolean timeContains(int reps) { + // Paranoia: acting on hearsay that accessing fields might be slow + // Should write a benchmark to test that! + Set<Integer> set = setToTest; + Integer[] queries = this.queries; + + // Allows us to use & instead of %, acting on hearsay that division operators (/%) are + // disproportionately expensive; should test this too! + int mask = Integer.highestOneBit(size * 2) - 1; + + boolean dummy = false; + for (int i = 0; i < reps; i++) { + dummy ^= set.contains(queries[i & mask]); + } + return dummy; + } + + // TODO: remove this from all examples when IDE plugins are ready + public static void main(String[] args) throws Exception { + Runner.main(SetContainsBenchmark.class, args); + } + + + // Just an experiment with a slightly nicer way to create Randoms for benchies + + public static class SpecialRandom extends Random { + public static SpecialRandom valueOf(String s) { + return (s.length() == 0) + ? new SpecialRandom() + : new SpecialRandom(Long.parseLong(s)); + } + + private final boolean hasSeed; + private final long seed; + + public SpecialRandom() { + this.hasSeed = false; + this.seed = 0; + } + + public SpecialRandom(long seed) { + super(seed); + this.hasSeed = true; + this.seed = seed; + } + + @Override public String toString() { + return hasSeed ? "(seed:" + seed : "(default seed)"; + } + + private static final long serialVersionUID = 0; + } +} diff --git a/test/com/google/caliper/examples/StringBuilderBenchmark.java b/src/examples/StringBuilderBenchmark.java index 2fa6819..35e34f7 100644 --- a/test/com/google/caliper/examples/StringBuilderBenchmark.java +++ b/src/examples/StringBuilderBenchmark.java @@ -14,23 +14,18 @@ * limitations under the License. */ -package com.google.caliper.examples; +package examples; -import com.google.caliper.Benchmark; import com.google.caliper.Param; import com.google.caliper.Runner; import com.google.caliper.SimpleBenchmark; -import java.util.Arrays; -import java.util.Collection; - /** * Tests the performance of various StringBuilder methods. */ public class StringBuilderBenchmark extends SimpleBenchmark { - @Param int length; - static Collection<Integer> lengthValues = Arrays.asList(1, 10, 100); + @Param({"1", "10", "100"}) private int length; public void timeAppendBoolean(int reps) { for (int i = 0; i < reps; ++i) { @@ -129,4 +124,10 @@ public class StringBuilderBenchmark extends SimpleBenchmark { } } } + + + // TODO: remove this from all examples when IDE plugins are ready + public static void main(String[] args) throws Exception { + Runner.main(StringBuilderBenchmark.class, args); + } } diff --git a/src/scripts/caliper b/src/scripts/caliper new file mode 100644 index 0000000..fb859a9 --- /dev/null +++ b/src/scripts/caliper @@ -0,0 +1,8 @@ +#!/bin/sh + +# rough + +export PATH=$PATH:$JAVA_HOME/bin +base=`dirname $0` +exec java -cp $base/lib/caliper-@VERSION@.jar:$CLASSPATH com.google.caliper.Runner $* + diff --git a/src/com/google/caliper/ExecutionException.java b/src/test/BrokenNoOpBenchmark.java index 7d8a592..95509fa 100644 --- a/src/com/google/caliper/ExecutionException.java +++ b/src/test/BrokenNoOpBenchmark.java @@ -1,4 +1,4 @@ -/* +/** * Copyright (C) 2009 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,15 +14,21 @@ * limitations under the License. */ -package com.google.caliper; +package test; + +import com.google.caliper.Runner; +import com.google.caliper.SimpleBenchmark; /** - * Thrown upon occurrence of a runtime failure during test construction or - * execution. + * This fails with a runtime out of range error. */ -public final class ExecutionException extends RuntimeException { +public class BrokenNoOpBenchmark extends SimpleBenchmark { + + public void timeNoOp(int reps) { + for (int i = 0; i < reps; i++) {} + } - public ExecutionException(Throwable throwable) { - super(throwable); + public static void main(String[] args) throws Exception { + Runner.main(BrokenNoOpBenchmark.class, args); } } diff --git a/test/com/google/caliper/AllTests.java b/src/test/BrokenSleepBenchmark.java index 510cc0a..964cf1a 100644 --- a/test/com/google/caliper/AllTests.java +++ b/src/test/BrokenSleepBenchmark.java @@ -1,4 +1,4 @@ -/* +/** * Copyright (C) 2009 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,15 +14,25 @@ * limitations under the License. */ -package com.google.caliper; +package test; -import junit.framework.Test; -import junit.framework.TestSuite; +import com.google.caliper.Runner; +import com.google.caliper.SimpleBenchmark; -public final class AllTests { - public static Test suite() { - TestSuite suite = new TestSuite(); - // tests go here :) - return suite; +/** + * Should fail with a measurement error. + */ +public class BrokenSleepBenchmark extends SimpleBenchmark { + // And look, IDEA tries to warn you + @SuppressWarnings({"UnusedDeclaration", "UnusedParameters"}) + public void timeSleepOneSecond(int reps) { + try { + Thread.sleep(1000); + } catch (InterruptedException ignored) { + } + } + + public static void main(String[] args) throws Exception { + Runner.main(BrokenSleepBenchmark.class, args); } } diff --git a/src/test/ErrorsInUserCodeTest.java b/src/test/ErrorsInUserCodeTest.java new file mode 100644 index 0000000..dbb9f88 --- /dev/null +++ b/src/test/ErrorsInUserCodeTest.java @@ -0,0 +1,146 @@ +/* + * 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 test; + +import com.google.caliper.Runner; +import com.google.caliper.SimpleBenchmark; +import com.google.caliper.UserException.AbstractBenchmarkException; +import com.google.caliper.UserException.DoesntImplementBenchmarkException; +import com.google.caliper.UserException.ExceptionFromUserCodeException; +import com.google.caliper.UserException.NoParameterlessConstructorException; +import junit.framework.TestCase; + +/** + * Unit test covering common user mistakes. + * + * @author Kevin Bourrillion + */ +public class ErrorsInUserCodeTest extends TestCase { + private Runner runner; + + @Override protected void setUp() throws Exception { + runner = new Runner(); + } + + public void testDidntSubclassAnything() { + try { + runner.run(NotABenchmark.class.getName()); + fail(); + } catch (DoesntImplementBenchmarkException expected) { + } + } + + static class NotABenchmark { + public void timeSomething(int reps) { + fail("" + reps); + } + } + + + public void testAbstract() { + try { + runner.run(AbstractBenchmark.class.getName()); + fail(); + } catch (AbstractBenchmarkException expected) { + } + } + + abstract static class AbstractBenchmark extends SimpleBenchmark { + public void timeSomething(int reps) { + fail("" + reps); + } + } + + + public void testNoSuitableConstructor() { + try { + runner.run(BadConstructorBenchmark.class.getName()); + fail(); + } catch (NoParameterlessConstructorException expected) { + } + } + + static class BadConstructorBenchmark extends SimpleBenchmark { + BadConstructorBenchmark(String damnParam) { + fail(damnParam); + } + + public void timeSomething(int reps) { + fail("" + reps); + } + } + + + @SuppressWarnings("serial") + static class SomeUserException extends RuntimeException {} + + private static void throwSomeUserException() { + throw new SomeUserException(); + } + + + public void testExceptionInInit() { + try { + runner.run(ExceptionInInitBenchmark.class.getName()); + fail(); + } catch (ExceptionFromUserCodeException expected) { + } + } + + static class ExceptionInInitBenchmark extends SimpleBenchmark { + static { + throwSomeUserException(); + } + + public void timeSomething(int reps) { + fail("" + reps); + } + } + + public void testExceptionInConstructor() { + try { + runner.run(ExceptionInConstructorBenchmark.class.getName()); + fail(); + } catch (ExceptionFromUserCodeException expected) { + } + } + + static class ExceptionInConstructorBenchmark extends SimpleBenchmark { + ExceptionInConstructorBenchmark() { + throw new SomeUserException(); + } + + public void timeSomething(int reps) { + fail("" + reps); + } + } + + // TODO: enable + public void XXXtestExceptionInMethod() { + try { + new Runner().run(ExceptionInMethodBenchmark.class.getName()); + fail(); + } catch (ExceptionFromUserCodeException ignored) { + } + } + + static class ExceptionInMethodBenchmark extends SimpleBenchmark { + public void timeSomething(int reps) { + throw new SomeUserException(); + } + } +} diff --git a/src/test/RunXmlTest.java b/src/test/RunXmlTest.java new file mode 100644 index 0000000..6dd2b63 --- /dev/null +++ b/src/test/RunXmlTest.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2010 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 test; + +import com.google.caliper.Run; +import com.google.caliper.Scenario; +import com.google.caliper.Xml; +import com.google.common.collect.ImmutableMap; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.util.Date; +import junit.framework.TestCase; + +public class RunXmlTest extends TestCase { + + public void testXmlRoundtrip() { + Scenario a15dalvik = new Scenario(ImmutableMap.of( + "foo", "A", "bar", "15", "vm", "dalvikvm")); + Scenario b15dalvik = new Scenario(ImmutableMap.of( + "foo", "B", "bar", "15", "vm", "dalvikvm")); + + Run toEncode = new Run(ImmutableMap.of(a15dalvik, 1200.1, b15dalvik, 1100.2), + "examples.FooBenchmark", "A0:1F:CAFE:BABE", new Date()); + ByteArrayOutputStream bytesOut = new ByteArrayOutputStream(); + Xml.runToXml(toEncode, bytesOut); + + assertEquals("", new String(bytesOut.toByteArray())); + + // we don't validate the XML directly because it's a hassle to cope with arbitrary orderings of + // an element's attributes + + ByteArrayInputStream bytesIn = new ByteArrayInputStream(bytesOut.toByteArray()); + Run decoded = Xml.runFromXml(bytesIn); + + assertEquals(toEncode, decoded); + } +} diff --git a/src/test/SystemOutAndErrBenchmark.java b/src/test/SystemOutAndErrBenchmark.java new file mode 100644 index 0000000..df37d76 --- /dev/null +++ b/src/test/SystemOutAndErrBenchmark.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2010 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 test; + +import com.google.caliper.SimpleBenchmark; +import com.google.caliper.Runner; + +/** + * Demonstrates that the benchmark can emit output without consequence. + */ +public class SystemOutAndErrBenchmark extends SimpleBenchmark { + + public void timeSystemOutAndSystemErr(int reps) { + for (int i = 0; i < reps; i++) { + System.out.println("hello, out"); + System.err.println("hello, err"); + } + } + + public static void main(String[] args) { + Runner.main(SystemOutAndErrBenchmark.class, args); + } +} diff --git a/src/com/google/caliper/Result.java b/src/test/ThreadSleepBenchmark.java index 888a9f4..bfb6c05 100644 --- a/src/com/google/caliper/Result.java +++ b/src/test/ThreadSleepBenchmark.java @@ -14,24 +14,25 @@ * limitations under the License. */ -package com.google.caliper; +package test; -import com.google.common.collect.ImmutableMap; - -import java.util.Map; +import com.google.caliper.Runner; +import com.google.caliper.SimpleBenchmark; /** - * The complete result of a benchmark suite run. + * If everything is working properly, this should report runtime very close to + * 1ms. */ -final class Result { - - private final ImmutableMap<Run, Double> measurements; +public class ThreadSleepBenchmark extends SimpleBenchmark { - public Result(Map<Run, Double> measurements) { - this.measurements = ImmutableMap.copyOf(measurements); + public void timeSleep(int reps) { + try { + Thread.sleep(reps); + } catch (InterruptedException ignored) { + } } - public ImmutableMap<Run, Double> getMeasurements() { - return measurements; + public static void main(String[] args) throws Exception { + Runner.main(ThreadSleepBenchmark.class, args); } } diff --git a/src/test/TracingBenchmark.java b/src/test/TracingBenchmark.java new file mode 100644 index 0000000..2f1c077 --- /dev/null +++ b/src/test/TracingBenchmark.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2010 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 test; + +import com.google.caliper.Benchmark; +import com.google.caliper.TimedRunnable; +import com.google.caliper.Runner; +import java.util.Set; +import java.util.Map; + +/** + * Proof-of-concept of a decorating benchmark. + */ +public class TracingBenchmark implements Benchmark { + + private final Benchmark delegate; + + public TracingBenchmark() { + this.delegate = new ThreadSleepBenchmark(); + } + + public Set<String> parameterNames() { + return delegate.parameterNames(); + } + + public Set<String> parameterValues(String parameterName) { + return delegate.parameterValues(parameterName); + } + + public TimedRunnable createBenchmark(Map<String, String> parameterValues) { + final TimedRunnable benchmark = delegate.createBenchmark(parameterValues); + + return new TimedRunnable() { + public Object run(int reps) throws Exception { + // TODO: can we move the setup/tear down work out of the timed loop? + Runtime.getRuntime().traceMethodCalls(true); + try { + return benchmark.run(reps); + } finally { + Runtime.getRuntime().traceMethodCalls(false); + } + } + }; + } + + public static void main(String[] args) { + Runner.main(TracingBenchmark.class); + } +} diff --git a/src/tutorial/Tutorial.java b/src/tutorial/Tutorial.java new file mode 100644 index 0000000..06e6e56 --- /dev/null +++ b/src/tutorial/Tutorial.java @@ -0,0 +1,189 @@ +/* + * 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 tutorial; + +import com.google.caliper.Param; +import com.google.caliper.SimpleBenchmark; + +/** + * Caliper tutorial. To run the example benchmarks in this file: + * {@code CLASSPATH=... [caliper_home]/caliper tutorial.Tutorial.Benchmark1} + * + * @author Kevin Bourrillion + */ +public class Tutorial { + + /* + * We begin the Caliper tutorial with the simplest benchmark you can write. + * We'd like to know how efficient the method System.nanoTime() is. + * + * Notice: + * + * - We write a class that extends com.google.caliper.SimpleBenchmark. + * - It contains a public instance method whose name begins with 'time' and + * and which accepts a single 'int reps' parameter. + * - The body of the method simply executes the code we wish to measure, + * 'reps' times. + * + * Example run: + * + * $ CLASSPATH=build/classes/test caliper tutorial.Tutorial.Benchmark1 + * [real-time results appear on this line] + * + * Summary report for tutorial.Tutorial$Benchmark1: + * + * Benchmark ns + * --------- --- + * NanoTime 233 + */ + public static class Benchmark1 extends SimpleBenchmark { + public void timeNanoTime(int reps) { + for (int i = 0; i < reps; i++) { + System.nanoTime(); + } + } + } + + /* + * Now let's compare two things: nanoTime() versus currentTimeMillis(). + * Notice: + * + * - We simply add another method, following the same rules as the first. + * + * Example run output: + * + * Benchmark ns + * ----------------- --- + * NanoTime 248 + * CurrentTimeMillis 118 + */ + public static class Benchmark2 extends SimpleBenchmark { + public void timeNanoTime(int reps) { + for (int i = 0; i < reps; i++) { + System.nanoTime(); + } + } + public void timeCurrentTimeMillis(int reps) { + for (int i = 0; i < reps; i++) { + System.currentTimeMillis(); + } + } + } + + /* + * Let's try iterating over a large array. This seems simple enough, but + * there is a problem! + */ + public static class Benchmark3 extends SimpleBenchmark { + private final int[] array = new int[1000000]; + + @SuppressWarnings("UnusedDeclaration") // IDEA tries to warn us! + public void timeArrayIteration_BAD(int reps) { + for (int i = 0; i < reps; i++) { + for (int ignoreMe : array) {} + } + } + } + + /* + * Caliper reported that the benchmark above ran in 4 nanoseconds. + * + * Wait, what? + * + * How can it possibly iterate over a million zeroes in 4 ns!? + * + * It is very important to sanity-check benchmark results with common sense! + * In this case, we're indeed getting a bogus result. The problem is that the + * Java Virtual Machine is too smart: it detected the fact that the loop was + * producing no actual result, so it simply compiled it right out. The method + * never looped at all. To fix this, we need to use a dummy result value. + * + * Notice: + * + * - We simply change the 'time' method from 'void' to any return type we + * wish. Then we return a value that can't be known without actually + * performing the work, and thus we defeat the runtime optimizations. + * - We're no longer timing *just* the code we want to be testing - our + * result will now be inflated by the (small) cost of addition. This is an + * unfortunate fact of life with microbenchmarking. In fact, we were + * already inflated by the cost of an int comparison, "i < reps" as it was. + * + * With this change, Caliper should report a much more realistic value, more + * on the order of an entire millisecond. + */ + public static class Benchmark4 extends SimpleBenchmark { + private final int[] array = new int[1000000]; + + public int timeArrayIteration_fixed(int reps) { + int dummy = 0; + for (int i = 0; i < reps; i++) { + for (int doNotIgnoreMe : array) { + dummy += doNotIgnoreMe; + } + } + return dummy; // framework ignores this, but it has served its purpose! + } + } + + /* + * Now we'd like to know how various other *sizes* of arrays perform. We + * don't want to have to cut and paste the whole benchmark just to provide a + * different size. What we need is a parameter! + * + * When you run this benchmark the same way you ran the previous ones, you'll + * now get an error: "No values provided for benchmark parameter 'size'". + * You can provide the value requested at the command line like this: + * + * [caliper_home]/caliper tutorial.Tutorial.Benchmark5 -Dsize=100} + * + * You'll see output like this: + * + * Benchmark size ns + * -------------- ---- --- + * ArrayIteration 100 51 + * + * Now that we've parameterized our benchmark, things are starting to get fun. + * Try passing '-Dsize=10,100,1000' and see what happens! + * + * Benchmark size ns + * -------------- ---- ----------------------------------- + * ArrayIteration 10 7 | + * ArrayIteration 100 49 |||| + * ArrayIteration 1000 477 |||||||||||||||||||||||||||||| + * + */ + public static class Benchmark5 extends SimpleBenchmark { + @Param int size; // set automatically by framework + + private int[] array; // set by us, in setUp() + + @Override protected void setUp() { + // @Param values are guaranteed to have been injected by now + array = new int[size]; + } + + public int timeArrayIteration(int reps) { + int dummy = 0; + for (int i = 0; i < reps; i++) { + for (int doNotIgnoreMe : array) { + dummy += doNotIgnoreMe; + } + } + return dummy; + } + } +} diff --git a/test/com/google/caliper/examples/CharacterBenchmark.java b/test/com/google/caliper/examples/CharacterBenchmark.java deleted file mode 100644 index 3ffeb01..0000000 --- a/test/com/google/caliper/examples/CharacterBenchmark.java +++ /dev/null @@ -1,173 +0,0 @@ -/* - * 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.Param; -import com.google.caliper.Runner; -import com.google.caliper.SimpleBenchmark; - -import java.util.Collection; -import java.util.EnumSet; - -/** - * Tests various Character methods, intended for testing multiple - * implementations against each other. - */ -public class CharacterBenchmark extends SimpleBenchmark { - - @Param CharacterSet characterSet; - static Collection<CharacterSet> characterSetValues = EnumSet.allOf(CharacterSet.class); - - char[] values; - - @Override protected void setUp() throws Exception { - values = characterSet.chars; - } - - enum CharacterSet { - ASCII(128), - UNICODE(65536); - char[] chars; - CharacterSet(int size) { - chars = new char[size]; - for (int i = 0; i < chars.length; ++i) { - chars[i] = (char) i; - } - } - } - - public void timeDigit(int reps) { - for (int i = 0; i < reps; ++i) { - for (char ch = 0; ch < '}'; ++ch) { - Character.digit(ch, 10); - } - } - } - - public void timeGetNumericValue(int reps) { - for (int i = 0; i < reps; ++i) { - for (char ch = 0; ch < '}'; ++ch) { - Character.getNumericValue(ch); - } - } - } - - public void timeIsDigit(int reps) { - for (int i = 0; i < reps; ++i) { - for (char ch = 0; ch < '}'; ++ch) { - Character.isDigit(ch); - } - } - } - - public void timeIsIdentifierIgnorable(int reps) { - for (int i = 0; i < reps; ++i) { - for (char ch = 0; ch < '}'; ++ch) { - Character.isIdentifierIgnorable(ch); - } - } - } - - public void timeIsJavaIdentifierPart(int reps) { - for (int i = 0; i < reps; ++i) { - for (char ch = 0; ch < '}'; ++ch) { - Character.isJavaIdentifierPart(ch); - } - } - } - - public void timeIsJavaIdentifierStart(int reps) { - for (int i = 0; i < reps; ++i) { - for (char ch = 0; ch < '}'; ++ch) { - Character.isJavaIdentifierStart(ch); - } - } - } - - public void timeIsLetter(int reps) { - for (int i = 0; i < reps; ++i) { - for (char ch = 0; ch < '}'; ++ch) { - Character.isLetter(ch); - } - } - } - - public void timeIsLetterOrDigit(int reps) { - for (int i = 0; i < reps; ++i) { - for (char ch = 0; ch < '}'; ++ch) { - Character.isLetterOrDigit(ch); - } - } - } - - public void timeIsLowerCase(int reps) { - for (int i = 0; i < reps; ++i) { - for (char ch = 0; ch < '}'; ++ch) { - Character.isLowerCase(ch); - } - } - } - - public void timeIsSpaceChar(int reps) { - for (int i = 0; i < reps; ++i) { - for (char ch = 0; ch < '}'; ++ch) { - Character.isSpaceChar(ch); - } - } - } - - public void timeIsUpperCase(int reps) { - for (int i = 0; i < reps; ++i) { - for (char ch = 0; ch < '}'; ++ch) { - Character.isUpperCase(ch); - } - } - } - - public void timeIsWhitespace(int reps) { - for (int i = 0; i < reps; ++i) { - for (char ch = 0; ch < '}'; ++ch) { - Character.isWhitespace(ch); - } - } - } - - public void timeIsNull(int reps) { - for (int i = 0; i < reps; ++i) { - for (char ch = 0; ch < '}'; ++ch) { - boolean b = (ch == ' '); - } - } - } - - public void timeToLowerCase(int reps) { - for (int i = 0; i < reps; ++i) { - for (char ch = 0; ch < '}'; ++ch) { - Character.toLowerCase(ch); - } - } - } - - public void timeToUpperCase(int reps) { - for (int i = 0; i < reps; ++i) { - for (char ch = 0; ch < '}'; ++ch) { - Character.toUpperCase(ch); - } - } - } -} |