Gizli performans Scala maliyet?
Bu karşısında old question geldim ve scala 2.10.3 ile aşağıdaki deneyi yaptı.
Açık kuyruk özyineleme kullanmak için Scala versiyonunu yazdım:
import scala.annotation.tailrec
object ScalaMain {
private val t = 20
private def run() {
var i = 10
while(!isEvenlyDivisible(2, i, t))
i = 2
println(i)
}
@tailrec private def isEvenlyDivisible(i: Int, a: Int, b: Int): Boolean = {
if (i > b) true
else (a % i == 0) && isEvenlyDivisible(i 1, a, b)
}
def main(args: Array[String]) {
val t1 = System.currentTimeMillis()
var i = 0
while (i < 20) {
run()
i = 1
}
val t2 = System.currentTimeMillis()
println("time: " (t2 - t1))
}
}
ve aşağıdaki Java sürümü ile karşılaştırdım. Ben bilinçli olarak işlevleri statik olmayan Scala ile adil bir karşılaştırma için:
public class JavaMain {
private final int t = 20;
private void run() {
int i = 10;
while (!isEvenlyDivisible(2, i, t))
i = 2;
System.out.println(i);
}
private boolean isEvenlyDivisible(int i, int a, int b) {
if (i > b) return true;
else return (a % i == 0) && isEvenlyDivisible(i 1, a, b);
}
public static void main(String[] args) {
JavaMain o = new JavaMain();
long t1 = System.currentTimeMillis();
for (int i = 0; i < 20; i)
o.run();
long t2 = System.currentTimeMillis();
System.out.println("time: " (t2 - t1));
}
}
Burada benim bilgisayarda sonuçları:
> java JavaMain
....
time: 9651
> scala ScalaMain
....
time: 20592
Bu 2.10.3 (Java Fi(TM) 64-Bit Server VM, Java 1.7.0_51) scala.
Benim sorum scala sürümü ile gizli maliyeti nedir?
Çok teşekkürler.
CEVAP
Peki, OP kıyaslama ideal değil. Etkileri ton hafifletilmiş olması, ısınma, ölü kod eleme, çatallaşma, vb dahil. Neyse ki, JMH zaten birçok şeyi halleder, ve her ikisi de Java ve Scala için bağlantıları vardır. Lütfen JMH sayfada prosedürleri kriter proje için izleyin, sonra aşağıdaki kriterler nakil edebilirsiniz.
Bu örnek Java kriter
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
@State(Scope.Benchmark)
@Fork(3)
@Warmup(iterations = 5)
@Measurement(iterations = 5)
public class JavaBench {
@Param({"1", "5", "10", "15", "20"})
int t;
private int run() {
int i = 10;
while(!isEvenlyDivisible(2, i, t))
i = 2;
return i;
}
private boolean isEvenlyDivisible(int i, int a, int b) {
if (i > b)
return true;
else
return (a % i == 0) && isEvenlyDivisible(i 1, a, b);
}
@GenerateMicroBenchmark
public int test() {
return run();
}
}
...ve bu örnek olduğunu Scala kriter:
@BenchmarkMode(Array(Mode.AverageTime))
@OutputTimeUnit(TimeUnit.MICROSECONDS)
@State(Scope.Benchmark)
@Fork(3)
@Warmup(iterations = 5)
@Measurement(iterations = 5)
class ScalaBench {
@Param(Array("1", "5", "10", "15", "20"))
var t: Int = _
private def run(): Int = {
var i = 10
while(!isEvenlyDivisible(2, i, t))
i = 2
i
}
@tailrec private def isEvenlyDivisible(i: Int, a: Int, b: Int): Boolean = {
if (i > b) true
else (a % i == 0) && isEvenlyDivisible(i 1, a, b)
}
@GenerateMicroBenchmark
def test(): Int = {
run()
}
}
Eğer yapışkan notlar 8 GA bu çalıştırırsanız, Linux x86_64, o zaman alırsınız:
Benchmark (t) Mode Samples Mean Mean error Units
o.s.ScalaBench.test 1 avgt 15 0.005 0.000 us/op
o.s.ScalaBench.test 5 avgt 15 0.489 0.001 us/op
o.s.ScalaBench.test 10 avgt 15 23.672 0.087 us/op
o.s.ScalaBench.test 15 avgt 15 3406.492 9.239 us/op
o.s.ScalaBench.test 20 avgt 15 2483221.694 5973.236 us/op
Benchmark (t) Mode Samples Mean Mean error Units
o.s.JavaBench.test 1 avgt 15 0.002 0.000 us/op
o.s.JavaBench.test 5 avgt 15 0.254 0.007 us/op
o.s.JavaBench.test 10 avgt 15 12.578 0.098 us/op
o.s.JavaBench.test 15 avgt 15 1628.694 11.282 us/op
o.s.JavaBench.test 20 avgt 15 1066113.157 11274.385 us/op
t
etkisi t
belirli bir değeri için yerel olup olmadığını görmek için hokkabazlık yapıyoruz. Etkisi sistematik ve Java sürümü iki kat daha hızlı olmak değildir.
PrintAssembly bu biraz ışık tutacaktır. Bu Scala kriter: sıcak taşıdır
0x00007fe759199d42: test %r8d,%r8d
0x00007fe759199d45: je 0x00007fe759199d76 ;*irem
; - org.sample.ScalaBench::isEvenlyDivisible@11 (line 52)
; - org.sample.ScalaBench::run@10 (line 45)
0x00007fe759199d47: mov ìx,êx
0x00007fe759199d49: cmp $0x80000000,êx
0x00007fe759199d4e: jne 0x00007fe759199d58
0x00007fe759199d50: xor íx,íx
0x00007fe759199d52: cmp $0xffffffffffffffff,%r8d
0x00007fe759199d56: je 0x00007fe759199d5c
0x00007fe759199d58: cltd
0x00007fe759199d59: idiv %r8d
...ve bu benzer Java: blok
0x00007f4a811848cf: movslq ëp,%r10
0x00007f4a811848d2: mov ëp,%r9d
0x00007f4a811848d5: sar $0x1f,%r9d
0x00007f4a811848d9: imul $0x55555556,%r10,%r10
0x00007f4a811848e0: sar $0x20,%r10
0x00007f4a811848e4: mov %r10d,%r11d
0x00007f4a811848e7: sub %r9d,%r11d ;*irem
; - org.sample.JavaBench::isEvenlyDivisible@9 (line 63)
; - org.sample.JavaBench::isEvenlyDivisible@19 (line 63)
; - org.sample.JavaBench::run@10 (line 54)
Fark nasıl Java derleyici çarpma içine tamsayı kalanı hesaplama çevirmek ve doğru kayması (Hacker Zevk, Ch bakın. için hile istihdam sürüm 10, Mezhep. 19). Bu tatlı optimizasyon hit Java gösteriyor sürekli, ama Scala sürümü karşı kalan bilgi işlem derleyici algılar vermedi zaman mümkün değildir. Bu bayt koduna müdahale ettiler anlamaya demontaj kazmak olabilir, ama bu egzersizin amacı kod oluşturma şaşırtıcı dakika farklılıklar kriterler tarafından çok fazla büyütülmüş.
P. S. çok @tailrec
...
GÜNCELLEME: etkisi daha ayrıntılı BİR açıklama: http://shipilev.net/blog/2014/java-scala-divided-we-fail/
Ne'in (gizli) maliyet'In laz...
Performans ve Java birlikte Çalışabili...
Neden bu Scala kod için küçük bir deği...
64-bit ile 32-bit döngü sayısı bir değ...
Hızlı performans: dizileri sıralama...