Skip to content

Commit 38f525e

Browse files
vamsi-parasaSandhya Viswanathan
authored andcommitted
8275821: Optimize random number generators developed in JDK-8248862 using Math.unsignedMultiplyHigh()
Reviewed-by: psandoz, jlaskey
1 parent 780b8b1 commit 38f525e

File tree

4 files changed

+75
-31
lines changed

4 files changed

+75
-31
lines changed

src/jdk.random/share/classes/jdk/random/L128X1024MixRandom.java

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -323,17 +323,7 @@ public long nextLong() {
323323
// Update the LCG subgenerator
324324
// The LCG is, in effect, s = ((1LL << 64) + ML) * s + a, if only we had 128-bit arithmetic.
325325
final long u = ML * sl;
326-
327-
// Note that Math.multiplyHigh computes the high half of the product of signed values,
328-
// but what we need is the high half of the product of unsigned values; for this we use the
329-
// formula "unsignedMultiplyHigh(a, b) = multiplyHigh(a, b) + ((a >> 63) & b) + ((b >> 63) & a)";
330-
// in effect, each operand is added to the result iff the sign bit of the other operand is 1.
331-
// (See Henry S. Warren, Jr., _Hacker's Delight_ (Second Edition), Addison-Wesley (2013),
332-
// Section 8-3, p. 175; or see the First Edition, Addison-Wesley (2003), Section 8-3, p. 133.)
333-
// If Math.unsignedMultiplyHigh(long, long) is ever implemented, the following line can become:
334-
// sh = (ML * sh) + Math.unsignedMultiplyHigh(ML, sl) + sl + ah;
335-
// and this entire comment can be deleted.
336-
sh = (ML * sh) + (Math.multiplyHigh(ML, sl) + ((ML >> 63) & sl) + ((sl >> 63) & ML)) + sl + ah;
326+
sh = (ML * sh) + Math.unsignedMultiplyHigh(ML, sl) + sl + ah;
337327
sl = u + al;
338328
if (Long.compareUnsigned(sl, u) < 0) ++sh; // Handle the carry propagation from low half to high half.
339329

src/jdk.random/share/classes/jdk/random/L128X128MixRandom.java

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -248,16 +248,7 @@ public long nextLong() {
248248
// Update the LCG subgenerator
249249
// The LCG is, in effect, s = ((1LL << 64) + ML) * s + a, if only we had 128-bit arithmetic.
250250
final long u = ML * sl;
251-
// Note that Math.multiplyHigh computes the high half of the product of signed values,
252-
// but what we need is the high half of the product of unsigned values; for this we use the
253-
// formula "unsignedMultiplyHigh(a, b) = multiplyHigh(a, b) + ((a >> 63) & b) + ((b >> 63) & a)";
254-
// in effect, each operand is added to the result iff the sign bit of the other operand is 1.
255-
// (See Henry S. Warren, Jr., _Hacker's Delight_ (Second Edition), Addison-Wesley (2013),
256-
// Section 8-3, p. 175; or see the First Edition, Addison-Wesley (2003), Section 8-3, p. 133.)
257-
// If Math.unsignedMultiplyHigh(long, long) is ever implemented, the following line can become:
258-
// sh = (ML * sh) + Math.unsignedMultiplyHigh(ML, sl) + sl + ah;
259-
// and this entire comment can be deleted.
260-
sh = (ML * sh) + (Math.multiplyHigh(ML, sl) + ((ML >> 63) & sl) + ((sl >> 63) & ML)) + sl + ah;
251+
sh = (ML * sh) + Math.unsignedMultiplyHigh(ML, sl) + sl + ah;
261252
sl = u + al;
262253
if (Long.compareUnsigned(sl, u) < 0) ++sh; // Handle the carry propagation from low half to high half.
263254

src/jdk.random/share/classes/jdk/random/L128X256MixRandom.java

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -269,16 +269,7 @@ public long nextLong() {
269269
// Update the LCG subgenerator
270270
// The LCG is, in effect, s = ((1LL << 64) + ML) * s + a, if only we had 128-bit arithmetic.
271271
final long u = ML * sl;
272-
// Note that Math.multiplyHigh computes the high half of the product of signed values,
273-
// but what we need is the high half of the product of unsigned values; for this we use the
274-
// formula "unsignedMultiplyHigh(a, b) = multiplyHigh(a, b) + ((a >> 63) & b) + ((b >> 63) & a)";
275-
// in effect, each operand is added to the result iff the sign bit of the other operand is 1.
276-
// (See Henry S. Warren, Jr., _Hacker's Delight_ (Second Edition), Addison-Wesley (2013),
277-
// Section 8-3, p. 175; or see the First Edition, Addison-Wesley (2003), Section 8-3, p. 133.)
278-
// If Math.unsignedMultiplyHigh(long, long) is ever implemented, the following line can become:
279-
// sh = (ML * sh) + Math.unsignedMultiplyHigh(ML, sl) + sl + ah;
280-
// and this entire comment can be deleted.
281-
sh = (ML * sh) + (Math.multiplyHigh(ML, sl) + ((ML >> 63) & sl) + ((sl >> 63) & ML)) + sl + ah;
272+
sh = (ML * sh) + Math.unsignedMultiplyHigh(ML, sl) + sl + ah;
282273
sl = u + al;
283274
if (Long.compareUnsigned(sl, u) < 0) ++sh; // Handle the carry propagation from low half to high half.
284275

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
package org.openjdk.bench.java.util;
24+
25+
import org.openjdk.jmh.annotations.Benchmark;
26+
import org.openjdk.jmh.annotations.BenchmarkMode;
27+
import org.openjdk.jmh.annotations.Mode;
28+
import org.openjdk.jmh.annotations.OutputTimeUnit;
29+
import org.openjdk.jmh.annotations.Scope;
30+
import org.openjdk.jmh.annotations.Setup;
31+
import org.openjdk.jmh.annotations.State;
32+
import org.openjdk.jmh.annotations.Param;
33+
import java.util.random.RandomGenerator;
34+
import java.util.random.RandomGeneratorFactory;
35+
import java.util.concurrent.TimeUnit;
36+
37+
/**
38+
* Tests java.util.random.RandomGenerator's different random number generators which use Math.unsignedMultiplyHigh().
39+
*/
40+
@BenchmarkMode(Mode.AverageTime)
41+
@OutputTimeUnit(TimeUnit.NANOSECONDS)
42+
@State(Scope.Thread)
43+
public class RandomGeneratorNext {
44+
45+
RandomGenerator randomGenerator;
46+
47+
@Param({"L128X128MixRandom", "L128X256MixRandom", "L128X1024MixRandom"})
48+
String randomGeneratorName;
49+
50+
long[] buffer;
51+
52+
@Param("1024")
53+
int size;
54+
55+
@Setup
56+
public void setup() {
57+
buffer = new long[size];
58+
randomGenerator = RandomGeneratorFactory.of(randomGeneratorName).create(randomGeneratorName.hashCode());
59+
}
60+
61+
@Benchmark
62+
public long testNextLong() {
63+
return randomGenerator.nextLong();
64+
}
65+
66+
@Benchmark
67+
public long[] testFillBufferWithNextLong() {
68+
for (int i = 0; i < size; i++) buffer[i] = randomGenerator.nextLong();
69+
return buffer;
70+
}
71+
72+
}

0 commit comments

Comments
 (0)