D, C ++ ile karşılaştırıldığında ne kadar hızlıdır?


133

D'nin bazı özelliklerini seviyorum, ancak çalışma süresi cezası ile gelirlerse ilgilenir miyim?

Karşılaştırmak için, hem C ++ hem de D'de birçok kısa vektörün skaler ürünlerini hesaplayan basit bir program uyguladım. Sonuç şaşırtıcı:

  • D: 18,9 sn [son çalışma süresi için aşağıya bakın]
  • C ++: 3,8 saniye

C ++ gerçekten neredeyse beş kat daha hızlı mı yoksa D programında bir hata mı yaptım?

C ++ 'ı g ++ -O3 (gcc-snapshot 2011-02-19) ile ve D'yi dmd -O (dmd 2.052) ile yeni bir Linux masaüstünde derledim. Sonuçlar birkaç çalışmada tekrarlanabilir ve standart sapmalar ihmal edilebilir düzeydedir.

İşte C ++ programı:

#include <iostream>
#include <random>
#include <chrono>
#include <string>

#include <vector>
#include <array>

typedef std::chrono::duration<long, std::ratio<1, 1000>> millisecs;
template <typename _T>
long time_since(std::chrono::time_point<_T>& time) {
      long tm = std::chrono::duration_cast<millisecs>( std::chrono::system_clock::now() - time).count();
  time = std::chrono::system_clock::now();
  return tm;
}

const long N = 20000;
const int size = 10;

typedef int value_type;
typedef long long result_type;
typedef std::vector<value_type> vector_t;
typedef typename vector_t::size_type size_type;

inline value_type scalar_product(const vector_t& x, const vector_t& y) {
  value_type res = 0;
  size_type siz = x.size();
  for (size_type i = 0; i < siz; ++i)
    res += x[i] * y[i];
  return res;
}

int main() {
  auto tm_before = std::chrono::system_clock::now();

  // 1. allocate and fill randomly many short vectors
  vector_t* xs = new vector_t [N];
  for (int i = 0; i < N; ++i) {
    xs[i] = vector_t(size);
      }
  std::cerr << "allocation: " << time_since(tm_before) << " ms" << std::endl;

  std::mt19937 rnd_engine;
  std::uniform_int_distribution<value_type> runif_gen(-1000, 1000);
  for (int i = 0; i < N; ++i)
    for (int j = 0; j < size; ++j)
      xs[i][j] = runif_gen(rnd_engine);
  std::cerr << "random generation: " << time_since(tm_before) << " ms" << std::endl;

  // 2. compute all pairwise scalar products:
  time_since(tm_before);
  result_type avg = 0;
  for (int i = 0; i < N; ++i)
    for (int j = 0; j < N; ++j) 
      avg += scalar_product(xs[i], xs[j]);
  avg = avg / N*N;
  auto time = time_since(tm_before);
  std::cout << "result: " << avg << std::endl;
  std::cout << "time: " << time << " ms" << std::endl;
}

Ve işte D versiyonu:

import std.stdio;
import std.datetime;
import std.random;

const long N = 20000;
const int size = 10;

alias int value_type;
alias long result_type;
alias value_type[] vector_t;
alias uint size_type;

value_type scalar_product(const ref vector_t x, const ref vector_t y) {
  value_type res = 0;
  size_type siz = x.length;
  for (size_type i = 0; i < siz; ++i)
    res += x[i] * y[i];
  return res;
}

int main() {   
  auto tm_before = Clock.currTime();

  // 1. allocate and fill randomly many short vectors
  vector_t[] xs;
  xs.length = N;
  for (int i = 0; i < N; ++i) {
    xs[i].length = size;
  }
  writefln("allocation: %i ", (Clock.currTime() - tm_before));
  tm_before = Clock.currTime();

  for (int i = 0; i < N; ++i)
    for (int j = 0; j < size; ++j)
      xs[i][j] = uniform(-1000, 1000);
  writefln("random: %i ", (Clock.currTime() - tm_before));
  tm_before = Clock.currTime();

  // 2. compute all pairwise scalar products:
  result_type avg = cast(result_type) 0;
  for (int i = 0; i < N; ++i)
    for (int j = 0; j < N; ++j) 
      avg += scalar_product(xs[i], xs[j]);
  avg = avg / N*N;
  writefln("result: %d", avg);
  auto time = Clock.currTime() - tm_before;
  writefln("scalar products: %i ", time);

  return 0;
}

