SORU
22 Mart 2014, CUMARTESİ


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
24 Mart 2014, PAZARTESİ


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/

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • Blunty

    Blunty

    13 Mart 2006
  • KSI

    KSI

    25 Temmuz 2009
  • Viktorija A.

    Viktorija A.

    28 Mart 2009