C ++에 비해 D는 얼마나 빠릅니까?


133

D의 일부 기능이 마음에 들지만 런타임 패널티가 있다면 관심이 있습니까?

비교하기 위해 C ++과 D에서 많은 짧은 벡터의 스칼라 곱을 계산하는 간단한 프로그램을 구현했습니다. 결과는 놀랍습니다.

  • D : 18.9 초 [최종 런타임은 아래 참조]
  • C ++ : 3.8 초

C ++이 실제로 거의 5 배나 빠르거나 D 프로그램에서 실수를 했습니까?

나는 최근 리눅스 데스크탑에서 g ++ -O3 (gcc-snapshot 2011-02-19) 및 Dmd -O (dmd 2.052)로 C ++를 컴파일했습니다. 결과는 여러 번의 실행에서 재현 가능하고 표준 편차는 무시할 수 있습니다.

여기에 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;
}

그리고 여기 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;
}

3
그건 그렇고, 당신의 프로그램은이 줄에 버그가 있습니다 : avg = avg / N*N(작업 순서).
블라디미르 판 텔레 예프

4
당신은 배열 / 벡터 연산을 사용하여 코드를 다시 시도 할 수 digitalmars.com/d/2.0/arrays.html
마이클 Minich에게

10
더 나은 비교를 제공하려면 동일한 컴파일러 백엔드를 사용해야합니다. DMD 및 DMC ++ 또는 GDC 및 G ++
he_the_great

1
@Sion Sheevok 불행히도 dmd 프로파일 링은 Linux에서 사용할 수없는 것 같습니다. (만약 내가 잘못 정정 해줘,하지만 난 말한다면 제발 dmd ... trace.def난을 얻을 error: unrecognized file extension def그리고위한 DMD 문서. optlink 언급은 Windows.
라스

1
아, .def 파일에 신경 쓰지 않았습니다. 타이밍은 .log 파일 안에 있습니다. "이것은 링커가 링크해야하는 순서대로 함수 목록을 포함합니다."-optlink가 무언가를 최적화하는 데 도움이됩니까? 또한 "ld는 객체 파일처럼 링커 명령 줄에 지정 될 수있는 표준"* .def "파일을 완벽하게 지원합니다. 따라서 원하는 경우 -L을 통해 trace.def를 전달할 수 있습니다. 에.
Trass3r

답변:


64

모든 최적화를 활성화하고 모든 안전 점검을 비활성화하려면 다음 DMD 플래그를 사용하여 D 프로그램을 컴파일하십시오.

-O -inline -release -noboundscheck

편집 : g ++, dmd 및 gdc로 프로그램을 시도했습니다. dmd는 뒤쳐 지지만 gdc는 g ++에 매우 가까운 성능을 달성합니다. 내가 사용한 명령 줄은 gdmd -O -release -inlinegdmd가 ddc 옵션을 허용하는 gdc를 감싸는 래퍼입니다.

어셈블러 목록을 보면 dmd 나 gdc inlined처럼 보이지 scalar_product않지만 g ++ / gdc는 MMX 명령을 내렸 으므로 루프를 자동 벡터화 할 수 있습니다.


3
@ CyberShadow : 그러나 안전 점검을 제거하면 ... D의 중요한 기능을 잃지 않습니까?
Matthieu M.

33
C ++에는 없었던 기능이 손실됩니다. 대부분의 언어는 당신에게 선택권을주지 않습니다.
블라디미르 판 텔레 예프

6
@CyberShadow : 이것을 일종의 디버그 대 릴리스 빌드로 생각할 수 있습니까?
프란체스코

7
@Bernard : 릴리스에서 안전 기능을 제외한 모든 코드에 대해 범위 검사가 해제됩니다. 경계 검사를 실제로 해제하려면 -release 및 -noboundscheck를 모두 사용하십시오.
Michal Minich

5
@CyberShadow 감사합니다! 이러한 플래그를 사용하면 런타임이 상당히 향상됩니다. 이제 D는 12.9 초입니다. 그러나 여전히 3 배 이상 실행됩니다. @Matthieu M. 슬로우 모션에서 경계 검사를 사용하여 프로그램을 테스트하는 것은 마음에 들지 않으며 일단 디버깅되면 경계 검사없이 계산을 수행 할 수 있습니다. (현재 C ++과 동일합니다.)
Lars

32

D 속도를 늦추는 것 중 하나는 하위 파 가비지 수집 구현입니다. GC에 큰 부담을주지 않는 벤치 마크는 동일한 컴파일러 백엔드로 컴파일 된 C 및 C ++ 코드와 매우 유사한 성능을 보여줍니다. GC에 큰 스트레스를주는 벤치 마크는 D가 심하게 작음을 보여줍니다. 그러나 이는 느리게 구현 된 보장이 아니라 단일 (심각한) 구현 품질 문제입니다. 또한 D를 사용하면 성능이 중요하지 않은 코드에서 GC를 선택 해제하고 메모리 관리를 조정하여 성능이 중요하지 않은 코드의 95 %에서 메모리를 계속 사용할 수 있습니다.

나는 한 최근 GC 성능을 향상에 어떤 노력을 하고 그 결과 적어도 합성 벤치 마크에서, 오히려 극적이었다. 이러한 변경 사항이 다음 몇 가지 릴리스 중 하나에 통합되어 문제가 완화되기를 바랍니다.


1
변경 사항 중 하나가 나누기에서 비트 이동으로 변경되었음을 알았습니다. 컴파일러가하는 일이 아니어야합니까?
GManNickG

3
@GMan : 예, 나누는 값이 컴파일 타임에 알려진 경우. 아니요, 값이 런타임에만 알려진 경우 최적화를 수행 한 경우입니다.
dsimcha

@ dsimcha : 흠. 나는 당신이 그것을 알고 있다면 컴파일러도 할 수 있다고 생각합니다. 구현 품질 문제 또는 컴파일러가 증명할 수 없다는 몇 가지 조건을 충족해야한다는 것을 놓치고 있지만 알고 있습니까? (나는 지금 D를 배우고 있기 때문에 컴파일러에 관한이 작은 것들이 갑자기 흥미 롭다. :))
GManNickG

