BLAS는 어떻게 이러한 극한의 성능을 얻습니까?


108

호기심으로 나는 BLAS 구현과 비교하여 내 자신의 행렬 곱셈 함수를 벤치마킹하기로 결정했습니다. 결과에 가장 놀란 것은 없었습니다.

사용자 정의 구현, 1000x1000 행렬 곱셈의 10 회 시행 :

Took: 15.76542 seconds.

BLAS 구현, 1000x1000 행렬 곱셈의 10 회 시행 :

Took: 1.32432 seconds.

이것은 단 정밀도 부동 소수점 숫자를 사용합니다.

내 구현 :

template<class ValT>
void mmult(const ValT* A, int ADim1, int ADim2, const ValT* B, int BDim1, int BDim2, ValT* C)
{
    if ( ADim2!=BDim1 )
        throw std::runtime_error("Error sizes off");

    memset((void*)C,0,sizeof(ValT)*ADim1*BDim2);
    int cc2,cc1,cr1;
    for ( cc2=0 ; cc2<BDim2 ; ++cc2 )
        for ( cc1=0 ; cc1<ADim2 ; ++cc1 )
            for ( cr1=0 ; cr1<ADim1 ; ++cr1 )
                C[cc2*ADim2+cr1] += A[cc1*ADim1+cr1]*B[cc2*BDim1+cc1];
}

두 가지 질문이 있습니다.

  1. 행렬-행렬 곱셈에서 nxm * mxn에는 n * n * m 곱셈이 필요하므로 1000 ^ 3 또는 1e9 연산을 초과하는 경우에는 곱셈이 필요합니다. BLAS 용 2.6Ghz 프로세서에서 어떻게 1.32 초 안에 10 * 1e9 작업을 수행 할 수 있습니까? 다중 작업이 단일 작업이고 다른 작업이 수행되지 않은 경우에도 4 초 정도 걸립니다.
  2. 내 구현이 왜 그렇게 느린가요?

17
BLAS는 해당 분야의 전문가에 의해 한 쪽과 아래쪽으로 최적화되었습니다. 칩의 SIMD 부동 소수점 단위를 활용하고 캐싱 동작을 개선하기 위해 많은 트릭을 수행한다고 가정합니다.
dmckee --- ex-moderator kitten

3
그래도 1.3 초 만에 2.63E9 사이클 / 초 프로세서에서 1E10 작업을 수행하는 방법은 무엇입니까?
DeusAduro

9
다중 실행 단위, 파이프 라이닝 및 단일 명령어 다중 데이터 ((SIMD)는 동시에 두 개 이상의 피연산자 쌍에 대해 동일한 연산을 수행함을 의미 함). 일부 컴파일러는 일반적인 칩에서 SIMD 단위를 대상으로 할 수 있지만 항상 명시 적으로 켜야하며 모든 작동 방식을 아는 것이 도움이됩니다 ( en.wikipedia.org/wiki/SIMD ). 캐시 미스에 대한 보장은 거의 확실히 어려운 부분입니다.
dmckee --- 전 중재자 새끼 고양이

13
가정이 잘못되었습니다. 알려진 더 나은 알고리즘이 있습니다. Wikipedia를 참조하십시오.
MSalters

2
@DeusAduro : Eigen과 경쟁 할 수있는 매트릭스 매트릭스 제품을 작성하는 방법에 대한 제 답변에서 ? 캐시 효율적인 매트릭스 매트릭스 제품을 구현하는 방법에 대한 작은 예제를 게시했습니다.
Michael Lehn

답변:


141

좋은 출발점은 Robert A. van de Geijn과 Enrique S. Quintana-Ortí 의 훌륭한 책 The Science of Programming Matrix Computations 입니다. 그들은 무료 다운로드 버전을 제공합니다.

