Lỗi biên dịch GCC với> 2 GB mã


108

Tôi có một số lượng lớn các chức năng tổng cộng khoảng 2,8 GB mã đối tượng (tiếc là không có cách nào xung quanh, máy tính khoa học ...)

Khi tôi cố gắng liên kết chúng, tôi nhận được relocation truncated to fit: R_X86_64_32Slỗi (dự kiến) , mà tôi hy vọng sẽ tránh được bằng cách chỉ định cờ trình biên dịch -mcmodel=medium. Tất cả các thư viện được liên kết thêm vào mà tôi có quyền kiểm soát đều được biên dịch với -fpiccờ.

Tuy nhiên, lỗi vẫn tiếp diễn và tôi cho rằng một số thư viện mà tôi liên kết đến không được biên dịch bằng PIC.

Đây là lỗi:

/usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../lib64/crt1.o: In function `_start':
(.text+0x12): relocation truncated to fit: R_X86_64_32S against symbol `__libc_csu_fini'     defined in .text section in /usr/lib64/libc_nonshared.a(elf-init.oS)
/usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../lib64/crt1.o: In function `_start':
(.text+0x19): relocation truncated to fit: R_X86_64_32S against symbol `__libc_csu_init'    defined in .text section in /usr/lib64/libc_nonshared.a(elf-init.oS)
/usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../lib64/crt1.o: In function `_start':
(.text+0x20): undefined reference to `main'
/usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../lib64/crti.o: In function    `call_gmon_start':
(.text+0x7): relocation truncated to fit: R_X86_64_GOTPCREL against undefined symbol      `__gmon_start__'
/usr/lib/gcc/x86_64-redhat-linux/4.1.2/crtbegin.o: In function `__do_global_dtors_aux':
crtstuff.c:(.text+0xb): relocation truncated to fit: R_X86_64_PC32 against `.bss' 
crtstuff.c:(.text+0x13): relocation truncated to fit: R_X86_64_32 against symbol `__DTOR_END__' defined in .dtors section in /usr/lib/gcc/x86_64-redhat-linux/4.1.2/crtend.o
crtstuff.c:(.text+0x19): relocation truncated to fit: R_X86_64_32S against `.dtors'
crtstuff.c:(.text+0x28): relocation truncated to fit: R_X86_64_PC32 against `.bss'
crtstuff.c:(.text+0x38): relocation truncated to fit: R_X86_64_PC32 against `.bss'
crtstuff.c:(.text+0x3f): relocation truncated to fit: R_X86_64_32S against `.dtors'
crtstuff.c:(.text+0x46): relocation truncated to fit: R_X86_64_PC32 against `.bss'
crtstuff.c:(.text+0x51): additional relocation overflows omitted from the output
collect2: ld returned 1 exit status
make: *** [testsme] Error 1

Và các thư viện hệ thống mà tôi liên kết với:

-lgfortran -lm -lrt -lpthread

Bất kỳ manh mối ở đâu để tìm kiếm vấn đề?

EDIT: Trước hết, cảm ơn bạn đã thảo luận ... Để làm rõ một chút, tôi có hàng trăm hàm (mỗi hàm có kích thước khoảng 1 MB trong các tệp đối tượng riêng biệt) như thế này:

