/* * Copyright (C) 2016 Linaro Limited. All rights reserved. * * 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. * */ /* * Description: Tracks performance of String intrinsics, Java, and native methods. * Main Focus: Looped memory compare. * Secondary Focus: Array access. * */ package org.linaro.benchmarks.micro; import java.lang.StringBuilder; import java.lang.System; import java.util.Random; import org.openjdk.jmh.annotations.*; import java.util.concurrent.TimeUnit; @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS) @State(Scope.Benchmark) public class StringOps { private static int RANDOM_STRING_8 = 0; private static int RANDOM_STRING_16 = 1; private static int RANDOM_STRING_32 = 2; private static int RANDOM_STRING_128 = 3; private static int RANDOM_STRING_512 = 4; private static int NUM_LENGTH_TESTS = 5; private static char MIN_RANDOM_CHAR = 65; private static char MAX_RANDOM_CHAR = 123; private static char searchChar; /* Intentionally use the same seed each time for consistency across benchmark runs. */ private static int SAME_SEED = 0; /* Random string data. */ private static Random rnd = new Random(SAME_SEED); private static String[] stringData = new String[NUM_LENGTH_TESTS]; /* Same random string data as above for comparing different instances of the same char data. */ private static Random rndAlt = new Random(SAME_SEED); private static String[] stringDataAlt = new String[NUM_LENGTH_TESTS]; /* Benchmark results cache for preventing DCE. */ private static boolean[] stringEqualsResults = new boolean[NUM_LENGTH_TESTS]; private static boolean[] stringEqualsIgnoreCaseResults = new boolean[NUM_LENGTH_TESTS]; private static boolean[] stringContentEqualsResults = new boolean[NUM_LENGTH_TESTS]; private static int[] stringCompareToResults = new int[NUM_LENGTH_TESTS]; private static int[] stringCompareToIgnoreCaseResults = new int[NUM_LENGTH_TESTS]; private static boolean[] stringRegionMatchesResults = new boolean[NUM_LENGTH_TESTS]; private static boolean[] stringRegionMatchesIgnoreCaseResults = new boolean[NUM_LENGTH_TESTS]; private static char stringCharAtResult; private static int stringIndexOfResult; private static int stringIndexOfAfterResult; private static String[] stringNewStringFromBytesResult = new String[NUM_LENGTH_TESTS]; private static String[] stringNewStringFromCharsResult = new String[NUM_LENGTH_TESTS]; private static String[] stringNewStringFromStringResult = new String[NUM_LENGTH_TESTS]; private static String[] stringGetCharsNoCheckResult = new String[NUM_LENGTH_TESTS]; private static char []chars_8 = new char[8]; private static char []chars_16 = new char[16]; private static char []chars_32 = new char[32]; private static char []chars_128 = new char[128]; private static char []chars_512 = new char[512]; private static String generateRandomString(int len, Random rnd) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < len - 1; i++) { /* Compose random string data from upper and lower case english alphabet entries plus a few * harmless characters in-between. */ sb.append(Character.valueOf((char)(MIN_RANDOM_CHAR + rnd.nextInt(MAX_RANDOM_CHAR - MIN_RANDOM_CHAR)))); } sb.append(Character.valueOf(MAX_RANDOM_CHAR)); return sb.toString(); } private static void generateRandomStrings(Random rnd, String[] output) { output[RANDOM_STRING_8] = generateRandomString(8, rnd); output[RANDOM_STRING_16] = generateRandomString(16, rnd); output[RANDOM_STRING_32] = generateRandomString(32, rnd); output[RANDOM_STRING_128] = generateRandomString(128, rnd); output[RANDOM_STRING_512] = generateRandomString(512, rnd); } static { searchChar = MAX_RANDOM_CHAR; generateRandomStrings(rnd, stringData); generateRandomStrings(rndAlt, stringDataAlt); } /** * String.equals */ @Benchmark public void jmhTimeStringEqualsSmall() { stringEqualsResults[RANDOM_STRING_8] ^= stringData[RANDOM_STRING_8].equals(stringDataAlt[RANDOM_STRING_8]); stringEqualsResults[RANDOM_STRING_16] ^= stringData[RANDOM_STRING_16].equals(stringDataAlt[RANDOM_STRING_16]); stringEqualsResults[RANDOM_STRING_32] ^= stringData[RANDOM_STRING_32].equals(stringDataAlt[RANDOM_STRING_32]); } @Benchmark public void jmhTimeStringEqualsLarge() { stringEqualsResults[RANDOM_STRING_128] ^= stringData[RANDOM_STRING_128].equals(stringDataAlt[RANDOM_STRING_128]); stringEqualsResults[RANDOM_STRING_512] ^= stringData[RANDOM_STRING_512].equals(stringDataAlt[RANDOM_STRING_512]); } /** * String.equalsIgnoreCase */ @Benchmark public void jmhTimeStringEqualsIgnoreCaseSmall() { stringEqualsIgnoreCaseResults[RANDOM_STRING_8] ^= stringData[RANDOM_STRING_8].equalsIgnoreCase( stringDataAlt[RANDOM_STRING_8]); stringEqualsIgnoreCaseResults[RANDOM_STRING_16] ^= stringData[RANDOM_STRING_16].equalsIgnoreCase( stringDataAlt[RANDOM_STRING_16]); stringEqualsIgnoreCaseResults[RANDOM_STRING_32] ^= stringData[RANDOM_STRING_32].equalsIgnoreCase( stringDataAlt[RANDOM_STRING_32]); } @Benchmark public void jmhTimeStringEqualsIgnoreCaseLarge() { stringEqualsIgnoreCaseResults[RANDOM_STRING_128] ^= stringData[RANDOM_STRING_128].equalsIgnoreCase( stringDataAlt[RANDOM_STRING_128]); stringEqualsIgnoreCaseResults[RANDOM_STRING_512] ^= stringData[RANDOM_STRING_512].equalsIgnoreCase( stringDataAlt[RANDOM_STRING_512]); } /** * String.contentEquals */ @Benchmark public void jmhTimeStringContentEqualsSmall() { stringContentEqualsResults[RANDOM_STRING_8] ^= stringData[RANDOM_STRING_8].contentEquals( stringDataAlt[RANDOM_STRING_8]); stringContentEqualsResults[RANDOM_STRING_16] ^= stringData[RANDOM_STRING_16].contentEquals( stringDataAlt[RANDOM_STRING_16]); stringContentEqualsResults[RANDOM_STRING_32] ^= stringData[RANDOM_STRING_32].contentEquals( stringDataAlt[RANDOM_STRING_32]); } @Benchmark public void jmhTimeStringContentEqualsLarge() { stringContentEqualsResults[RANDOM_STRING_128] ^= stringData[RANDOM_STRING_128].contentEquals( stringDataAlt[RANDOM_STRING_128]); stringContentEqualsResults[RANDOM_STRING_512] ^= stringData[RANDOM_STRING_512].contentEquals( stringDataAlt[RANDOM_STRING_512]); } /** * String.compareTo */ @Benchmark public void jmhTimeStringCompareToSmall() { stringCompareToResults[RANDOM_STRING_8] += stringData[RANDOM_STRING_8].compareTo(stringDataAlt[RANDOM_STRING_8]); stringCompareToResults[RANDOM_STRING_16] += stringData[RANDOM_STRING_16].compareTo(stringDataAlt[RANDOM_STRING_16]); stringCompareToResults[RANDOM_STRING_32] += stringData[RANDOM_STRING_32].compareTo(stringDataAlt[RANDOM_STRING_32]); } @Benchmark public void jmhTimeStringCompareToLarge() { stringCompareToResults[RANDOM_STRING_128] += stringData[RANDOM_STRING_128].compareTo(stringDataAlt[RANDOM_STRING_128]); stringCompareToResults[RANDOM_STRING_512] += stringData[RANDOM_STRING_512].compareTo(stringDataAlt[RANDOM_STRING_512]); } /** * String.compareToIgnoreCase */ @Benchmark public void jmhTimeStringCompareToIgnoreCaseSmall() { stringCompareToIgnoreCaseResults[RANDOM_STRING_8] += stringData[RANDOM_STRING_8].compareToIgnoreCase( stringDataAlt[RANDOM_STRING_8]); stringCompareToIgnoreCaseResults[RANDOM_STRING_16] += stringData[RANDOM_STRING_16].compareToIgnoreCase( stringDataAlt[RANDOM_STRING_16]); stringCompareToIgnoreCaseResults[RANDOM_STRING_32] += stringData[RANDOM_STRING_32].compareToIgnoreCase( stringDataAlt[RANDOM_STRING_32]); } @Benchmark public void jmhTimeStringCompareToIgnoreCaseLarge() { stringCompareToIgnoreCaseResults[RANDOM_STRING_128] += stringData[RANDOM_STRING_128].compareToIgnoreCase( stringDataAlt[RANDOM_STRING_128]); stringCompareToIgnoreCaseResults[RANDOM_STRING_512] += stringData[RANDOM_STRING_512].compareToIgnoreCase( stringDataAlt[RANDOM_STRING_512]); } /** * String.regionMatches */ @Benchmark public void jmhTimeStringRegionMatchesSmall() { stringRegionMatchesResults[RANDOM_STRING_8] ^= stringData[RANDOM_STRING_8].regionMatches( 0, stringDataAlt[RANDOM_STRING_8], 0, 8); stringRegionMatchesResults[RANDOM_STRING_16] ^= stringData[RANDOM_STRING_16].regionMatches( 0, stringDataAlt[RANDOM_STRING_16], 0, 16); stringRegionMatchesResults[RANDOM_STRING_32] ^= stringData[RANDOM_STRING_32].regionMatches( 0, stringDataAlt[RANDOM_STRING_32], 0, 32); } @Benchmark public void jmhTimeStringRegionMatchesLarge() { stringRegionMatchesResults[RANDOM_STRING_128] ^= stringData[RANDOM_STRING_128].regionMatches( 0, stringDataAlt[RANDOM_STRING_128], 0, 128); stringRegionMatchesResults[RANDOM_STRING_512] ^= stringData[RANDOM_STRING_512].regionMatches( 0, stringDataAlt[RANDOM_STRING_512], 0, 512); } /** * String.regionMatches */ @Benchmark public void jmhTimeStringRegionMatchesIgnoreCaseSmall() { stringRegionMatchesIgnoreCaseResults[RANDOM_STRING_8] ^= stringData[RANDOM_STRING_8].regionMatches( true, 0, stringDataAlt[RANDOM_STRING_8], 0, 8); stringRegionMatchesIgnoreCaseResults[RANDOM_STRING_16] ^= stringData[RANDOM_STRING_16].regionMatches( true, 0, stringDataAlt[RANDOM_STRING_16], 0, 16); stringRegionMatchesIgnoreCaseResults[RANDOM_STRING_32] ^= stringData[RANDOM_STRING_32].regionMatches( true, 0, stringDataAlt[RANDOM_STRING_32], 0, 32); } @Benchmark public void jmhTimeStringRegionMatchesIgnoreCaseLarge() { stringRegionMatchesIgnoreCaseResults[RANDOM_STRING_128] ^= stringData[RANDOM_STRING_128].regionMatches( true, 0, stringDataAlt[RANDOM_STRING_128], 0, 128); stringRegionMatchesIgnoreCaseResults[RANDOM_STRING_512] ^= stringData[RANDOM_STRING_512].regionMatches( true, 0, stringDataAlt[RANDOM_STRING_512], 0, 512); } /** * String.charAt */ @Benchmark public void jmhTimeStringCharAt() { for (int j = 0; j < 512; j++) { stringCharAtResult = stringData[RANDOM_STRING_512].charAt(j); } } /** * String.indexOf */ @Benchmark public void jmhTimeStringIndexOfSmall() { stringIndexOfResult += stringData[RANDOM_STRING_8].indexOf(searchChar); stringIndexOfResult += stringData[RANDOM_STRING_16].indexOf(searchChar); stringIndexOfResult += stringData[RANDOM_STRING_32].indexOf(searchChar); } @Benchmark public void jmhTimeStringIndexOfLarge() { stringIndexOfResult += stringData[RANDOM_STRING_128].indexOf(searchChar); stringIndexOfResult += stringData[RANDOM_STRING_512].indexOf(searchChar); } /** * String.indexOfAfter */ @Benchmark public void jmhTimeStringIndexOfAfterSmall() { stringIndexOfAfterResult += stringData[RANDOM_STRING_8].indexOf(searchChar, 1); stringIndexOfAfterResult += stringData[RANDOM_STRING_16].indexOf(searchChar, 1); stringIndexOfAfterResult += stringData[RANDOM_STRING_32].indexOf(searchChar, 1); } @Benchmark public void jmhTimeStringIndexOfAfterLarge() { stringIndexOfAfterResult += stringData[RANDOM_STRING_128].indexOf(searchChar, 1); stringIndexOfAfterResult += stringData[RANDOM_STRING_512].indexOf(searchChar, 1); } /** * NewStringFromBytes */ @Benchmark public void jmhTimeStringNewStringFromBytesSmall() { byte[] bytes = stringData[RANDOM_STRING_8].getBytes(); stringNewStringFromBytesResult[RANDOM_STRING_8] = new String(bytes); byte[] bytes2 = stringData[RANDOM_STRING_16].getBytes(); stringNewStringFromBytesResult[RANDOM_STRING_16] = new String(bytes2); byte[] bytes3 = stringData[RANDOM_STRING_32].getBytes(); stringNewStringFromBytesResult[RANDOM_STRING_32] = new String(bytes3); } @Benchmark public void jmhTimeStringNewStringFromBytesLarge() { byte[] bytes = stringData[RANDOM_STRING_128].getBytes(); stringNewStringFromBytesResult[RANDOM_STRING_128] = new String(bytes); byte[] bytes2 = stringData[RANDOM_STRING_512].getBytes(); stringNewStringFromBytesResult[RANDOM_STRING_512] = new String(bytes2); } /** * NewStringFromChars */ @Benchmark public void jmhTimeStringNewStringFromCharsSmall() { char[] chars = new char[8]; stringData[RANDOM_STRING_8].getChars(0, 8, chars, 0); stringNewStringFromCharsResult[RANDOM_STRING_8] = new String(chars); char[] chars2 = new char[16]; stringData[RANDOM_STRING_16].getChars(0, 16, chars2, 0); stringNewStringFromCharsResult[RANDOM_STRING_16] = new String(chars2); char[] chars3 = new char[32]; stringData[RANDOM_STRING_32].getChars(0, 32, chars3, 0); stringNewStringFromCharsResult[RANDOM_STRING_32] = new String(chars3); } @Benchmark public void jmhTimeStringNewStringFromCharsLarge() { char[] chars = new char[128]; stringData[RANDOM_STRING_128].getChars(0, 128, chars, 0); stringNewStringFromCharsResult[RANDOM_STRING_128] = new String(chars); char[] chars2 = new char[512]; stringData[RANDOM_STRING_512].getChars(0, 512, chars2, 0); stringNewStringFromCharsResult[RANDOM_STRING_512] = new String(chars2); } /** * NewStringFromString */ @Benchmark public void jmhTimeStringNewStringFromStringSmall() { stringNewStringFromStringResult[RANDOM_STRING_8] = new String(stringData[RANDOM_STRING_8]); stringNewStringFromStringResult[RANDOM_STRING_16] = new String(stringData[RANDOM_STRING_16]); stringNewStringFromStringResult[RANDOM_STRING_32] = new String(stringData[RANDOM_STRING_32]); } @Benchmark public void jmhTimeStringNewStringFromStringLarge() { stringNewStringFromStringResult[RANDOM_STRING_128] = new String(stringData[RANDOM_STRING_128]); stringNewStringFromStringResult[RANDOM_STRING_512] = new String(stringData[RANDOM_STRING_512]); } /** * String.getCharsNoCheck */ @Benchmark public void jmhTimeStringGetCharsNoCheckSmall() { stringData[RANDOM_STRING_8].getChars(0, 8, chars_8, 0); stringGetCharsNoCheckResult[RANDOM_STRING_8] = new String(chars_8); stringData[RANDOM_STRING_16].getChars(0, 16, chars_16, 0); stringGetCharsNoCheckResult[RANDOM_STRING_16] = new String(chars_16); stringData[RANDOM_STRING_32].getChars(0, 32, chars_32, 0); stringGetCharsNoCheckResult[RANDOM_STRING_32] = new String(chars_32); } @Benchmark public void jmhTimeStringGetCharsNoCheckLarge() { stringData[RANDOM_STRING_128].getChars(0, 128, chars_128, 0); stringGetCharsNoCheckResult[RANDOM_STRING_128] = new String(chars_128); stringData[RANDOM_STRING_512].getChars(0, 512, chars_512, 0); stringGetCharsNoCheckResult[RANDOM_STRING_512] = new String(chars_512); } }