BLAS는 세 가지 수준으로 나뉩니다.

  • 수준 1은 벡터에서만 작동하는 선형 대수 함수 집합을 정의합니다. 이러한 함수는 벡터화 (예 : SSE 사용)의 이점을 얻습니다.

  • 레벨 2 함수는 행렬-벡터 연산입니다 (예 : 일부 행렬-벡터 곱). 이러한 기능은 Level1 기능으로 구현할 수 있습니다. 그러나 공유 메모리와 함께 일부 다중 프로세서 아키텍처를 사용하는 전용 구현을 제공 할 수 있다면이 함수의 성능을 높일 수 있습니다.

  • 레벨 3 함수는 행렬-행렬 곱과 같은 연산입니다. 다시 레벨 2 기능으로 구현할 수 있습니다. 그러나 Level3 함수는 O (N ^ 2) 데이터에 대해 O (N ^ 3) 연산을 수행합니다. 따라서 플랫폼에 캐시 계층이있는 경우 캐시 최적화 / 캐시 친화적 인 전용 구현을 제공하면 성능을 높일 수 있습니다 . 이것은 책에 잘 설명되어 있습니다. Level3 기능의 주요 향상은 캐시 최적화에서 비롯됩니다. 이 향상은 병렬 처리 및 기타 하드웨어 최적화로 인한 두 번째 향상을 훨씬 능가합니다.

그건 그렇고, 고성능 BLAS 구현의 대부분 (또는 전부)은 Fortran에서 구현되지 않습니다. ATLAS는 C로 구현됩니다. GotoBLAS / OpenBLAS는 C로 구현되고 성능에 중요한 부분은 Assembler에서 구현됩니다. BLAS의 참조 구현 만 Fortran에서 구현됩니다. 그러나 이러한 모든 BLAS 구현은 LAPACK에 연결할 수있는 Fortran 인터페이스를 제공합니다 (LAPACK은 BLAS에서 모든 성능을 얻음).

최적화 된 컴파일러는이 점에서 사소한 역할을합니다 (GotoBLAS / OpenBLAS의 경우 컴파일러는 전혀 중요하지 않습니다).

IMHO no BLAS 구현은 Coppersmith–Winograd 알고리즘 또는 Strassen 알고리즘과 같은 알고리즘을 사용합니다. 나는 그 이유에 대해 정확히 확신하지 못하지만 이것은 내 추측입니다.

  • 이러한 알고리즘의 캐시 최적화 구현을 제공하는 것이 불가능할 수도 있습니다 (즉, 이길 것보다 더 많이 느슨해 질 것입니다).
  • 이러한 알고리즘은 수치 적으로 안정적이지 않습니다. BLAS는 LAPACK의 계산 커널이기 때문에 이것이 불가능합니다.

편집 / 업데이트 :

이 주제에 대한 새롭고 획기적인 논문은 BLIS 논문 입니다. 그들은 매우 잘 쓰여졌습니다. "고성능 컴퓨팅을위한 소프트웨어 기초"강의에서 나는 그들의 논문에 따라 매트릭스 매트릭스 제품을 구현했습니다. 사실 저는 매트릭스 매트릭스 제품의 여러 변형을 구현했습니다. 가장 단순한 변형은 전적으로 일반 C로 작성되었으며 450 줄 미만의 코드가 있습니다. 다른 모든 변형은 루프를 최적화 할뿐입니다.

    for (l=0; l<MR*NR; ++l) {
        AB[l] = 0;
    }
    for (l=0; l<kc; ++l) {
        for (j=0; j<NR; ++j) {
            for (i=0; i<MR; ++i) {
                AB[i+j*MR] += A[i]*B[j];
            }
        }
        A += MR;
        B += NR;
    }

매트릭스 매트릭스 제품의 전반적인 성능은 이러한 루프 에만 의존합니다. 약 99.9 %의 시간이 여기에서 소비됩니다. 다른 변형에서는 성능을 향상시키기 위해 내장 함수와 어셈블러 코드를 사용했습니다. 여기에서 모든 변형을 다루는 자습서를 볼 수 있습니다.

ulmBLAS : GEMM (Matrix-Matrix 제품)에 대한 자습서

BLIS 문서와 함께 인텔 MKL과 같은 라이브러리가 이러한 성능을 얻을 수있는 방법을 이해하는 것은 상당히 쉽습니다. 그리고 행 또는 열 주요 스토리지를 사용하는지 여부가 왜 중요하지 않습니다!