3
Bu arada, programınızda bu satırda bir hata var: avg = avg / N*N(işlem sırası).
Vladimir Panteleev

4
Dizi / vektör işlemlerini kullanarak kodu yeniden yazmayı deneyebilirsiniz digitalmars.com/d/2.0/arrays.html
Michal Minich

10
Daha iyi bir karşılaştırma sağlamak için aynı derleyici arka ucunu kullanmalısınız. DMD ve DMC ++ veya GDC ve G ++
he_the_great

1
@Sion Sheevok Maalesef, dmd profili oluşturma Linux için kullanılamıyor gibi görünüyor? (hatam varsa düzeltin ama dersem lütfen dmd ... trace.defben bir olsun error: unrecognized file extension defVe için dmd docs. optlink söz yalnızca Windows.
Lars

1
Ah, o .def dosyası hiç umursamadı. Zamanlamalar .log dosyasının içindedir. "Bağlayıcının bağlanması gereken sırayla işlevlerin listesini içerir" - belki bir şeyi optimize etmek için optlink yardımcı olur? Ayrıca, "Ayrıca, ld'nin, bağlayıcı komut satırında bir nesne dosyası gibi belirtilebilecek standart" * .def "dosyalarını tam olarak desteklediğine de dikkat edin" - bu nedenle, eğer canınız isterseniz, trace.def'yi -L aracılığıyla geçirmeyi deneyebilirsiniz. için.
Trass3r

Yanıtlar:


64

Tüm optimizasyonları etkinleştirmek ve tüm güvenlik kontrollerini devre dışı bırakmak için, D programınızı aşağıdaki DMD bayraklarıyla derleyin:

-O -inline -release -noboundscheck

DÜZENLEME : Programlarınızı g ++, dmd ve gdc ile denedim. dmd geride kalıyor, ancak gdc g ++ 'ya çok yakın bir performans sağlıyor. Kullandığım komut satırı gdmd -O -release -inline(gdmd, dmd seçeneklerini kabul eden gdc etrafında bir sarmalayıcıdır).

Birleştirici listesine bakıldığında, ne dmd ne de gdc satır içi gibi görünür scalar_product, ancak g ++ / gdc MMX komutlarını yaydı, bu nedenle döngüyü otomatik olarak vektörleştiriyor olabilirler.


3
@CyberShadow: ama güvenlik kontrolünü kaldırırsanız ... D'nin bazı önemli özelliklerini kaybetmiyor musunuz?
Matthieu M.

33
C ++ 'ın hiç sahip olmadığı özellikleri kaybediyorsunuz. Çoğu dil size seçenek sunmaz.
Vladimir Panteleev

6
@CyberShadow: Bunu bir tür hata ayıklama veya sürüm oluşturma olarak düşünebilir miyiz?
Francesco

7
@Bernard: -release'de, güvenli işlevler dışındaki tüm kodlar için sınır denetimi kapatıldı. sınır kontrolünü gerçekten kapatmak için -release ve-noboundscheck kullanın.
Michal Minich

5
@CyberShadow Teşekkürler! Bu bayraklarla çalışma zamanı önemli ölçüde iyileşir. Şimdi D 12.9 saniyede. Ama yine de 3 kattan fazla uzun sürüyor. @Matthieu M. Ağır çekimde sınır denetimi olan bir programı test etmeyi umursamıyorum ve hata ayıklandıktan sonra hesaplamalarını sınır denetimi yapmadan yapmasına izin verin. (Şimdi aynı şeyi C ++ ile yapıyorum.)
Lars

32

D'yi yavaşlatan büyük bir şey, küçük bir çöp toplama uygulamasıdır. GC'yi çok fazla vurgulamayan kıyaslamalar, aynı derleyici arka uç ile derlenen C ve C ++ koduna çok benzer performans gösterecektir. GC'yi ağır şekilde vurgulayan kıyaslamalar, D'nin aşırı derecede performans gösterdiğini gösterecektir. Yine de, bunun tek bir (ciddi olsa da) uygulama kalitesi sorunu olduğundan emin olun, yavaşlığın tam bir garantisi değil. Ayrıca D, size GC'yi devre dışı bırakma ve performans açısından kritik bitlerde bellek yönetimini ayarlama olanağı sağlarken, onu kodunuzun performans açısından daha az kritik olan% 95'inde kullanmaya devam eder.

Son zamanlarda GC performansını iyileştirmek için biraz çaba sarf ettim ve sonuçlar oldukça dramatik oldu, en azından sentetik kıyaslamalarda. Umarım bu değişiklikler önümüzdeki birkaç sürümden birine entegre edilecek ve sorunu hafifletecektir.


1
Değişikliklerinizden birinin bölmeden bit kaymasına geçiş olduğunu fark ettim. Bu derleyicinin yaptığı bir şey olmamalı mı?
GManNickG

3
@GMan: Evet, böldüğünüz değer derleme zamanında biliniyorsa. Hayır, değer yalnızca çalışma zamanında biliniyorsa, bu optimizasyonu yaptığım durum buydu.
dsimcha

@dsimcha: Hm. Yapacağınızı biliyorsanız, derleyici de yapabilir. Uygulama kalitesi sorunu ya da derleyicinin kanıtlayamayacağı bazı koşulların tatmin edilmesi gerektiğini özlüyorum, ama biliyor musunuz? (Şimdi D öğreniyorum, bu yüzden derleyici hakkındaki bu küçük şeyler aniden benim için ilginç oldu. :))
GManNickG

