C có chậm hơn Fortran trong loạt bắn định mức phổ (sử dụng gcc, intel và các trình biên dịch khác) không?


13

Kết luận ở đây:

Trình biên dịch Fortran thực sự tốt hơn bao nhiêu?

là gfortran và gcc nhanh như mã đơn giản. Vì vậy, tôi muốn thử một cái gì đó phức tạp hơn. Tôi lấy ví dụ về tiêu chuẩn loạt đá luân lưu. Trước tiên, tôi xác định trước ma trận 2D A (:, :), và sau đó tính toán định mức. (Tôi nghĩ rằng giải pháp này không được phép trong loạt đá luân lưu.) Tôi đã triển khai phiên bản Fortran và C. Đây là mã:

https://github.com/certik/spectral_norm

Các phiên bản gfortran nhanh nhất là Spectral_norm2.f90 và Spectral_norm6.f90 (một phiên bản sử dụng matmul và dot_product tích hợp của Fortran, hai chức năng này thực hiện hai chức năng này trong mã - không có sự khác biệt về tốc độ). Mã C / C ++ nhanh nhất mà tôi có thể viết là Spectral_norm7.cpp. Thời gian kể từ phiên bản git 457d9d9 trên máy tính xách tay của tôi là:

$ time ./spectral_norm6 5500
1.274224153

real    0m2.675s
user    0m2.520s
sys 0m0.132s


$ time ./spectral_norm7 5500
1.274224153

real    0m2.871s
user    0m2.724s
sys 0m0.124s

Vì vậy, phiên bản của gfortran nhanh hơn một chút. Tại sao vậy? Nếu bạn gửi yêu cầu kéo với triển khai C nhanh hơn (hoặc chỉ dán mã), tôi sẽ cập nhật kho lưu trữ.

Trong Fortran tôi chuyển một mảng 2D xung quanh, trong khi ở CI sử dụng mảng 1D. Hãy sử dụng một mảng 2D hoặc bất kỳ cách nào khác mà bạn thấy phù hợp.

Đối với trình biên dịch, hãy so sánh gcc với gfortran, icc vs ifort, v.v. (Không giống như trang bắn súng, so sánh ifort vs gcc.)

Cập nhật : sử dụng phiên bản 179dae2, giúp cải thiện matmul3 () trong phiên bản C của tôi, giờ đây chúng nhanh như sau:

$ time ./spectral_norm6 5500
1.274224153

real    0m2.669s
user    0m2.500s
sys 0m0.144s

$ time ./spectral_norm7 5500
1.274224153

real    0m2.665s
user    0m2.472s
sys 0m0.168s

Phiên bản véc tơ của Pedro dưới đây nhanh hơn:

$ time ./spectral_norm8 5500
1.274224153

real    0m2.523s
user    0m2.336s
sys 0m0.156s

Cuối cùng, như các báo cáo laxxy dưới đây cho các trình biên dịch Intel, dường như không có sự khác biệt lớn nào ở đó và ngay cả mã Fortran đơn giản nhất (Spectral_norm1) cũng thuộc loại nhanh nhất.


5
Tôi không ở bất cứ nơi nào gần trình biên dịch ngay bây giờ, nhưng hãy xem xét thêm từ khóa hạn chế vào mảng của bạn. Bí danh của con trỏ thường là sự khác biệt giữa các lệnh gọi hàm Fortran và C trên mảng. Ngoài ra, Fortran lưu trữ bộ nhớ theo thứ tự chính cột và C trong hàng chính.
moyner

1
-1 Phần thân của câu hỏi này nói về việc triển khai, nhưng tiêu đề hỏi ngôn ngữ nào nhanh hơn? Làm thế nào một ngôn ngữ có thể có một thuộc tính của tốc độ? Bạn nên chỉnh sửa tiêu đề câu hỏi để nó phản ánh cơ thể của câu hỏi.
milancurcic

