ข้อผิดพลาดในการคอมไพล์ GCC ด้วยรหัส> 2 GB


108

ฉันมีฟังก์ชั่นจำนวนมากรวมประมาณ 2.8 GB ของรหัสวัตถุ (น่าเสียดายที่ไม่มีวิธีการคำนวณทางวิทยาศาสตร์ ... )

เมื่อฉันพยายามที่จะเชื่อมโยงพวกเขาก็จะได้รับ (คาดว่า) relocation truncated to fit: R_X86_64_32Sข้อผิดพลาดที่ผมหวังว่าจะหลีกเลี่ยงโดย specifing -mcmodel=mediumธงคอมไพเลอร์ ไลบรารีทั้งหมดที่เชื่อมโยงนอกเหนือจากที่ฉันควบคุมจะถูกคอมไพล์ด้วย-fpicแฟล็ก

ถึงกระนั้นข้อผิดพลาดยังคงมีอยู่และฉันคิดว่าบางไลบรารีที่ฉันเชื่อมโยงไม่ได้คอมไพล์ด้วย PIC

นี่คือข้อผิดพลาด:

/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

และไลบรารีระบบที่ฉันเชื่อมโยงกับ:

-lgfortran -lm -lrt -lpthread

เบาะแสใดที่จะค้นหาปัญหา?

แก้ไข: ก่อนอื่นขอขอบคุณสำหรับการสนทนา ... เพื่อชี้แจงเล็กน้อยฉันมีฟังก์ชั่นหลายร้อยรายการ (แต่ละขนาดประมาณ 1 MB ในไฟล์ออบเจ็กต์แยกต่างหาก) ดังนี้:

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

วัตถุsมีขนาดค่อนข้างเล็กและคงค่าคงที่ที่ต้องการ x14, x15, ... , ds0, ... ฯลฯ ในขณะที่tiส่งคืนค่าสองเท่าจากไลบรารีภายนอก อย่างที่คุณเห็นcsc[]คือแผนที่ค่าที่คำนวณไว้ล่วงหน้าซึ่งได้รับการประเมินในไฟล์ออบเจ็กต์ที่แยกจากกัน (อีกหลายร้อยไฟล์โดยมีขนาดประมาณ ~ 1 MB) ของรูปแบบต่อไปนี้:

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

    // ...
}

เกี่ยวกับมัน. ขั้นตอนสุดท้ายก็ประกอบด้วยการเรียกสิ่งเหล่านั้นทั้งหมดfunc[i]และสรุปผลลัพธ์

เกี่ยวกับความจริงที่ว่านี่เป็นกรณีที่ค่อนข้างพิเศษและผิดปกติ: ใช่แล้ว นี่คือสิ่งที่ผู้คนต้องรับมือเมื่อพยายามคำนวณความแม่นยำสูงสำหรับฟิสิกส์อนุภาค

แก้ไข 2: ฉันควรเพิ่มว่า x12, x13 ฯลฯ ไม่ใช่ค่าคงที่จริงๆ ค่าเหล่านี้ถูกตั้งค่าเป็นค่าเฉพาะฟังก์ชันเหล่านั้นทั้งหมดจะรันและผลลัพธ์ที่ส่งกลับจากนั้นจึงเลือกชุดใหม่ของ x12, x13 และอื่น ๆ เพื่อสร้างค่าถัดไป และสิ่งนี้จะต้องทำ 10 ^ 5 ถึง 10 ^ 6 ครั้ง ...

แก้ไข 3: ขอบคุณสำหรับข้อเสนอแนะและการสนทนาจนถึงตอนนี้ ... ฉันจะพยายามหมุนลูปขึ้นในการสร้างโค้ดไม่แน่ใจว่าจะทำอย่างไรให้ตรงไปตรงมา แต่นี่เป็นทางออกที่ดีที่สุด

BTW ฉันไม่ได้พยายามซ่อนตัว "นี่คือการคำนวณทางวิทยาศาสตร์ - ไม่มีทางเพิ่มประสิทธิภาพ" เพียงแค่ว่าพื้นฐานของรหัสนี้เป็นสิ่งที่มาจาก "กล่องดำ" ซึ่งฉันไม่สามารถเข้าถึงได้จริงและยิ่งกว่านั้นสิ่งทั้งหมดทำงานได้ดีด้วยตัวอย่างง่ายๆและฉันรู้สึกหนักใจกับสิ่งที่เกิดขึ้นจริงเป็นหลัก แอพพลิเคชั่นโลก ...