13
@GMan: Bit kaydırma yalnızca böldüğünüz sayı ikinin üssü ise çalışır. Sayı yalnızca çalışma zamanında biliniyorsa derleyici bunu kanıtlayamaz ve test etme ve dallanma, div komutunu kullanmaktan daha yavaş olacaktır. Durumum alışılmadık çünkü değer yalnızca çalışma zamanında biliniyor, ancak derleme zamanında ikinin bir gücü olacağını biliyorum.
dsimcha

7
Bu örnekte yayınlanan programın zaman alan kısımda tahsis yapmadığını unutmayın.
Vladimir Panteleev

27

Bu çok öğretici bir konu, OP'ye ve yardımcılarına tüm çalışmalar için teşekkürler.

Bir not - bu test genel bir soyutlama / özellik cezası sorununu ve hatta arka uç kalitesiyle ilgili olanı değerlendirmiyor. Neredeyse tek bir optimizasyona (döngü optimizasyonu) odaklanır. Gcc'nin arka ucunun dmd'lerden biraz daha rafine olduğunu söylemenin adil olduğunu düşünüyorum, ancak aralarındaki boşluğun tüm görevler için bu kadar büyük olduğunu varsaymak yanlış olur.


4
Tamamen katılıyorum. Daha sonra eklendiği gibi, esas olarak döngü optimizasyonunun muhtemelen en önemli olduğu sayısal hesaplamalar için performansla ilgileniyorum. Sayısal hesaplama için başka hangi optimizasyonların önemli olacağını düşünüyorsunuz? Ve hangi hesaplamalar onları test eder? Testimi tamamlamak ve birkaç test daha uygulamak isterdim (kabaca bu kadar basitlerse). Ama evtl. bu kendi başına başka bir soru mu?
Lars

11
C ++ 'da dişlerini kesen bir mühendis olarak benim kahramanımsın. Ancak saygıyla, bu bir cevap değil, bir yorum olmalıdır.
Alan

14

Kesinlikle bir uygulama kalitesi sorunu gibi görünüyor.