@ IRO-bot, tôi đã sửa nó. Hãy cho tôi biết nếu nó có vẻ ổn để bạn biết.
Ondřej Čertík

1
Trên thực tế, kết luận về "Trình biên dịch Fortran thực sự tốt hơn bao nhiêu?" không hoàn toàn chính xác trong chủ đề đó. Tôi đã thử điểm chuẩn trên một trình biên dịch Cray với trình biên dịch GCC, PGI, CRAY và Intel và với 3 trình biên dịch, Fortran nhanh hơn C (b / w 5-40%). Trình biên dịch Cray tạo ra mã Fortran / C nhanh nhất nhưng mã Fortran nhanh hơn 40%. Tôi sẽ đăng kết quả chi tiết khi tôi có thời gian. Btw bất cứ ai có quyền truy cập vào máy Cray đều có thể xác minh điểm chuẩn. Đây là một nền tảng tốt vì 4-5 trình biên dịch có sẵn và các cờ có liên quan được tự động tham gia bởi trình bao bọc ftn / cc.
stali

cũng đã kiểm tra với pgf95 / pgcc (11.10) trên hệ thống Opteron: # 1 và # 2 là nhanh nhất (nhanh hơn ifort ~ 20%), sau đó # 6, # 8, # 7 (theo thứ tự đó). pgf95 nhanh hơn ifort cho tất cả các mã fortran của bạn và icpc nhanh hơn pgcpp cho tất cả C - Tôi nên đề cập rằng đối với công cụ của tôi, tôi thường tìm thấy ifort nhanh hơn, ngay cả trên cùng hệ thống AMD.
laxxy

Câu trả lời:


12

Trước hết, cảm ơn bạn đã đăng câu hỏi / thử thách này! Từ chối trách nhiệm, tôi là một lập trình viên C bản địa có một số kinh nghiệm về Fortran và cảm thấy thoải mái nhất khi ở nhà C, vì vậy, tôi sẽ chỉ tập trung vào việc cải thiện phiên bản C. Tôi cũng mời tất cả các hack của Fortran đi!

Chỉ để nhắc nhở những người mới về những gì này là về: Những tiền đề cơ bản trong này chủ đề là gcc / fortran và icc / ifort nên, kể từ khi họ có cùng một back-đầu tương ứng, sản xuất mã tương đương cho cùng một chương trình (ngữ nghĩa giống hệt nhau), không phân biệt của nó ở C hoặc Fortran. Chất lượng của kết quả chỉ phụ thuộc vào chất lượng của việc thực hiện tương ứng.

Tôi đã chơi xung quanh với mã một chút và trên máy tính của tôi (ThinkPad 201x, Intel Core i5 M560, 2.67 GHz), sử dụng gcc4.6.1 và các cờ trình biên dịch sau:

GCCFLAGS= -O3 -g -Wall -msse2 -march=native -funroll-loops -ffast-math -fomit-frame-pointer -fstrict-aliasing

Tôi cũng đã tiếp tục và viết một phiên bản ngôn ngữ C được mã hóa bằng SIMD của mã C ++ , spectral_norm_vec.c:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

/* Define the generic vector type macro. */  
#define vector(elcount, type)  __attribute__((vector_size((elcount)*sizeof(type)))) type

double Ac(int i, int j)
{
    return 1.0 / ((i+j) * (i+j+1)/2 + i+1);
}

double dot_product2(int n, double u[], double v[])
{
    double w;
    int i;
    union {
        vector(2,double) v;
        double d[2];
        } *vu = u, *vv = v, acc[2];

    /* Init some stuff. */
    acc[0].d[0] = 0.0; acc[0].d[1] = 0.0;
    acc[1].d[0] = 0.0; acc[1].d[1] = 0.0;

    /* Take in chunks of two by two doubles. */
    for ( i = 0 ; i < (n/2 & ~1) ; i += 2 ) {
        acc[0].v += vu[i].v * vv[i].v;
        acc[1].v += vu[i+1].v * vv[i+1].v;
        }
    w = acc[0].d[0] + acc[0].d[1] + acc[1].d[0] + acc[1].d[1];

    /* Catch leftovers (if any) */
    for ( i = n & ~3 ; i < n ; i++ )
        w += u[i] * v[i];

    return w;

}

