Seberapa cepat D dibandingkan dengan C ++?

133

Saya suka beberapa fitur D, tetapi akan tertarik jika mereka datang dengan penalti runtime?

Sebagai perbandingan, saya mengimplementasikan program sederhana yang menghitung produk skalar dari banyak vektor pendek baik dalam C ++ maupun dalam D. Hasilnya mengejutkan:

  • D: 18,9 dt [lihat di bawah untuk runtime akhir]
  • C ++: 3,8 dtk

Apakah C ++ benar-benar hampir lima kali lebih cepat atau apakah saya membuat kesalahan dalam program D.

Saya mengkompilasi C ++ dengan g ++ -O3 (gcc-snapshot 2011-02-19) dan D dengan dmd -O (dmd 2.052) pada desktop linux moderat terbaru. Hasilnya dapat direproduksi dalam beberapa proses dan standar deviasi dapat diabaikan.

Di sini program C ++:

#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;
}

Dan di sini versi D:

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;
}
Lars
sumber
3
Omong-omong, program Anda memiliki bug di baris ini: avg = avg / N*N(urutan operasi).
Vladimir Panteleev
4
Anda dapat mencoba menulis ulang kode menggunakan operasi array / vektor digitalmars.com/d/2.0/arrays.html
Michal Minich
10
Untuk memberikan perbandingan yang lebih baik, Anda harus menggunakan kompiler back-end yang sama. Baik DMD dan DMC ++ atau GDC dan G ++
he_the_great
1
@Sion Sheevok Sayangnya, pembuatan profil dmd tampaknya tidak tersedia untuk Linux? (tolong perbaiki saya jika saya salah, tetapi jika saya katakan dmd ... trace.defsaya dapat error: unrecognized file extension def. Dan dokumen dmd untuk optlink hanya menyebutkan Windows.
Lars
1
Ah, tidak pernah peduli tentang file .def yang dimuntahkannya. Pengaturan waktu ada di dalam file .log. "Ini berisi daftar fungsi dalam urutan tautan harus menautkannya" - mungkin itu membantu optlink untuk mengoptimalkan sesuatu? Perhatikan juga bahwa "Selain itu, ld sepenuhnya mendukung file" * .def "standar, yang dapat ditentukan pada baris perintah linker seperti file objek" - sehingga Anda dapat mencoba untuk melewatkan trace.def via -L jika Anda ingin untuk.
Trass3r

Jawaban:

64

Untuk mengaktifkan semua optimasi dan menonaktifkan semua pemeriksaan keamanan, kompilasi program D Anda dengan flag DMD berikut:

-O -inline -release -noboundscheck

EDIT : Saya sudah mencoba program Anda dengan g ++, dmd dan gdc. dmd memang ketinggalan, tetapi gdc mencapai kinerja yang sangat dekat dengan g ++. Baris perintah yang saya gunakan adalah gdmd -O -release -inline(gdmd adalah pembungkus di sekitar gdc yang menerima opsi dmd).

Melihat daftar assembler, sepertinya dmd atau gdc tidak bergaris scalar_product, tetapi g ++ / gdc memang memancarkan instruksi MMX, jadi mereka mungkin secara otomatis meng-vektor-kan loop.

Vladimir Panteleev
sumber
3
@CyberShadow: tetapi jika Anda menghapus pemeriksaan keamanan ... bukankah Anda kehilangan beberapa fitur penting D?
Matthieu M.
33
Anda kehilangan fitur yang tidak dimiliki C ++. Sebagian besar bahasa tidak memberi Anda pilihan.
Vladimir Panteleev
6
@CyberShadow: bisakah kita menganggap ini sebagai semacam versi debug vs rilis?
Francesco
7
@Bernard: di -release, memeriksa batas dimatikan untuk semua kode kecuali fungsi yang aman. untuk benar-benar mematikan batas memeriksa gunakan -release dan-noboundscheck.
Michal Minich
5
@CyberShadow Terima kasih! Dengan bendera ini runtime meningkat secara signifikan. Sekarang D berada pada 12,9 detik. Namun masih berjalan lebih dari 3 kali lebih lama. @ Matthieu M. Saya tidak akan keberatan untuk menguji program dengan boundschecking dalam gerakan lambat dan setelah debugged biarkan ia melakukan perhitungannya tanpa boundschecking. (Saya melakukan hal yang sama dengan C ++ sekarang.)
Lars
32

Satu hal besar yang memperlambat D down adalah implementasi pengumpulan sampah di bawah standar. Benchmark yang tidak terlalu menekankan GC akan menunjukkan kinerja yang sangat mirip dengan kode C dan C ++ yang dikompilasi dengan backend kompiler yang sama. Benchmark yang sangat menekankan GC akan menunjukkan bahwa D berkinerja buruk. Namun, yakinlah, ini adalah masalah implementasi-kualitas tunggal (meskipun parah), bukan jaminan kelambatan. Juga, D memberi Anda kemampuan untuk keluar dari GC dan menyelaraskan manajemen memori dalam bit-bit yang kritis terhadap kinerja, sambil tetap menggunakannya dalam 95% kode Anda yang kurang kritis terhadap kinerja.

Saya telah berupaya meningkatkan kinerja GC belakangan ini dan hasilnya agak dramatis, setidaknya pada tolok ukur sintetis. Semoga perubahan ini akan diintegrasikan ke dalam salah satu dari beberapa rilis berikutnya dan akan mengurangi masalah ini.

dsimcha
sumber
1
Saya perhatikan salah satu perubahan Anda adalah perubahan dari divisi ke bit shift. Bukankah itu seharusnya sesuatu yang dilakukan kompiler?
GManNickG
3
@ GM: Ya, jika nilai yang Anda bagi diketahui diketahui pada waktu kompilasi. Tidak, jika nilainya hanya diketahui saat runtime, yang merupakan kasus di mana saya membuat optimasi itu.
dsimcha
@dsimcha: Hm. Saya pikir jika Anda tahu untuk membuatnya, kompiler juga bisa. Kualitas masalah implementasi, atau saya kehilangan beberapa kondisi yang harus dipenuhi bahwa kompiler tidak dapat membuktikan, tetapi Anda tahu? (Saya belajar D sekarang, jadi hal-hal kecil tentang kompiler ini tiba-tiba menarik bagi saya. :))
GManNickG
13
@ GM: Bit shifting hanya berfungsi jika angka yang Anda bagi adalah kekuatan dua. Kompiler tidak dapat membuktikan hal ini jika nomornya diketahui hanya pada saat runtime, dan pengujian dan percabangan akan lebih lambat daripada hanya menggunakan instruksi div. Kasus saya tidak biasa karena nilainya hanya diketahui pada saat runtime, tetapi saya tahu pada waktu kompilasi bahwa itu akan menjadi kekuatan dua.
dsimcha
7
Perhatikan bahwa program yang diposting dalam contoh ini tidak melakukan alokasi dalam porsi yang memakan waktu.
Vladimir Panteleev
27