OP'nin kodu ile bazı testler yaptım ve bazı değişiklikler yaptım. Aslında D'yi LDC / clang ++ için daha hızlı hale getirdim , dizilerin dinamik olarak tahsis edilmesi ( ve ilişkili skalerlerin) gerektiği varsayımıyla çalışıyorum xs. Bazı numaralar için aşağıya bakın.

OP için sorular

C ++ 'nın her yinelemesi için aynı tohumun kullanılması kasıtlı mıdır, ancak D için böyle değil mi?

Kurmak

Orijinal D kaynağını (dublajlı scalar.d) platformlar arasında taşınabilir hale getirmek için değiştirdim. Bu sadece dizilerin boyutlarına erişmek ve bunları değiştirmek için kullanılan sayıların türünü değiştirmeyi içeriyordu.

Bundan sonra şu değişiklikleri yaptım:

  • Kullanılan uninitializedArrayxs içinde skalerler için varsayılan INITs önlemek için (muhtemelen en büyük fark yarattı). Bu önemlidir, çünkü D normalde her şeyi sessizce başlatır, ancak C ++ bunu yapmaz.

  • Kodu basmak etki dışı ve yerine writeflnilewriteln

  • Seçici olacak şekilde değiştirilen ithalatlar
  • ^^Ortalama hesaplamanın son adımı için manuel çarpma yerine güç operatörü ( ) kullanıldı
  • Kaldırıldı size_typeve yeni index_typetakma adla uygun şekilde değiştirildi

... böylece scalar2.cpp( pastebin ) ile sonuçlanır :

    import std.stdio : writeln;
    import std.datetime : Clock, Duration;
    import std.array : uninitializedArray;
    import std.random : uniform;

    alias result_type = long;
    alias value_type = int;
    alias vector_t = value_type[];
    alias index_type = typeof(vector_t.init.length);// Make index integrals portable - Linux is ulong, Win8.1 is uint

    immutable long N = 20000;
    immutable int size = 10;

    // Replaced for loops with appropriate foreach versions
    value_type scalar_product(in ref vector_t x, in ref vector_t y) { // "in" is the same as "const" here
      value_type res = 0;
      for(index_type i = 0; i < size; ++i)
        res += x[i] * y[i];
      return res;
    }

    int main() {
      auto tm_before = Clock.currTime;
      auto countElapsed(in string taskName) { // Factor out printing code
        writeln(taskName, ": ", Clock.currTime - tm_before);
        tm_before = Clock.currTime;
      }

      // 1. allocate and fill randomly many short vectors
      vector_t[] xs = uninitializedArray!(vector_t[])(N);// Avoid default inits of inner arrays
      for(index_type i = 0; i < N; ++i)
        xs[i] = uninitializedArray!(vector_t)(size);// Avoid more default inits of values
      countElapsed("allocation");

      for(index_type i = 0; i < N; ++i)
        for(index_type j = 0; j < size; ++j)
          xs[i][j] = uniform(-1000, 1000);
      countElapsed("random");

      // 2. compute all pairwise scalar products:
      result_type avg = 0;
      for(index_type i = 0; i < N; ++i)
        for(index_type j = 0; j < N; ++j)
          avg += scalar_product(xs[i], xs[j]);
      avg /= N ^^ 2;// Replace manual multiplication with pow operator
      writeln("result: ", avg);
      countElapsed("scalar products");

      return 0;
    }