void matmul2(int n, double v[], double A[], double u[])
{
    int i, j;
    union {
        vector(2,double) v;
        double d[2];
        } *vu = u, *vA, vi;

    bzero( u , sizeof(double) * n );

    for (i = 0; i < n; i++) {
        vi.d[0] = v[i];
        vi.d[1] = v[i];
        vA = &A[i*n];
        for ( j = 0 ; j < (n/2 & ~1) ; j += 2 ) {
            vu[j].v += vA[j].v * vi.v;
            vu[j+1].v += vA[j+1].v * vi.v;
            }
        for ( j = n & ~3 ; j < n ; j++ )
            u[j] += A[i*n+j] * v[i];
        }

}


void matmul3(int n, double A[], double v[], double u[])
{
    int i;

    for (i = 0; i < n; i++)
        u[i] = dot_product2( n , &A[i*n] , v );

}

void AvA(int n, double A[], double v[], double u[])
{
    double tmp[n] __attribute__ ((aligned (16)));
    matmul3(n, A, v, tmp);
    matmul2(n, tmp, A, u);
}


double spectral_game(int n)
{
    double *A;
    double u[n] __attribute__ ((aligned (16)));
    double v[n] __attribute__ ((aligned (16)));
    int i, j;

    /* Aligned allocation. */
    /* A = (double *)malloc(n*n*sizeof(double)); */
    if ( posix_memalign( (void **)&A , 4*sizeof(double) , sizeof(double) * n * n ) != 0 ) {
        printf( "spectral_game:%i: call to posix_memalign failed.\n" , __LINE__ );
        abort();
        }


    for (i = 0; i < n; i++) {
        for (j = 0; j < n; j++) {
            A[i*n+j] = Ac(i, j);
        }
    }


    for (i = 0; i < n; i++) {
        u[i] = 1.0;
    }
    for (i = 0; i < 10; i++) {
        AvA(n, A, u, v);
        AvA(n, A, v, u);
    }
    free(A);
    return sqrt(dot_product2(n, u, v) / dot_product2(n, v, v));
}

int main(int argc, char *argv[]) {
    int i, N = ((argc >= 2) ? atoi(argv[1]) : 2000);
    for ( i = 0 ; i < 10 ; i++ )
        printf("%.9f\n", spectral_game(N));
    return 0;
}

Tất cả ba phiên bản được biên dịch với cùng một cờ và cùng một gccphiên bản. Lưu ý rằng tôi đã gói lệnh gọi hàm chính trong một vòng lặp từ 0..9 để có được thời gian chính xác hơn.

$ time ./spectral_norm6 5500
1.274224153
...
real    0m22.682s
user    0m21.113s
sys 0m1.500s

$ time ./spectral_norm7 5500
1.274224153
...
real    0m21.596s
user    0m20.373s
sys 0m1.132s

$ time ./spectral_norm_vec 5500
1.274224153
...
real    0m21.336s
user    0m19.821s
sys 0m1.444s

Vì vậy, với các cờ biên dịch "tốt hơn", phiên bản C ++ thực hiện tốt hơn phiên bản Fortran và các vòng lặp được mã hóa bằng tay chỉ cung cấp một cải tiến nhỏ. Nhìn nhanh vào trình biên dịch cho phiên bản C ++ cho thấy các vòng lặp chính cũng đã được vector hóa, mặc dù không được kiểm soát mạnh mẽ hơn.