แก้ไข 4: ดังนั้นฉันจึงสามารถลดขนาดโค้ดของcscคำจำกัดความได้ประมาณหนึ่งในสี่โดยการทำให้นิพจน์ง่ายขึ้นในระบบพีชคณิตคอมพิวเตอร์ ( Mathematica ) ตอนนี้ฉันเห็นวิธีการลดขนาดตามลำดับขนาดอื่นหรือมากกว่านั้นโดยใช้เทคนิคอื่น ๆ ก่อนสร้างโค้ด (ซึ่งจะทำให้ส่วนนี้ลดลงเหลือประมาณ 100 MB) และฉันหวังว่าแนวคิดนี้จะใช้ได้ผล

ตอนนี้เกี่ยวข้องกับคำตอบของคุณ: ฉันกำลังพยายามหมุนลูปสำรองอีกครั้งในfuncs ซึ่ง CAS จะไม่ช่วยอะไรมากนัก แต่ฉันมีแนวคิดบางอย่างแล้ว ตัวอย่างเช่นการเรียงลำดับนิพจน์ตามตัวแปรเช่นx12, x13,...แยกวิเคราะห์cscs ด้วย Python และสร้างตารางที่เกี่ยวข้องกัน จากนั้นอย่างน้อยฉันก็สามารถสร้างส่วนเหล่านี้เป็นลูปได้ เนื่องจากนี่เป็นวิธีแก้ปัญหาที่ดีที่สุดฉันจึงทำเครื่องหมายว่านี่เป็นคำตอบที่ดีที่สุด

อย่างไรก็ตามขอให้เครดิตกับ VJo ด้วย GCC 4.6 ทำงานได้ดีกว่ามากสร้างโค้ดที่เล็กลงและเร็วขึ้น การใช้แบบจำลองขนาดใหญ่จะทำงานที่รหัสตามที่เป็นอยู่ ดังนั้นในทางเทคนิคนี่คือคำตอบที่ถูกต้อง แต่การเปลี่ยนแนวคิดทั้งหมดเป็นแนวทางที่ดีกว่ามาก

ขอบคุณทุกท่านสำหรับคำแนะนำและความช่วยเหลือ หากใครสนใจฉันจะโพสต์ผลสุดท้ายทันทีที่ฉันพร้อม

ข้อสังเกต: มีเพียงข้อสังเกตบางประการสำหรับคำตอบอื่น ๆ : รหัสที่ฉันพยายามเรียกใช้ไม่ได้เกิดจากการขยายฟังก์ชัน / อัลกอริทึมที่เรียบง่ายและการคลายตัวที่ไม่จำเป็น สิ่งที่เกิดขึ้นจริงคือสิ่งที่เราเริ่มต้นด้วยเป็นวัตถุทางคณิตศาสตร์ที่ค่อนข้างซับซ้อนและนำมันไปสู่รูปแบบที่คำนวณได้เชิงตัวเลขจะสร้างนิพจน์เหล่านี้ ปัญหาอยู่ที่ทฤษฎีทางกายภาพพื้นฐาน ความซับซ้อนของนิพจน์ระดับกลางจะปรับขนาดตามแฟกทอเรียลซึ่งเป็นที่รู้จักกันดี แต่เมื่อรวมสิ่งเหล่านี้ทั้งหมดเข้ากับสิ่งที่วัดได้ทางกายภาพซึ่งเป็นสิ่งที่สังเกตได้ - มันจะลดลงเหลือเพียงไม่กี่ฟังก์ชันที่เป็นพื้นฐานของนิพจน์ (มีบางอย่าง "ผิด" แน่นอนในแง่นี้กับทั่วไปและใช้ได้เฉพาะansatzซึ่งเรียกว่า "ทฤษฎีการก่อกวน") เราพยายามนำ ansatz นี้ไปสู่อีกระดับหนึ่งซึ่งไม่สามารถวิเคราะห์ได้อีกต่อไปและไม่ทราบพื้นฐานของฟังก์ชันที่จำเป็น เราก็เลยพยายามบังคับมันแบบนี้ ไม่ใช่วิธีที่ดีที่สุด แต่หวังว่าจะเป็นวิธีที่ช่วยให้เราเข้าใจฟิสิกส์ได้ในที่สุด ...