13
@GMan : 비트 쉬프팅은 나누는 숫자가 2의 거듭 제곱 인 경우에만 작동합니다. 런타임에서만 숫자를 알고 있고 테스트 및 분기가 div 명령어를 사용하는 것보다 느리면 컴파일러에서이를 증명할 수 없습니다. 값은 런타임에만 알려지기 때문에 예외입니다.하지만 컴파일 타임에는 2의 거듭 제곱이 될 것입니다.
dsimcha

7
이 예제에 게시 된 프로그램은 시간이 많이 걸리는 부분에 할당되지 않습니다.
블라디미르 판 텔레 예프

27

OP와 도우미의 모든 작업에 감사드립니다.

한 가지 참고 사항-이 테스트는 추상화 / 기능 페널티 또는 백엔드 품질에 대한 일반적인 질문을 평가하지 않습니다. 사실상 하나의 최적화 (루프 최적화)에 중점을 둡니다. 나는 gcc의 백엔드가 dmd의 백엔드보다 약간 더 세련되었다고 말하는 것이 공평하다고 생각하지만, 그들 사이의 간격이 모든 작업에 대해 크다고 가정하는 것은 실수 일 것입니다.


4
완전히 동의 해. 나중에 추가 할 때 루프 최적화가 가장 중요한 수치 계산의 성능에 주로 관심이 있습니다. 수치 컴퓨팅에 중요한 다른 최적화 방법은 무엇입니까? 그리고 어떤 계산을 통해 테스트합니까? 테스트를 보완하고 더 간단한 테스트를 구현하는 데 관심이 있습니다. 그러나 evtl. 이것은 또 다른 질문입니까?
Lars

11
C ++에서 이빨을 깎는 엔지니어는 내 영웅입니다. 그러나 각 각의 의견은 답변이 아니라 의견이어야합니다.
Alan

14

분명히 구현 품질 문제처럼 보입니다.

OP 코드로 몇 가지 테스트를 실행하고 약간 변경했습니다. 실제로 배열을 동적으로 할당 해야 한다는 가정 ( xs및 관련 스칼라)을 사용 하여 LDC / clang ++에 대해 D가 더 빨라졌습니다 . 일부 숫자는 아래를 참조하십시오.

OP에 대한 질문

C에 대한 반복마다 동일한 시드를 사용하고 D에는 그렇지 않은 것이 의도적 인 것입니까?

설정