Tôi cũng đã xem xét trình biên dịch được tạo bởi gfortranvà đây là một bất ngờ lớn: không có vector hóa. Tôi cho rằng thực tế là nó chỉ chậm hơn một chút đối với vấn đề bị giới hạn băng thông, ít nhất là trên kiến ​​trúc của tôi. Đối với mỗi phép nhân ma trận, 230 MB dữ liệu được duyệt qua, điều này khá nhiều thay đổi tất cả các cấp độ của bộ đệm. Nếu bạn sử dụng giá trị đầu vào nhỏ hơn, vd100 sự khác biệt về hiệu suất sẽ tăng đáng kể.

Như một lưu ý phụ, thay vì ám ảnh về vector hóa, căn chỉnh và cờ trình biên dịch, tối ưu hóa rõ ràng nhất sẽ là tính toán một vài lần lặp đầu tiên trong số học chính xác đơn, cho đến khi chúng ta có ~ 8 chữ số của kết quả. Các hướng dẫn chính xác đơn không chỉ nhanh hơn mà lượng bộ nhớ phải di chuyển cũng giảm đi một nửa.


Cảm ơn rất nhiều vì thời gian của bạn! Tôi đã hy vọng bạn sẽ trả lời. :) Vì vậy, trước tiên tôi đã cập nhật Makefile để sử dụng cờ của bạn. Sau đó, tôi đặt mã C của bạn là Spectral_norm8.c và đã cập nhật README. Tôi đã cập nhật thời gian trên máy của mình ( github.com/certik/spectral_norm/wiki/Timings ) và như bạn có thể thấy, cờ trình biên dịch không làm cho phiên bản C nhanh hơn trên máy của tôi (tức là gfortran vẫn thắng), nhưng SIMD của bạn phiên bản nhịp đập gfortran.
Ondřej Čertík

@ OndřejČertík: Chỉ cần ra khỏi tò mò, những gì phiên bản của gcc/ gfortranbạn đang sử dụng? Trong các chủ đề trước, các phiên bản khác nhau đã cho kết quả khác nhau đáng kể.
Pedro

Tôi sử dụng 4.6.1-9ubfox3. Bạn có quyền truy cập vào trình biên dịch intel? Kinh nghiệm của tôi với gfortran là đôi khi nó không (chưa) tạo ra mã tối ưu. IFort thường làm.
Ondřej Čertík

1
@ OndřejČertík: Bây giờ kết quả có ý nghĩa hơn! Tôi đã bỏ qua rằng matmul2trong phiên bản Fortran tương đương về mặt ngữ nghĩa với matmul3phiên bản C của tôi. Hai phiên bản thực sự giống nhau và do đó gcc/ gfortran nên tạo ra kết quả giống nhau cho cả hai, ví dụ: không có giao diện / ngôn ngữ nào tốt hơn phiên bản kia trong trường hợp này. gccchỉ có lợi thế là chúng ta có thể khai thác các hướng dẫn véc tơ mà chúng ta nên chọn.
Pedro

1
@ cjordan1: Tôi đã chọn sử dụng vector_sizethuộc tính để làm cho mã độc lập với nền tảng mã, tức là sử dụng cú pháp này, gcccó thể tạo mã vector cho các nền tảng khác, ví dụ như sử dụng AltiVec trên kiến ​​trúc Power của IBM.
Pedro

7

Câu trả lời của user389 đã bị xóa nhưng hãy để tôi nói rằng tôi chắc chắn trong trại của anh ấy: Tôi không thấy những gì chúng ta học được bằng cách so sánh điểm chuẩn vi mô trong các ngôn ngữ khác nhau. Tôi không ngạc nhiên lắm khi C và Fortran có được hiệu suất tương tự trên điểm chuẩn này với mức độ ngắn của nó. Nhưng điểm chuẩn cũng nhàm chán vì nó có thể dễ dàng được viết bằng cả hai ngôn ngữ trong vài chục dòng. Từ quan điểm phần mềm, đó không phải là trường hợp đại diện: chúng ta nên quan tâm đến phần mềm có 10.000 hoặc 100.000 dòng mã và cách trình biên dịch thực hiện trên đó. Tất nhiên, ở quy mô đó, người ta sẽ nhanh chóng tìm ra những thứ khác: ngôn ngữ A yêu cầu 10.000 dòng trong khi ngôn ngữ B yêu cầu 50.000. Hoặc cách khác, tùy thuộc vào những gì bạn muốn làm. Và đột nhiên nó '