Ini adalah utas yang sangat instruktif, terima kasih atas semua kerja untuk OP dan para pembantunya.

Satu catatan - tes ini tidak menilai pertanyaan umum abstraksi / penalti fitur atau bahkan kualitas backend. Ini berfokus pada hampir satu optimasi (optimasi lingkaran). Saya pikir itu adil untuk mengatakan bahwa backend gcc agak lebih halus daripada dmd, tetapi itu akan menjadi kesalahan untuk mengasumsikan bahwa kesenjangan di antara mereka sama besar untuk semua tugas.

Andrei Alexandrescu
sumber
4
Saya sangat setuju. Seperti yang ditambahkan kemudian, saya terutama tertarik pada kinerja untuk perhitungan numerik di mana optimasi loop mungkin yang paling penting. Menurut Anda, optimasi apa yang penting untuk komputasi numerik? Dan perhitungan mana yang akan mengujinya? Saya akan tertarik untuk melengkapi tes saya dan menerapkan beberapa tes lagi (jika mereka kira-kira sesederhana). Tapi evtl ini pertanyaan lain?
Lars
11
Sebagai seorang insinyur yang memotong giginya di C ++, Anda adalah pahlawan saya. Namun, dengan hormat, ini harus berupa komentar, bukan jawaban.
Alan
14

Jelas tampak seperti masalah kualitas implementasi.

Saya menjalankan beberapa tes dengan kode OP dan membuat beberapa perubahan. Saya benar-benar mendapatkan D lebih cepat untuk LDC / clang ++, beroperasi dengan asumsi bahwa array harus dialokasikan secara dinamis ( xsdan skalar terkait). Lihat di bawah untuk beberapa angka.

Pertanyaan untuk OP

Apakah disengaja bahwa benih yang sama digunakan untuk setiap iterasi C ++, sementara tidak demikian untuk D?

Mempersiapkan

