18
18
import io .netty .microbench .util .AbstractMicrobenchmark ;
19
19
import io .netty .util .internal .PlatformDependent ;
20
20
import io .netty .util .internal .StringUtil ;
21
+ import org .jctools .util .Pow2 ;
21
22
import org .openjdk .jmh .annotations .Benchmark ;
23
+ import org .openjdk .jmh .annotations .CompilerControl ;
24
+ import org .openjdk .jmh .annotations .CompilerControl .Mode ;
22
25
import org .openjdk .jmh .annotations .Measurement ;
23
26
import org .openjdk .jmh .annotations .OutputTimeUnit ;
24
27
import org .openjdk .jmh .annotations .Param ;
28
31
import org .openjdk .jmh .annotations .Warmup ;
29
32
30
33
import java .util .Arrays ;
34
+ import java .util .Random ;
31
35
import java .util .concurrent .TimeUnit ;
32
36
33
37
@ State (Scope .Benchmark )
@@ -43,37 +47,75 @@ public class DecodeHexBenchmark extends AbstractMicrobenchmark {
43
47
"4DDeA5gDD1C6fE567E1b6gf0C40FEcDg" ,
44
48
})
45
49
private String hex ;
46
- private char [] hexDigits ;
50
+ // Needs to specify a high number of inputs to allow the current strategy
51
+ // on nextHexDigits to produce enough branch-misses
52
+ @ Param ({ "2048" })
53
+ private int inputs ;
54
+ private char [][] hexDigits ;
55
+ private static final long SEED = 1578675524L ;
56
+ private long next ;
47
57
48
58
@ Setup
49
59
public void init () {
50
- hexDigits = hex .toCharArray ();
60
+ final char [] hexCh = hex .toCharArray ();
61
+ next = 0 ;
62
+ inputs = Pow2 .roundToPowerOfTwo (inputs );
63
+ hexDigits = new char [inputs ][];
64
+ hexDigits [0 ] = hexCh ;
65
+ if (inputs > 1 ) {
66
+ final Random rnd = new Random (SEED );
67
+ for (int i = 1 ; i < inputs ; i ++) {
68
+ hexDigits [i ] = shuffle (Arrays .copyOf (hexCh , hexCh .length ), rnd );
69
+ }
70
+ }
71
+ }
72
+
73
+ // https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle
74
+ private static char [] shuffle (char [] chars , Random rnd ) {
75
+ int index ;
76
+ char tmp ;
77
+ for (int i = chars .length - 1 ; i > 0 ; i --) {
78
+ index = rnd .nextInt (i + 1 );
79
+ tmp = chars [index ];
80
+ chars [index ] = chars [i ];
81
+ chars [i ] = tmp ;
82
+ }
83
+ return chars ;
84
+ }
85
+
86
+ private int nextHexDigits () {
87
+ final int idx = (int ) (next & (inputs - 1 ));
88
+ next ++;
89
+ return idx ;
51
90
}
52
91
53
92
@ Benchmark
93
+ @ CompilerControl (Mode .DONT_INLINE )
54
94
public long hexDigits () {
55
95
long v = 0 ;
56
- final char [] hexDigits = this .hexDigits ;
96
+ final char [] hexDigits = this .hexDigits [ nextHexDigits ()] ;
57
97
for (int i = 0 , size = hexDigits .length ; i < size ; i ++) {
58
98
v += StringUtil .decodeHexNibble (hexDigits [i ]);
59
99
}
60
100
return v ;
61
101
}
62
102
63
103
@ Benchmark
104
+ @ CompilerControl (Mode .DONT_INLINE )
64
105
public long hexDigitsWithChecks () {
65
106
long v = 0 ;
66
- final char [] hexDigits = this .hexDigits ;
107
+ final char [] hexDigits = this .hexDigits [ nextHexDigits ()] ;
67
108
for (int i = 0 , size = hexDigits .length ; i < size ; i ++) {
68
109
v += decodeHexNibbleWithCheck (hexDigits [i ]);
69
110
}
70
111
return v ;
71
112
}
72
113
73
114
@ Benchmark
115
+ @ CompilerControl (Mode .DONT_INLINE )
74
116
public long hexDigitsOriginal () {
75
117
long v = 0 ;
76
- final char [] hexDigits = this .hexDigits ;
118
+ final char [] hexDigits = this .hexDigits [ nextHexDigits ()] ;
77
119
for (int i = 0 , size = hexDigits .length ; i < size ; i ++) {
78
120
v += decodeHexNibble (hexDigits [i ]);
79
121
}
0 commit comments