Nói cách khác, với tôi không có vấn đề gì với tôi, có lẽ ứng dụng của tôi có thể nhanh hơn 50% nếu tôi phát triển nó trong Fortran 77 nếu thay vào đó tôi sẽ chỉ mất 1 tháng để chạy nó một cách chính xác trong khi tôi phải mất 3 tháng trong F77. Vấn đề với câu hỏi ở đây là nó tập trung vào một khía cạnh (các hạt nhân riêng lẻ) không liên quan trong thực tế theo quan điểm của tôi.


Đã đồng ý. Đối với những gì nó có giá trị, ngoài các chỉnh sửa rất, rất nhỏ (-3 ký tự, +9 ký tự), tôi đồng ý với tình cảm chính của câu trả lời của anh ấy. Theo như tôi biết, trình biên dịch C ++ / C / Fortran chỉ tranh luận khi người ta sử dụng hết mọi con đường có thể khác để nâng cao hiệu suất, đó là lý do tại sao, đối với 99,9% mọi người, những so sánh này không thành vấn đề. Tôi không thấy cuộc thảo luận đặc biệt sáng tỏ, nhưng tôi biết ít nhất một người trên trang có thể chứng thực việc chọn Fortran thay vì C và C ++ vì lý do hiệu suất, đó là lý do tại sao tôi không thể nói nó hoàn toàn vô dụng.
Geoff Oxberry

4
Tôi đồng ý với quan điểm chính của bạn, nhưng tôi vẫn nghĩ rằng cuộc thảo luận này rất hữu ích vì có được một số người ra có những người vẫn bằng cách nào đó tin rằng có một số kỳ diệu mà làm cho một ngôn ngữ "nhanh" hơn người kia, mặc dù việc sử dụng các trình biên dịch giống hệt nhau phụ trợ. Tôi đóng góp cho những cuộc tranh luận này chủ yếu để cố gắng xua tan huyền thoại này. Đối với phương pháp luận, không có "trường hợp đại diện", và theo tôi, lấy một cái gì đó đơn giản như bội số ma trận là một điều tốt, vì nó cung cấp cho trình biên dịch đủ không gian để hiển thị những gì họ có thể làm hoặc không.
Pedro

@GeoffOxberry: Chắc chắn, bạn sẽ luôn tìm thấy những người sử dụng một ngôn ngữ thay vì ngôn ngữ khác vì những lý do rõ ràng và ít rõ ràng hơn. Tuy nhiên, câu hỏi của tôi sẽ là Fortran sẽ nhanh đến mức nào nếu người ta sử dụng các cấu trúc dữ liệu xuất hiện trong một mạng lưới phần tử hữu hạn thích ứng, không cấu trúc. Bên cạnh thực tế là điều này sẽ rất khó thực hiện trong Fortran (tất cả những người thực hiện điều này trong C ++ đều sử dụng STL trong suốt), liệu Fortran có thực sự nhanh hơn đối với loại mã không có vòng lặp chặt chẽ, nhiều lỗi, nhiều if?
Wolfgang Bangerth