double func1(std::tr1::unordered_map<int, double> & csc, 
             std::vector<EvaluationNode::Ptr> & ti, 
             ProcessVars & s)
{
    double sum, prefactor, expr;

    prefactor = +s.ds8*s.ds10*ti[0]->value();
    expr =       ( - 5/243.*(s.x14*s.x15*csc[49300] + 9/10.*s.x14*s.x15*csc[49301] +
           1/10.*s.x14*s.x15*csc[49302] - 3/5.*s.x14*s.x15*csc[49303] -
           27/10.*s.x14*s.x15*csc[49304] + 12/5.*s.x14*s.x15*csc[49305] -
           3/10.*s.x14*s.x15*csc[49306] - 4/5.*s.x14*s.x15*csc[49307] +
           21/10.*s.x14*s.x15*csc[49308] + 1/10.*s.x14*s.x15*csc[49309] -
           s.x14*s.x15*csc[51370] - 9/10.*s.x14*s.x15*csc[51371] -
           1/10.*s.x14*s.x15*csc[51372] + 3/5.*s.x14*s.x15*csc[51373] +
           27/10.*s.x14*s.x15*csc[51374] - 12/5.*s.x14*s.x15*csc[51375] +
           3/10.*s.x14*s.x15*csc[51376] + 4/5.*s.x14*s.x15*csc[51377] -
           21/10.*s.x14*s.x15*csc[51378] - 1/10.*s.x14*s.x15*csc[51379] -
           2*s.x14*s.x15*csc[55100] - 9/5.*s.x14*s.x15*csc[55101] -
           1/5.*s.x14*s.x15*csc[55102] + 6/5.*s.x14*s.x15*csc[55103] +
           27/5.*s.x14*s.x15*csc[55104] - 24/5.*s.x14*s.x15*csc[55105] +
           3/5.*s.x14*s.x15*csc[55106] + 8/5.*s.x14*s.x15*csc[55107] -
           21/5.*s.x14*s.x15*csc[55108] - 1/5.*s.x14*s.x15*csc[55109] -
           2*s.x14*s.x15*csc[55170] - 9/5.*s.x14*s.x15*csc[55171] -
           1/5.*s.x14*s.x15*csc[55172] + 6/5.*s.x14*s.x15*csc[55173] +
           27/5.*s.x14*s.x15*csc[55174] - 24/5.*s.x14*s.x15*csc[55175] +
           // ...
           ;

        sum += prefactor*expr;
    // ...
    return sum;
}

Đối tượng stương đối nhỏ và giữ các hằng số cần thiết x14, x15, ..., ds0, ..., v.v. trong khi tichỉ trả về một giá trị kép từ thư viện bên ngoài. Như bạn có thể thấy, csc[]là một bản đồ giá trị được tính toán trước cũng được đánh giá trong các tệp đối tượng riêng biệt (hàng trăm với kích thước mỗi tệp khoảng ~ 1 MB) có dạng sau:

void cscs132(std::tr1::unordered_map<int,double> & csc, ProcessVars & s)
{
    {
    double csc19295 =       + s.ds0*s.ds1*s.ds2 * ( -
           32*s.x12pow2*s.x15*s.x34*s.mbpow2*s.mWpowinv2 -
           32*s.x12pow2*s.x15*s.x35*s.mbpow2*s.mWpowinv2 -
           32*s.x12pow2*s.x15*s.x35*s.x45*s.mWpowinv2 -
           32*s.x12pow2*s.x25*s.x34*s.mbpow2*s.mWpowinv2 -
           32*s.x12pow2*s.x25*s.x35*s.mbpow2*s.mWpowinv2 -
           32*s.x12pow2*s.x25*s.x35*s.x45*s.mWpowinv2 +
           32*s.x12pow2*s.x34*s.mbpow4*s.mWpowinv2 +
           32*s.x12pow2*s.x34*s.x35*s.mbpow2*s.mWpowinv2 +
           32*s.x12pow2*s.x34*s.x45*s.mbpow2*s.mWpowinv2 +
           32*s.x12pow2*s.x35*s.mbpow4*s.mWpowinv2 +
           32*s.x12pow2*s.x35pow2*s.mbpow2*s.mWpowinv2 +
           32*s.x12pow2*s.x35pow2*s.x45*s.mWpowinv2 +
           64*s.x12pow2*s.x35*s.x45*s.mbpow2*s.mWpowinv2 +
           32*s.x12pow2*s.x35*s.x45pow2*s.mWpowinv2 -
           64*s.x12*s.p1p3*s.x15*s.mbpow4*s.mWpowinv2 +
           64*s.x12*s.p1p3*s.x15pow2*s.mbpow2*s.mWpowinv2 +
           96*s.x12*s.p1p3*s.x15*s.x25*s.mbpow2*s.mWpowinv2 -
           64*s.x12*s.p1p3*s.x15*s.x35*s.mbpow2*s.mWpowinv2 -
           64*s.x12*s.p1p3*s.x15*s.x45*s.mbpow2*s.mWpowinv2 -
           32*s.x12*s.p1p3*s.x25*s.mbpow4*s.mWpowinv2 +
           32*s.x12*s.p1p3*s.x25pow2*s.mbpow2*s.mWpowinv2 -
           32*s.x12*s.p1p3*s.x25*s.x35*s.mbpow2*s.mWpowinv2 -
           32*s.x12*s.p1p3*s.x25*s.x45*s.mbpow2*s.mWpowinv2 -
           32*s.x12*s.p1p3*s.x45*s.mbpow2 +
           64*s.x12*s.x14*s.x15pow2*s.x35*s.mWpowinv2 +
           96*s.x12*s.x14*s.x15*s.x25*s.x35*s.mWpowinv2 +
           32*s.x12*s.x14*s.x15*s.x34*s.mbpow2*s.mWpowinv2 -
           32*s.x12*s.x14*s.x15*s.x35*s.mbpow2*s.mWpowinv2 -
           64*s.x12*s.x14*s.x15*s.x35pow2*s.mWpowinv2 -
           32*s.x12*s.x14*s.x15*s.x35*s.x45*s.mWpowinv2 +
           32*s.x12*s.x14*s.x25pow2*s.x35*s.mWpowinv2 +
           32*s.x12*s.x14*s.x25*s.x34*s.mbpow2*s.mWpowinv2 -
           32*s.x12*s.x14*s.x25*s.x35pow2*s.mWpowinv2 -
           // ...

       csc.insert(cscMap::value_type(192953, csc19295));
    }

    {
       double csc19296 =      // ... ;

       csc.insert(cscMap::value_type(192956, csc19296));
    }

    // ...
}

Đó là về nó. Bước cuối cùng sau đó chỉ bao gồm gọi tất cả những thứ đó func[i]và tính tổng kết quả.

Liên quan đến thực tế là đây là một trường hợp khá đặc biệt và bất thường: Vâng, nó là. Đây là những gì mọi người phải đối phó khi cố gắng thực hiện các phép tính chính xác cao cho vật lý hạt.

EDIT2: Tôi cũng nên thêm rằng x12, x13, v.v. không thực sự là hằng số. Chúng được đặt thành các giá trị cụ thể, tất cả các hàm đó được chạy và kết quả trả về, sau đó một tập hợp x12, x13, v.v. mới được chọn để tạo ra giá trị tiếp theo. Và điều này phải được thực hiện 10 ^ 5 đến 10 ^ 6 lần ...

EDIT3: Cảm ơn bạn vì những gợi ý và cuộc thảo luận cho đến nay ... Tôi sẽ cố gắng cuộn lại các vòng lặp khi tạo mã bằng cách nào đó, không chắc chắn về cách chính xác, thành thật mà nói, nhưng đây là cách tốt nhất.

BTW, tôi không cố giấu đằng sau "đây là máy tính khoa học - không có cách nào để tối ưu hóa". Chỉ là cơ sở cho mã này là một thứ gì đó xuất hiện từ "hộp đen" mà tôi không có quyền truy cập thực sự và hơn nữa, toàn bộ mọi thứ hoạt động tuyệt vời với các ví dụ đơn giản và tôi chủ yếu cảm thấy choáng ngợp với những gì xảy ra trong thực tế ứng dụng thế giới ...

EDIT4: Vì vậy, tôi đã cố gắng giảm kích thước mã của các cscđịnh nghĩa xuống khoảng một phần bằng cách đơn giản hóa các biểu thức trong hệ thống đại số máy tính ( Mathematica ). Tôi thấy bây giờ cũng có một số cách để giảm nó theo một thứ tự cường độ khác bằng cách áp dụng một số thủ thuật khác trước khi tạo mã (sẽ làm giảm phần này xuống khoảng 100 MB) và tôi hy vọng ý tưởng này có hiệu quả.

Bây giờ liên quan đến câu trả lời của bạn: Tôi đang cố gắng cuộn lại các vòng lặp lại trong funcs, nơi CAS sẽ không giúp được nhiều, nhưng tôi đã có một số ý tưởng. Ví dụ: sắp xếp các biểu thức theo các biến như x12, x13,..., phân tích cú pháp các cscs bằng Python và tạo các bảng liên quan chúng với nhau. Sau đó, ít nhất tôi có thể tạo các phần này dưới dạng vòng lặp. Vì đây có vẻ là giải pháp tốt nhất cho đến nay, tôi đánh dấu đây là câu trả lời tốt nhất.

Tuy nhiên, tôi cũng muốn ghi công cho VJo. GCC 4.6 thực sự hoạt động tốt hơn nhiều , tạo ra mã nhỏ hơn và nhanh hơn. Sử dụng mô hình lớn hoạt động ở mã như hiện tại. Vì vậy, về mặt kỹ thuật thì đây là câu trả lời chính xác, nhưng thay đổi toàn bộ khái niệm là một cách tiếp cận tốt hơn nhiều.

Cảm ơn tất cả các bạn đã góp ý và giúp đỡ. Nếu ai quan tâm, tôi sẽ đăng kết quả cuối cùng ngay khi tôi sẵn sàng.

NHẬN XÉT: Chỉ là một số nhận xét cho một số câu trả lời khác: Đoạn mã tôi đang cố chạy không bắt nguồn từ sự mở rộng của các chức năng / thuật toán đơn giản và việc mở cuộn không cần thiết một cách ngu ngốc. Điều thực sự xảy ra là thứ mà chúng ta bắt đầu là các đối tượng toán học khá phức tạp và đưa chúng về dạng số có thể tính toán được sẽ tạo ra các biểu thức này. Vấn đề thực sự nằm ở lý thuyết vật lý cơ bản. Mức độ phức tạp của các biểu thức trung gian quy mô theo thực tế, điều này ai cũng biết, nhưng khi kết hợp tất cả những thứ này với một thứ có thể đo lường được về mặt vật lý - một thứ có thể quan sát được - nó chỉ tóm gọn lại chỉ một số hàm rất nhỏ tạo thành cơ sở của biểu thức. (Ở khía cạnh này chắc chắn có cái gì đó "sai sai" với cái chung và chỉansatz được gọi là "lý thuyết nhiễu loạn") Chúng tôi cố gắng đưa ansatz này lên một cấp độ khác, không còn khả thi về mặt phân tích nữa và ở đó cơ sở của các chức năng cần thiết không được biết đến. Vì vậy, chúng tôi cố gắng cưỡng bức nó như thế này. Không phải là cách tốt nhất, nhưng hy vọng một cách cuối cùng sẽ giúp ích cho sự hiểu biết của chúng ta về vật lý ...

CHỈNH SỬA CUỐI CÙNG: Nhờ tất cả các đề xuất của bạn, tôi đã quản lý để giảm kích thước mã đáng kể, sử dụng Mathematica và một sửa đổi của trình tạo mã cho các funcphần dọc theo dòng của câu trả lời trên cùng :)

Tôi đã đơn giản hóa các cscchức năng với Mathematica, giảm nó xuống 92 MB. Đây là phần không thể thay đổi được. Những lần thử đầu tiên mất nhiều thời gian, nhưng sau một số tối ưu hóa, điều này hiện chạy trong khoảng 10 phút trên một CPU.

Ảnh hưởng đối với các funcs là rất đáng kể: Toàn bộ kích thước mã cho chúng giảm xuống còn khoảng 9 MB, vì vậy mã hiện tổng cộng trong phạm vi 100 MB. Giờ đây, việc bật tối ưu hóa là rất hợp lý và việc thực thi diễn ra khá nhanh.

Một lần nữa, cảm ơn tất cả các bạn đã góp ý, tôi đã học được rất nhiều.


17
Nếu bạn có nhiều dữ liệu đó, bạn nên di chuyển nó ra khỏi các tệp nguồn và thay vào mmapđó là chính nó từ tệp nhị phân bên ngoài trong thời gian chạy.
R .. GitHub DỪNG GIÚP ICE

3
Bạn có thể cho một ví dụ về một (hoặc hai) chức năng này? Điều này thực sự trông kỳ lạ. Bạn cũng có thể tải các hàm này một cách linh hoạt với hàm dl *.
Patrick Schlüter

7
@bbtrb: Bản năng đầu tiên của tôi tương tự như R .., nó có vẻ là một vấn đề thiết kế. Phải thừa nhận rằng tôi không biết điều gì phổ biến trong giới máy tính khoa học, nhưng tôi chưa bao giờ nghe nói về ai đó đang cố gắng liên kết tệp đối tượng 2,8 GB hoặc bất kỳ thứ gì từ xa gần với nó và tôi không chắc GCC sẽ thực sự hỗ trợ nó. Thành thật mà nói, tôi mong đợi bất kỳ khối mã nào có kích thước đó đều là mì Ý nguyên chất.
Nicholas Knight

46
hoàn toàn không có cách nào mà giải pháp tối ưu cho vấn đề liên quan đến 2gb tệp đối tượng.
David Heffernan

35
không đưa dữ liệu của bạn trong mã
David Heffernan

Câu trả lời:


53

Vì vậy, bạn đã có một chương trình tạo ra văn bản này:

prefactor = +s.ds8*s.ds10*ti[0]->value();
expr = ( - 5/243.*(s.x14*s.x15*csc[49300] + 9/10.*s.x14*s.x15*csc[49301] +
       1/10.*s.x14*s.x15*csc[49302] - 3/5.*s.x14*s.x15*csc[49303] -...

double csc19295 =       + s.ds0*s.ds1*s.ds2 * ( -
       32*s.x12pow2*s.x15*s.x34*s.mbpow2*s.mWpowinv2 -
       32*s.x12pow2*s.x15*s.x35*s.mbpow2*s.mWpowinv2 -
       32*s.x12pow2*s.x15*s.x35*s.x45*s.mWpowinv2 -...

đúng?

Nếu tất cả các hàm của bạn có "định dạng" tương tự (nhân n số m lần và cộng kết quả - hoặc một cái gì đó tương tự) thì tôi nghĩ bạn có thể làm điều này:

  • thay đổi chương trình của trình tạo thành các hiệu số đầu ra thay vì chuỗi (nghĩa là thay vì chuỗi "s.ds0", nó sẽ tạo ra offsetof(ProcessVars, ds0)
  • tạo ra một loạt các hiệu số như vậy
  • viết một trình đánh giá chấp nhận mảng ở trên và địa chỉ cơ sở của con trỏ cấu trúc và tạo ra một kết quả

Bộ đánh giá mảng + sẽ đại diện cho cùng một logic như một trong các hàm của bạn, nhưng chỉ bộ đánh giá mới là mã. Mảng là "dữ liệu" và có thể được tạo trong thời gian chạy hoặc được lưu trên đĩa và đọc các khối hoặc với một tệp được ánh xạ bộ nhớ.

Ví dụ cụ thể của bạn trong Func1 tưởng tượng làm thế nào bạn sẽ viết lại các chức năng thông qua một đánh giá nếu bạn có quyền truy cập vào địa chỉ cơ sở của scscvà cũng là một vector như đại diện của các hằng số và hiệu số bạn cần phải thêm vào các địa chỉ cơ sở để có được x14, ds8csc[51370]

Bạn cần tạo một dạng "dữ liệu" mới sẽ mô tả cách xử lý dữ liệu thực tế mà bạn chuyển cho số lượng chức năng khổng lồ của mình.


45

Các x86-64 ABI sử dụng bởi Linux định nghĩa một "mô hình lớn" đặc biệt để tránh giới hạn kích thước như vậy, trong đó bao gồm các loại di dời 64-bit cho GOT và PLT. (Xem bảng trong phần 4.4.2 và các trình tự hướng dẫn trong 3.5.5 cho thấy cách chúng được sử dụng.)

Vì các chức năng của bạn đang chiếm 2,8 GB, bạn không gặp may vì gcc không hỗ trợ các mô hình lớn. Những gì bạn có thể làm là tổ chức lại mã của mình theo cách cho phép bạn chia nó thành các thư viện được chia sẻ mà bạn sẽ liên kết động.

Nếu điều đó là không thể, như ai đó đã đề xuất, thay vì đặt dữ liệu của bạn vào mã (biên dịch và liên kết nó), vì nó rất lớn, bạn có thể tải nó vào lúc chạy (dưới dạng tệp bình thường hoặc bạn có thể mmap nó).

BIÊN TẬP

Có vẻ như mô hình lớn được hỗ trợ bởi gcc 4.6 (xem trang này ). Bạn có thể thử điều đó, nhưng điều trên vẫn áp dụng khi tổ chức lại mã của bạn.


Vì vậy, những gì bạn đang nói là khi tôi nhóm các tệp đối tượng trong một số thư viện chia sẻ nhỏ, tôi sẽ khắc phục được những hạn chế?
bbtrb

3
@bbtrb Đúng. Nhưng tôi vẫn sẽ tìm kiếm một cách khác để thực hiện các chức năng của bạn. Tôi cá rằng quá trình biên dịch của bạn sẽ mất vĩnh viễn
BЈовић

18
WTF? Mã này phải được tạo bởi một số tập lệnh; không ai viết mã megabyte bằng tay! Logic tương tự tạo ra mã cũng có thể được sử dụng để chạy tính toán.
zvrba

6
Tôi thực sự khuyên bạn nên thử gcc 4.6, rất có thể tạo ra mã cao cấp cho chương trình này hơn gcc 4.1; nó thậm chí có thể nén toàn bộ thành 2GB mà bạn không cần phải làm bất cứ điều gì thông minh, loại bỏ vấn đề (hãy thử kết hợp -Os, -fwhole-program và -flto - với khối lượng mã này, tối ưu hóa kích thước tối ưu hóa cho tốc độ). Tuy nhiên, nếu điều đó vẫn chưa đủ, bạn cũng nên lưu ý rằng để mô hình lớn hoạt động, bạn sẽ phải xây dựng lại ít nhất một phần của thư viện C trong mô hình lớn (crt * .o, libc_nonshared.a và libpthread_nonshared.a).
zwol

1
@bdonlan Liên kết tĩnh cũng là một khả năng.
zvrba

37

Với một chương trình của bên đó, bộ nhớ cache bỏ sót mã rất có thể vượt quá chi phí lặp lại trong thời gian chạy. Tôi khuyên bạn nên quay lại trình tạo mã của mình và yêu cầu nó tạo ra một số biểu diễn nhỏ gọn cho những gì nó muốn được đánh giá (tức là một biểu diễn có khả năng phù hợp với D-cache), sau đó thực thi điều đó với trình thông dịch trong chương trình của bạn. Bạn cũng có thể xem liệu bạn có thể tính ra các hạt nhân nhỏ hơn vẫn có số lượng hoạt động đáng kể hay không, sau đó sử dụng chúng làm 'hướng dẫn' trong mã được diễn giải.


21

Lỗi xảy ra do bạn có quá nhiều CODE, không phải dữ liệu! Điều này được chỉ ra bởi ví dụ __libc_csu_fini(đó là một hàm) được tham chiếu từ _startvà việc chuyển vị trí được cắt bớt để phù hợp. Điều này có nghĩa là _start(điểm vào thực sự của chương trình) đang cố gắng gọi hàm đó thông qua độ lệch 32-bit SIGNED, chỉ có phạm vi 2 GB. Vì tổng số lượng mã đối tượng của bạn là ~ 2,8 GB, các dữ kiện sẽ được kiểm tra.

Nếu bạn có thể thiết kế lại cấu trúc dữ liệu của mình, phần lớn mã của bạn có thể được "nén" bằng cách viết lại các biểu thức khổng lồ dưới dạng các vòng lặp đơn giản.

Ngoài ra, bạn có thể tính toán csc[]trong một chương trình khác, lưu trữ kết quả trong một tệp và chỉ tải chúng khi cần thiết.


Bạn có thể cung cấp một ví dụ về cách bạn sẽ viết lại các hàm bằng các vòng lặp đơn giản không? Tôi không theo dõi bạn chính xác. csc[]phải được tính toán rất thường xuyên và tôi muốn tránh I / O đĩa.
bbtrb

4
@bbtr: Ví dụ, đối với func1ở trên, một cái gì đó như: for (int i = 0; i < N; ++i) expr += constants[i].*s.x14*s.x15*csc[49300 + i];.
HighCommander 4

@ HighCommander4: hoàn toàn đồng ý. Tôi chỉ nghĩ đến cách tạo ra một cái gì đó như thế này một cách tự động. Có lẽ với một mảng riêng biệt mà các cửa hàng các chỉ số ...
bbtrb

2
@bbtrb: Vì không có ai viết đủ nguồn để tạo ra 2,8GB mã đối tượng bằng tay, đặc biệt là với những tên ký hiệu khó nhớ như vậy, nên phải sử dụng một trình tạo mã . Làm việc với điều đó.
Donal Fellows

15

Tôi nghĩ rằng mọi người đều đồng ý rằng nên có một cách khác nhau để làm những gì bạn muốn. Biên dịch hàng trăm megabyte (gigabyte?) Mã, liên kết nó thành một tệp thực thi có kích thước nhiều gigabyte và chạy nó nghe có vẻ rất kém hiệu quả.

Nếu tôi hiểu vấn đề của bạn một cách chính xác, bạn sử dụng một số loại trình tạo mã, G, để tạo ra một loạt các hàm func1...Nlấy một loạt các bản đồ csc1...Mlàm đầu vào. Những gì bạn muốn làm là tính toán csc1...Mvà chạy một vòng lặp 1.000.000 lần cho các đầu vào khác nhau và mỗi lần tìm thấy s = func1 + func2 + ... + funcN. Bạn đã không chỉ định làm thế nào fucn1...Ncó liên quan đến csc1...Mmặc dù.

Nếu tất cả những điều đó là đúng, có vẻ như bạn có thể giải quyết vấn đề theo cách khác có thể dễ quản lý hơn nhiều và thậm chí có thể nhanh hơn (tức là để bộ nhớ cache của máy hoạt động thực sự).

Bên cạnh vấn đề thực tế về kích thước tệp đối tượng, chương trình hiện tại của bạn sẽ không hiệu quả vì nó không bản địa hóa quyền truy cập vào dữ liệu (quá nhiều bản đồ khổng lồ) và không thực thi mã cục bộ (quá nhiều hàm rất dài).

Làm thế nào về việc chia nhỏ chương trình của bạn thành 3 giai đoạn: Giai đoạn 1 xây dựng csc1...Mvà lưu trữ chúng. Giai đoạn 2 xây dựng từng cái funcmột, chạy 1.000.000 lần với mỗi đầu vào và lưu trữ kết quả. Giai đoạn 3 tìm tổng kết quả của các func1...Nkết quả được lưu trữ cho mỗi lần chạy trong số 1.000.000 lần. Phần tốt của giải pháp này là nó có thể dễ dàng được thực hiện song song trên một số máy độc lập.

Chỉnh sửa: @bbtrb, bạn có thể tạo một func và một csc nào đó có sẵn không? Chúng dường như rất thường xuyên và có thể nén được. Ví dụ: func1 dường như chỉ là một tổng của các biểu thức, mỗi biểu thức bao gồm 1 hệ số, 2 chỉ mục cho các biến trong s và 1 chỉ mục vào csc. Vì vậy, nó có thể được giảm thành một vòng lặp đẹp. Nếu bạn cung cấp các ví dụ hoàn chỉnh, tôi chắc chắn có thể tìm thấy các cách để nén chúng thành các vòng lặp thay vì các biểu thức dài.


Vâng, bạn hiểu đúng :) Mặc dù vậy, có một số vấn đề với đề xuất của bạn: 1. funcs xấu nhất phụ thuộc vào hầu hết tất cả các cscs và những con số đó cũng phải được tính 10 ^ 6 lần. 2. Đầu vào sẽ được lấy từ một bộ tích phân Monte Carlo thích ứng, có nghĩa là bộ tích phân phải biết kết quả đầy đủ tại mỗi điểm để có thể giảm lỗi kết quả bằng cách tinh chỉnh lưới trong vùng lân cận của điểm nếu cần. 3. Các biểu thức lớn cho csckiên trì ...
bbtrb

1
Vì vậy, nó có nghĩa là bạn không thể tính toán mỗi csctrong mỗi lần lặp độc lập với những người khác? Nếu chúng độc lập, bạn vẫn có thể chạy mỗi cái 10 ^ 6 lần và lưu trữ kết quả. Tuy nhiên, nếu có các phụ thuộc trong số đó, có thể bạn cần tìm hiểu xem cái nào liên quan đến cái nào, giống như biểu đồ phụ thuộc, sau đó thử xem liệu bạn có thể chia nó thành nhiều biểu đồ con độc lập hay không. Tựu chung lại, tôi nghĩ chìa khóa là chia vấn đề thành nhiều vấn đề con, độc lập.
AlefSin

5

Nếu tôi đọc chính xác lỗi của bạn, điều khiến bạn vượt quá giới hạn là phần dữ liệu được khởi tạo (nếu đó là mã, bạn sẽ có nhiều lỗi hơn IMHO). Bạn có mảng dữ liệu toàn cầu lớn không? Nếu đúng như vậy, tôi sẽ cấu trúc lại chương trình để chúng được phân bổ động. Nếu dữ liệu được khởi tạo, tôi sẽ đọc nó từ tệp cấu hình.

BTW thấy điều này:

(.text + 0x20): tham chiếu không xác định đến `chính '

Tôi nghĩ bạn có một vấn đề khác.


1
Có bạn đúng, sai lầm ngu ngốc, nhưng nó không giải quyết được các lỗi khác.
bbtrb

3

Đối với tôi, có vẻ như mã đang thực hiện tích hợp số bằng cách sử dụng một số loại phương pháp chiều sâu thích ứng. Thật không may, trình tạo mã (hay đúng hơn là tác giả của trình tạo mã) quá ngu ngốc khi tạo ra một hàm cho mỗi bản vá chứ không phải một cho mỗi loại bản vá. Do đó, nó tạo ra quá nhiều mã để được biên dịch, và ngay cả khi nó có thể được biên dịch, việc thực thi của nó sẽ rất khó khăn vì không có gì được chia sẻ ở bất kỳ đâu. (Bạn có thể tưởng tượng được nỗi đau do phải tải từng trang mã đối tượng từ đĩa vì không có gì được chia sẻ và vì vậy nó luôn là ứng cử viên cho hệ điều hành loại bỏ. Không nói gì đến bộ nhớ đệm hướng dẫn, điều này sẽ vô dụng.)

Cách khắc phục là dừng việc hủy cuộn mọi thứ; đối với loại mã này, bạn muốn tối đa hóa chia sẻ vì chi phí của các hướng dẫn bổ sung để truy cập dữ liệu trong các mẫu phức tạp hơn sẽ bị chi phí xử lý với tập dữ liệu cơ bản lớn (có thể là) lớn hơn. Cũng có thể trình tạo mã thậm chí sẽ làm điều này theo mặc định và nhà khoa học đã nhìn thấy một số tùy chọn để mở cuộn (với lưu ý rằng những tùy chọn này đôi khi cải thiện tốc độ) và bật tất cả chúng cùng một lúc và hiện đang nhấn mạnh rằng kết quả lộn xộn này được chấp nhận bởi máy tính, thay vì chấp nhận các hạn chế thực của máy và sử dụng phiên bản chính xác về số được tạo theo mặc định. Nhưng nếu trình tạo mã không làm điều đó, hãy lấy một mã sẽ làm được (hoặc hack mã hiện có).

Điểm mấu chốt: biên dịch và liên kết 2,8GB mã không hoạt động và không nên bị buộc phải hoạt động. Tìm một cách khác.


3

Một vài đề xuất: - Tối ưu hóa cho kích thước (-Os). Thực hiện các cuộc gọi hàm nội tuyến, gọi hàm thông thường. Bật tổng hợp chuỗi.

Hãy thử tách mọi thứ thành các tệp DLL khác nhau (đối tượng được chia sẻ, .so cho linux, .dylib cho Mac OS X). Đảm bảo rằng chúng có thể được dỡ bỏ. Sau đó, triển khai một cái gì đó để tải những thứ theo yêu cầu và giải phóng chúng khi không cần thiết.

Nếu không, hãy chia mã của bạn thành các tệp thực thi khác nhau và sử dụng thứ gì đó để giao tiếp giữa chúng (đường ống, ổ cắm, thậm chí ghi / đọc vào tệp). Vụng về, nhưng bạn có những lựa chọn nào?

Hoàn toàn thay thế: - Sử dụng ngôn ngữ động với JIT . Ngay trên đầu tôi - sử dụng LuaJIT - và viết lại (tạo lại?) Rất nhiều biểu thức này bằng Lua , hoặc các ngôn ngữ và thời gian chạy khác như vậy cho phép mã được thu thập rác.

LuaJIT khá hiệu quả, đôi khi đánh bại C / C ++ đối với một số thứ nhất định, nhưng thường rất gần (đôi khi có thể chậm do thu gom rác chưa tốt ở đó). Kiểm tra cho chính mình:

http://luajit.org/performance_x86.html

Tải xuống scimark2.luatệp từ đó và so sánh nó với phiên bản "C" (google nó) - thường kết quả rất gần.


2

Trình liên kết đang cố gắng tạo ra các hiệu số chuyển vị trí 32 bit trong một tệp nhị phân mà bằng cách nào đó đã vượt quá những giới hạn này. Hãy thử giảm các yêu cầu về không gian địa chỉ của chương trình chính.

Bạn có thể chia một số / hầu hết mã đối tượng thành một hoặc nhiều thư viện (cũng được biên dịch với -fpic / -fPIC) không? Sau đó, tạo một nhị phân không tĩnh liên kết với các lib này. Các thư viện sẽ nằm trong các khối bộ nhớ rời rạc và hiệu số di dời của bạn sẽ là động / tuyệt đối (64-bit) chứ không phải là tương đối (32-bit).


2

Đối với tôi, những biểu hiện đó giống như một chuỗi xen kẽ. Tôi không biết phần còn lại của đoạn mã trông như thế nào, nhưng có vẻ như không khó để tìm ra biểu thức tạo. Nó có lẽ cũng đáng giá vào thời gian thực thi, đặc biệt nếu bạn có 2,8 GB mã 2 KB chưa được cuộn.


1

Điều này có vẻ như kết quả của quá trình tạo mã bị sai, có thể do đại số ký hiệu và / hoặc thao tác giải nén thủ công. Các thao tác biểu tượng nổi tiếng là phát triển theo cấp số nhân theo chiều sâu của cây biểu thức hoặc đồ thị tính toán. Có khả năng là sự phân biệt tự động có thể được sử dụng ở đây, điều này sẽ làm cho kích thước mã khá nhỏ và cũng tăng tốc độ thực thi một cách đáng kể.

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.