Saya telah men-tweak sumber D asli (dijuluki scalar.d) untuk membuatnya portabel antar platform. Ini hanya melibatkan mengubah jenis angka yang digunakan untuk mengakses dan memodifikasi ukuran array.

Setelah ini, saya membuat perubahan berikut:

  • Digunakan uninitializedArrayuntuk menghindari init default untuk skalar di xs (mungkin membuat perbedaan terbesar). Ini penting karena D biasanya menginisialisasi semuanya diam-diam, yang tidak C ++.

  • Diperhatikan kode pencetakan dan diganti writeflndenganwriteln

  • Impor yang diubah menjadi selektif
  • Operator pow bekas ( ^^) alih-alih penggandaan manual untuk langkah akhir penghitungan rata-rata
  • Dihapus size_typedan diganti dengan tepat dengan index_typealias baru

... sehingga menghasilkan scalar2.cpp( 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
      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;
    }

Setelah pengujian scalar2.d(yang memprioritaskan optimasi untuk kecepatan), karena penasaran saya mengganti loop maindengan yang foreachsetara, dan menyebutnya 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;
    }

Saya mengkompilasi masing-masing tes ini menggunakan kompiler berbasis LLVM, karena LDC tampaknya menjadi pilihan terbaik untuk kompilasi D dalam hal kinerja. Pada instalasi Arch Linux x86_64 saya, saya menggunakan paket-paket berikut:

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

Saya menggunakan perintah berikut untuk mengkompilasi masing-masing:

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

Hasil

Hasil ( tangkapan layar output konsol mentah ) dari setiap versi sumber sebagai berikut:

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

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

    C ++ menetapkan standar pada 2582 ms .

  2. scalar.d (sumber OP yang dimodifikasi):

    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 

    Ini berjalan selama ~ 2957 ms . Lebih lambat dari implementasi C ++, tetapi tidak terlalu banyak.

  3. scalar2.d (indeks / perubahan jenis panjang dan optimasi Array tidak diinisialisasi):

    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

    Dengan kata lain, ~ 1860 ms . Sejauh ini memimpin.

  4. scalar3.d (dahi):

    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 lebih lambat daripada scalar2.d, tetapi lebih cepat dari versi C ++.

Kesimpulan

Dengan optimasi yang benar, implementasi D sebenarnya berjalan lebih cepat daripada implementasi C ++ yang setara menggunakan kompiler berbasis LLVM yang tersedia. Kesenjangan saat ini antara D dan C ++ untuk sebagian besar aplikasi tampaknya hanya didasarkan pada batasan implementasi saat ini.

Erich Gubler
sumber
8

dmd adalah implementasi referensi bahasa dan dengan demikian sebagian besar pekerjaan diletakkan di frontend untuk memperbaiki bug daripada mengoptimalkan backend.

"in" lebih cepat dalam kasus Anda karena Anda menggunakan array dinamis yang merupakan tipe referensi. Dengan ref Anda memperkenalkan tingkat tipuan yang lain (yang biasanya digunakan untuk mengubah array itu sendiri dan tidak hanya konten).

Vektor biasanya diimplementasikan dengan struct di mana const ref masuk akal. Lihat smallptD vs smallpt untuk contoh dunia nyata yang menampilkan banyak operasi vektor dan keacakan.

Perhatikan bahwa 64-Bit juga dapat membuat perbedaan. Saya pernah melewatkan bahwa pada x64 gcc mengkompilasi kode 64-Bit sementara dmd masih default ke 32 (akan berubah ketika codegen 64-Bit matang). Ada speedup luar biasa dengan "dmd -m64 ...".

Trass3r
sumber
7

Apakah C ++ atau D lebih cepat cenderung sangat tergantung pada apa yang Anda lakukan. Saya akan berpikir bahwa ketika membandingkan C ++ yang ditulis dengan baik dengan kode D yang ditulis dengan baik, mereka umumnya akan memiliki kecepatan yang sama, atau C ++ akan lebih cepat, tetapi apa yang dikelola oleh kompiler tertentu untuk dioptimalkan dapat memiliki efek besar sepenuhnya selain dari bahasa diri.