@WolfgangBangerth: Giống như tôi đã nói trong bình luận đầu tiên của mình, tôi đồng ý với bạn và với người dùng389 (Jonathan Dursi), vì vậy hỏi tôi câu hỏi đó là vô nghĩa. Điều đó nói rằng, tôi sẽ mời những ai không tin rằng sự lựa chọn của ngôn ngữ (trong C ++ / C / Fortran) là rất quan trọng để thực hiện trong ứng dụng của họ để trả lời câu hỏi của bạn. Đáng buồn thay, tôi nghi ngờ loại tranh luận này có thể có cho các phiên bản trình biên dịch.
Geoff Oxberry

@GeoffOxberry: Vâng, và tôi rõ ràng không có nghĩa là bạn cần trả lời câu hỏi đó.
Wolfgang Bangerth

5

Hóa ra tôi có thể viết mã Python (sử dụng numpy để thực hiện các thao tác BLAS) nhanh hơn mã Fortran được biên dịch bằng trình biên dịch gfortran của hệ thống.

$ gfortran -o sn6a sn6a.f90 -O3 -march=native
    
    $ ./sn6a 5500
1.274224153
1.274224153
1.274224153
   1.9640001      sec per iteration

$ python ./foo1.py
1.27422415279
1.27422415279
1.27422415279
1.20618661245 sec per iteration

foo1.py:

import numpy
import scipy.linalg
import timeit

def specNormDot(A,n):
    u = numpy.ones(n)
    v = numpy.zeros(n)

    for i in xrange(10):
        v  = numpy.dot(numpy.dot(A,u),A)
        u  = numpy.dot(numpy.dot(A,v),A)

    print numpy.sqrt(numpy.vdot(u,v)/numpy.vdot(v,v))

    return

n = 5500

ii, jj = numpy.meshgrid(numpy.arange(1,n+1), numpy.arange(1,n+1))
A  = (1./((ii+jj-2.)*(ii+jj-1.)/2. + ii))

t = timeit.Timer("specNormDot(A,n)", "from __main__ import specNormDot,A,n")
ntries = 3

print t.timeit(ntries)/ntries, "sec per iteration"

và sn6a.f90, một Spectral_norm6.f90 được sửa đổi rất nhẹ:

program spectral_norm6
! This uses spectral_norm3 as a starting point, but does not use the
! Fortrans
! builtin matmul and dotproduct (to make sure it does not call some
! optimized
! BLAS behind the scene).
implicit none

integer, parameter :: dp = kind(0d0)
real(dp), allocatable :: A(:, :), u(:), v(:)
integer :: i, j, n
character(len=6) :: argv
integer :: calc, iter
integer, parameter :: niters=3

call get_command_argument(1, argv)
read(argv, *) n

allocate(u(n), v(n), A(n, n))
do j = 1, n
    do i = 1, n
        A(i, j) = Ac(i, j)
    end do
end do

call tick(calc)

do iter=1,niters
    u = 1
    do i = 1, 10
        v = AvA(A, u)
        u = AvA(A, v)
    end do

    write(*, "(f0.9)") sqrt(dot_product2(u, v) / dot_product2(v, v))
enddo

print *, tock(calc)/niters, ' sec per iteration'

contains

pure real(dp) function Ac(i, j) result(r)
integer, intent(in) :: i, j
r = 1._dp / ((i+j-2) * (i+j-1)/2 + i)
end function

pure function matmul2(v, A) result(u)
! Calculates u = matmul(v, A), but much faster (in gfortran)
real(dp), intent(in) :: v(:), A(:, :)
real(dp) :: u(size(v))
integer :: i
do i = 1, size(v)
    u(i) = dot_product2(A(:, i), v)
end do
end function

pure real(dp) function dot_product2(u, v) result(w)
! Calculates w = dot_product(u, v)
real(dp), intent(in) :: u(:), v(:)
integer :: i
w = 0
do i = 1, size(u)
    w = w + u(i)*v(i)
end do
end function

