मैं इस तरह एक विधि लिखने के लिए कोशिश कर रहा हूँ:यह जेएमएच बेंचमार्क मशीनों पर असंगत है - क्यों?
static boolean fitsInDouble(long x) {
// return true if x can be represented
// as a numerically-equivalent double
}
और मैं सबसे कुशल कार्यान्वयन खोजने की कोशिश कर रहा हूँ। मैं एक पर बस गया, लेकिन फिर एक सहकर्मी ने बेंचमार्क चलाया और विभिन्न सापेक्ष परिणाम प्राप्त किए। मेरे लिए सबसे तेज़ कार्यान्वयन उसके लिए सबसे तेज़ नहीं है।
क्या इन मानकों में कुछ गड़बड़ है?
package rnd;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.Warmup;
import org.openjdk.jmh.infra.Blackhole;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import java.math.BigDecimal;
import java.util.concurrent.TimeUnit;
@State(Scope.Thread)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Fork(1)
@Measurement(iterations = 5)
@Warmup(iterations = 5)
public class Benchmarks {
public static void main(String[] args) throws Exception {
Options options = new OptionsBuilder()
.include(Benchmarks.class.getName())
.build();
new Runner(options).run();
}
@Benchmark
public void bigDecimal(Blackhole bh) {
for (long x : NUMBERS) bh.consume(bigDecimal(x));
}
@Benchmark
public void cast(Blackhole bh) {
for (long x : NUMBERS) bh.consume(cast(x));
}
@Benchmark
public void zeros(Blackhole bh) {
for (long x : NUMBERS) bh.consume(zeros(x));
}
public static boolean bigDecimal(long x) {
BigDecimal a = new BigDecimal(x);
BigDecimal b = new BigDecimal((double) x);
return a.compareTo(b) == 0;
}
public static boolean cast(long x) {
return x == (long) (double) x
&& x != Long.MAX_VALUE;
}
public static boolean zeros(long x) {
long a = Math.abs(x);
int z = Long.numberOfLeadingZeros(a);
return z > 10 || Long.numberOfTrailingZeros(a) > 10 - z;
}
private static final long[] NUMBERS = {
0,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
-1, -2, -3, -4, -5, -6, -7, -8, -9, -10,
123, 456, 789,
-123, -456, -789,
101112, 131415, 161718,
-101112, -131415, -161718,
11L,
222L,
3333L,
44444L,
555555L,
6666666L,
77777777L,
888888888L,
9999999999L,
1111L,
22222L,
333333L,
4444444L,
55555555L,
666666666L,
7777777777L,
88888888888L,
999999999999L,
11111111,
222222222,
3333333333L,
44444444444L,
555555555555L,
6666666666666L,
77777777777777L,
888888888888888L,
9999999999999999L,
Long.MAX_VALUE,
Long.MAX_VALUE - 1,
Long.MIN_VALUE,
Long.MIN_VALUE + 1,
(1L << 53),
(1l << 53) + 1,
(1l << 53) + 2,
(1l << 60),
(1l << 60) + 1,
(1l << 60) + 8,
(1l << 60) + 32,
(1l << 60) + 64,
(1l << 60) + 128,
(1l << 60) + 256,
(-1L << 53),
(-1L << 53) - 1,
(-1L << 53) - 2,
(-1l << 60),
(-1l << 60) - 1,
(-1l << 60) - 8,
(-1l << 60) - 32,
(-1l << 60) - 64,
(-1l << 60) - 128,
(-1l << 60) - 256
};
}
हमारे वातावरण में छोटे अंतर हैं।
मुझे: Windows 10, JDK 1.8.0_45, "शून्य" है सबसे तेजी से
उसे: विंडोज 7, JDK 1.8.0_20, "डाली" सबसे तेज
हमारे परिणाम आत्म-संगत कर रहे हैं चलाने के लिए, चाहे आईडीई में या कमांड लाइन से चल रहा हो। हम जेएमएच 1.10.5 का उपयोग कर रहे हैं।
यहां क्या हो रहा है? बेंचमार्क अविश्वसनीय लगता है और मुझे नहीं पता कि इसे कैसे ठीक किया जाए।
मैं बेंचमार्क की गुणवत्ता का न्याय करने के लिए सक्षम नहीं हूं, लेकिन आपके प्रश्न का एक बहुत ही सरल जवाब है: परिणाम अलग हैं क्योंकि पर्यावरण अलग है: वही JVM नहीं, एक ही ओएस नहीं, शायद नहीं वही हार्डवेयर इससे परिणाम अलग-अलग होने के तीन अच्छे कारण बनते हैं। –
@JBNizet अगर यह एक जेडीके मामूली संस्करण या विंडोज संस्करण या प्रोसेसर-विशिष्ट चीज बन जाता है, जो निराशाजनक होगा, लेकिन कम से कम मुझे इसका जवाब होगा। मैं जानना चाहता हूं कि वास्तव में क्या कारण है। अंतिम लक्ष्य इस विधि को पुस्तकालय में रखना है। यदि परिणाम पर्यावरण में किसी चीज़ पर निर्भर हैं, तो मैं समझना चाहता हूं कि * अधिक संभावना * तेज होने के लिए कौन सा है। अभी यह एक सिक्का फ्लिप की तरह दिखता है। मुझे आशा है कि मैंने बेंचमार्क कोड में एक बेवकूफ त्रुटि की है। –
मेरे पास 1.8.0_45 और 1.8.0_20 दोनों स्थापित हैं। दोनों जेवीएम 'कास्ट' परीक्षण पर बेहतर परिणाम दिखाते हैं, हालांकि अंतर बहुत अधिक नहीं है (जैसे 380 एनएस बनाम 390 एनएस)। आगे की जांच के लिए कृपया दोनों मशीनों के लिए पूर्ण प्रति-पुनरावृत्ति लॉग प्रदान करें। –