summaryrefslogtreecommitdiff
path: root/src/main/java/org/linaro/benchmarks/micro
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/org/linaro/benchmarks/micro')
-rw-r--r--src/main/java/org/linaro/benchmarks/micro/ArrayAccess.java68
-rw-r--r--src/main/java/org/linaro/benchmarks/micro/Base64.java139
-rw-r--r--src/main/java/org/linaro/benchmarks/micro/BitfieldRotate.java302
-rw-r--r--src/main/java/org/linaro/benchmarks/micro/ControlFlowRecursive.java84
-rw-r--r--src/main/java/org/linaro/benchmarks/micro/Exceptions.java118
-rw-r--r--src/main/java/org/linaro/benchmarks/micro/HashMapBench.java101
-rw-r--r--src/main/java/org/linaro/benchmarks/micro/PrefetchLoopedArrayAccess.java78
-rw-r--r--src/main/java/org/linaro/benchmarks/micro/ShifterOperand.java548
-rw-r--r--src/main/java/org/linaro/benchmarks/micro/StringEquals.java73
-rw-r--r--src/main/java/org/linaro/benchmarks/micro/StringOps.java425
-rw-r--r--src/main/java/org/linaro/benchmarks/micro/SystemArrayCopy.java115
-rw-r--r--src/main/java/org/linaro/benchmarks/micro/VectorCalc.java83
-rw-r--r--src/main/java/org/linaro/benchmarks/micro/intrinsics/CRC32Bench.java70
-rw-r--r--src/main/java/org/linaro/benchmarks/micro/intrinsics/Intrinsics.java272
-rw-r--r--src/main/java/org/linaro/benchmarks/micro/intrinsics/MathIntrinsics.java367
15 files changed, 2843 insertions, 0 deletions
diff --git a/src/main/java/org/linaro/benchmarks/micro/ArrayAccess.java b/src/main/java/org/linaro/benchmarks/micro/ArrayAccess.java
new file mode 100644
index 0000000..5480562
--- /dev/null
+++ b/src/main/java/org/linaro/benchmarks/micro/ArrayAccess.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2016 Linaro Limited.
+ *
+ * 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 accessing array locations using variables and constants
+ * as indexes.
+ * Main Focus: Memory accesses using arrays.
+ *
+ */
+
+package org.linaro.benchmarks.micro;
+
+import org.openjdk.jmh.annotations.*;
+import java.util.concurrent.TimeUnit;
+
+@BenchmarkMode(Mode.AverageTime)
+@OutputTimeUnit(TimeUnit.MICROSECONDS)
+@State(Scope.Benchmark)
+
+public class ArrayAccess {
+
+ private static final int ITER_COUNT = 1000;
+ private int[] array = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+
+ public static void accessArrayConstants(int[] array) {
+ for (int j = 0; j < 100000; j++) {
+ array[4]++;
+ array[5]++;
+ }
+ }
+
+ public static void accessArrayVariables(int[] array, int i) {
+ for (int j = 0; j < 100000; j++) {
+ array[i]++;
+ array[i + 1]++;
+ array[i + 2]++;
+ array[i - 2]++;
+ array[i - 1]++;
+ }
+ }
+
+ @Benchmark
+ public void jmhTimeAccessArrayConstants() {
+ for (int i = 0; i < 1000; i++) {
+ accessArrayConstants(array);
+ }
+ }
+
+ @Benchmark
+ public void jmhTimeAccessArrayVariables() {
+ for (int i = 0; i < 1000; i++) {
+ accessArrayVariables(array, 5);
+ }
+ }
+}
diff --git a/src/main/java/org/linaro/benchmarks/micro/Base64.java b/src/main/java/org/linaro/benchmarks/micro/Base64.java
new file mode 100644
index 0000000..df58234
--- /dev/null
+++ b/src/main/java/org/linaro/benchmarks/micro/Base64.java
@@ -0,0 +1,139 @@
+/*
+ * encode and decode methods from:
+ * https://en.wikipedia.org/wiki/Base64#Sample_Implementation_in_Java
+ * Available under the Creative Commons Attribution-ShareAlike License.
+ * http://creativecommons.org/licenses/by-sa/3.0/
+ * Modifiication: added test code
+ */
+
+/*
+ * Description: Uses a Base64 MIME implementation to check for regressions
+ in loops, array access, load/store, and string manipulation.
+ * Main Focus: General operations related to Base64 encoding/decoding.
+ * Secondary Focus: Array access, load/store, string manipulation.
+ *
+ */
+
+package org.linaro.benchmarks.micro;
+
+import java.lang.IllegalArgumentException;
+import java.lang.StringBuilder;
+import java.lang.System;
+import java.lang.Thread;
+import java.util.Random;
+import org.openjdk.jmh.annotations.*;
+import java.util.concurrent.TimeUnit;
+
+@BenchmarkMode(Mode.AverageTime)
+@OutputTimeUnit(TimeUnit.MICROSECONDS)
+@State(Scope.Benchmark)
+
+public class Base64 {
+ private static Random rnd = new Random();
+ private static final int ENC_Length = 64;
+ private static final int NUM_Encodings = 16;
+ private static String[] randomStrings = new String[NUM_Encodings];
+ private static String[] randomBase64 = new String[NUM_Encodings];
+ private static String[] encodeResults = new String[NUM_Encodings];
+ private static String[] decodeResults = new String[NUM_Encodings];
+ private static final String codes =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
+ private static char base64Pad = '=';
+
+ static {
+ generateRandomStrings();
+ generateRandomBase64();
+ }
+
+ private static void generateRandomStrings() {
+ for (int i = 0; i < NUM_Encodings; i++) {
+ StringBuilder sb = new StringBuilder();
+ for (int j = 0; j < ENC_Length; j++) {
+ sb.append(Character.valueOf((char)rnd.nextInt()));
+ }
+ randomStrings[i] = sb.toString();
+ }
+ }
+
+ private static void generateRandomBase64() {
+ for (int i = 0; i < NUM_Encodings; i++) {
+ StringBuilder sb = new StringBuilder();
+ for (int j = 0; j < ENC_Length; j++) {
+ sb.append(codes.charAt(rnd.nextInt(codes.length() - 1)));
+ }
+ randomBase64[i] = sb.toString();
+ }
+ }
+
+ private static String encode(String str) {
+ byte[] in = str.getBytes();
+ StringBuffer out = new StringBuffer((in.length * 4) / 3);
+ int b;
+ for (int i = 0; i < in.length; i += 3) {
+ b = (in[i] & 0xFC) >> 2;
+ out.append(codes.charAt(b));
+ b = (in[i] & 0x03) << 4;
+ if (i + 1 < in.length) {
+ b |= (in[i + 1] & 0xF0) >> 4;
+ out.append(codes.charAt(b));
+ b = (in[i + 1] & 0x0F) << 2;
+ if (i + 2 < in.length) {
+ b |= (in[i + 2] & 0xC0) >> 6;
+ out.append(codes.charAt(b));
+ b = in[i + 2] & 0x3F;
+ out.append(codes.charAt(b));
+ } else {
+ out.append(codes.charAt(b));
+ out.append('=');
+ }
+ } else {
+ out.append(codes.charAt(b));
+ out.append("==");
+ }
+ }
+
+ return out.toString();
+ }
+
+ private static byte[] decode(String input) {
+ if (input.length() % 4 != 0) {
+ System.err.println("Invalid base64 input");
+ return null;
+ }
+ int eqPos = input.indexOf('=');
+ int len = input.length();
+ byte[] decoded =
+ new byte[((len * 3) / 4) - (eqPos > 0 ? (len - eqPos) : 0)];
+ char[] inChars = input.toCharArray();
+ int j = 0;
+ int[] b = new int[4];
+ for (int i = 0; i < inChars.length; i += 4) {
+ b[0] = codes.indexOf(inChars[i]);
+ b[1] = codes.indexOf(inChars[i + 1]);
+ b[2] = codes.indexOf(inChars[i + 2]);
+ b[3] = codes.indexOf(inChars[i + 3]);
+ decoded[j++] = (byte) ((b[0] << 2) | (b[1] >> 4));
+ if (b[2] < 64) {
+ decoded[j++] = (byte) ((b[1] << 4) | (b[2] >> 2));
+ if (b[3] < 64) {
+ decoded[j++] = (byte) ((b[2] << 6) | b[3]);
+ }
+ }
+ }
+ return decoded;
+ }
+
+ @Benchmark
+ public void jmhTimeEncode() {
+ for (int j = 0; j < NUM_Encodings; j++) {
+ encodeResults[j] = encode(randomStrings[j]);
+ }
+ }
+
+ @Benchmark
+ public void jmhTimeDecode() {
+ for (int j = 0; j < NUM_Encodings; j++) {
+ decodeResults[j] = new String(decode(randomBase64[j]));
+ }
+ }
+}
diff --git a/src/main/java/org/linaro/benchmarks/micro/BitfieldRotate.java b/src/main/java/org/linaro/benchmarks/micro/BitfieldRotate.java
new file mode 100644
index 0000000..f3185da
--- /dev/null
+++ b/src/main/java/org/linaro/benchmarks/micro/BitfieldRotate.java
@@ -0,0 +1,302 @@
+/*
+ * Copyright (c) 2000-2015 The Legion of the Bouncy Castle Inc. (http://www.bouncycastle.org)
+ *
+ * Modifications copyright (c) 2015 Linaro Limited.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+ * associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/*
+ * Description: Check for regressions effecting Bouncy Castle SHA1Digest processing.
+ * Main Focus: Bitfield rotations.
+ * Secondary Focus: Loop optimizations.
+ */
+
+package org.linaro.benchmarks.micro;
+
+import java.nio.ByteBuffer;
+import org.openjdk.jmh.annotations.*;
+import java.util.concurrent.TimeUnit;
+
+@BenchmarkMode(Mode.AverageTime)
+@OutputTimeUnit(TimeUnit.NANOSECONDS)
+@State(Scope.Benchmark)
+
+public class BitfieldRotate {
+ private static final String SOURCE_Text = "That though I loved them for their faults\n" +
+ "As much as for their good,\n" +
+ "My friends were enemies on stilts\n" +
+ "With their heads in a cunning cloud.\n";
+
+ private int h1;
+ private int h2;
+ private int h3;
+ private int h4;
+ private int h5;
+ private int[] x = new int[80];
+ private int xOff;
+
+ //
+ // Additive constants
+ //
+ private static final int y1 = 0x5a827999;
+ private static final int y2 = 0x6ed9eba1;
+ private static final int y3 = 0x8f1bbcdc;
+ private static final int y4 = 0xca62c1d6;
+
+ private int ffunc(
+ int u,
+ int v,
+ int w) {
+ return ((u & v) | ((~u) & w));
+ }
+
+ private int hfunc(
+ int u,
+ int v,
+ int w) {
+ return (u ^ v ^ w);
+ }
+
+ private int gfunc(
+ int u,
+ int v,
+ int w) {
+ return ((u & v) | (u & w) | (v & w));
+ }
+
+ protected void processBlock() {
+ //
+ // expand 16 word block into 80 word block.
+ //
+ for (int i = 16; i < 80; i++) {
+ int t = x[i - 3] ^ x[i - 8] ^ x[i - 14] ^ x[i - 16];
+ x[i] = t << 1 | t >>> 31;
+ }
+
+ //
+ // set up working variables.
+ //
+ int a = h1;
+ int b = h2;
+ int c = h3;
+ int d = h4;
+ int e = h5;
+
+ //
+ // round 1
+ //
+ int idx = 0;
+
+ for (int j = 0; j < 4; j++) {
+ // E = rotateLeft(a, 5) + ffunc(b, c, d) + E + x[idx++] + y1
+ // B = rotateLeft(b, 30)
+ e += (a << 5 | a >>> 27) + ffunc(b, c, d) + x[idx++] + y1;
+ b = b << 30 | b >>> 2;
+
+ d += (e << 5 | e >>> 27) + ffunc(a, b, c) + x[idx++] + y1;
+ a = a << 30 | a >>> 2;
+
+ c += (d << 5 | d >>> 27) + ffunc(e, a, b) + x[idx++] + y1;
+ e = e << 30 | e >>> 2;
+
+ b += (c << 5 | c >>> 27) + ffunc(d, e, a) + x[idx++] + y1;
+ d = d << 30 | d >>> 2;
+
+ a += (b << 5 | b >>> 27) + ffunc(c, d, e) + x[idx++] + y1;
+ c = c << 30 | c >>> 2;
+ }
+
+ //
+ // round 2
+ //
+ for (int j = 0; j < 4; j++) {
+ // E = rotateLeft(a, 5) + hfunc(b, c, d) + E + x[idx++] + y2
+ // B = rotateLeft(b, 30)
+ e += (a << 5 | a >>> 27) + hfunc(b, c, d) + x[idx++] + y2;
+ b = b << 30 | b >>> 2;
+
+ d += (e << 5 | e >>> 27) + hfunc(a, b, c) + x[idx++] + y2;
+ a = a << 30 | a >>> 2;
+
+ c += (d << 5 | d >>> 27) + hfunc(e, a, b) + x[idx++] + y2;
+ e = e << 30 | e >>> 2;
+
+ b += (c << 5 | c >>> 27) + hfunc(d, e, a) + x[idx++] + y2;
+ d = d << 30 | d >>> 2;
+
+ a += (b << 5 | b >>> 27) + hfunc(c, d, e) + x[idx++] + y2;
+ c = c << 30 | c >>> 2;
+ }
+
+ //
+ // round 3
+ //
+ for (int j = 0; j < 4; j++) {
+ // E = rotateLeft(a, 5) + gfunc(b, c, d) + E + x[idx++] + y3
+ // B = rotateLeft(b, 30)
+ e += (a << 5 | a >>> 27) + gfunc(b, c, d) + x[idx++] + y3;
+ b = b << 30 | b >>> 2;
+
+ d += (e << 5 | e >>> 27) + gfunc(a, b, c) + x[idx++] + y3;
+ a = a << 30 | a >>> 2;
+
+ c += (d << 5 | d >>> 27) + gfunc(e, a, b) + x[idx++] + y3;
+ e = e << 30 | e >>> 2;
+
+ b += (c << 5 | c >>> 27) + gfunc(d, e, a) + x[idx++] + y3;
+ d = d << 30 | d >>> 2;
+
+ a += (b << 5 | b >>> 27) + gfunc(c, d, e) + x[idx++] + y3;
+ c = c << 30 | c >>> 2;
+ }
+
+ //
+ // round 4
+ //
+ for (int j = 0; j <= 3; j++) {
+ // E = rotateLeft(a, 5) + hfunc(b, c, d) + E + x[idx++] + y4
+ // B = rotateLeft(b, 30)
+ e += (a << 5 | a >>> 27) + hfunc(b, c, d) + x[idx++] + y4;
+ b = b << 30 | b >>> 2;
+
+ d += (e << 5 | e >>> 27) + hfunc(a, b, c) + x[idx++] + y4;
+ a = a << 30 | a >>> 2;
+
+ c += (d << 5 | d >>> 27) + hfunc(e, a, b) + x[idx++] + y4;
+ e = e << 30 | e >>> 2;
+
+ b += (c << 5 | c >>> 27) + hfunc(d, e, a) + x[idx++] + y4;
+ d = d << 30 | d >>> 2;
+
+ a += (b << 5 | b >>> 27) + hfunc(c, d, e) + x[idx++] + y4;
+ c = c << 30 | c >>> 2;
+ }
+
+ h1 += a;
+ h2 += b;
+ h3 += c;
+ h4 += d;
+ h5 += e;
+
+ //
+ // reset start of the buffer.
+ //
+ xOff = 0;
+ for (int i = 0; i < 16; i++) {
+ x[i] = 0;
+ }
+ }
+
+ @Benchmark
+ public void jmhTimeSHA1DigestProcessBlock() {
+ h1 = h2 = h3 = h4 = h5 = 0;
+ processBlock();
+ }
+
+ /**
+ * Integer rotate right patterns.
+ */
+
+ int resultIntegerRightRegVCSubV;
+ int resultIntegerRightRegVNegV;
+
+ public static int rotateIntegerRightRegVCSubV(int value, int distance) {
+ return (value >>> distance) | (value << (32 - distance));
+ }
+
+ public static int rotateIntegerRightRegVNegV(int value, int distance) {
+ return (value >>> distance) | (value << -distance);
+ }
+
+ @Benchmark
+ public void jmhTimeIntegerRotateRight() {
+ for (int distance = 0; distance < Integer.SIZE; distance++) {
+ resultIntegerRightRegVCSubV += rotateIntegerRightRegVCSubV(0xCAFEBABE, distance);
+ resultIntegerRightRegVNegV += rotateIntegerRightRegVNegV(0xCAFEBABE, distance);
+ }
+ }
+
+ /**
+ * Integer rotate left patterns.
+ */
+
+ int resultIntegerLeftRegCSubVV;
+ int resultIntegerLeftRegNegVV;
+
+ public static int rotateIntegerLeftRegCSubVV(int value, int distance) {
+ return (value >>> (32 - distance)) | (value << distance);
+ }
+
+ public static int rotateIntegerLeftRegNegVV(int value, int distance) {
+ return (value >>> -distance) | (value << distance);
+ }
+
+ @Benchmark
+ public void jmhTimeIntegerRotateLeft() {
+ for (int distance = 0; distance < Integer.SIZE; distance++) {
+ resultIntegerLeftRegCSubVV += rotateIntegerLeftRegCSubVV(0xCAFEBABE, distance);
+ resultIntegerLeftRegNegVV += rotateIntegerLeftRegNegVV(0xCAFEBABE, distance);
+ }
+ }
+
+ /**
+ * Long rotate right patterns.
+ */
+
+ int resultLongRightRegVCSubV;
+ int resultLongRightRegVNegV;
+
+ public static long rotateLongRightRegVCSubV(long value, int distance) {
+ return (value >>> distance) | (value << (64 - distance));
+ }
+
+ public static long rotateLongRightRegVNegV(long value, int distance) {
+ return (value >>> distance) | (value << -distance);
+ }
+
+ @Benchmark
+ public void jmhTimeLongRotateRight() {
+ for (int distance = 0; distance < Long.SIZE; distance++) {
+ resultLongRightRegVCSubV += rotateLongRightRegVCSubV(0xCAFEBABEBAADF00DL, distance);
+ resultLongRightRegVNegV += rotateLongRightRegVNegV(0xCAFEBABEBAADF00DL, distance);
+ }
+ }
+
+ /**
+ * Long rotate left patterns.
+ */
+
+ int resultLongLeftRegCSubVV;
+ int resultLongLeftRegNegVV;
+
+ public static long rotateLongLeftRegCSubVV(long value, int distance) {
+ return (value >>> (64 - distance)) | (value << distance);
+ }
+
+ public static long rotateLongLeftRegNegVV(long value, int distance) {
+ return (value >>> -distance) | (value << distance);
+ }
+
+ @Benchmark
+ public void jmhTimeLongRotateLeft() {
+ for (int distance = 0; distance < Long.SIZE; distance++) {
+ resultLongLeftRegCSubVV += rotateLongLeftRegCSubVV(0xCAFEBABEBAADF00DL, distance);
+ resultLongLeftRegNegVV += rotateLongLeftRegNegVV(0xCAFEBABEBAADF00DL, distance);
+ }
+ }
+}
+
diff --git a/src/main/java/org/linaro/benchmarks/micro/ControlFlowRecursive.java b/src/main/java/org/linaro/benchmarks/micro/ControlFlowRecursive.java
new file mode 100644
index 0000000..26b4bf9
--- /dev/null
+++ b/src/main/java/org/linaro/benchmarks/micro/ControlFlowRecursive.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2015, Linaro Limited. Ported to Java from:
+ * https://github.com/WebKit/webkit/blob/master/PerformanceTests/SunSpider/tests/sunspider-1.0.2/controlflow-recursive.js
+ * and added Tarai.
+ *
+ * Description: A control flow recursive micro benchmark case.
+ */
+
+
+// The Computer Language Shootout
+// http://shootout.alioth.debian.org/
+// contributed by Isaac Gouy
+
+// http://benchmarksgame.alioth.debian.org/license.html (BSD 3-clause license)
+// See NOTICE file for license.
+
+package org.linaro.benchmarks.micro;
+
+import org.openjdk.jmh.annotations.*;
+import java.util.concurrent.TimeUnit;
+
+@BenchmarkMode(Mode.AverageTime)
+@OutputTimeUnit(TimeUnit.MICROSECONDS)
+@State(Scope.Benchmark)
+
+public class ControlFlowRecursive {
+ private int result = 0;
+ private final int expected = 57775;
+
+ private int ack(int m, int n) {
+ if (m == 0) {
+ return n + 1;
+ }
+ if (n == 0) {
+ return ack(m - 1, 1);
+ }
+ return ack(m - 1, ack(m, n - 1));
+ }
+
+ private int fib(int n) {
+ if (n < 2) {
+ return 1;
+ }
+ return fib(n - 2) + fib(n - 1);
+ }
+
+ private int tak(int x, int y, int z) {
+ if (y >= x) {
+ return z;
+ }
+ return tak(tak(x - 1, y, z), tak(y - 1, z, x), tak(z - 1, x, y));
+ }
+
+ private int tarai(int x, int y, int z) {
+ if (y >= x) {
+ return y;
+ }
+ return tarai(tarai(x - 1, y, z), tarai(y - 1, z, x), tarai(z - 1, x, y));
+ }
+
+ @Benchmark
+ public void jmhTimeTak() {
+ for (int i = 3; i <= 5; i++) {
+ tak(3 * i + 3, 2 * i + 2, i + 1);
+ }
+ }
+
+ @Benchmark
+ public void jmhTimeTarai() {
+ for (int i = 3; i <= 5; i++) {
+ tarai(3 * i + 3, 2 * i + 2, i + 1);
+ }
+ }
+
+ @Benchmark
+ public void jmhTimeControlFlowRecursive() {
+ result = 0;
+ for (int i = 3; i <= 5; i++) {
+ result += ack(3, i);
+ result += fib(17 + i);
+ result += tak(3 * i + 3, 2 * i + 2, i + 1);
+ }
+ }
+}
diff --git a/src/main/java/org/linaro/benchmarks/micro/Exceptions.java b/src/main/java/org/linaro/benchmarks/micro/Exceptions.java
new file mode 100644
index 0000000..3150f42
--- /dev/null
+++ b/src/main/java/org/linaro/benchmarks/micro/Exceptions.java
@@ -0,0 +1,118 @@
+/*
+ * 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: Exceptions code utilization.
+ * Main Focus:
+ *
+ */
+
+package org.linaro.benchmarks.micro;
+
+import org.openjdk.jmh.annotations.*;
+import java.util.concurrent.TimeUnit;
+
+@BenchmarkMode(Mode.AverageTime)
+@OutputTimeUnit(TimeUnit.MICROSECONDS)
+@State(Scope.Benchmark)
+
+public class Exceptions {
+
+ private final int SIZE = 10;
+ private int[] smallArray = new int[SIZE];
+ private static final int ARITHM_DOUBLE_ITERS = 20000;
+
+ /**
+ * Three following examples do the same arithmetics on double, but
+ * - arithmDouble: just does calculations
+ * - arirhmDoubleException: does calculations but has a try-catch which never fires.
+ * - arirhmDoubleExceptionFires: does calculations but has a try-catch which always fires.
+ */
+ private int arithmDoubleExceptionFires(int n) {
+ double x = 1.0 * (double)n;
+ double y = 2.0 * (double)n;
+ double z = 3.0 * (double)n;
+ double expr = 0.0;
+ int a = 0;
+
+ for (int i = 0; i < ARITHM_DOUBLE_ITERS; i++) {
+ expr += x + y + z * x + y * y + x * z;
+ try {
+ a += smallArray[i%SIZE + 5];
+ smallArray[i%SIZE + 5] += a;
+ } catch (Exception e) {
+ a--;
+ }
+ }
+
+ return (int)expr + a + (int)x + (int)y + (int)z;
+ }
+
+ private int arithmDoubleException(int n) {
+ double x = 1.0 * (double)n;
+ double y = 2.0 * (double)n;
+ double z = 3.0 * (double)n;
+ double expr = 0.0;
+ int a = 0;
+
+ for (int i = 0; i < ARITHM_DOUBLE_ITERS; i++) {
+ expr += x + y + z * x + y * y + x * z;
+ try {
+ a += smallArray[i%SIZE];
+ smallArray[i%SIZE] += a;
+ } catch (Exception e) {
+ a--;
+ }
+ }
+
+ return (int)expr + a + (int)x + (int)y + (int)z;
+ }
+
+ private int arithmDouble(int n) {
+ double x = 1.0 * (double)n;
+ double y = 2.0 * (double)n;
+ double z = 3.0 * (double)n;
+ double expr = 0.0;
+ int a = 0;
+
+ for (int i = 0; i < ARITHM_DOUBLE_ITERS; i++) {
+ expr += x + y + z * x + y * y + x * z;
+ a += smallArray[i%SIZE];
+ smallArray[i%SIZE] += a;
+ }
+
+ return (int)expr + a + (int)x + (int)y + (int)z;
+ }
+
+ @Benchmark
+ public void jmhTimeArithmDoubleException() {
+ //TODO (jmh) Following art-testing, use current iteration as arithmDoubleException's arg instead of 10.
+ arithmDoubleException(10);
+ }
+
+ @Benchmark
+ public void jmhTimeArithmDoubleExceptionFires() {
+ //TODO (jmh) Following art-testing, use current iteration as arithmDoubleException's arg instead of 20.
+ arithmDoubleExceptionFires(20);
+ }
+
+ @Benchmark
+ public void jmhTimeArithmDouble() {
+ //TODO (jmh) Following art-testing, use current iteration as arithmDoubleException's arg instead of 30.
+ arithmDouble(30);
+ }
+}
diff --git a/src/main/java/org/linaro/benchmarks/micro/HashMapBench.java b/src/main/java/org/linaro/benchmarks/micro/HashMapBench.java
new file mode 100644
index 0000000..02ffe14
--- /dev/null
+++ b/src/main/java/org/linaro/benchmarks/micro/HashMapBench.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2015, Linaro Limited. Ported to Java from:
+ * http://browserbench.org/JetStream/sources/hash-map.js
+ *
+ * Description: A benchmark case for hash map
+ */
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE below for additional
+ * information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/******* NOTICE *********
+
+ Apache Harmony
+ Copyright 2006, 2010 The Apache Software Foundation.
+
+ This product includes software developed at
+ The Apache Software Foundation (http://www.apache.org/).
+
+ Portions of Apache Harmony were originally developed by
+ Intel Corporation and are licensed to the Apache Software
+ Foundation under the "Software Grant and Corporate Contribution
+ License Agreement" and for which the following copyright notices
+ apply
+ (C) Copyright 2005 Intel Corporation
+ (C) Copyright 2005-2006 Intel Corporation
+ (C) Copyright 2006 Intel Corporation
+
+
+ The following copyright notice(s) were affixed to portions of the code
+ with which this file is now or was at one time distributed
+ and are placed here unaltered.
+
+ (C) Copyright 1997,2004 International Business Machines Corporation.
+ All rights reserved.
+
+ (C) Copyright IBM Corp. 2003.
+
+
+ This software contains code derived from UNIX V7, Copyright(C)
+ Caldera International Inc.
+
+ ************************/
+
+package org.linaro.benchmarks.micro;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.openjdk.jmh.annotations.*;
+import java.util.concurrent.TimeUnit;
+
+@BenchmarkMode(Mode.AverageTime)
+@OutputTimeUnit(TimeUnit.MICROSECONDS)
+@State(Scope.Benchmark)
+
+public class HashMapBench {
+
+ private static final int COUNT = 5000;
+ private static final int resultExpect = 1050000;
+ private static final long keySumExpect = 12497500;
+ private static final int valueSumExpect = 210000;
+ private int result = 0;
+ private long keySum = 0;
+ private int valueSum = 0;
+
+ private Map<Integer, Integer> map = new HashMap<Integer, Integer>();
+
+ @Benchmark
+ public void jmhTimeTestHashMap() {
+ for (int j = 0; j < COUNT; j++) {
+ map.put(j, 42);
+ }
+
+ result = 0;
+ for (int k = 0; k < 5; k++) {
+ for (int j = 0; j < COUNT; j++) {
+ result += map.get(j);
+ }
+ }
+
+ keySum = 0;
+ valueSum = 0;
+ for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
+ keySum += entry.getKey();
+ valueSum += entry.getValue();
+ }
+ }
+}
diff --git a/src/main/java/org/linaro/benchmarks/micro/PrefetchLoopedArrayAccess.java b/src/main/java/org/linaro/benchmarks/micro/PrefetchLoopedArrayAccess.java
new file mode 100644
index 0000000..d70a20a
--- /dev/null
+++ b/src/main/java/org/linaro/benchmarks/micro/PrefetchLoopedArrayAccess.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2015 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 looped array access to Java Objects.
+ * BitSet is an arbitrary choice. 1024 pool and update list
+ * sizes showed benefits when prefetching 8 references ahead
+ * during looped array access. Other benchmarks for different
+ * and mixed Object sizes would be beneficial.
+ * Main Focus: Looped array access to semi-random memory access patterns.
+ * Secondary Focus:
+ *
+ */
+
+package org.linaro.benchmarks.micro;
+
+import java.util.BitSet;
+import java.util.Random;
+import org.openjdk.jmh.annotations.*;
+import java.util.concurrent.TimeUnit;
+
+@BenchmarkMode(Mode.AverageTime)
+@OutputTimeUnit(TimeUnit.MICROSECONDS)
+@State(Scope.Benchmark)
+
+public class PrefetchLoopedArrayAccess {
+
+ private static final Random rnd = new Random(0);
+ private static final int POOL_Size = 1024;
+ private static final int UPDATE_Size = 1024;
+
+ private BitSet[] bits;
+ private BitSet[] updateList;
+
+ {
+ initBitSets();
+ initUpdateList();
+ }
+
+ private void initUpdateList() {
+ updateList = new BitSet[UPDATE_Size];
+ for (int i = 0; i < UPDATE_Size; i++) {
+ updateList[i] = bits[rnd.nextInt(POOL_Size)];
+ }
+ }
+
+ private void initBitSets() {
+ bits = new BitSet[POOL_Size];
+ for (int i = 0; i < POOL_Size; i++) {
+ bits[i] = new BitSet();
+ }
+ }
+
+ private void updateBitSets() {
+ for (int i = 0; i < UPDATE_Size; i++) {
+ updateList[i].set(7);
+ }
+ }
+
+ @Benchmark
+ public void jmhTimeRun() {
+ updateBitSets();
+ }
+}
diff --git a/src/main/java/org/linaro/benchmarks/micro/ShifterOperand.java b/src/main/java/org/linaro/benchmarks/micro/ShifterOperand.java
new file mode 100644
index 0000000..b29f551
--- /dev/null
+++ b/src/main/java/org/linaro/benchmarks/micro/ShifterOperand.java
@@ -0,0 +1,548 @@
+/*
+ * Copyright (C) 2015 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.
+ *
+ */
+
+package org.linaro.benchmarks.micro;
+
+import org.openjdk.jmh.annotations.*;
+import java.util.concurrent.TimeUnit;
+
+@BenchmarkMode(Mode.AverageTime)
+@OutputTimeUnit(TimeUnit.NANOSECONDS)
+@State(Scope.Benchmark)
+
+
+/*
+ * Description: Tests around binary operations taking shifts or type conversions
+ * as inputs that can be merged into the shifter operand.
+ *
+ * Main Focus: shifter operand
+ *
+ * Secondary Focus: instruction scheduling
+ *
+ * Some comments in this file assume that shift or extend operations are merged
+ * into the shifter operand of the binary operations using them.
+ */
+
+// We declare many temporary local variables with similar names. Avoid the extra
+// lines that would be required with one declaration per line.
+// CHECKSTYLE.OFF: MultipleVariableDeclarations
+
+public class ShifterOperand {
+
+ private static final int LOOP_SIZE = 32;
+
+ @Benchmark
+ public static int jmhTimeIntSingleUseLatency1() {
+ int t1 = 0;
+ for (int iter = 0; iter < LOOP_SIZE; iter++) {
+ // Each bitfield operation has a single use.
+ // Results are used one instruction after being produced.
+ t1 |= iter >> 1;
+ t1 &= iter << 2;
+ t1 ^= iter >>> 3;
+ t1 += (byte)iter;
+ t1 -= (char)iter;
+ t1 += (short)iter;
+ }
+ return t1;
+ }
+
+ // The `ThreadN` suffix indicates that the loop contains `N` independent
+ // computation threads that execute (almost exactly) the same thing. The
+ // multiple threads allow for instruction scheduling to kick in.
+
+ @Benchmark
+ public static int jmhTimeIntSingleUseLatency1Thread2() {
+ int t1 = 0, t2 = 1;
+ for (int iter1 = 0, iter2 = 1;
+ iter1 < LOOP_SIZE;
+ iter1++, iter2++) {
+ // Each bitfield operation has a single use.
+ // Results are used one instruction after being produced.
+ // Computation thread 1.
+ t1 |= iter1 >> 1;
+ t1 &= iter1 << 2;
+ t1 ^= iter1 >>> 3;
+ t1 += (byte)iter1;
+ t1 -= (char)iter1;
+ t1 += (short)iter1;
+ // Computation thread 2.
+ t2 |= iter2 >> 1;
+ t2 &= iter2 << 2;
+ t2 ^= iter2 >>> 3;
+ t2 += (byte)iter2;
+ t2 -= (char)iter2;
+ t2 += (short)iter2;
+ }
+ return t1;
+ }
+
+ @Benchmark
+ public static int jmhTimeIntSingleUseLatency1Thread3() {
+ int t1 = 0, t2 = 1, t3 = 2;
+ // Each bitfield operation has a single use.
+ // Results are used one instruction after being produced.
+ for (int iter1 = 0, iter2 = 1, iter3 = 2;
+ iter1 < LOOP_SIZE;
+ iter1++, iter2++, iter3++) {
+ // Computation thread 1.
+ t1 |= iter1 >> 1;
+ t1 &= iter1 << 2;
+ t1 ^= iter1 >>> 3;
+ t1 += (byte)iter1;
+ t1 -= (char)iter1;
+ t1 += (short)iter1;
+ // Computation thread 2.
+ t2 |= iter2 >> 1;
+ t2 &= iter2 << 2;
+ t2 ^= iter2 >>> 3;
+ t2 += (byte)iter2;
+ t2 -= (char)iter2;
+ t2 += (short)iter2;
+ // Computation thread 3.
+ t3 |= iter3 >> 1;
+ t3 &= iter3 << 2;
+ t3 ^= iter3 >>> 3;
+ t3 += (byte)iter3;
+ t3 -= (char)iter3;
+ t3 += (short)iter3;
+ }
+ return t1;
+ }
+
+ @Benchmark
+ public static int jmhTimeIntSingleUseLatency1Thread4() {
+ int t1 = 0, t2 = 1, t3 = 2, t4 = 3;
+ // Each bitfield operation has a single use.
+ // Results are used one instruction after being produced.
+
+ for (int iter1 = 0, iter2 = 1, iter3 = 2, iter4 = 3;
+ iter1 < LOOP_SIZE;
+ iter1++, iter2++, iter3++, iter4++) {
+ // Computation thread 1.
+ t1 |= iter1 >> 1;
+ t1 &= iter1 << 2;
+ t1 ^= iter1 >>> 3;
+ t1 += (byte)iter1;
+ t1 -= (char)iter1;
+ t1 += (short)iter1;
+ // Computation thread 2.
+ t2 |= iter2 >> 1;
+ t2 &= iter2 << 2;
+ t2 ^= iter2 >>> 3;
+ t2 += (byte)iter2;
+ t2 -= (char)iter2;
+ t2 += (short)iter2;
+ // Computation thread 3.
+ t3 |= iter3 >> 1;
+ t3 &= iter3 << 2;
+ t3 ^= iter3 >>> 3;
+ t3 += (byte)iter3;
+ t3 -= (char)iter3;
+ t3 += (short)iter3;
+ // Computation thread 4.
+ t4 |= iter4 >> 1;
+ t4 &= iter4 << 2;
+ t4 ^= iter4 >>> 3;
+ t4 += (byte)iter4;
+ t4 -= (char)iter4;
+ t4 += (short)iter4;
+ }
+ return t1;
+ }
+
+ @Benchmark
+ public static int jmhTimeIntSingleUseLatency2() {
+ int t1 = 0, t2 = 0;
+ for (int iter = 0; iter < LOOP_SIZE; iter++) {
+ // Each bitfield operation has a single use.
+ // Results are used two instructions after being produced.
+ t1 |= iter >> 1;
+ t2 &= iter << 2;
+ t1 ^= iter >>> 3;
+ t2 += (byte)iter;
+ t1 -= (char)iter;
+ t2 += (short)iter;
+ }
+ return t1 | t2;
+ }
+
+ @Benchmark
+ public static int jmhTimeIntSingleUseLatency3() {
+ int t1 = 0, t2 = 0, t3 = 0;
+ for (int iter = 0; iter < LOOP_SIZE; iter++) {
+ // Each bitfield operation has a single use.
+ // Results are used three instructions after being produced.
+ t1 |= iter >> 1;
+ t2 &= iter << 2;
+ t3 ^= iter >>> 3;
+ t1 += (byte)iter;
+ t2 -= (char)iter;
+ t3 += (short)iter;
+ }
+ return t1 | t2;
+ }
+
+ @Benchmark
+ public static int jmhTimeIntSingleUseLatencyLoop() {
+ int t1 = 0, t2 = 0, t3 = 0, t4 = 0, t5 = 0, t6 = 0;
+ for (int iter = 0; iter < LOOP_SIZE; iter++) {
+ // Each bitfield operation has a single use.
+ // Results are only used in the next iteration of the loop.
+ t1 |= iter >> 1;
+ t2 &= iter << 2;
+ t3 ^= iter >>> 3;
+ t4 += (byte)iter;
+ t5 -= (char)iter;
+ t6 += (short)iter;
+ }
+ return t1 | t2 | t3 | t4 | t5 | t6;
+ }
+
+ @Benchmark
+ public static long jmhTimeLongSingleUseLatency1() {
+ long t1 = 0;
+ for (long iter = 0; iter < LOOP_SIZE; iter++) {
+ // Each bitfield operation has a single use.
+ // Results are used one instruction after being produced.
+ t1 |= iter >> 1;
+ t1 &= iter << 2;
+ t1 ^= iter >>> 3;
+ t1 += (byte)iter;
+ t1 -= (char)iter;
+ t1 += (short)iter;
+ }
+ return t1;
+ }
+
+ // The `ThreadN` suffix indicates that the loop contains `N` independent
+ // computation threads that execute (almost exactly) the same thing. The
+ // multiple threads allow for instruction scheduling to kick in.
+ @Benchmark
+ public static long jmhTimeLongSingleUseLatency1Thread2() {
+ long t1 = 0, t2 = 1;
+ for (long iter1 = 0, iter2 = 1;
+ iter1 < LOOP_SIZE;
+ iter1++, iter2++) {
+ // Each bitfield operation has a single use.
+ // Results are used one instruction after being produced.
+ // Computation thread 1.
+ t1 |= iter1 >> 1;
+ t1 &= iter1 << 2;
+ t1 ^= iter1 >>> 3;
+ t1 += (byte)iter1;
+ t1 -= (char)iter1;
+ t1 += (short)iter1;
+ // Computation thread 2.
+ t2 |= iter2 >> 1;
+ t2 &= iter2 << 2;
+ t2 ^= iter2 >>> 3;
+ t2 += (byte)iter2;
+ t2 -= (char)iter2;
+ t2 += (short)iter2;
+ }
+ return t1;
+ }
+
+ @Benchmark
+ public static long jmhTimeLongSingleUseLatency1Thread3() {
+ long t1 = 0, t2 = 1, t3 = 2;
+ // Each bitfield operation has a single use.
+ // Results are used one instruction after being produced.
+ for (long iter1 = 0, iter2 = 1, iter3 = 2;
+ iter1 < LOOP_SIZE;
+ iter1++, iter2++, iter3++) {
+ // Computation thread 1.
+ t1 |= iter1 >> 1;
+ t1 &= iter1 << 2;
+ t1 ^= iter1 >>> 3;
+ t1 += (byte)iter1;
+ t1 -= (char)iter1;
+ t1 += (short)iter1;
+ // Computation thread 2.
+ t2 |= iter2 >> 1;
+ t2 &= iter2 << 2;
+ t2 ^= iter2 >>> 3;
+ t2 += (byte)iter2;
+ t2 -= (char)iter2;
+ t2 += (short)iter2;
+ // Computation thread 3.
+ t3 |= iter3 >> 1;
+ t3 &= iter3 << 2;
+ t3 ^= iter3 >>> 3;
+ t3 += (byte)iter3;
+ t3 -= (char)iter3;
+ t3 += (short)iter3;
+ }
+ return t1;
+ }
+
+ @Benchmark
+ public static long jmhTimeLongSingleUseLatency1Thread4() {
+ long t1 = 0, t2 = 1, t3 = 2, t4 = 3;
+ // Each bitfield operation has a single use.
+ // Results are used one instruction after being produced.
+
+ for (long iter1 = 0, iter2 = 1, iter3 = 2, iter4 = 3;
+ iter1 < LOOP_SIZE;
+ iter1++, iter2++, iter3++, iter4++) {
+ // Computation thread 1.
+ t1 |= iter1 >> 1;
+ t1 &= iter1 << 2;
+ t1 ^= iter1 >>> 3;
+ t1 += (byte)iter1;
+ t1 -= (char)iter1;
+ t1 += (short)iter1;
+ // Computation thread 2.
+ t2 |= iter2 >> 1;
+ t2 &= iter2 << 2;
+ t2 ^= iter2 >>> 3;
+ t2 += (byte)iter2;
+ t2 -= (char)iter2;
+ t2 += (short)iter2;
+ // Computation thread 3.
+ t3 |= iter3 >> 1;
+ t3 &= iter3 << 2;
+ t3 ^= iter3 >>> 3;
+ t3 += (byte)iter3;
+ t3 -= (char)iter3;
+ t3 += (short)iter3;
+ // Computation thread 4.
+ t4 |= iter4 >> 1;
+ t4 &= iter4 << 2;
+ t4 ^= iter4 >>> 3;
+ t4 += (byte)iter4;
+ t4 -= (char)iter4;
+ t4 += (short)iter4;
+ }
+ return t1;
+ }
+
+ @Benchmark
+ public static long jmhTimeLongSingleUseLatency2() {
+ long t1 = 0, t2 = 0;
+ for (long iter = 0; iter < LOOP_SIZE; iter++) {
+ // Each bitfield operation has a single use.
+ // Results are used two instructions after being produced.
+ t1 |= iter >> 1;
+ t2 &= iter << 2;
+ t1 ^= iter >>> 3;
+ t2 += (byte)iter;
+ t1 -= (char)iter;
+ t2 += (short)iter;
+ }
+ return t1 | t2;
+ }
+
+ @Benchmark
+ public static long jmhTimeLongSingleUseLatency3() {
+ long t1 = 0, t2 = 0, t3 = 0;
+ for (long iter = 0; iter < LOOP_SIZE; iter++) {
+ // Each bitfield operation has a single use.
+ // Results are used three instructions after being produced.
+ t1 |= iter >> 1;
+ t2 &= iter << 2;
+ t3 ^= iter >>> 3;
+ t1 += (byte)iter;
+ t2 -= (char)iter;
+ t3 += (short)iter;
+ }
+ return t1 | t2;
+ }
+
+ @Benchmark
+ public static long jmhTimeLongSingleUseLatencyLoop() {
+ long t1 = 0, t2 = 0, t3 = 0, t4 = 0, t5 = 0, t6 = 0;
+ for (long iter = 0; iter < LOOP_SIZE; iter++) {
+ // Each bitfield operation has a single use.
+ // Results are only used in the next iteration of the loop.
+ t1 |= iter >> 1;
+ t2 &= iter << 2;
+ t3 ^= iter >>> 3;
+ t4 += (byte)iter;
+ t5 -= (char)iter;
+ t6 += (short)iter;
+ }
+ return t1 | t2 | t3 | t4 | t5 | t6;
+ }
+
+ @Benchmark
+ public static int jmhTimeMultipleUsesDifferentPathInt() {
+ int res = 0;
+ for (int iter = 0; iter < LOOP_SIZE; iter++) {
+ // Each bitfield operation has two uses on different paths.
+ int temp1 = iter >> 1;
+ int temp2 = iter << 2;
+ int temp3 = iter >>> 3;
+ int temp4 = (byte)iter;
+ int temp5 = (char)iter;
+ int temp6 = (short)iter;
+ int temp7 = (int)iter;
+ // The condition is true most of the time, so the branch predictor should
+ // predict it correctly.
+ if (iter > 1) {
+ res += (((((temp1 | temp2) & temp3) ^ temp4) + temp5) - temp6) + temp7;
+ } else {
+ res += (((((temp1 + temp2) | temp3) & temp4) & temp5) + temp6) - temp7;
+ }
+ }
+ return res;
+ }
+
+ @Benchmark
+ public static long jmhTimeMultipleUsesDifferentPathLong() {
+ long res = 0;
+ for (long iter = 0; iter < LOOP_SIZE; iter++) {
+ // Each bitfield operation has two uses on different paths.
+ long temp1 = iter >> 1;
+ long temp2 = iter << 2;
+ long temp3 = iter >>> 3;
+ long temp4 = (byte)iter;
+ long temp5 = (char)iter;
+ long temp6 = (short)iter;
+ long temp7 = (int)iter;
+ // The condition is true most of the time, so the branch predictor should
+ // predict it correctly.
+ if (iter > 1) {
+ res += (((((temp1 | temp2) & temp3) ^ temp4) + temp5) - temp6) + temp7;
+ } else {
+ res += (((((temp1 + temp2) | temp3) & temp4) & temp5) + temp6) - temp7;
+ }
+ }
+ return res;
+ }
+
+ @Benchmark
+ public static int jmhTimeMultipleSuccessiveUsesSamePathInt() {
+ int res = 0;
+ for (int iter = 0; iter < LOOP_SIZE; iter++) {
+ // Each bitfield operation has two successive uses on the same path.
+ int temp1 = iter >> 1;
+ res += temp1;
+ res += temp1;
+ int temp2 = iter << 2;
+ res += temp2;
+ res += temp2;
+ int temp3 = iter >>> 3;
+ res += temp3;
+ res += temp3;
+ int temp4 = (byte)iter;
+ res += temp4;
+ res += temp4;
+ int temp5 = (char)iter;
+ res += temp5;
+ res += temp5;
+ int temp6 = (short)iter;
+ res += temp6;
+ res += temp6;
+ int temp7 = (int)iter;
+ res += temp7;
+ res += temp7;
+ }
+ return res;
+ }
+
+ @Benchmark
+ public static long jmhTimeMultipleSuccessiveUsesSamePathLong() {
+ long res = 0;
+ for (long iter = 0; iter < LOOP_SIZE; iter++) {
+ // Each bitfield operation has two successive uses on the same path.
+ long temp1 = iter >> 1;
+ res += temp1;
+ res += temp1;
+ long temp2 = iter << 2;
+ res += temp2;
+ res += temp2;
+ long temp3 = iter >>> 3;
+ res += temp3;
+ res += temp3;
+ long temp4 = (byte)iter;
+ res += temp4;
+ res += temp4;
+ long temp5 = (char)iter;
+ res += temp5;
+ res += temp5;
+ long temp6 = (short)iter;
+ res += temp6;
+ res += temp6;
+ long temp7 = (int)iter;
+ res += temp7;
+ res += temp7;
+ }
+ return res;
+ }
+
+ @Benchmark
+ public static int jmhTimeMultipleSeparatedUsesSamePathInt() {
+ int res = 0;
+ for (int iter = 0; iter < LOOP_SIZE; iter++) {
+ // Each bitfield operation has two separated uses on the same path.
+ int temp1 = iter >> 1;
+ res += temp1;
+ int temp2 = iter << 2;
+ res += temp2;
+ res += temp1;
+ int temp3 = iter >>> 3;
+ res += temp3;
+ res += temp2;
+ int temp4 = (byte)iter;
+ res += temp4;
+ res += temp3;
+ int temp5 = (char)iter;
+ res += temp5;
+ res += temp4;
+ int temp6 = (short)iter;
+ res += temp6;
+ res += temp5;
+ int temp7 = (int)iter;
+ res += temp7;
+ res += temp6;
+ res += temp7;
+ }
+ return res;
+ }
+
+ @Benchmark
+ public static long jmhTimeMultipleSeparatedUsesSamePathLong() {
+ long res = 0;
+ for (long iter = 0; iter < LOOP_SIZE; iter++) {
+ // Each bitfield operation has two separated uses on the same path.
+ long temp1 = iter >> 1;
+ res += temp1;
+ long temp2 = iter << 2;
+ res += temp2;
+ res += temp1;
+ long temp3 = iter >>> 3;
+ res += temp3;
+ res += temp2;
+ long temp4 = (byte)iter;
+ res += temp4;
+ res += temp3;
+ long temp5 = (char)iter;
+ res += temp5;
+ res += temp4;
+ long temp6 = (short)iter;
+ res += temp6;
+ res += temp5;
+ long temp7 = (int)iter;
+ res += temp7;
+ res += temp6;
+ res += temp7;
+ }
+ return res;
+ }
+}
diff --git a/src/main/java/org/linaro/benchmarks/micro/StringEquals.java b/src/main/java/org/linaro/benchmarks/micro/StringEquals.java
new file mode 100644
index 0000000..e0dbc72
--- /dev/null
+++ b/src/main/java/org/linaro/benchmarks/micro/StringEquals.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2015 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.equals when working with
+ * cache-limiting amounts of character data. Some prefetch
+ * hint investigations have shown a performance gain here.
+ * Main Focus: Comparison of many, very large (re: L1 cache) strings.
+ * Secondary Focus:
+ *
+ */
+
+/*
+ * TODO: Test various sizes of strings.
+ * TODO: Benchmark other cases, like comparing strings of different
+ * sizes together (probably the most command case), or similar
+ * strings that have a run of equal characters to begin with.
+ */
+
+package org.linaro.benchmarks.micro;
+
+import java.lang.StringBuilder;
+import java.util.Random;
+import org.openjdk.jmh.annotations.*;
+import java.util.concurrent.TimeUnit;
+
+@BenchmarkMode(Mode.AverageTime)
+@OutputTimeUnit(TimeUnit.MICROSECONDS)
+@State(Scope.Benchmark)
+
+public class StringEquals {
+ private static Random rnd = new Random(0);
+ private static final int NUM_Equals = 1024;
+ private static final int STR_Length = 512;
+ private static String[] randomStrings = new String[NUM_Equals];
+ private static Boolean[] equalsResults = new Boolean[NUM_Equals - 1];
+
+ @Setup
+ public void setup() {
+ generateRandomStrings();
+ }
+
+ private static void generateRandomStrings() {
+ for (int i = 0; i < NUM_Equals; i++) {
+ StringBuilder sb = new StringBuilder();
+ for (int j = 0; j < STR_Length; j++) {
+ sb.append(Character.valueOf((char)(rnd.nextInt(25) + 65)));
+ }
+ randomStrings[i] = sb.toString();
+ }
+ }
+
+ @Benchmark
+ public void jmhTimeEquals() {
+ for (int j = 0; j < NUM_Equals - 1; j++) {
+ equalsResults[j] = randomStrings[j].equals(randomStrings[j + 1]);
+ }
+ }
+}
diff --git a/src/main/java/org/linaro/benchmarks/micro/StringOps.java b/src/main/java/org/linaro/benchmarks/micro/StringOps.java
new file mode 100644
index 0000000..5851c36
--- /dev/null
+++ b/src/main/java/org/linaro/benchmarks/micro/StringOps.java
@@ -0,0 +1,425 @@
+/*
+ * 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);
+ }
+}
diff --git a/src/main/java/org/linaro/benchmarks/micro/SystemArrayCopy.java b/src/main/java/org/linaro/benchmarks/micro/SystemArrayCopy.java
new file mode 100644
index 0000000..230bd4b
--- /dev/null
+++ b/src/main/java/org/linaro/benchmarks/micro/SystemArrayCopy.java
@@ -0,0 +1,115 @@
+/*
+ * 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 System.arraycopy intrinsics.
+ * Main Focus: Looped load store for varying copy lengths.
+ * Secondary Focus:
+ *
+ */
+
+package org.linaro.benchmarks.micro;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.StringReader;
+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 SystemArrayCopy {
+
+ private static Random rnd = new Random();
+ private static int ARRAY_COPY_SMALL = 16;
+ private static int ARRAY_COPY_MEDIUM = 128;
+ private static int ARRAY_COPY_LARGE = 1024;
+ private static int MAX_BUFFER_BYTES = 8192;
+ private static int ARRAY_LENGTH = 1024;
+ private static String RANDOM_STRING = generateRandomString(MAX_BUFFER_BYTES);
+ private static char[] cbuf = new char[MAX_BUFFER_BYTES];
+ private static char arrayCopyCharBufferedReadSmallResult;
+ private static char arrayCopyCharBufferedReadMediumResult;
+ private static char arrayCopyCharBufferedReadLargeResult;
+
+ private static String[] stringArray = new String[ARRAY_LENGTH];
+ private static String[] stringArraySmall = new String[ARRAY_LENGTH];
+ private static String[] stringArrayMedium = new String[ARRAY_LENGTH];
+ private static String[] stringArrayLarge = new String[ARRAY_LENGTH];
+
+ private static String generateRandomString(int sz) {
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < sz; i++) {
+ sb.append(Character.valueOf((char)rnd.nextInt()));
+ }
+ return sb.toString();
+ }
+
+ static {
+ for (int i = 0; i < ARRAY_LENGTH; i++) {
+ stringArray[i] = String.valueOf(i);
+ }
+ }
+
+ private void bufferedReadLoop(char[] cbuf, int copyLength) throws IOException {
+ BufferedReader reader = new BufferedReader(new StringReader(RANDOM_STRING));
+ int offset = 0;
+ String s;
+ /* Read 16Kb RANDOM_STRING in chunks of copyLength chars until EOF */
+ while (offset < MAX_BUFFER_BYTES && (reader.read(cbuf, offset, copyLength)) != -1) {
+ offset += copyLength;
+ }
+ }
+
+ @Benchmark
+ public void jmhTimeArrayCopyCharBufferedReadSmall() throws IOException {
+ bufferedReadLoop(cbuf, ARRAY_COPY_SMALL);
+ arrayCopyCharBufferedReadSmallResult = cbuf[MAX_BUFFER_BYTES - 1];
+ }
+
+ @Benchmark
+ public void jmhTimeArrayCopyCharBufferedReadMedium() throws IOException {
+ bufferedReadLoop(cbuf, ARRAY_COPY_MEDIUM);
+ arrayCopyCharBufferedReadMediumResult = cbuf[MAX_BUFFER_BYTES - 1];
+ }
+
+ @Benchmark
+ public void jmhTimeArrayCopyCharBufferedReadLarge() throws IOException {
+ bufferedReadLoop(cbuf, ARRAY_COPY_LARGE);
+ arrayCopyCharBufferedReadLargeResult = cbuf[MAX_BUFFER_BYTES - 1];
+ }
+
+ @Benchmark
+ public void jmhTimeArrayCopySmall() {
+ System.arraycopy(stringArray, 0, stringArraySmall, 0, ARRAY_COPY_SMALL);
+ }
+
+ @Benchmark
+ public void jmhTimeArrayCopyMedium() {
+ System.arraycopy(stringArray, 0, stringArrayMedium, 0, ARRAY_COPY_MEDIUM);
+ }
+
+ @Benchmark
+ public void jmhTimeArrayCopyLarge() {
+ System.arraycopy(stringArray, 0, stringArrayLarge, 0, ARRAY_COPY_LARGE);
+ }
+}
diff --git a/src/main/java/org/linaro/benchmarks/micro/VectorCalc.java b/src/main/java/org/linaro/benchmarks/micro/VectorCalc.java
new file mode 100644
index 0000000..0c2ad2a
--- /dev/null
+++ b/src/main/java/org/linaro/benchmarks/micro/VectorCalc.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2015 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: Some generic vector operations.
+ * Main Focus: Boundary checks in loops
+ * Secondary Focus: Array access, load/store.
+ *
+ */
+
+package org.linaro.benchmarks.micro;
+
+import org.openjdk.jmh.annotations.*;
+import java.util.concurrent.TimeUnit;
+
+@BenchmarkMode(Mode.AverageTime)
+@OutputTimeUnit(TimeUnit.NANOSECONDS)
+@State(Scope.Benchmark)
+
+public class VectorCalc {
+
+ public static final int ARRAY_SIZE = 500;
+ public static final int COEFFICIENT = 2;
+ public static final int MAIN_ITERATIONS = 80000;
+ public int[] array1 = new int[ARRAY_SIZE];
+ public int[] array2 = new int[ARRAY_SIZE];
+ public int[] array3 = new int[ARRAY_SIZE];
+
+ // index : loop induction variable + loop invariable
+ public void setArrayValues(int[] array, int start, int length, int startValue, int step) {
+ for (int i = 0, value = startValue; i < length; ++i, value += step) {
+ array[i + start] = value;
+ }
+ }
+
+ // index : loop induction variable
+ // multiple arrays
+ public void copyArray(int[] dst, int[] src, int start, int length) {
+ for (int i = start, end = start + length; i < end; ++i) {
+ dst[i] = src[i];
+ }
+ }
+
+ // index : loop induction variable + loop invariable
+ // multiple arrays
+ public void scaleProduct(int[] dst, int[] src, int start, int length, int coefficient) {
+ for (int i = 0; i < length; ++i) {
+ dst[i + start] = coefficient * src[i + start];
+ }
+ }
+
+ // index-1 : loop induction variable
+ // index-2 : loop invariable
+ // multiple arrays
+ public void dotProduct(int[] src1, int[] src2, int start, int length, int[] output,
+ int outputOffset) {
+ for (int i = start, end = start + length; i < end; ++i) {
+ output[outputOffset] += src1[i] * src2[i];
+ }
+ }
+
+ @Benchmark
+ public void jmhTimeRun() {
+ setArrayValues(array1, 0, ARRAY_SIZE, 0, 1);
+ copyArray(array2, array1, 0, ARRAY_SIZE);
+ scaleProduct(array3, array1, 0, ARRAY_SIZE, COEFFICIENT);
+ dotProduct(array2, array3, 0, ARRAY_SIZE, array1, 0);
+ }
+}
diff --git a/src/main/java/org/linaro/benchmarks/micro/intrinsics/CRC32Bench.java b/src/main/java/org/linaro/benchmarks/micro/intrinsics/CRC32Bench.java
new file mode 100644
index 0000000..3d8d817
--- /dev/null
+++ b/src/main/java/org/linaro/benchmarks/micro/intrinsics/CRC32Bench.java
@@ -0,0 +1,70 @@
+/*
+ * 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: Simple loops around CRC32 intrinsics.
+ * Main Focus: CRC32-related intrinsics.
+ */
+
+package org.linaro.benchmarks.micro.intrinsics;
+
+import java.util.Random;
+import java.util.zip.CRC32;
+import org.openjdk.jmh.annotations.*;
+import java.util.concurrent.TimeUnit;
+
+@BenchmarkMode(Mode.AverageTime)
+@OutputTimeUnit(TimeUnit.MICROSECONDS)
+@State(Scope.Benchmark)
+
+public class CRC32Bench {
+ private byte []bytes = new byte[8192];
+ private CRC32 crc32 = new CRC32();
+ private static final int iterCount = 100;
+ private static final int loopSize = 3000;
+
+ public CRC32Bench() {
+ Random rnd = new Random(0);
+ rnd.nextBytes(bytes);
+ }
+
+ @Benchmark
+ public void jmhTimeUpdateInt() {
+ benchUpdateInt();
+ }
+
+ @Benchmark
+ public void jmhTimeUpdateBytes() {
+ benchUpdateBytes();
+ }
+
+ public void benchUpdateInt() {
+ int count = loopSize * 230;
+ crc32.reset();
+ for (int i = 0; i < count; i++) {
+ crc32.update(i);
+ }
+ }
+
+ public void benchUpdateBytes() {
+ crc32.reset();
+
+ for (int i = 0; i < loopSize*100; i++) {
+ crc32.update(bytes);
+ }
+ }
+}
diff --git a/src/main/java/org/linaro/benchmarks/micro/intrinsics/Intrinsics.java b/src/main/java/org/linaro/benchmarks/micro/intrinsics/Intrinsics.java
new file mode 100644
index 0000000..f43d977
--- /dev/null
+++ b/src/main/java/org/linaro/benchmarks/micro/intrinsics/Intrinsics.java
@@ -0,0 +1,272 @@
+/*
+ * Copyright (c) 2015, ARM 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.
+ *
+ */
+
+package org.linaro.benchmarks.micro.intrinsics;
+
+import java.lang.System;
+import java.util.EnumMap;
+import java.util.Map;
+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 Intrinsics {
+
+ /* Invoke each intrinsic in question the same no. of times */
+ private static final int NUM_INVOKES = 128;
+
+ /* Random pool size.
+ * Use a power of two to make the modulo operations below fast. */
+ private static final int NUM_RANDS = 1024;
+
+ /* Pre-allocated pool of random integers from [0, Integer.MAX_VALUE) */
+ private static final int[] rand = new int[NUM_RANDS];
+
+ static {
+ // Allocate a pool of random integers to use in benchmarks that
+ // want to try and force branch mispredicts without the overhead
+ // of calling random.nextInt in times code. Same seed every time.
+ Random random = new Random(42L);
+ for (int i = 0; i < NUM_RANDS; i++) {
+ rand[i] = random.nextInt(Integer.MAX_VALUE);
+ }
+ }
+
+ /**
+ * NumberOfLeadingZeros.
+ **/
+
+ private static int[] resultsNumberOfLeadingZerosInteger = new int[NUM_INVOKES];
+ private static int[] resultsNumberOfLeadingZerosLong = new int[NUM_INVOKES];
+ private static int[] resultsNumberOfLeadingZerosIntegerRandom = new int[NUM_INVOKES];
+ private static int[] resultsNumberOfLeadingZerosLongRandom = new int[NUM_INVOKES];
+
+ @Benchmark
+ public void jmhTimeNumberOfLeadingZerosInteger() {
+ for (int i = 0; i < NUM_INVOKES; ++i) {
+ resultsNumberOfLeadingZerosInteger[i] =
+ Integer.numberOfLeadingZeros(0x80000000 >>> i);
+ }
+ }
+
+ @Benchmark
+ public void jmhTimeNumberOfLeadingZerosLong() {
+ for (int i = 0; i < NUM_INVOKES; ++i) {
+ resultsNumberOfLeadingZerosLong[i] =
+ Long.numberOfLeadingZeros(0x8000000000000000L >>> i);
+ }
+ }
+
+ @Benchmark
+ public void jmhTimeNumberOfLeadingZerosIntegerRandom() {
+ for (int i = 0; i < NUM_INVOKES; ++i) {
+ resultsNumberOfLeadingZerosIntegerRandom[i] =
+ Integer.numberOfLeadingZeros(rand[i % NUM_RANDS] >>> rand[i % NUM_RANDS]);
+ }
+ }
+
+ @Benchmark
+ public void jmhTimeNumberOfLeadingZerosLongRandom() {
+ for (int i = 0; i < NUM_INVOKES; ++i) {
+ resultsNumberOfLeadingZerosLongRandom[i] =
+ Long.numberOfLeadingZeros(1 << (rand[i % NUM_RANDS] % Long.SIZE));
+ }
+ }
+
+ /**
+ * NumberOfTrailingZeros.
+ **/
+
+ private static int[] resultsNumberOfTrailingZerosInteger = new int[NUM_INVOKES];
+ private static int[] resultsNumberOfTrailingZerosLong = new int[NUM_INVOKES];
+ private static int[] resultsNumberOfTrailingZerosIntegerRandom = new int[NUM_INVOKES];
+ private static int[] resultsNumberOfTrailingZerosLongRandom = new int[NUM_INVOKES];
+
+ @Benchmark
+ public void jmhTimeNumberOfTrailingZerosInteger() {
+ for (int i = 0; i < NUM_INVOKES; ++i) {
+ resultsNumberOfTrailingZerosInteger[i] =
+ Integer.numberOfTrailingZeros(0x80000000 >>> i);
+ }
+ }
+
+ @Benchmark
+ public void jmhTimeNumberOfTrailingZerosLong() {
+ for (int i = 0; i < NUM_INVOKES; ++i) {
+ resultsNumberOfTrailingZerosLong[i] =
+ Long.numberOfTrailingZeros(0x8000000000000000L >>> i);
+ }
+ }
+
+ @Benchmark
+ public void jmhTimeNumberOfTrailingZerosIntegerRandom() {
+ for (int i = 0; i < NUM_INVOKES; ++i) {
+ resultsNumberOfTrailingZerosIntegerRandom[i] =
+ Integer.numberOfTrailingZeros(rand[i % NUM_RANDS] >>> rand[i % NUM_RANDS]);
+ }
+ }
+
+ @Benchmark
+ public void jmhTimeNumberOfTrailingZerosLongRandom() {
+ for (int i = 0; i < NUM_INVOKES; ++i) {
+ resultsNumberOfTrailingZerosLongRandom[i] =
+ Long.numberOfTrailingZeros(1 << (rand[i % NUM_RANDS] % Long.SIZE));
+ }
+ }
+
+ /**
+ * BitCount.
+ **/
+
+ // both Integer and Long's bitCount() return int type.
+ private static int[] resultsBitCountInteger = new int[NUM_INVOKES];
+ private static int[] resultsBitCountLong = new int[NUM_INVOKES];
+ private static int[] resultsBitCountIntegerRandom = new int[NUM_INVOKES];
+ private static int[] resultsBitCountLongRandom = new int[NUM_INVOKES];
+
+ @Benchmark
+ public void jmhTimeBitCountInteger() {
+ for (int i = 0; i < NUM_INVOKES; ++i) {
+ resultsBitCountInteger[i] = Integer.bitCount(0x1234abcd);
+ }
+ }
+
+ @Benchmark
+ public void jmhTimeBitCountLong() {
+ for (int i = 0; i < NUM_INVOKES; ++i) {
+ resultsBitCountLong[i] = Long.bitCount(0x1234abcd1234abcdL);
+ }
+ }
+
+ @Benchmark
+ public void jmhTimeBitCountIntegerRandom() {
+ for (int i = 0; i < NUM_INVOKES; ++i) {
+ resultsBitCountIntegerRandom[i] = Integer.bitCount(rand[i % NUM_RANDS]);
+ }
+ }
+
+ @Benchmark
+ public void jmhTimeBitCountLongRandom() {
+ for (int i = 0; i < NUM_INVOKES; ++i) {
+ resultsBitCountLongRandom[i] =
+ Long.bitCount((long)rand[i % NUM_RANDS] << 32 + rand[i % NUM_RANDS]);
+ }
+ }
+
+ /**
+ * RotateRight.
+ **/
+
+ private static int[] resultsRotateRightInteger = new int[NUM_INVOKES];
+ private static int[] resultsRotateRightIntegerConstant = new int[NUM_INVOKES];
+ private static long[] resultsRotateRightLong = new long[NUM_INVOKES];
+ private static long[] resultsRotateRightLongConstant = new long[NUM_INVOKES];
+
+ @Benchmark
+ public void jmhTimeRotateRightInteger() {
+ for (int i = 0; i < NUM_INVOKES; ++i) {
+ resultsRotateRightInteger[i] = Integer.rotateRight(0xFF0000DD, i);
+ }
+ }
+
+ @Benchmark
+ public void jmhTimeRotateRightIntegerConstant() {
+ for (int i = 0; i < NUM_INVOKES; ++i) {
+ resultsRotateRightIntegerConstant[i] = Integer.rotateRight(0xFF0000DD, 16);
+ }
+ }
+
+ @Benchmark
+ public void jmhTimeRotateRightLong() {
+ for (int i = 0; i < NUM_INVOKES; ++i) {
+ resultsRotateRightLong[i] = Long.rotateRight(0xBBAAAADDFF0000DDL, i);
+ }
+ }
+
+ @Benchmark
+ public void jmhTimeRotateRightLongConstant() {
+ for (int i = 0; i < NUM_INVOKES; ++i) {
+ resultsRotateRightLongConstant[i] = Long.rotateRight(0xBBAAAADDFF0000DDL, 48);
+ }
+ }
+
+ /**
+ * RotateLeft.
+ **/
+
+ private static int[] resultsRotateLeftInteger = new int[NUM_INVOKES];
+ private static int[] resultsRotateLeftIntegerConstant = new int[NUM_INVOKES];
+ private static long[] resultsRotateLeftLong = new long[NUM_INVOKES];
+ private static long[] resultsRotateLeftLongConstant = new long[NUM_INVOKES];
+
+ @Benchmark
+ public void jmhTimeRotateLeftInteger() {
+ for (int i = 0; i < NUM_INVOKES; ++i) {
+ resultsRotateLeftInteger[i] = Integer.rotateLeft(0xFF0000DD, i);
+ }
+ }
+
+ @Benchmark
+ public void jmhTimeRotateLeftIntegerConstant() {
+ for (int i = 0; i < NUM_INVOKES; ++i) {
+ resultsRotateLeftIntegerConstant[i] = Integer.rotateLeft(0xFF0000DD, 16);
+ }
+ }
+
+ @Benchmark
+ public void jmhTimeRotateLeftLong() {
+ for (int i = 0; i < NUM_INVOKES; ++i) {
+ resultsRotateLeftLong[i] = Long.rotateLeft(0xBBAAAADDFF0000DDL, i);
+ }
+ }
+
+ @Benchmark
+ public void jmhTimeRotateLeftLongConstant() {
+ for (int i = 0; i < NUM_INVOKES; ++i) {
+ resultsRotateLeftLongConstant[i] = Long.rotateLeft(0xBBAAAADDFF0000DDL, 48);
+ }
+ }
+
+ /**
+ * RotateRandom.
+ **/
+
+ private static int[] resultsRotateRandomInteger = new int[NUM_INVOKES];
+ private static long[] resultsRotateRandomLong = new long[NUM_INVOKES];
+
+ @Benchmark
+ public void jmhTimeRotateRandomInteger() {
+ for (int i = 0; i < NUM_INVOKES; ++i) {
+ resultsRotateRandomInteger[i] = (rand[i % NUM_RANDS] % 2 > 0)
+ ? Integer.rotateLeft(0xFF0000DD, rand[i % NUM_RANDS])
+ : Integer.rotateRight(0xFF0000DD, rand[i % NUM_RANDS]);
+ }
+ }
+
+ @Benchmark
+ public void jmhTimeRotateRandomLong() {
+ for (int i = 0; i < NUM_INVOKES; ++i) {
+ resultsRotateRandomLong[i] = (rand[i % NUM_RANDS] % 2 > 0)
+ ? Long.rotateLeft(0xBBAAAADDFF0000DDL, rand[i % NUM_RANDS])
+ : Long.rotateRight(0xBBAAAADDFF0000DDL, rand[i % NUM_RANDS]);
+ }
+ }
+}
diff --git a/src/main/java/org/linaro/benchmarks/micro/intrinsics/MathIntrinsics.java b/src/main/java/org/linaro/benchmarks/micro/intrinsics/MathIntrinsics.java
new file mode 100644
index 0000000..a1a86a6
--- /dev/null
+++ b/src/main/java/org/linaro/benchmarks/micro/intrinsics/MathIntrinsics.java
@@ -0,0 +1,367 @@
+/*
+ * 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: Simple loops around math-related intrinsics: rounding, min/max, etc.
+ * Main Focus: Math-related intrinsics.
+ */
+
+package org.linaro.benchmarks.micro.intrinsics;
+
+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 MathIntrinsics {
+ // The java.util.Random only generates random float/double numbers between 0 and 1.
+ // So we implement our own random floating point numbers here,
+ // based on a well known quick and dirty approach.
+ static final class MyRandom extends Random {
+ static int im = 139968;
+ static int ia = 3877;
+ static int ic = 29573;
+ static int seed = 0;
+
+ public double nextDouble() {
+ double scale = 1000.0d / im;
+ seed = (seed * ia + ic) % im;
+ return scale * seed;
+ }
+
+ public float nextFloat() {
+ float scale = 1000.0f / im;
+ seed = (seed * ia + ic) % im;
+ return scale * seed;
+ }
+ }
+
+ /* Invoke each intrinsic in question the same no. of times */
+ private static final int NUM_INVOKES = 64;
+
+ /* Random pool size.
+ * Use a power of two to make the modulo operations below fast. */
+ private static final int NUM_RANDS = 1024;
+
+ /* Pre-allocated pool of random numbers. */
+ private static final float[] rand_float = new float[NUM_RANDS];
+ private static final double[] rand_double = new double[NUM_RANDS];
+
+ private static final float[] rand_pos_float = new float[NUM_RANDS];
+ private static final double[] rand_pos_double = new double[NUM_RANDS];
+
+ private static final float[] rand_neg_float = new float[NUM_RANDS];
+ private static final double[] rand_neg_double = new double[NUM_RANDS];
+
+ private static final int[] rand_int = new int[NUM_RANDS];
+ private static final long[] rand_long = new long[NUM_RANDS];
+
+ // These are written but not read. The computation routines below store their
+ // result to these static variables to ensure the computation code is not
+ // removed by DCE.
+ private static float res_float;
+ private static double res_double;
+ private static int res_int;
+ private static long res_long;
+
+ static {
+ MyRandom rand = new MyRandom();
+
+ for (int i = 0; i < NUM_RANDS; i++) {
+ rand_int[i] = rand.nextInt();
+ rand_long[i] = rand.nextLong();
+
+ rand_pos_float[i] = rand.nextFloat();
+ rand_pos_double[i] = rand.nextDouble();
+
+ rand_neg_float[i] = rand.nextFloat() * -1f;
+ rand_neg_double[i] = rand.nextDouble() * -1f;
+
+ if (rand.nextInt() % 2 == 0) {
+ rand_float[i] = rand_pos_float[i];
+ rand_double[i] = rand_pos_double[i];
+ } else {
+ rand_float[i] = rand_neg_float[i];
+ rand_double[i] = rand_neg_double[i];
+ }
+ }
+ }
+
+ @Benchmark
+ public void jmhTimeRoundPositiveFloat() {
+ int res = 0;
+ for (int i = 0; i < NUM_INVOKES; ++i) {
+ res += Math.round(rand_pos_float[i % NUM_RANDS]);
+ }
+ res_int = res;
+ }
+
+ @Benchmark
+ public void jmhTimeRoundNegativeFloat() {
+ int res = 0;
+ for (int i = 0; i < NUM_INVOKES; ++i) {
+ res += Math.round(rand_neg_float[i % NUM_RANDS]);
+ }
+ res_int = res;
+ }
+
+ @Benchmark
+ public void jmhTimeRoundFloat() {
+ int res = 0;
+ for (int i = 0; i < NUM_INVOKES; ++i) {
+ res += Math.round(rand_float[i % NUM_RANDS]);
+ }
+ res_int = res;
+ }
+
+ @Benchmark
+ public void jmhTimeRoundPositiveDouble() {
+ long res = 0;
+ for (int i = 0; i < NUM_INVOKES; ++i) {
+ res += Math.round(rand_pos_double[i % NUM_RANDS]);
+ }
+ res_double = res;
+ }
+
+ @Benchmark
+ public void jmhTimeRoundNegativeDouble() {
+ long res = 0;
+ for (int i = 0; i < NUM_INVOKES; ++i) {
+ res += Math.round(rand_neg_double[i % NUM_RANDS]);
+ }
+ res_long = res;
+ }
+
+ @Benchmark
+ public void jmhTimeRoundDouble() {
+ long res = 0;
+ for (int i = 0; i < NUM_INVOKES; ++i) {
+ res += Math.round(rand_double[i % NUM_RANDS]);
+ }
+ res_double = res;
+ }
+
+ @Benchmark
+ public void jmhTimeFloorPositiveFloat() {
+ float res = 0.0f;
+ for (int i = 0; i < NUM_INVOKES; ++i) {
+ res += Math.floor(rand_pos_float[i % NUM_RANDS]);
+ }
+ res_float = res;
+ }
+
+ @Benchmark
+ public void jmhTimeFloorNegativeFloat() {
+ float res = 0.0f;
+ for (int i = 0; i < NUM_INVOKES; ++i) {
+ res += Math.floor(rand_neg_float[i % NUM_RANDS]);
+ }
+ res_float = res;
+ }
+
+ @Benchmark
+ public void jmhTimeFloorFloat() {
+ float res = 0.0f;
+ for (int i = 0; i < NUM_INVOKES; ++i) {
+ res += Math.floor(rand_float[i % NUM_RANDS]);
+ }
+ res_float = res;
+ }
+
+ @Benchmark
+ public void jmhTimeFloorPositiveDouble() {
+ double res = 0.0;
+ for (int i = 0; i < NUM_INVOKES; ++i) {
+ res += Math.floor(rand_pos_double[i % NUM_RANDS]);
+ }
+ res_double = res;
+ }
+
+ @Benchmark
+ public void jmhTimeFloorNegativeDouble() {
+ double res = 0.0;
+ for (int i = 0; i < NUM_INVOKES; ++i) {
+ res += Math.floor(rand_neg_double[i % NUM_RANDS]);
+ }
+ res_double = res;
+ }
+
+ @Benchmark
+ public void jmhTimeFloorDouble() {
+ double res = 0.0;
+ for (int i = 0; i < NUM_INVOKES; ++i) {
+ res += Math.floor(rand_double[i % NUM_RANDS]);
+ }
+ res_double = res;
+ }
+
+ @Benchmark
+ public void jmhTimeCeilPositiveFloat() {
+ float res = 0.0f;
+ for (int i = 0; i < NUM_INVOKES; ++i) {
+ res += Math.ceil(rand_pos_float[i % NUM_RANDS]);
+ }
+ res_float = res;
+ }
+
+ @Benchmark
+ public void jmhTimeCeilNegativeFloat() {
+ float res = 0.0f;
+ for (int i = 0; i < NUM_INVOKES; ++i) {
+ res += Math.ceil(rand_neg_float[i % NUM_RANDS]);
+ }
+ res_float = res;
+ }
+
+ @Benchmark
+ public void jmhTimeCeilFloat() {
+ float res = 0.0f;
+ for (int i = 0; i < NUM_INVOKES; ++i) {
+ res += Math.ceil(rand_float[i % NUM_RANDS]);
+ }
+ res_float = res;
+ }
+
+ @Benchmark
+ public void jmhTimeCeilPositiveDouble() {
+ double res = 0.0;
+ for (int i = 0; i < NUM_INVOKES; ++i) {
+ res += Math.ceil(rand_pos_double[i % NUM_RANDS]);
+ }
+ res_double = res;
+ }
+
+
+ @Benchmark
+ public void jmhTimeCeilNegativeDouble() {
+ double res = 0.0;
+ for (int i = 0; i < NUM_INVOKES; ++i) {
+ res += Math.ceil(rand_neg_double[i % NUM_RANDS]);
+ }
+ res_double = res;
+ }
+
+ @Benchmark
+ public void jmhTimeCeilDouble() {
+ double res = 0.0;
+ for (int i = 0; i < NUM_INVOKES; ++i) {
+ res += Math.ceil(rand_double[i % NUM_RANDS]);
+ }
+ res_double = res;
+ }
+
+ @Benchmark
+ public void jmhTimeRint() {
+ double res = 0.0;
+ for (int i = 0; i < NUM_INVOKES; ++i) {
+ res += Math.rint(rand_double[i % NUM_RANDS]);
+ }
+ res_double = res;
+ }
+
+ @Benchmark
+ public void jmhTimeMinDouble() {
+ double res = 0.0;
+ for (int i = 0; i < NUM_INVOKES; ++i) {
+ double a = rand_double[i % NUM_RANDS];
+ double b = rand_double[(i + 1) % NUM_RANDS];
+ res += Math.min(a, b);
+ }
+ res_double = res;
+ }
+
+ @Benchmark
+ public void jmhTimeMaxDouble() {
+ double res = 0.0;
+ for (int i = 0; i < NUM_INVOKES; ++i) {
+ double a = rand_double[i % NUM_RANDS];
+ double b = rand_double[(i + 1) % NUM_RANDS];
+ res += Math.max(a, b);
+ }
+ res_double = res;
+ }
+
+ @Benchmark
+ public void jmhTimeMinFloat() {
+ float res = 0.0f;
+ for (int i = 0; i < NUM_INVOKES; ++i) {
+ float a = rand_float[i % NUM_RANDS];
+ float b = rand_float[(i + 1) % NUM_RANDS];
+ res += Math.min(a, b);
+ }
+ res_float = res;
+ }
+
+ @Benchmark
+ public void jmhTimeMaxFloat() {
+ float res = 0.0f;
+ for (int i = 0; i < NUM_INVOKES; ++i) {
+ float a = rand_float[i % NUM_RANDS];
+ float b = rand_float[(i + 1) % NUM_RANDS];
+ res += Math.max(a, b);
+ }
+ res_float = res;
+ }
+
+ @Benchmark
+ public void jmhTimeMinLong() {
+ long res = 0;
+ for (int i = 0; i < NUM_INVOKES; ++i) {
+ long a = rand_long[i % NUM_RANDS];
+ long b = rand_long[(i + 1) % NUM_RANDS];
+ res += Math.min(a, b);
+ }
+ res_long = res;
+ }
+
+ @Benchmark
+ public void jmhTimeMaxLong() {
+ long res = 0;
+ for (int i = 0; i < NUM_INVOKES; ++i) {
+ long a = rand_long[i % NUM_RANDS];
+ long b = rand_long[(i + 1) % NUM_RANDS];
+ res += Math.max(a, b);
+ }
+ res_long = res;
+ }
+
+ @Benchmark
+ public void jmhTimeMinInt() {
+ int res = 0;
+ for (int i = 0; i < NUM_INVOKES; ++i) {
+ int a = rand_int[i % NUM_RANDS];
+ int b = rand_int[(i + 1) % NUM_RANDS];
+ res += Math.min(a, b);
+ }
+ res_int = res;
+ }
+
+ @Benchmark
+ public void jmhTimeMaxInt() {
+ int res = 0;
+ for (int i = 0; i < NUM_INVOKES; ++i) {
+ int a = rand_int[i % NUM_RANDS];
+ int b = rand_int[(i + 1) % NUM_RANDS];
+ res += Math.max(a, b);
+ }
+ res_int = res;
+ }
+}