최종 벤치 마크는 다음과 같습니다 (프로젝트 ulmBLAS라고 함).

ulmBLAS, BLIS, MKL, openBLAS 및 Eigen에 대한 벤치 마크

다른 편집 / 업데이트 :

또한 선형 방정식 시스템을 푸는 것과 같은 수치 선형 대수 문제에 BLAS를 사용하는 방법에 대한 자습서를 작성했습니다.

고성능 LU 분해

(이 LU 분해는 예를 들어 Matlab에서 선형 방정식 시스템을 해결하는 데 사용됩니다.)

PLASMA 에서와 같이 확장 성이 뛰어난 LU 분해의 병렬 구현을 실현하는 방법을 설명하고 시연하기 위해 자습서를 확장 할 시간을 찾고 싶습니다 .

자, 시작합니다 : 캐시 최적화 병렬 LU 분해 코딩

추신 : 또한 uBLAS의 성능을 개선하기위한 몇 가지 실험을했습니다. 실제로 uBLAS의 성능을 높이는 것은 매우 간단합니다 (예, 단어로 재생 :)).

uBLAS에 대한 실험 .

여기에 BLAZE 와 유사한 프로젝트가 있습니다 .

BLAZE에 대한 실험 .


3
"ulmBLAS, BLIS, MKL, openBLAS 및 Eigen에 대한 벤치 마크"에 대한 새 링크 : apfel.mathematik.uni-ulm.de/~lehn/ulmBLAS/#toc3
Ahmed Fasih

- IBM의 ESSL은 쉬트 라쎈 알고리즘의 변형 사용에서 그것은집니다 ibm.com/support/knowledgecenter/en/SSFHY8/essl_welcome.html
벤 - 브레

2
링크의 대부분이 죽었습니다
Aurélien Pierre

TSoPMC의 PDF는 저자의 페이지에서 찾을 수 있습니다. cs.utexas.edu/users/rvdg/tmp/TSoPMC.pdf
Alex Shpilkin

Coppersmith-Winograd 알고리즘은 종이에 좋은 시간 복잡성을 가지고 있지만 Big O 표기법은 매우 큰 상수를 숨기므로 엄청나게 큰 행렬에 대해서만 실행 가능해지기 시작합니다.
DiehardTheTryhard

26

따라서 우선 BLAS는 약 50 개 기능의 인터페이스입니다. 인터페이스의 여러 경쟁 구현이 있습니다.

먼저 나는 거의 관련이없는 것들을 언급 할 것입니다.

  • Fortran과 C는 차이가 없습니다.
  • Strassen과 같은 고급 매트릭스 알고리즘, 구현은 실제로 도움이되지 않으므로 사용하지 않습니다.

대부분의 구현은 각 작업을 다소 분명한 방식으로 작은 차원 행렬 또는 벡터 작업으로 나눕니다. 예를 들어 큰 1000x1000 행렬 곱셈은 일련의 50x50 행렬 곱셈으로 나눌 수 있습니다.

이러한 고정 크기 소형 작업 (커널이라고 함)은 대상의 여러 CPU 기능을 사용하여 CPU 특정 어셈블리 코드로 하드 ​​코딩됩니다.

  • SIMD 스타일 지침
  • 명령어 수준 병렬성
  • 캐시 인식

또한 이러한 커널은 일반적인 맵 축소 디자인 패턴에서 여러 스레드 (CPU 코어)를 사용하여 서로에 대해 병렬로 실행될 수 있습니다.

가장 일반적으로 사용되는 오픈 소스 BLAS 구현 인 ATLAS를 살펴보십시오. 경쟁하는 커널이 많고 ATLAS 라이브러리 빌드 프로세스 중에 경쟁을 실행합니다 (일부는 매개 변수화되기 때문에 동일한 커널이 다른 설정을 가질 수 있음). 다른 구성을 시도한 다음 특정 대상 시스템에 가장 적합한 것을 선택합니다.

(팁 : 그렇기 때문에 ATLAS를 사용하는 경우 특정 머신에 대해 라이브러리를 직접 빌드하고 튜닝 한 다음 미리 빌드 된 머신을 사용하는 것이 좋습니다.)