Test ettikten sonra scalar2.d(hız için olan öncelik optimizasyonu), merak dışında döngüler ikame mainile foreacheşdeğer ve denilen scalar3.d( pastebin ):

    import std.stdio : writeln;
    import std.datetime : Clock, Duration;
    import std.array : uninitializedArray;
    import std.random : uniform;

    alias result_type = long;
    alias value_type = int;
    alias vector_t = value_type[];
    alias index_type = typeof(vector_t.init.length);// Make index integrals portable - Linux is ulong, Win8.1 is uint

    immutable long N = 20000;
    immutable int size = 10;

    // Replaced for loops with appropriate foreach versions
    value_type scalar_product(in ref vector_t x, in ref vector_t y) { // "in" is the same as "const" here
      value_type res = 0;
      for(index_type i = 0; i < size; ++i)
        res += x[i] * y[i];
      return res;
    }

    int main() {
      auto tm_before = Clock.currTime;
      auto countElapsed(in string taskName) { // Factor out printing code
        writeln(taskName, ": ", Clock.currTime - tm_before);
        tm_before = Clock.currTime;
      }

      // 1. allocate and fill randomly many short vectors
      vector_t[] xs = uninitializedArray!(vector_t[])(N);// Avoid default inits of inner arrays
      foreach(ref x; xs)
        x = uninitializedArray!(vector_t)(size);// Avoid more default inits of values
      countElapsed("allocation");

      foreach(ref x; xs)
        foreach(ref val; x)
          val = uniform(-1000, 1000);
      countElapsed("random");

      // 2. compute all pairwise scalar products:
      result_type avg = 0;
      foreach(const ref x; xs)
        foreach(const ref y; xs)
          avg += scalar_product(x, y);
      avg /= N ^^ 2;// Replace manual multiplication with pow operator
      writeln("result: ", avg);
      countElapsed("scalar products");

      return 0;
    }

LDC, performans açısından D derlemesi için en iyi seçenek gibi göründüğünden, bu testlerin her birini LLVM tabanlı bir derleyici kullanarak derledim. X86_64 Arch Linux kurulumumda aşağıdaki paketleri kullandım:

  • clang 3.6.0-3
  • ldc 1:0.15.1-4
  • dtools 2.067.0-2

Her birini derlemek için aşağıdaki komutları kullandım:

  • C ++: clang++ scalar.cpp -o"scalar.cpp.exe" -std=c++11 -O3
  • D: rdmd --compiler=ldc2 -O3 -boundscheck=off <sourcefile>

Sonuçlar

Kaynağın her sürümünün sonuçları ( ham konsol çıktısının ekran görüntüsü ) aşağıdaki gibidir:

  1. scalar.cpp (orijinal C ++):

    allocation: 2 ms
    
    random generation: 12 ms
    
    result: 29248300000
    
    time: 2582 ms

    C ++ standardı 2582 ms olarak ayarlar .

  2. scalar.d (değiştirilmiş OP kaynağı):

    allocation: 5 ms, 293 μs, and 5 hnsecs 
    
    random: 10 ms, 866 μs, and 4 hnsecs 
    
    result: 53237080000
    
    scalar products: 2 secs, 956 ms, 513 μs, and 7 hnsecs 

    Bu ~ 2957 ms sürdü . C ++ uygulamasından daha yavaş, ancak çok fazla değil.

  3. scalar2.d (dizin / uzunluk türü değişikliği ve başlatılmamış Dizi optimizasyonu):

    allocation: 2 ms, 464 μs, and 2 hnsecs
    
    random: 5 ms, 792 μs, and 6 hnsecs
    
    result: 59
    
    scalar products: 1 sec, 859 ms, 942 μs, and 9 hnsecs

    Başka bir deyişle, ~ 1860 ms . Şimdiye kadar bu önde.

  4. scalar3.d (Foreaches):

    allocation: 2 ms, 911 μs, and 3 hnsecs
    
    random: 7 ms, 567 μs, and 8 hnsecs
    
    result: 189
    
    scalar products: 2 secs, 182 ms, and 366 μs

    ~ 2182 ms , scalar2.dC ++ sürümünden daha yavaş , ancak daha hızlıdır.

Sonuç

Doğru optimizasyonlarla, D uygulaması, mevcut LLVM tabanlı derleyicileri kullanan eşdeğer C ++ uygulamasından daha hızlı gitti. Çoğu uygulama için D ve C ++ arasındaki mevcut boşluk, yalnızca mevcut uygulamaların sınırlamalarına dayanıyor gibi görünüyor.


8