แก้ไขล่าสุด: ขอบคุณคำแนะนำทั้งหมดของคุณฉันสามารถลดขนาดโค้ดลงได้มากโดยใช้ Mathematica และการปรับเปลี่ยนตัวสร้างโค้ดสำหรับfuncs ตามแนวของคำตอบด้านบน :)

ฉันได้ทำให้cscฟังก์ชั่นง่ายขึ้นด้วย Mathematica โดยลดขนาดลงเหลือ 92 MB นี่คือส่วนที่ไม่สามารถแก้ไขได้ ความพยายามครั้งแรกใช้เวลาตลอดไป แต่หลังจากการเพิ่มประสิทธิภาพบางอย่างตอนนี้จะทำงานผ่านในเวลาประมาณ 10 นาทีบน CPU ตัวเดียว

เอฟเฟกต์ที่มีต่อfuncs นั้นน่าทึ่ง: ขนาดโค้ดทั้งหมดสำหรับพวกเขาลดลงเหลือประมาณ 9 MB ดังนั้นโค้ดจึงรวมอยู่ในช่วง 100 MB ตอนนี้มันสมเหตุสมผลแล้วที่จะเปิดการเพิ่มประสิทธิภาพและการดำเนินการก็ค่อนข้างเร็ว

ขอขอบคุณทุกท่านอีกครั้งสำหรับคำแนะนำฉันได้เรียนรู้มากมาย


17
หากคุณมีข้อมูลมากขนาดนั้นคุณควรย้ายออกจากไฟล์ต้นฉบับและแทนที่mmapด้วยตัวคุณเองจากไบนารีภายนอกที่รันไทม์
R .. GitHub STOP HELPING ICE

3
คุณช่วยยกตัวอย่างหนึ่ง (หรือสอง) ของฟังก์ชันเหล่านี้ได้ไหม นี่ดูแปลกจริงๆ คุณยังสามารถโหลดฟังก์ชันเหล่านี้แบบไดนามิกด้วยฟังก์ชัน dl *
Patrick Schlüter

7
@bbtrb: สัญชาตญาณแรกของฉันคล้ายกับ R .. ดูเหมือนปัญหาในการออกแบบ เป็นที่ยอมรับว่าฉันไม่รู้ว่ามีอะไรเกิดขึ้นทั่วไปในวงการคอมพิวเตอร์ทางวิทยาศาสตร์ แต่ฉันไม่เคยได้ยินว่ามีใครพยายามเชื่อมโยงไฟล์ออบเจ็กต์ 2.8GB หรืออะไรก็ตามที่อยู่ใกล้ ๆ จากระยะไกลและฉันไม่แน่ใจว่า GCC จะสนับสนุนอย่างแท้จริง ตรงไปตรงมาฉันคาดหวังว่าโค้ดใด ๆ ที่มีขนาดเท่าสปาเก็ตตี้บริสุทธิ์
Nicholas Knight

46
ไม่มีวิธีใดที่วิธีแก้ปัญหาที่ดีที่สุดสำหรับปัญหานี้เกี่ยวข้องกับไฟล์อ็อบเจ็กต์ 2gb
David Heffernan

35
อย่าใส่รหัสของคุณ
David Heffernan

คำตอบ:


53

ดังนั้นคุณมีโปรแกรมที่สร้างข้อความนี้แล้ว:

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 -...

ขวา?