ATLAS는 더 이상 가장 일반적으로 사용되는 오픈 소스 BLAS 구현이 아닙니다. OpenBLAS (GotoBLAS의 포크)와 ​​BLIS (GotoBLAS의 리팩토링)가 능가했습니다.
Robert van de Geijn

1
@ ulaff.net : 아마도. 이것은 6 년 전에 작성되었습니다. 현재 (물론 인텔에서) 가장 빠른 BLAS 구현은 인텔 MKL이지만 오픈 소스는 아닙니다.
Andrew Tomazos

14

첫째, 사용하는 것보다 행렬 곱셈을위한 더 효율적인 알고리즘이 있습니다.

둘째, CPU는 한 번에 하나 이상의 명령을 수행 할 수 있습니다.

CPU는주기 당 3-4 개의 명령을 실행하고 SIMD 장치를 사용하는 경우 각 명령은 4 개의 부동 소수점 또는 2 개의 double을 처리합니다. (물론 CPU는 일반적으로 사이클 당 하나의 SIMD 명령 만 처리 할 수 ​​있으므로이 수치도 정확하지 않습니다.)

셋째, 코드가 최적이 아닙니다.

  • 원시 포인터를 사용하고 있습니다. 즉, 컴파일러는 별칭이있을 수 있다고 가정해야합니다. 컴파일러에 별칭이 없음을 알리기 위해 지정할 수있는 컴파일러 관련 키워드 또는 플래그가 있습니다. 또는 문제를 처리하는 원시 포인터 이외의 다른 유형을 사용해야합니다.
  • 입력 행렬의 각 행 / 열에 대해 순진한 순회를 수행하여 캐시를 스 래싱하고 있습니다. 다음 블록으로 이동하기 전에 블로킹을 사용하여 CPU 캐시에 맞는 더 작은 매트릭스 블록에서 가능한 한 많은 작업을 수행 할 수 있습니다.
  • 순전히 수치 작업의 경우 Fortran은 거의 타의 추종을 불허하며 C ++는 비슷한 속도를 얻기 위해 많은 동조를 취합니다. 할 수 있고 그것을 시연하는 라이브러리가 몇 개 있지만 (일반적으로 표현식 템플릿을 사용함) 사소한 것도 아니고 그냥 일어나는 것도 아닙니다 .

감사합니다. Justicle의 제안에 따라 올바른 코드 제한을 추가했지만 크게 개선되지 않았으며 블록 단위 아이디어가 마음에 듭니다. 호기심에서 CPU의 캐시 크기를 모른 채 최적의 코드 하나가 어떻게 될까요?
DeusAduro

2
당신은하지 않습니다. 최적의 코드를 얻으려면 CPU의 캐시 크기를 알아야합니다. 물론 이것의 단점은 CPU 제품군에서 최상의 성능을 위해 코드를 효과적으로 하드 코딩한다는 것 입니다.
jalf 2009.08.21

2
적어도 여기의 내부 루프는 스트라이드 부하를 피합니다. 이미 전치중인 하나의 행렬에 대해 작성된 것 같습니다. 이것이 BLAS보다 "단지"한 자릿수 느린 이유입니다! 그러나 네, 캐시 차단이 없기 때문에 여전히 스 래싱 중입니다. 포트란이 많은 도움을 줄 것이라고 확신하십니까? 여기서 얻을 수있는 모든 restrict것은 C / C ++에서와 달리 (앨리어싱 없음)이 기본값이라는 것입니다. (불행히도 ISO C ++에는 restrict키워드가 없으므로 __restrict__이를 확장으로 제공하는 컴파일러 에서 사용해야 합니다).
Peter Cordes

11

BLAS 구현에 대해 구체적으로 알지 못하지만 O (n3) 복잡성보다 더 나은 Matrix Multiplication에 대한 더 효율적인 alogorithms가 있습니다. 잘 아는 사람은 Strassen 알고리즘입니다.


8
Strassen 알고리즘은 다음 두 가지 이유로 숫자에 사용되지 않습니다. 1) 안정적이지 않습니다. 2) 일부 계산을 저장하지만 캐시 계층을 이용할 수있는 대가가 따릅니다. 실제로는 성능이 저하됩니다.
Michael Lehn