pure function matmul3(A, v) result(u)
! Calculates u = matmul(v, A), but much faster (in gfortran)
real(dp), intent(in) :: v(:), A(:, :)
real(dp) :: u(size(v))
integer :: i, j
u = 0
do j = 1, size(v)
    do i = 1, size(v)
        u(i) = u(i) + A(i, j)*v(j)
    end do
end do
end function

pure function AvA(A, v) result(u)
! Calculates u = matmul2(matmul3(A, v), A)
! In gfortran, this function is sligthly faster than calling
! matmul2(matmul3(A, v), A) directly.
real(dp), intent(in) :: v(:), A(:, :)
real(dp) :: u(size(v))
u = matmul2(matmul3(A, v), A)
end function

subroutine tick(t)
    integer, intent(OUT) :: t

    call system_clock(t)
end subroutine tick

! returns time in seconds from now to time described by t 
real function tock(t)
    integer, intent(in) :: t
    integer :: now, clock_rate

    call system_clock(now,clock_rate)

    tock = real(now - t)/real(clock_rate)
end function tock
end program

1
Lưỡi trong má, tôi đoán?
Robert Harvey

-1 vì không trả lời câu hỏi, nhưng tôi nghĩ bạn đã biết điều đó rồi.
Pedro

Thật thú vị, bạn đã sử dụng phiên bản gfortran nào và bạn đã kiểm tra mã C có sẵn trong kho lưu trữ với cờ của Pedro chưa?
Aron Ahmadia

1
Trên thực tế, tôi nghĩ bây giờ rõ ràng hơn, giả sử bạn không bị mỉa mai.
Robert Harvey

1
Vì bài đăng này, và không có câu hỏi hay bài đăng nào khác, đang được Aron chỉnh sửa theo cách phù hợp hơn với ý kiến ​​của anh ấy, mặc dù toàn bộ quan điểm của tôi là tất cả các bài đăng nên được dán nhãn chính xác như vậy "những kết quả này là vô nghĩa" Hãy cẩn thận, tôi chỉ cần xóa nó.

3

Đã kiểm tra điều này với trình biên dịch Intel. Với 11.1 (-fast, ngụ ý -O3) và với 12.0 (-O2), những cái nhanh nhất là 1,2,6,7 và 8 (tức là mã Fortran và C "đơn giản nhất" và C được vector hóa bằng tay) - những thứ này không thể phân biệt được với nhau ở mức ~ 1,5 giây. Các thử nghiệm 3 và 5 (với mảng là một hàm) chậm hơn; # 4 Tôi không thể biên dịch.

Đáng chú ý, nếu biên dịch với 12.0 và -O3, thay vì -O2, mã Fortran 2 ("đơn giản nhất") đầu tiên làm chậm A RẤT (1,5 -> 10,2 giây) - đây không phải là lần đầu tiên tôi thấy một cái gì đó như Điều này, nhưng đây có thể là ví dụ ấn tượng nhất. Nếu đây vẫn là trường hợp trong bản phát hành hiện tại, tôi nghĩ sẽ là một ý tưởng tốt để báo cáo với Intel, vì rõ ràng có điều gì đó rất sai với tối ưu hóa của họ trong trường hợp khá đơn giản này.

Mặt khác, tôi đồng ý với Jonathan rằng đây không phải là một bài tập đặc biệt nhiều thông tin :)


Cảm ơn đã kiểm tra nó! Điều này khẳng định kinh nghiệm của tôi, rằng gfortran vẫn chưa hoàn toàn trưởng thành, bởi vì một số lý do, hoạt động matmul chậm. Vì vậy, kết luận cho tôi chỉ đơn giản là sử dụng matmul và giữ mã Fortran đơn giản.
Ondřej Čertík

Mặt khác, tôi nghĩ gfortran có tùy chọn dòng lệnh để tự động chuyển đổi tất cả các cuộc gọi matmul () thành các cuộc gọi BLAS (có thể cả dot_product (), không chắc chắn). Không bao giờ thử nó mặc dù.
laxxy
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.