dmd, dilin referans uygulamasıdır ve bu nedenle çoğu iş, arka ucu optimize etmek yerine hataları düzeltmek için ön uca yerleştirilir.

Sizin durumunuzda "in" daha hızlıdır, çünkü referans türleri olan dinamik dizileri kullanıyorsunuzdur. Ref ile başka bir dolaylama düzeyi sunarsınız (bu normalde dizinin kendisini değiştirmek için kullanılır, yalnızca içeriği değil).

Vektörler genellikle const ref'in mükemmel bir anlam ifade ettiği yapılarla gerçekleştirilir. Çok sayıda vektör işlemi ve rastgelelik içeren gerçek dünya örneği için smallptD'ye karşı smallpt'e bakın .

64-Bit'in de bir fark yaratabileceğini unutmayın. Bir keresinde x64 gcc'de 64-Bit kod derlerken, dmd hala varsayılan olarak 32'dir (64-Bit kod oluşturucu olgunlaştığında değişecektir). "Dmd -m64 ..." ile dikkate değer bir hızlanma oldu.


7

C ++ veya D'nin daha hızlı olup olmadığı, büyük olasılıkla yaptığınız şeye bağlıdır. İyi yazılmış C ++ ile iyi yazılmış D kodunu karşılaştırırken, genellikle ya benzer hızda olacaklarını ya da C ++ 'nın daha hızlı olacağını düşünürdüm, ancak belirli derleyicinin optimize etmeyi başardığı şey dilden tamamen ayrı büyük bir etkiye sahip olabilir. kendisi.