Namun, ada yang beberapa kasus di mana D berdiri sebuah kesempatan baik untuk mengalahkan C ++ untuk kecepatan. Yang utama yang terlintas dalam pikiran adalah pemrosesan string. Berkat kemampuan mengiris array D, string (dan array secara umum) dapat diproses lebih cepat daripada yang dapat Anda lakukan dengan mudah di C ++. Untuk D1, prosesor XML Tango sangat cepat , terutama berkat kemampuan mengiris array D (dan mudah-mudahan D2 akan memiliki parser XML yang sama cepat setelah yang sedang dikerjakan untuk Phobos telah selesai). Jadi, pada akhirnya apakah D atau C ++ akan menjadi lebih cepat akan sangat tergantung pada apa yang Anda lakukan.

Sekarang, saya sedang terkejut bahwa Anda melihat perbedaan dalam kecepatan dalam kasus ini, tetapi itu adalah semacam hal yang saya harapkan untuk meningkatkan sebagai DMD membaik. Menggunakan gdc mungkin menghasilkan hasil yang lebih baik dan kemungkinan akan menjadi perbandingan yang lebih dekat dari bahasa itu sendiri (bukan backend) mengingat bahwa itu berbasis gcc. Tapi itu tidak akan mengejutkan saya sama sekali jika ada beberapa hal yang dapat dilakukan untuk mempercepat kode yang dmd hasilkan. Saya tidak berpikir bahwa ada banyak pertanyaan bahwa gcc lebih dewasa daripada dmd pada saat ini. Dan optimasi kode adalah salah satu buah utama dari kematangan kode.

Pada akhirnya, yang penting adalah seberapa baik dmd berkinerja untuk aplikasi khusus Anda, tetapi saya setuju bahwa pasti akan menyenangkan untuk mengetahui seberapa baik C ++ dan D dibandingkan secara umum. Secara teori, mereka harusnya hampir sama, tetapi itu benar-benar tergantung pada implementasinya. Saya pikir satu set tolok ukur komprehensif akan diperlukan untuk benar-benar menguji seberapa baik keduanya membandingkan saat ini.

Jonathan M Davis
sumber
4
Ya saya akan terkejut jika input / output secara signifikan lebih cepat di kedua bahasa, atau jika matematika murni secara signifikan lebih cepat di kedua bahasa, tetapi operasi string, manajemen memori, dan beberapa hal lainnya dapat dengan mudah membiarkan satu bahasa bersinar.
Max Lybbert
1
Sangat mudah untuk melakukan yang lebih baik (lebih cepat) daripada C ++ iostreams. Tapi itu terutama masalah implementasi perpustakaan (pada semua versi yang diketahui dari vendor paling populer).
Ben Voigt
4

Anda dapat menulis kode C sejauh D yang lebih cepat, itu akan tergantung pada banyak hal:

  • Kompiler apa yang Anda gunakan
  • Fitur apa yang Anda gunakan
  • seberapa agresif Anda mengoptimalkan

Perbedaan yang pertama tidak adil untuk diseret. Yang kedua mungkin memberi C ++ keuntungan karena, jika ada, memiliki fitur berat yang lebih sedikit. Yang ketiga adalah yang menyenangkan: kode D dalam beberapa hal lebih mudah dioptimalkan karena secara umum lebih mudah dipahami. Juga memiliki kemampuan untuk melakukan program generatif tingkat besar yang memungkinkan hal-hal seperti verbose dan kode berulang tetapi cepat ditulis dalam bentuk yang lebih pendek.

BCS
sumber
3

Sepertinya kualitas masalah implementasi. Misalnya, inilah yang telah saya uji:

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);
}

Dengan ManualInlinedidefinisikan saya mendapatkan 28 detik, tetapi tanpa saya mendapatkan 32. Jadi kompiler bahkan tidak menggarisbawahi fungsi sederhana ini, yang saya pikir sudah jelas seharusnya.

(Baris perintah saya adalah dmd -O -noboundscheck -inline -release ....)

GManNickG
sumber
1
Timing Anda tidak ada artinya kecuali Anda memberikan perbandingan dengan timing C ++ Anda juga.
deceleratedcaviar
3
@Aniel: Anda tidak mengerti intinya. Itu untuk menunjukkan optimasi D secara terpisah, yaitu untuk kesimpulan yang saya nyatakan: "Jadi kompiler bahkan tidak menggarisbawahi fungsi sederhana ini, yang saya pikir sudah jelas seharusnya." Saya bahkan mencoba membandingkannya dengan C ++, seperti yang saya jelaskan dalam kalimat pertama : "Sepertinya kualitas masalah implementasi."
GManNickG
Ah benar, maaf :). Anda juga akan menemukan kompiler DMD tidak membuat vektor loop sama sekali.
deceleratedcaviar