หากฟังก์ชันทั้งหมดของคุณมี "รูปแบบ" ที่คล้ายกัน (คูณ n ตัวเลข m คูณและเพิ่มผลลัพธ์ - หรือสิ่งที่คล้ายกัน) ฉันคิดว่าคุณสามารถทำได้:

  • เปลี่ยนโปรแกรมเครื่องกำเนิดไฟฟ้าเป็นเอาต์พุตออฟเซ็ตแทนสตริง (เช่นแทนที่จะเป็นสตริง "s.ds0" ซึ่งจะสร้าง offsetof(ProcessVars, ds0)
  • สร้างอาร์เรย์ของการชดเชยดังกล่าว
  • เขียนผู้ประเมินซึ่งยอมรับอาร์เรย์ด้านบนและที่อยู่ฐานของตัวชี้โครงสร้างและสร้างผลลัพธ์

อาร์เรย์ + ผู้ประเมินจะแสดงตรรกะเดียวกันกับฟังก์ชันหนึ่งของคุณ แต่มีเพียงผู้ประเมินเท่านั้นที่เป็นรหัส อาร์เรย์คือ "ข้อมูล" และสามารถสร้างขึ้นที่รันไทม์หรือบันทึกไว้ในดิสก์และอ่าน i chunks หรือไฟล์ที่แมปหน่วยความจำ

ตัวอย่างเช่นคุณโดยเฉพาะใน func1 จินตนาการว่าคุณจะเขียนฟังก์ชั่นผ่านทางผู้ประเมินถ้าคุณมีการเข้าถึงไปยังที่อยู่ที่ฐานของsและcscและยังเป็นเวกเตอร์เหมือนเป็นตัวแทนของค่าคงที่และการชดเชยที่คุณต้องการที่จะเพิ่มไปยังที่อยู่ฐานที่จะได้รับx14, ds8และcsc[51370]

คุณต้องสร้าง "ข้อมูล" รูปแบบใหม่ที่จะอธิบายวิธีการประมวลผลข้อมูลจริงที่คุณส่งผ่านไปยังฟังก์ชันจำนวนมากของคุณ


45

x86-64 ABI ใช้ลินุกซ์โดยกำหนด "รุ่นใหญ่" โดยเฉพาะเพื่อหลีกเลี่ยงข้อ จำกัด ของขนาดดังกล่าวซึ่งรวมถึงประเภท 64 บิตสำหรับการย้ายถิ่นฐานและ GOT PLT (ดูตารางในหัวข้อ 4.4.2 และลำดับคำสั่งใน 3.5.5 ซึ่งแสดงวิธีการใช้งาน)

เนื่องจากฟังก์ชั่นของคุณใช้พื้นที่ 2.8 GB คุณจึงโชคไม่ดีเพราะ gcc ไม่รองรับรุ่นใหญ่ สิ่งที่คุณทำได้คือการจัดระเบียบรหัสของคุณใหม่ในลักษณะที่จะช่วยให้คุณสามารถแบ่งมันออกเป็นไลบรารีที่ใช้ร่วมกันซึ่งคุณจะเชื่อมโยงแบบไดนามิก

หากเป็นไปไม่ได้ตามที่มีคนแนะนำแทนที่จะใส่ข้อมูลของคุณลงในโค้ด (รวบรวมและเชื่อมโยง) เนื่องจากมีขนาดใหญ่คุณสามารถโหลดได้ในขณะรัน (ไม่ว่าจะเป็นไฟล์ปกติหรือคุณสามารถ mmap ก็ได้)

แก้ไข

ดูเหมือนว่าโมเดลขนาดใหญ่รองรับโดย gcc 4.6 (ดูหน้านี้ ) คุณสามารถลองได้ แต่ข้างต้นยังคงใช้กับการจัดระเบียบโค้ดของคุณใหม่


ดังนั้นสิ่งที่คุณกำลังพูดคือเมื่อฉันจะจัดกลุ่มไฟล์อ็อบเจ็กต์ในไลบรารีที่ใช้ร่วมกันขนาดเล็กหลาย ๆ ไลบรารีฉันจะเอาชนะข้อ จำกัด ได้หรือไม่
bbtrb

3
@bbtrb ขวา. แต่ฉันยังคงค้นหาวิธีอื่นในการใช้ฟังก์ชันของคุณ ฉันพนันได้เลยว่าการรวบรวมของคุณจะใช้เวลาตลอดไป
BЈовић

18
WTF? โค้ดนี้ต้องสร้างโดยสคริปต์บางตัว ไม่มีใครเขียนโค้ดด้วยมือเป็นเมกะไบต์! ตรรกะเดียวกันกับที่สร้างรหัสสามารถใช้เพื่อรันการคำนวณได้
zvrba

6
ฉันขอแนะนำอย่างยิ่งให้ลองใช้ gcc 4.6 ซึ่งมีโอกาสมากที่จะสร้างรหัสที่เหนือกว่าสำหรับโปรแกรมนี้มากกว่า gcc 4.1 มันอาจจะสามารถบีบทั้งสิ่งให้เป็น 2GB ได้โดยที่คุณไม่ต้องทำอะไรที่ฉลาดเลยเพื่อขจัดปัญหา (ลองใช้ชุด -Os, -fwhole-program และ -flto - ด้วยโค้ดปริมาณนี้การปรับขนาดให้เหมาะสมคือการปรับความเร็วให้เหมาะสม) อย่างไรก็ตามหากยังไม่ช่วยเพียงพอคุณควรทราบด้วยว่าเพื่อให้โมเดลขนาดใหญ่ใช้งานได้คุณจะต้องสร้างไลบรารี C อย่างน้อยบางส่วนในโมเดลขนาดใหญ่ (crt * .o, libc_nonshared.a และ libpthread_nonshared.a)
zwol

1
@bdonlan การเชื่อมโยงแบบคงที่ก็เป็นไปได้เช่นกัน
zvrba

37

ด้วยโปรแกรมของฝั่งนั้นการพลาดแคชสำหรับโค้ดมีแนวโน้มที่จะเกินค่าใช้จ่ายในการวนซ้ำในรันไทม์ ฉันอยากจะแนะนำให้คุณกลับไปที่ตัวสร้างโค้ดของคุณและให้มันสร้างการแสดงที่กะทัดรัดสำหรับสิ่งที่ต้องการประเมิน (เช่นอันที่น่าจะพอดีกับ D-cache) จากนั้นดำเนินการกับล่ามในโปรแกรมของคุณ นอกจากนี้คุณยังสามารถดูว่าคุณสามารถแยกเมล็ดขนาดเล็กที่ยังมีการดำเนินการจำนวนมากได้หรือไม่จากนั้นใช้เป็น 'คำแนะนำ' ในรหัสที่ตีความ


21

ข้อผิดพลาดเกิดขึ้นเนื่องจากคุณมีรหัสมากเกินไปไม่ใช่ข้อมูล! สิ่งนี้ถูกระบุโดยตัวอย่าง__libc_csu_fini(ซึ่งเป็นฟังก์ชัน) ที่อ้างอิงจาก_startและการย้ายตำแหน่งจะถูกตัดให้พอดี ซึ่งหมายความว่า_start (จุดเริ่มต้นที่แท้จริงของโปรแกรม) พยายามเรียกใช้ฟังก์ชันนั้นผ่านออฟเซ็ต 32 บิตที่ลงชื่อซึ่งมีช่วง 2 GB เท่านั้น เนื่องจากจำนวนรหัสออบเจ็กต์ของคุณทั้งหมดอยู่ที่ ~ 2.8 GB โปรดตรวจสอบข้อเท็จจริง

หากคุณสามารถออกแบบโครงสร้างข้อมูลของคุณใหม่โค้ดส่วนใหญ่ของคุณอาจถูก "บีบอัด" โดยเขียนนิพจน์ขนาดใหญ่ขึ้นมาใหม่เป็นลูปง่ายๆ

นอกจากนี้คุณสามารถคำนวณcsc[]ในโปรแกรมอื่นจัดเก็บผลลัพธ์ในไฟล์และโหลดเมื่อจำเป็น


คุณช่วยยกตัวอย่างได้ไหมว่าคุณจะเขียนฟังก์ชันใหม่ด้วยลูปง่ายๆได้อย่างไร ฉันไม่ทำตามคุณแน่ ๆ csc[]ต้องคำนวณบ่อยมากและฉันต้องการหลีกเลี่ยงดิสก์ I / O
bbtrb

4
@bbtr: ตัวอย่างfunc1ข้างต้นสิ่งที่ชอบ: for (int i = 0; i < N; ++i) expr += constants[i].*s.x14*s.x15*csc[49300 + i];.
HighCommander4

@ HighCommander4: แน่นอนฉันเห็นด้วย มันอยู่เหนือหัวของฉันที่จะสร้างสิ่งนี้โดยอัตโนมัติ อาจจะมีอาร์เรย์แยกต่างหากที่เก็บดัชนี ...
bbtrb

2
@bbtrb: เนื่องจากไม่มีวิธีที่แปลกประหลาดที่ใคร ๆ ก็เขียนซอร์สโค้ดมากพอที่จะสร้างโค้ดอ็อบเจ็กต์ 2.8GB ด้วยมือโดยเฉพาะอย่างยิ่งกับชื่อสัญลักษณ์ที่ไม่ช่วยในการจำเช่นนี้จึงต้องใช้ตัวสร้างรหัส ทำงานกับสิ่งนั้น
Donal Fellows

15

ฉันคิดว่าทุกคนเห็นด้วยว่าควรมีวิธีอื่นในการทำสิ่งที่คุณต้องการทำ การรวบรวมโค้ดหลายร้อยเมกะไบต์ (กิกะไบต์?) เชื่อมโยงเข้ากับไฟล์ปฏิบัติการขนาดหลายกิกะไบต์และเรียกใช้งานมันก็ฟังดูไม่มีประสิทธิภาพมาก

ถ้าฉันเข้าใจปัญหาของคุณอย่างถูกต้องคุณจะใช้ตัวสร้างรหัสบางประเภท G เพื่อสร้างฟังก์ชันมากมายfunc1...Nที่ใช้แผนที่จำนวนมากcsc1...Mเป็นอินพุต สิ่งที่คุณต้องการจะทำคือการคำนวณcsc1...Mและเรียกห่วง 1,000,000 s = func1 + func2 + ... + funcNครั้งสำหรับปัจจัยการผลิตที่แตกต่างกันและทุกครั้งที่พบกับ คุณไม่ได้ระบุว่าfucn1...Nเกี่ยวข้องcsc1...Mอย่างไร

หากทุกอย่างเป็นจริงดูเหมือนว่าคุณควรจะสามารถแก้ไขปัญหาในรูปแบบที่แตกต่างออกไปซึ่งสามารถจัดการได้มากกว่าและอาจเร็วกว่า (เช่นปล่อยให้แคชของเครื่องทำงานได้จริง)

นอกจากปัญหาในทางปฏิบัติของขนาดไฟล์ออบเจ็กต์แล้วโปรแกรมปัจจุบันของคุณจะไม่มีประสิทธิภาพเนื่องจากไม่ได้แปลการเข้าถึงข้อมูล (แผนที่ขนาดใหญ่มากเกินไป) และไม่มีการเรียกใช้โค้ดที่แปลเป็นภาษาท้องถิ่น (มีฟังก์ชันที่ยาวมากเกินไป)

วิธีแบ่งโปรแกรมของคุณออกเป็น 3 เฟส: เฟส 1 สร้างcsc1...Mและจัดเก็บ ขั้นตอนที่ 2 สร้างทีfuncละรายการเรียกใช้ 1,000,000 ครั้งกับแต่ละอินพุตและเก็บผลลัพธ์ ระยะที่ 3 หาผลรวมของผลลัพธ์ที่จัดเก็บไว้func1...Nสำหรับแต่ละครั้งที่หมด 1,000,000 ครั้ง ส่วนที่ดีเกี่ยวกับโซลูชันนี้คือสามารถสร้างแบบขนานบนเครื่องอิสระหลายเครื่องได้อย่างง่ายดาย

แก้ไข: @bbtrb คุณช่วยสร้าง func หนึ่งอันและ csc หนึ่งอันใช้ได้ไหม ดูเหมือนว่าจะมีความสม่ำเสมอและสามารถบีบอัดได้สูง ตัวอย่างเช่น func1 ดูเหมือนจะเป็นเพียงผลรวมของนิพจน์แต่ละรายการประกอบด้วยค่าสัมประสิทธิ์ 1 ตัวดัชนี 2 ตัวสำหรับตัวแปรใน s และ 1 ดัชนีใน csc จึงสามารถลดลงเป็นลูปได้ หากคุณมีตัวอย่างทั้งหมดฉันแน่ใจว่าจะพบวิธีบีบอัดเป็นลูปแทนที่จะเป็นนิพจน์ยาว ๆ


ใช่คุณเข้าใจถูกต้อง :) มีปัญหาหลายประการเกี่ยวกับคำแนะนำของคุณ: 1. สิ่งที่แย่ที่สุดfuncขึ้นอยู่กับ s เกือบทั้งหมดcscและตัวเลขเหล่านั้นจะต้องคำนวณ 10 ^ 6 ครั้งด้วย 2. อินพุตจะได้รับจากตัวปรับแต่งมอนติคาร์โลซึ่งหมายความว่าผู้รวมต้องทราบผลลัพธ์ทั้งหมดในแต่ละจุดเพื่อให้สามารถลดข้อผิดพลาดที่เกิดขึ้นได้โดยการปรับแต่งตาข่ายในบริเวณใกล้เคียงของจุดหากจำเป็น 3. นิพจน์ขนาดใหญ่สำหรับการcscคงอยู่ ...
bbtrb