4
BLAS 라이브러리 소스 코드에 밀접하게 구축 된 Strassen 알고리즘의 실제 구현을 위해 SC16의 " Strassen Algorithm Reloaded " 라는 최근 간행물이 있습니다. 문제 크기 1000x1000에서도 BLAS보다 높은 성능을 달성합니다.
Jianyu Huang

4

두 번째 질문에 대한 대부분의 주장 (어셈블러, 블록으로 분할 등) (그러나 N ^ 3 알고리즘 미만은 아니지만 실제로 과도하게 개발 됨)이 역할을합니다. 그러나 알고리즘의 느린 속도는 본질적으로 매트릭스 크기와 세 개의 중첩 루프의 불행한 배열로 인해 발생합니다. 행렬이 너무 커서 캐시 메모리에 한 번에 맞지 않습니다. 가능한 한 캐시의 한 행에서 수행되도록 루프를 재 배열 할 수 있습니다. 이렇게하면 캐시 새로 고침이 크게 감소합니다 (BTW를 작은 블록으로 분할하면 아날로그 효과가 있으며 블록에 대한 루프가 비슷하게 배열 된 경우 가장 좋습니다). 정사각형 행렬에 대한 모델 구현은 다음과 같습니다. 내 컴퓨터에서 시간 소비는 표준 구현에 비해 약 1:10이었습니다. 즉, "를 따라 행렬 곱셈을 프로그래밍하지 마십시오.

    void vector(int m, double ** a, double ** b, double ** c) {
      int i, j, k;
      for (i=0; i<m; i++) {
        double * ci = c[i];
        for (k=0; k<m; k++) ci[k] = 0.;
        for (j=0; j<m; j++) {
          double aij = a[i][j];
          double * bj = b[j];
          for (k=0; k<m; k++)  ci[k] += aij*bj[k];
        }
      }
    }

한 가지 더 언급 :이 구현은 모든 것을 BLAS 루틴 cblas_dgemm으로 대체하는 것보다 내 컴퓨터에서 더 좋습니다 (컴퓨터에서 시도해보세요!). 그러나 훨씬 빠른 속도 (1 : 4)는 Fortran 라이브러리의 dgemm_을 직접 호출합니다. 이 루틴은 사실 Fortran이 아니라 어셈블러 코드라고 생각합니다 (라이브러리에 무엇이 있는지, 소스가 없습니다). 내가 아는 한 dgemm_의 래퍼에 불과하기 때문에 cblas_dgemm이 왜 빠르지 않은지 완전히 명확하지 않습니다.


3

이것은 현실적인 속도 향상입니다. C ++ 코드를 통해 SIMD 어셈블러로 수행 할 수있는 작업의 예를 보려면 몇 가지 iPhone 매트릭스 함수 예를 참조하십시오. 이러한 함수 는 C 버전보다 8 배 이상 빠르며 "최적화 된"어셈블리도 아닙니다. 아직 파이프 라이닝이 없습니다. 불필요한 스택 작업입니다.

또한 코드가 " 올바른 제한 "이 아닙니다 . 컴파일러가 C를 수정할 때 A와 B를 수정하지 않는다는 것을 어떻게 알 수 있습니까?


물론 mmult (A ..., A ..., A); 당신은 확실히 예상 된 결과를 얻지 못할 것입니다. 다시 말하지만, BLAS를이기거나 다시 구현하려고하지 않았지만 실제로 얼마나 빠른지 확인했기 때문에 오류 검사는 염두에 두지 않고 기본 기능 만 고려했습니다.
DeusAduro

3
죄송합니다. 제가 말하고자하는 것은 포인터에 "restrict"를 입력하면 훨씬 빠른 코드를 얻을 수 있다는 것입니다. 이는 C를 수정할 때마다 컴파일러가 A와 B를 다시로드 할 필요가 없기 때문에 내부 루프의 속도가 크게 빨라집니다. 나를 믿지 않는다면 분해를 확인하십시오.
Justicle 2009-08-20

