150 lines
3.9 KiB
Java
150 lines
3.9 KiB
Java
/*
|
|
* Copyright (C) 2015 The Guava Authors
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package com.google.common.hash;
|
|
|
|
import com.google.caliper.BeforeExperiment;
|
|
import com.google.caliper.Benchmark;
|
|
import com.google.caliper.Param;
|
|
import java.security.MessageDigest;
|
|
import java.util.Arrays;
|
|
import java.util.Random;
|
|
|
|
/**
|
|
* Benchmarks for comparing the various {@link HashCode#equals} methods.
|
|
*
|
|
* <p>Parameters for the benchmark are:
|
|
*
|
|
* <ul>
|
|
* <li>size: the length of the byte array to hash
|
|
* <li>whereToDiffer: where in the array the bytes should differ
|
|
* <li>equalsImpl: which implementation of array equality to use
|
|
* </ul>
|
|
*
|
|
* <p><b>Important note:</b> the primary goal of this benchmark is to ensure that varying {@code
|
|
* whereToDiffer} produces no observable change in performance. We want to make sure that the array
|
|
* equals implementation is *not* short-circuiting to prevent timing-based attacks. Being fast is
|
|
* only a secondary goal.
|
|
*
|
|
* @author Kurt Alfred Kluever
|
|
*/
|
|
public class HashCodeBenchmark {
|
|
|
|
// Use a statically configured random instance for all of the benchmarks
|
|
private static final Random random = new Random(42);
|
|
|
|
@Param({"1000", "100000"})
|
|
private int size;
|
|
|
|
@Param WhereToDiffer whereToDiffer;
|
|
|
|
@Param EqualsImplementation equalsImpl;
|
|
|
|
private enum WhereToDiffer {
|
|
ONE_PERCENT_IN,
|
|
LAST_BYTE,
|
|
NOT_AT_ALL;
|
|
}
|
|
|
|
private enum EqualsImplementation {
|
|
ANDING_BOOLEANS {
|
|
@Override
|
|
boolean doEquals(byte[] a, byte[] b) {
|
|
if (a.length != b.length) {
|
|
return false;
|
|
}
|
|
boolean areEqual = true;
|
|
for (int i = 0; i < a.length; i++) {
|
|
areEqual &= (a[i] == b[i]);
|
|
}
|
|
return areEqual;
|
|
}
|
|
},
|
|
XORING_TO_BYTE {
|
|
@Override
|
|
boolean doEquals(byte[] a, byte[] b) {
|
|
if (a.length != b.length) {
|
|
return false;
|
|
}
|
|
byte result = 0;
|
|
for (int i = 0; i < a.length; i++) {
|
|
result = (byte) (result | a[i] ^ b[i]);
|
|
}
|
|
return (result == 0);
|
|
}
|
|
},
|
|
XORING_TO_INT {
|
|
@Override
|
|
boolean doEquals(byte[] a, byte[] b) {
|
|
if (a.length != b.length) {
|
|
return false;
|
|
}
|
|
int result = 0;
|
|
for (int i = 0; i < a.length; i++) {
|
|
result |= a[i] ^ b[i];
|
|
}
|
|
return (result == 0);
|
|
}
|
|
},
|
|
MESSAGE_DIGEST_IS_EQUAL {
|
|
@Override
|
|
boolean doEquals(byte[] a, byte[] b) {
|
|
return MessageDigest.isEqual(a, b);
|
|
}
|
|
},
|
|
ARRAYS_EQUALS {
|
|
@Override
|
|
boolean doEquals(byte[] a, byte[] b) {
|
|
return Arrays.equals(a, b);
|
|
}
|
|
};
|
|
|
|
abstract boolean doEquals(byte[] a, byte[] b);
|
|
}
|
|
|
|
private byte[] testBytesA;
|
|
private byte[] testBytesB;
|
|
|
|
@BeforeExperiment
|
|
void setUp() {
|
|
testBytesA = new byte[size];
|
|
random.nextBytes(testBytesA);
|
|
testBytesB = Arrays.copyOf(testBytesA, size);
|
|
int indexToDifferAt = -1;
|
|
switch (whereToDiffer) {
|
|
case ONE_PERCENT_IN:
|
|
indexToDifferAt = (int) (size * 0.01);
|
|
break;
|
|
case LAST_BYTE:
|
|
indexToDifferAt = size - 1;
|
|
break;
|
|
case NOT_AT_ALL:
|
|
}
|
|
if (indexToDifferAt != -1) {
|
|
testBytesA[indexToDifferAt] = (byte) (testBytesB[indexToDifferAt] - 1);
|
|
}
|
|
}
|
|
|
|
@Benchmark
|
|
boolean hashFunction(int reps) {
|
|
boolean result = true;
|
|
for (int i = 0; i < reps; i++) {
|
|
result ^= equalsImpl.doEquals(testBytesA, testBytesB);
|
|
}
|
|
return result;
|
|
}
|
|
}
|