1
หมายความว่าคุณไม่สามารถคำนวณแต่ละครั้งcscในการวนซ้ำแต่ละครั้งโดยไม่ขึ้นกับค่าอื่น ๆ ได้หรือไม่? หากเป็นอิสระคุณยังคงเรียกใช้แต่ละ 10 ^ 6 ครั้งและเก็บผลลัพธ์ได้ อย่างไรก็ตามหากมีการอ้างอิงในหมู่พวกเขาบางทีคุณอาจต้องหาว่าอันไหนเกี่ยวข้องกับอะไรเช่นกราฟการอ้างอิงจากนั้นลองดูว่าคุณสามารถแบ่งมันออกเป็นกราฟย่อยอิสระหลาย ๆ กราฟได้หรือไม่ โดยรวมแล้วฉันคิดว่ากุญแจสำคัญคือการแบ่งปัญหาออกเป็นหลาย ๆ ปัญหาย่อยที่เป็นอิสระ
AlefSin

5

หากฉันอ่านข้อผิดพลาดของคุณอย่างถูกต้องสิ่งที่ทำให้คุณดำเนินการเกินขีด จำกัด คือส่วนข้อมูลเริ่มต้น (หากเป็นรหัสคุณจะมีข้อผิดพลาดมากกว่า IMHO) คุณมีอาร์เรย์ข้อมูลส่วนกลางขนาดใหญ่หรือไม่? หากเป็นกรณีนี้ฉันจะปรับโครงสร้างโปรแกรมใหม่เพื่อให้มีการจัดสรรแบบไดนามิก หากข้อมูลเริ่มต้นฉันจะอ่านจากไฟล์กำหนดค่า