@DeusAduro : 이것은 오류 검사가 아닙니다. 컴파일러가 내부 루프에서 B [] 배열에 대한 액세스를 최적화 할 수없는 경우가 있습니다. A 및 C 포인터가 B를 별칭으로 지정하지 않는다는 것을 파악하지 못할 수도 있기 때문입니다. 정렬. 앨리어싱이 있으면 내부 루프가 실행되는 동안 B 배열의 값이 변경 될 수 있습니다. 내부 루프에서 B [] 값에 대한 액세스 권한을 가져 와서 로컬 변수에 넣으면 컴파일러가 B []에 대한 지속적인 액세스를 피할 수 있습니다.
Michael Burr

1
흠, 그래서 먼저 VS 2008에서 '__restrict'키워드를 사용하여 A, B, C에 적용 해 보았습니다. 결과에는 변화가 없었습니다. 그러나 B에 대한 액세스를 가장 안쪽 루프에서 바깥 쪽 루프로 이동하면 시간이 ~ 10 % 향상되었습니다.
DeusAduro

1
죄송합니다. VC에 대해 잘 모르겠지만 GCC를 사용하려면 -fstrict-aliasing. 여기에 "제한"에 대한 더 나은 설명도 있습니다. cellperformance.beyond3d.com/articles/2006/05/…
Justicle

2

MM 곱하기의 원래 코드와 관련하여 대부분의 작업에 대한 메모리 참조가 성능 저하의 주요 원인입니다. 메모리는 캐시보다 100-1000 배 느리게 실행됩니다.

대부분의 속도 향상은 MM 곱하기에서이 트리플 루프 기능에 대한 루프 최적화 기술을 사용하여 발생합니다. 두 가지 주요 루프 최적화 기술이 사용됩니다. 풀기 및 차단. 언 롤링과 관련하여 가장 바깥 쪽 두 개의 루프를 풀고 캐시에서 데이터 재사용을 위해 차단합니다. 외부 루프 언 롤링은 전체 작업 동안 서로 다른 시간에 동일한 데이터에 대한 메모리 참조 수를 줄임으로써 일시적으로 데이터 액세스를 최적화하는 데 도움이됩니다. 특정 번호에서 루프 인덱스를 차단하면 데이터를 캐시에 유지하는 데 도움이됩니다. L2 캐시 또는 L3 캐시를 최적화하도록 선택할 수 있습니다.

https://en.wikipedia.org/wiki/Loop_nest_optimization


-24

여러 이유들로.

첫째, Fortran 컴파일러는 고도로 최적화되어 있으며 언어를 통해 그렇게 할 수 있습니다. C와 C ++는 배열 처리 측면에서 매우 느슨합니다 (예 : 동일한 메모리 영역을 참조하는 포인터의 경우). 즉, 컴파일러는 무엇을해야할지 미리 알 수 없으며 일반 코드를 작성해야합니다. Fortran에서는 케이스가 더 능률화되고 컴파일러는 발생하는 일을 더 잘 제어 할 수 있으므로 더 많이 최적화 할 수 있습니다 (예 : 레지스터 사용).

또 다른 점은 Fortran은 항목을 열 단위로 저장하고 C는 데이터를 행 단위로 저장한다는 것입니다. 나는 당신의 코드를 확인하지 않았지만 당신이 제품을 어떻게 수행하는지 조심하십시오. C에서는 행 방식을 스캔해야합니다. 이렇게하면 연속 메모리를 따라 배열을 스캔하여 캐시 누락을 줄일 수 있습니다. 캐시 미스는 비 효율성의 첫 번째 원인입니다.

셋째, 사용중인 blas 구현에 따라 다릅니다. 일부 구현은 어셈블러로 작성되고 사용중인 특정 프로세서에 맞게 최적화 될 수 있습니다. netlib 버전은 포트란 77로 작성되었습니다.

또한 많은 작업을 수행하고 있으며 대부분은 반복되고 중복됩니다. 인덱스를 얻기위한 모든 곱셈은 성능에 해를 끼칩니다. BLAS에서 이것이 어떻게 수행되는지 실제로는 모르지만 값 비싼 작업을 방지하는 많은 트릭이 있습니다.