Ancak, orada olan D hız için C ++ yenme şansının birkaç durum. Akla gelen en önemli şey dizi işleme olacaktır. D'nin dizi dilimleme yetenekleri sayesinde, dizeler (ve genel olarak diziler) C ++ 'da kolayca yapabileceğinizden çok daha hızlı işlenebilir. D1 için, Tango'nun XML işlemcisi, öncelikle D'nin dizi dilimleme yetenekleri sayesinde son derece hızlıdır (ve umarız, şu anda Phobos için üzerinde çalışılan işlem tamamlandığında D2'nin benzer şekilde hızlı bir XML ayrıştırıcısı olacaktır). Yani, sonuçta D veya C ++ 'nın daha hızlı olup olmayacağı, yaptığınız şeye çok bağlı olacaktır.

Şimdi, ben size bu özel durumda hız böyle bir fark görüyorsunuz şaşırttı ama ben dmd geliştikçe geliştirmek beklediğiniz o türden bir şey olduğunu. Gdc'yi kullanmak daha iyi sonuçlar verebilir ve gcc tabanlı olduğu için muhtemelen dilin kendisinin (arka uçtan ziyade) daha yakın bir karşılaştırması olacaktır. Ancak, dmd'nin ürettiği kodu hızlandırmak için yapılabilecek bir dizi şey olması beni hiç şaşırtmaz. Bu noktada gcc'nin dmd'den daha olgun olduğuna dair çok fazla soru olduğunu sanmıyorum. Ve kod optimizasyonları, kod olgunluğunun en önemli meyvelerinden biridir.

Nihayetinde, önemli olan, dmd'nin özel uygulamanız için ne kadar iyi performans gösterdiğidir, ancak C ++ ve D'nin genel olarak ne kadar iyi karşılaştırıldığını bilmenin kesinlikle güzel olacağını kabul ediyorum. Teorik olarak, hemen hemen aynı olmaları gerekir, ancak bu gerçekten uygulamaya bağlıdır. Bununla birlikte, ikisinin şu anda ne kadar iyi karşılaştırdığını gerçekten test etmek için kapsamlı bir kıyaslama setinin gerekli olacağını düşünüyorum.


4
Evet, girdi / çıktının her iki dilde de önemli ölçüde daha hızlı olması veya her iki dilde de saf matematik önemli ölçüde daha hızlı olsaydı şaşırırdım, ancak dizgi işlemleri, bellek yönetimi ve diğer birkaç şey bir dilin parlamasına kolayca izin verebilirdi.
Max Lybbert

1
C ++ iostreams'den daha iyi (daha hızlı) yapmak kolaydır. Ancak bu öncelikle bir kitaplık uygulama sorunu (en popüler satıcıların tüm bilinen sürümlerinde).
Ben Voigt

4

C kodu D yazabilirsiniz, bu nedenle hangisinin daha hızlı olduğu, birçok şeye bağlı olacaktır:

  • Hangi derleyiciyi kullanıyorsun
  • Hangi özelliği kullanıyorsun
  • ne kadar agresif bir şekilde optimize edersiniz

İlkindeki farklılıkların içeri sürüklenmesi adil değildir. İkincisi, C ++ 'ya bir avantaj sağlayabilir, çünkü eğer varsa, daha az ağır özelliklere sahiptir. Üçüncüsü eğlenceli olanıdır: D kodunu bazı yönlerden optimize etmek daha kolaydır çünkü genel olarak anlaşılması daha kolaydır. Ayrıca, ayrıntılı ve tekrarlayan ancak hızlı kod gibi şeylerin daha kısa formlarda yazılmasına izin veren büyük ölçüde üretken programlama yeteneğine sahiptir.


3

Bir uygulama kalitesi sorunu gibi görünüyor. Örneğin, test ettiğim şey:

import std.datetime, std.stdio, std.random;

version = ManualInline;

immutable N = 20000;
immutable Size = 10;

alias int value_type;
alias long result_type;
alias value_type[] vector_type;

result_type scalar_product(in vector_type x, in vector_type y)
in
{
    assert(x.length == y.length);
}
body
{
    result_type result = 0;

    foreach(i; 0 .. x.length)
        result += x[i] * y[i];

    return result;
}

void main()
{   
    auto startTime = Clock.currTime();

    // 1. allocate vectors
    vector_type[] vectors = new vector_type[N];
    foreach(ref vec; vectors)
        vec = new value_type[Size];

    auto time = Clock.currTime() - startTime;
    writefln("allocation: %s ", time);
    startTime = Clock.currTime();

    // 2. randomize vectors
    foreach(ref vec; vectors)
        foreach(ref e; vec)
            e = uniform(-1000, 1000);

    time = Clock.currTime() - startTime;
    writefln("random: %s ", time);
    startTime = Clock.currTime();

    // 3. compute all pairwise scalar products
    result_type avg = 0;

    foreach(vecA; vectors)
        foreach(vecB; vectors)
        {
            version(ManualInline)
            {
                result_type result = 0;

                foreach(i; 0 .. vecA.length)
                    result += vecA[i] * vecB[i];

                avg += result;
            }
            else
            {
                avg += scalar_product(vecA, vecB);
            }
        }

    avg = avg / (N * N);

    time = Clock.currTime() - startTime;
    writefln("scalar products: %s ", time);
    writefln("result: %s", avg);
}

Tanımla ManualInline28 saniye elde ederim, ancak 32 saniye elde etmezim. Yani derleyici bu basit işlevi satıra bile eklemiyor, ki bence bu açık olmalı.

(Benim komut satırım dmd -O -noboundscheck -inline -release ....)


1
C ++ zamanlamalarınızla da karşılaştırma yapmadığınız sürece zamanlamalarınız anlamsızdır.
deceleratedcaviar

3
@Daniel: Noktayı kaçırıyorsun. D optimizasyonlarını tek başına göstermekti, yani şu sonuca varmak içindi: "Yani derleyici bu basit işlevi satır içine almıyor, ki bence olması gerektiği açık." Hatta ilk cümlede açıkça belirttiğim gibi, bunu C ++ ile karşılaştırmaya bile çalışıyorum : "Bir uygulama kalitesi sorunu gibi görünüyor."
GManNickG

Ah doğru, özür dilerim :). Ayrıca, DMD derleyicisinin de döngüleri vektörleştirmediğini göreceksiniz.
deceleratedcaviar
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.