BTW เห็นสิ่งนี้:

(.text + 0x20): ไม่ได้กำหนดการอ้างอิงถึง `main '

ฉันคิดว่าคุณมีปัญหาอื่น


1
ใช่คุณพูดถูกความผิดพลาดโง่ ๆ แต่มันไม่ได้แก้ข้อผิดพลาดอื่น ๆ
bbtrb

3

สำหรับฉันดูเหมือนว่าโค้ดกำลังทำการรวมตัวเลขโดยใช้วิธีการปรับความลึกแบบปรับได้ แต่น่าเสียดายที่รหัสเครื่องกำเนิดไฟฟ้า (หรือมากกว่าผู้เขียนของเครื่องกำเนิดไฟฟ้ารหัส) จึงเป็นเรื่องโง่ที่จะสร้างฟังก์ชันหนึ่งต่อแพทช์มากกว่าต่อหนึ่งประเภทของแพทช์ ด้วยเหตุนี้จึงมีการสร้างโค้ดมากเกินไปที่จะคอมไพล์และแม้ว่าจะสามารถคอมไพล์ได้การดำเนินการก็จะเป็นเรื่องที่เจ็บปวดเพราะไม่มีอะไรแบ่งปันได้ทุกที่ (คุณลองนึกภาพความเจ็บปวดที่เกิดจากการต้องโหลดรหัสออบเจ็กต์แต่ละหน้าจากดิสก์เนื่องจากไม่มีการแชร์อะไรเลยดังนั้นจึงมักเป็นตัวเลือกให้ OS ขับไล่ไม่ต้องพูดแคชคำสั่งซึ่งจะไม่มีประโยชน์)

การแก้ไขคือการหยุดคลายทุกอย่าง สำหรับรหัสประเภทนี้คุณต้องการเพิ่มการแบ่งปันให้มากที่สุดเนื่องจากค่าใช้จ่ายของคำสั่งพิเศษในการเข้าถึงข้อมูลในรูปแบบที่ซับซ้อนมากขึ้นจะถูกดูดซับโดยค่าใช้จ่ายในการจัดการกับชุดข้อมูลพื้นฐานขนาดใหญ่ (น่าจะเป็น) อยู่ดี นอกจากนี้ยังเป็นไปได้ว่าตัวสร้างรหัสจะทำสิ่งนี้ตามค่าเริ่มต้นและนักวิทยาศาสตร์เห็นตัวเลือกบางอย่างสำหรับการคลาย (โดยสังเกตว่าบางครั้งสิ่งเหล่านี้จะปรับปรุงความเร็ว) และเปิดใช้งานทั้งหมดในครั้งเดียวและตอนนี้ยืนยันว่าจะยอมรับข้อผิดพลาดที่เกิดขึ้นนี้ โดยคอมพิวเตอร์แทนที่จะยอมรับข้อ จำกัด จริงของเครื่องและใช้เวอร์ชันที่ถูกต้องตามตัวเลขที่สร้างขึ้นโดยค่าเริ่มต้น แต่ถ้าตัวสร้างโค้ดไม่ทำให้รับรหัสที่จะ (หรือแฮ็กโค้ดที่มีอยู่)

บรรทัดล่าง:การรวบรวมและเชื่อมโยงโค้ด 2.8GB ไม่ทำงานและไม่ควรบังคับให้ทำงาน หาวิธีอื่น.


3

คำแนะนำสองสามข้อ: - ปรับขนาดให้เหมาะสม (-Os) เรียกใช้ฟังก์ชันแบบอินไลน์ของคุณเรียกฟังก์ชันปกติ เปิดใช้งานการรวมสตริง

ลองแบ่งสิ่งต่างๆออกเป็น DLL (วัตถุที่ใช้ร่วมกัน, .so สำหรับ linux, .dylib สำหรับ Mac OS X) ตรวจสอบให้แน่ใจว่าสามารถยกเลิกการโหลดได้ จากนั้นใช้บางสิ่งเพื่อโหลดสิ่งต่างๆตามต้องการและปลดปล่อยเมื่อไม่จำเป็น

หากไม่เป็นเช่นนั้นให้แยกโค้ดของคุณออกเป็นไฟล์ปฏิบัติการที่แตกต่างกันและใช้บางอย่างเพื่อสื่อสารระหว่างกัน (ไปป์ซ็อกเก็ตหรือแม้แต่การเขียน / อ่านไปยังไฟล์) ซุ่มซ่าม แต่คุณมีทางเลือกอะไรบ้าง?

ทั้งหมดทางเลือก: - การใช้ภาษาแบบไดนามิกที่มีJIT อยู่บนหัวของฉัน - ใช้LuaJIT - และเขียนใหม่ (สร้างใหม่?) นิพจน์เหล่านี้จำนวนมากในLuaหรือภาษาและเวลาทำงานอื่น ๆ ที่อนุญาตให้เก็บรหัสเป็นขยะ

LuaJIT ค่อนข้างมีประสิทธิภาพบางครั้งก็เอาชนะ C / C ++ สำหรับบางสิ่ง แต่มักจะเข้าใกล้มาก (บางครั้งอาจช้าเนื่องจากการเก็บขยะไม่ดี) ตรวจสอบตัวเอง:

http://luajit.org/performance_x86.html

ดาวน์โหลดscimark2.luaไฟล์จากที่นั่นและเปรียบเทียบกับเวอร์ชัน "C" (google it) - ผลลัพธ์มักจะใกล้เคียงมาก


2

ตัวเชื่อมโยงกำลังพยายามสร้างออฟเซ็ตการย้ายตำแหน่ง 32 บิตภายในไบนารีที่เกินข้อ จำกัด เหล่านี้ ลองลดความต้องการพื้นที่แอดเดรสของโปรแกรมหลัก

คุณสามารถแยกรหัสออบเจ็กต์บางส่วน / ส่วนใหญ่ออกเป็นไลบรารีอย่างน้อยหนึ่งไลบรารีได้หรือไม่ (คอมไพล์ด้วย -fpic / -fPIC) จากนั้นสร้างไบนารีแบบไม่คงที่ที่เชื่อมโยงกับ libs เหล่านี้ ไลบรารีจะอยู่ในบล็อกหน่วยความจำที่ไม่ต่อเนื่องและการชดเชยการย้ายของคุณจะเป็นแบบไดนามิก / สัมบูรณ์ (64 บิต) แทนที่จะเป็นแบบสัมพัทธ์ (32 บิต)


2

สำนวนเหล่านั้นดูเหมือนกับซีรีส์ที่สลับกันสำหรับฉัน ฉันไม่รู้ว่าส่วนที่เหลือของโค้ดจะเป็นอย่างไร แต่ดูเหมือนว่ามันจะไม่ยากที่จะหานิพจน์ที่สร้างขึ้นมา มันอาจจะคุ้มค่าในเวลาดำเนินการเช่นกันโดยเฉพาะอย่างยิ่งถ้าคุณมี 2.8 GB ของ 2 KB unrolled code


1

ดูเหมือนว่าผลลัพธ์ของการสร้างโค้ดจะผิดพลาดบางทีอาจเกิดจากพีชคณิตสัญลักษณ์และ / หรือการคลายการสุ่มด้วยตนเอง การปรับแต่งสัญลักษณ์เป็นที่ทราบกันดีว่าเติบโตแบบทวีคูณในความลึกของแผนภูมิการแสดงออกหรือกราฟเชิงคำนวณ เป็นไปได้ว่าสามารถใช้การสร้างความแตกต่างโดยอัตโนมัติได้ที่นี่ซึ่งจะทำให้ขนาดโค้ดค่อนข้างเล็กและเร่งความเร็วในการดำเนินการอย่างมาก

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.