예를 들어 다음과 같이 코드를 재 작업 할 수 있습니다.

template<class ValT>
void mmult(const ValT* A, int ADim1, int ADim2, const ValT* B, int BDim1, int BDim2, ValT* C)
{
if ( ADim2!=BDim1 ) throw std::runtime_error("Error sizes off");

memset((void*)C,0,sizeof(ValT)*ADim1*BDim2);
int cc2,cc1,cr1, a1,a2,a3;
for ( cc2=0 ; cc2<BDim2 ; ++cc2 ) {
    a1 = cc2*ADim2;
    a3 = cc2*BDim1
    for ( cc1=0 ; cc1<ADim2 ; ++cc1 ) {
          a2=cc1*ADim1;
          ValT b = B[a3+cc1];
          for ( cr1=0 ; cr1<ADim1 ; ++cr1 ) {
                    C[a1+cr1] += A[a2+cr1]*b;
           }
     }
  }
} 

시도해보세요. 무언가를 구할 것이라고 확신합니다.

# 1 질문에서 이유는 간단한 알고리즘을 사용하면 행렬 곱셈이 O (n ^ 3)로 확장된다는 것입니다. 훨씬 더 잘 확장 되는 알고리즘이 있습니다 .


36
이 대답은 완전히 잘못되었습니다. 죄송합니다. BLAS 구현은 포트란으로 작성되지 않습니다. 성능에 중요한 코드는 어셈블리로 작성되고 요즘 가장 일반적인 코드는 그 위에 C로 작성됩니다. 또한 BLAS는 인터페이스의 일부로 행 / 열 순서를 지정하며 구현은 모든 조합을 처리 할 수 ​​있습니다.
Andrew Tomazos

10
예,이 대답 완전히 틀 렸습니다. 불행히도 그것은 일반적인 말도 안되는 소리로 가득 차 있습니다. 예를 들어 Fortran 때문에 BLAS가 더 빠르다는 주장이 있습니다. 20 (!) 개의 긍정적 인 평가를받는 것은 나쁜 일입니다. 이제이 말도 안되는 것은 Stackoverflow의 인기로 인해 더 퍼졌습니다!
Michael Lehn 2013 년

12
최적화되지 않은 참조 구현을 프로덕션 구현과 혼동하고 있다고 생각합니다. 참조 구현은 라이브러리의 인터페이스와 동작을 지정하기위한 것이며 역사적인 이유로 Fortran으로 작성되었습니다. 프로덕션 용이 아닙니다. 프로덕션에서 사람들은 참조 구현과 동일한 동작을 나타내는 최적화 된 구현을 사용합니다. 나는 ATLAS (옥타브를 뒷받침하는 리눅스 "MATLAB")의 내부를 연구했는데, 내부적으로 C / ASM으로 직접 작성되었음을 확인할 수있다. 상업적 구현도 거의 확실합니다.
Andrew Tomazos 2013-10-05

5
@KyleKanos : 예, 여기 ATLAS의 소스가 있습니다 : sourceforge.net/projects/math-atlas/files/Stable/3.10.1 내가 아는 한 가장 일반적으로 사용되는 오픈 소스 휴대용 BLAS 구현입니다. C / ASM으로 작성되었습니다. Intel과 같은 고성능 CPU 제조업체는 특히 칩에 최적화 된 BLAS 구현을 제공합니다. 나는 인텔 라이브러리의 저수준 부분이 (duuh) x86 어셈블리로 작성된다는 것을 보증하며 중간 수준 부분은 C 또는 C ++로 작성 될 것이라고 확신합니다.
Andrew Tomazos 2013-10-05

9
@KyleKanos : 당신은 혼란 스러워요. Netlib BLAS는 참조 구현입니다. 참조 구현은 최적화 된 구현보다 훨씬 느립니다 ( 성능 비교 참조 ). 누군가가 클러스터에서 netlib BLAS를 사용하고 있다고해서 실제로 netlib 참조 구현을 사용하고 있다는 의미는 아닙니다. 그것은 단지 어리석은 일입니다. netlib blas와 동일한 인터페이스로 lib를 사용하고 있음을 의미합니다.
Andrew Tomazos
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.