scalar.d플랫폼간에 이식성을 갖도록 원본 D 소스 ( )를 조정했습니다 . 여기에는 배열의 크기에 액세스하고 수정하는 데 사용되는 숫자 유형 만 변경하는 것이 포함되었습니다.

그 후에 다음과 같이 변경했습니다.

  • uninitializedArrayxs의 스칼라에 대한 기본 초기화를 피하는 데 사용 됩니다 (아마도 가장 큰 차이를 만들었 음). D는 일반적으로 모든 것을 자동으로 초기화하지만 C ++에서는 그렇지 않기 때문에 중요합니다.

  • 코드를 인쇄에서 고려 교체 writefln와 함께writeln

  • 선택적 가져 오기로 변경
  • ^^평균 계산의 마지막 단계에 수동 곱셈 대신 pow 연산자 ( )를 사용했습니다.
  • 를 제거하고 size_typeindex_type별칭으로 적절하게 교체

... 따라서 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;
    }

테스트 후 scalar2.d(속도 최적화를 우선 순위로 한) 호기심으로 루프 mainforeach동등한 것으로 대체하고 scalar3.d( pastbin ) 이라고했습니다 .

    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가 성능 측면에서 D 컴파일에 가장 적합한 옵션 인 것처럼 보이기 때문에 LLVM 기반 컴파일러를 사용하여 이러한 각 테스트를 컴파일했습니다. x86_64 Arch Linux 설치에서 다음 패키지를 사용했습니다.

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

다음 명령을 사용하여 각각을 컴파일했습니다.

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

결과

각 소스 버전의 결과 ( 원시 콘솔 출력 스크린 샷 )는 다음과 같습니다.

  1. scalar.cpp (원래 C ++) :

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

    C ++는 표준을 2582ms로 설정합니다 .

  2. scalar.d (수정 된 OP 소스) :

    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 

    이것은 ~ 2957 ms 동안 실행되었습니다 . C ++ 구현보다 느리지 만 너무 많지는 않습니다.

  3. scalar2.d (인덱스 / 길이 유형 변경 및 초기화되지 않은 배열 최적화) :

    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

    다시 말해, ~ 1860 ms 입니다. 지금까지 이것은 주도하고 있습니다.

  4. scalar3.d (두려움) :

    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

    ~ 2182ms~ 보다 느리지 scalar2.d만 C ++ 버전보다 빠릅니다.

결론

올바른 최적화를 통해 D 구현은 실제로 사용 가능한 LLVM 기반 컴파일러를 사용하는 동등한 C ++ 구현보다 빠릅니다. 대부분의 응용 프로그램에서 D와 C ++ 사이의 현재 격차는 현재 구현의 한계에 기반한 것으로 보입니다.


8

dmd는 언어의 참조 구현이므로 대부분의 작업은 백엔드를 최적화하는 대신 버그를 수정하기 위해 프론트 엔드에 배치됩니다.

"in"이 더 빠를 경우 참조 유형 인 동적 배열을 사용하게됩니다. ref를 사용하면 다른 수준의 간접 지시를 도입합니다 (일반적으로 내용뿐만 아니라 배열 자체를 변경하는 데 사용됨).

벡터는 일반적으로 const ref가 완벽하게 이해되는 구조체로 구현됩니다. 많은 벡터 연산과 임의성을 특징으로하는 실제 예제는 smallptDsmallpt 를 참조하십시오 .

64 비트도 차이를 만들 수 있습니다. x64에서 gcc는 64 비트 코드를 컴파일하는 반면 dmd는 여전히 32로 기본 설정되어 있습니다 (64 비트 codegen이 성숙 할 때 변경됨). "dmd -m64 ..."로 놀라운 속도 향상이있었습니다.


7

C ++ 또는 D가 더 빠른지 여부는 수행중인 작업에 따라 크게 달라질 수 있습니다. 잘 작성된 C ++을 잘 작성된 D 코드와 비교할 때 일반적으로 비슷한 속도이거나 C ++이 빠를 것이지만 특정 컴파일러가 최적화하도록 관리하는 것은 언어와는 별도로 큰 영향을 줄 수 있다고 생각합니다. 그 자체.

그러나이 있다 D는 속도 ++ C 박동의 좋은 기회를 의미합니다 몇 가지 경우가. 가장 중요한 것은 문자열 처리입니다. D의 배열 슬라이싱 기능 덕분에 문자열 (및 일반적으로 배열)은 C ++에서보다 훨씬 빠르게 처리 할 수 ​​있습니다. D1의 경우 Tango의 XML 프로세서는 주로 D의 어레이 슬라이싱 기능 덕분에 매우 빠릅니다 (D2는 현재 Phobos에서 작업하고있는 XML 구문 분석기가 완료되면 유사하게 빠른 XML 파서를 갖기를 바랍니다). 따라서 궁극적으로 D 또는 C ++가 더 빨라질 지 여부는 수행중인 작업에 따라 크게 달라집니다.

지금, 나는 하고 이 특정 경우에 속도가 이러한 차이를보고있는 것을 놀라게하지만 내가 DMD가 향상으로 개선 될 전망 것이라고 물건의 일종이다. gdc를 사용하면 더 나은 결과를 얻을 수 있으며 gcc 기반이기 때문에 백엔드가 아닌 언어 자체를 더 자세히 비교할 수 있습니다. 그러나 dmd가 생성하는 코드의 속도를 높이기 위해 할 수있는 일이 많이 있다면 놀라지 않을 것입니다. 나는이 시점에서 gcc가 dmd보다 성숙하다는 질문이 많이 없다고 생각합니다. 그리고 코드 최적화는 코드 성숙의 주요 결과 중 하나입니다.

궁극적으로 중요한 것은 특정 응용 프로그램에서 dmd가 얼마나 잘 수행되는지이지만 C ++과 D가 일반적으로 얼마나 잘 비교되는지 아는 것이 분명하다는 데 동의합니다. 이론적으로는 거의 동일해야하지만 실제로 구현에 달려 있습니다. 그러나 현재 두 제품이 얼마나 잘 비교되는지 테스트하려면 종합적인 벤치 마크 세트가 필요하다고 생각합니다.


4
예, 어느 언어에서나 입력 / 출력이 현저히 빨라지거나 어느 언어에서나 순수 수학이 훨씬 빠르더라도 놀라 울 것입니다. 그러나 문자열 연산, 메모리 관리 및 기타 몇 가지로 쉽게 하나의 언어가 빛날 수 있습니다.
Max Lybbert

1
C ++ iostream보다 더 빠르게 (빠르게) 수행하는 것이 쉽습니다. 그러나 이는 주로 라이브러리 구현 문제입니다 (가장 인기있는 공급 업체의 알려진 모든 버전에서).
Ben Voigt

4

C 코드를 D로 작성할 수 있습니다. 빠를수록 많은 것들에 달려 있습니다.

  • 사용하는 컴파일러
  • 사용하는 기능
  • 얼마나 적극적으로 최적화

첫 번째 차이점은 불공평합니다. 두 번째 차이점은 C ++에 무거운 기능이 적기 때문에 이점이 있습니다. 세 번째는 재미있는 것입니다. 일반적으로 이해하기 쉽기 때문에 어떤 방식으로 D 코드를 최적화하는 것이 더 쉽습니다. 또한 장황하고 반복적이지만 빠른 코드와 같은 것들을 더 짧은 형태로 작성할 수 있도록 대규모 생성 프로그램을 수행 할 수 있습니다.


3

구현 품질 문제인 것 같습니다. 예를 들어, 테스트 한 내용은 다음과 같습니다.

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

으로 ManualInline정의 I 28 초 얻을 수 있지만, 컴파일러는 심지어 내가 그것해야 취소 생각이 간단한 함수를 인라인하지 않습니다 그래서 내가 (32)를 얻을 수없는.

(내 명령 줄은 dmd -O -noboundscheck -inline -release ...입니다.)


1
C ++ 타이밍과 비교하지 않으면 타이밍이 의미가 없습니다.
감속 캐비어

3
@Daniel : 당신은 요점을 놓치고 있습니다. D 최적화를 따로 따로 설명하는 것이 었습니다. 즉, "컴파일러는이 간단한 함수를 인라인하지도 않습니다. 분명해야한다고 생각합니다." 첫 번째 문장 에서 분명히 언급했듯이 "구현 품질 문제인 것 같습니다." 라고 C ++과 비교하려고합니다 .
GManNickG

아 사실, 미안 :). 또한 DMD 컴파일러는 루프를 전혀 벡터화하지 않습니다.
감속 캐비어
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.