อะไรคือกลยุทธ์ที่ดีสำหรับการปรับปรุงประสิทธิภาพของรหัสของฉัน


66

ฉันทำงานในวิทยาศาสตร์การคำนวณและด้วยเหตุนี้ฉันจึงใช้เวลาไม่มากกับการพยายามเพิ่มปริมาณงานทางวิทยาศาสตร์ของรหัสจำนวนมากรวมทั้งการทำความเข้าใจประสิทธิภาพของรหัสเหล่านี้

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

อะไรคือสิ่งสำคัญที่สุดที่ควรลองก่อน ฉันจะรู้ได้อย่างไรว่าได้ประสิทธิภาพมากแค่ไหน?

คำตอบ:


66

ก่อนอื่นเลยในฐานะช่างฝีมือและแดนได้ชี้ให้เห็นว่าการทำโปรไฟล์เป็นสิ่งจำเป็น ฉันใช้VTune AmplifierบนIntelเป็นการส่วนตัวเพราะมันให้ภาพรวมที่ละเอียดมากว่าเวลาใช้ไปทำอะไร

หากคุณจะไม่เปลี่ยนอัลกอริทึม (เช่นหากไม่มีการเปลี่ยนแปลงที่สำคัญซึ่งจะทำให้การเพิ่มประสิทธิภาพทั้งหมดของคุณล้าสมัย) ดังนั้นฉันขอแนะนำให้มองหารายละเอียดการติดตั้งทั่วไปที่อาจทำให้เกิดความแตกต่างใหญ่:

  • หน่วยความจำท้องถิ่น : ข้อมูลที่อ่าน / ใช้ร่วมกันถูกจัดเก็บไว้ด้วยกันหรือไม่หรือคุณกำลังรวบรวมบิตและส่วนต่าง ๆ

  • การจัดตำแหน่งหน่วยความจำ : คู่ของคุณอยู่ในแนวเดียวกันถึง 4 ไบต์หรือไม่ คุณแพ็คของคุณstructsอย่างไร เพื่อเป็นความรู้ให้ใช้แทนposix_memalignmalloc

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

  • Vectorization : ไม่ไม่ต้องกังวลกับแอสเซมเบลอร์ที่เขียนด้วยมือ gccเสนอประเภทเวกเตอร์ที่แปลเป็น SSE / AltiVec / คำแนะนำแบบอัตโนมัติ

  • Instruction-Level Parallelism : บุตรชายนอกสมรสของ vectorization หากการคำนวณที่เกิดซ้ำบ่อยครั้งบางอย่างไม่ได้ทำให้เกิดเวกเตอร์ที่ดีคุณสามารถลองรวบรวมค่าอินพุตและคำนวณค่าหลายค่าพร้อมกัน มันเหมือนกับวงวนที่คลี่ออก สิ่งที่คุณใช้ประโยชน์จากที่นี่คือโดยปกติแล้ว CPU ของคุณจะมีหน่วยทศนิยมมากกว่าหนึ่งต่อแกน

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

บางส่วนของเทคนิคเหล่านี้จะถูกนำมาใช้ในdaxpy_cvec นี้ด้าย ต้องบอกว่าถ้าคุณใช้ Fortran (ไม่ใช่ภาษาระดับต่ำในหนังสือของฉัน) คุณจะสามารถควบคุม "ลูกเล่น" เหล่านี้ได้เล็กน้อย

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

ปรับปรุง

นานมาแล้วที่ฉันเขียนสิ่งนี้และฉันไม่ได้สังเกตว่ามันได้กลายเป็นคำตอบยอดนิยม ด้วยเหตุนี้ฉันต้องการเพิ่มจุดสำคัญหนึ่งข้อ:

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

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

จากประสบการณ์ของฉันในฐานะนักวิทยาศาสตร์คอมพิวเตอร์ (CS) เคล็ดลับคือการได้รับทั้งความคาดหวังและการสื่อสารที่ถูกต้อง

ความคาดหวังในทิศทางเดียว CS จะช่วยคุณได้ก็ต่อเมื่อเขา / เธอคิดว่าปัญหาของคุณน่าสนใจ สิ่งนี้ไม่รวมการพยายามเพิ่มประสิทธิภาพ / เวกเตอร์ / ขนานชิ้นส่วนของรหัสที่คุณเขียน แต่ไม่ได้ให้ความเห็นจริงๆสำหรับปัญหาที่พวกเขาไม่เข้าใจ CS มักสนใจปัญหาพื้นฐานเช่นอัลกอริทึมที่ใช้ในการแก้ปัญหา ไม่ให้พวกเขาของคุณแก้ปัญหาให้พวกเขาของคุณมีปัญหา

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

การสื่อสาร -wise จำไว้ว่า CSS ส่วนใหญ่จะไม่ผู้เชี่ยวชาญในสาขาของคุณและอธิบายปัญหาในแง่ของสิ่งที่คุณกำลังทำอยู่เมื่อเทียบกับวิธีการและเหตุผล เรามักจะไม่สนใจว่าทำไมและอะไรคือสิ่งที่เราทำได้ดีที่สุด

ตัวอย่างเช่นฉันกำลังทำงานกับพวงของการคำนวณ cosmologists ในการเขียนรุ่นที่ดีกว่าของรหัสจำลองของพวกเขาขึ้นอยู่กับSPHและmultipoles การประชุมประมาณสามครั้งเพื่อหยุดการพูดคุยในแง่ของสสารมืดและกาแล็กซี่รัศมี (huh?) และเจาะลึกลงไปถึงแกนกลางของการคำนวณนั่นคือพวกเขาต้องการค้นหาเพื่อนบ้านทั้งหมดภายในรัศมีที่กำหนดของแต่ละอนุภาค ปริมาณมากกว่าพวกเขาแล้วเรียกใช้เพื่อนบ้านที่กล่าวถึงทั้งหมดอีกครั้งและใช้ปริมาณนั้นในการคำนวณอื่น ๆ จากนั้นย้ายอนุภาคหรืออย่างน้อยก็บางส่วนและทำมันทั้งหมดอีกครั้ง คุณเห็นในขณะที่อดีตอาจน่าสนใจอย่างไม่น่าเชื่อ (คือ!) หลังคือสิ่งที่ฉันต้องเข้าใจเพื่อเริ่มคิดเกี่ยวกับอัลกอริทึม

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


4
เป็นเครื่องมือในการทำโปรไฟล์ไปฉันจะไม่ลืมเกี่ยวกับvalgrind
GertVdE

1
ฉันเห็นด้วยกับคุณเปโดรเมื่อโปรแกรมที่ได้รับการปรับให้เหมาะสมนั้นเปรียบเสมือนรถแข่ง F1 ใกล้จะถึงจุดสูงสุดแล้ว โปรแกรมที่ฉันเห็นในทางปฏิบัติทางวิทยาศาสตร์และไม่ใช่บ่อยครั้งมากขึ้นเช่น Cadillac Coupe DeVilles เพื่อให้ได้ประสิทธิภาพที่แท้จริงไขมันจำนวนมากสามารถถูกตัดออกไปได้ หลังจากนั้นวงจรการโกนหนวดก็จะเริ่มก้าวย่าง
Mike Dunlavey

1
@ MikeDunlavey: เห็นด้วยอย่างยิ่ง ฉันได้เพิ่มการอัปเดตลงในคำตอบของฉันเพื่อแก้ไขปัญหาที่เกี่ยวข้องกับอัลกอริทึมมากขึ้น
Pedro

1
@ MikeDunlavey ฉันเป็น CS พื้นบ้าน :)
Pedro

2
ฉันแสดงสิ่งนี้ในการพูดคุยที่ U Mass Lowell มันเป็นการสาธิตสดซึ่งแสดงทุกขั้นตอนของการเร่งความเร็ว 730x ฉันคิดว่าศาสตราจารย์คนหนึ่งมีประเด็นออกมาจากครึ่งโหล
Mike Dunlavey

38

ซอฟต์แวร์ทางวิทยาศาสตร์นั้นไม่แตกต่างจากซอฟต์แวร์อื่นมากเท่าที่จะทราบได้ว่าต้องปรับอะไร

วิธีที่ผมใช้คือการหยุดชั่วคราวสุ่ม นี่คือบางส่วนของ speedups ที่พบสำหรับฉัน:

หากใช้เวลาส่วนใหญ่ในฟังก์ชั่นเช่นlogและexpฉันสามารถดูว่าข้อโต้แย้งของฟังก์ชั่นเหล่านั้นเป็นฟังก์ชั่นของจุดที่พวกเขาถูกเรียกจาก บ่อยครั้งที่พวกเขาถูกเรียกซ้ำด้วยเหตุผลเดียวกัน ถ้าเป็นเช่นนั้นการบันทึกช่วยจำจะสร้างปัจจัยเร่งความเร็วขนาดใหญ่

ถ้าฉันใช้ฟังก์ชัน BLAS หรือ LAPACK ฉันอาจพบว่ามีการใช้เวลาส่วนใหญ่ในการทำสำเนาอาร์เรย์อาร์เรย์เมทริกซ์คูณการแปลง choleski เป็นต้น

  • รูทีนการคัดลอกอาร์เรย์ไม่ได้อยู่ที่ความเร็ว แต่มีเพื่อความสะดวก คุณอาจพบว่ามีวิธีที่สะดวกน้อยลง แต่เร็วกว่านั้น

  • รูทีนการคูณหรือกลับเมทริกซ์หรือใช้การแปลง choleski มักจะมีอาร์กิวเมนต์ตัวอักษรที่ระบุตัวเลือกเช่น 'U' หรือ 'L' สำหรับสามเหลี่ยมด้านบนหรือล่าง อีกครั้งที่มีเพื่อความสะดวก สิ่งที่ฉันพบคือเนื่องจากเมทริกซ์ของฉันไม่ใหญ่มากกิจวัตรใช้เวลามากกว่าครึ่งในการเรียกรูทีนย่อยเพื่อเปรียบเทียบอักขระเพื่อถอดรหัสตัวเลือก การเขียนเวอร์ชั่นคณิตศาสตร์ที่มีค่าใช้จ่ายมากที่สุดเพื่อเพิ่มความเร็วเป็นพิเศษ

ถ้าฉันสามารถขยายในภายหลัง: matrix-multiply กิจวัตร DGEMM เรียก LSAME เพื่อถอดรหัสอาร์กิวเมนต์ตัวละคร การดูเวลารวมเปอร์เซ็นต์ (สถิติที่ควรค่าแก่การดู) ผู้ดูโปรไฟล์ที่ถือว่า "ดี" สามารถแสดง DGEMM โดยใช้เปอร์เซ็นต์ของเวลาทั้งหมดเช่น 80% และ LSAME โดยใช้เปอร์เซ็นต์ของเวลาทั้งหมดเช่น 50% เมื่อมองไปที่อดีตคุณจะถูกล่อลวงให้พูดว่า "ต้องมีการปรับให้เหมาะสมอย่างมากดังนั้นจึงไม่สามารถทำอะไรได้มากนัก" เมื่อมองไปทางหลังคุณจะถูกล่อลวงให้พูดว่า "อืม? มีอะไรเกี่ยวกับอะไรบ้าง? นั่นเป็นเพียงกิจวัตรเล็ก ๆ น้อย ๆ ผู้สร้างนี้ต้องผิด!"

มันไม่ผิดหรอกมันแค่ไม่บอกคุณว่าคุณต้องรู้อะไร สิ่งที่หยุดชั่วคราวแบบสุ่มแสดงให้คุณเห็นว่า DGEMM อยู่ที่ 80% ของตัวอย่างสแต็กและ LSAME อยู่ที่ 50% (คุณไม่จำเป็นต้องมีตัวอย่างจำนวนมากในการตรวจสอบว่า 10 มักจะมีจำนวนมาก) ยิ่งไปกว่านั้นสำหรับตัวอย่างเหล่านี้จำนวนมาก DGEMM อยู่ในกระบวนการของการเรียก LSAMEจากรหัสที่ต่างกันสองบรรทัด

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

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

เพิ่ม: ดังนั้นเพื่อตอบคำถามสองข้อสุดท้ายของคุณ:

อะไรคือสิ่งสำคัญที่สุดที่ควรลองก่อน

ใช้ตัวอย่าง 10-20 กองและอย่าเพิ่งสรุปให้เข้าใจสิ่งที่แต่ละคนบอกคุณ ทำสิ่งนี้ก่อนสุดท้ายและในระหว่าง (ไม่มี "ลอง" รุ่นเยาว์ของ Skywalker)

ฉันจะรู้ได้อย่างไรว่าได้ประสิทธิภาพมากแค่ไหน?

ตัวอย่างสแต็กจะให้ค่าประมาณคร่าวๆของเศษส่วนของเวลาที่จะบันทึกให้คุณ (ตามหลังการกระจายโดยที่คือจำนวนตัวอย่างที่แสดงสิ่งที่คุณกำลังจะแก้ไขและคือจำนวนตัวอย่างทั้งหมดที่ไม่นับ ค่าใช้จ่ายของรหัสที่คุณใช้เพื่อแทนที่ซึ่งหวังว่าจะมีขนาดเล็ก) จากนั้นอัตราส่วนการเร่งความเร็วคือซึ่งอาจมีขนาดใหญ่ สังเกตว่ามันทำงานอย่างไรในเชิงคณิตศาสตร์ ถ้าและค่าเฉลี่ยและโหมดของคือ 0.5 สำหรับอัตราเร่งที่ 2 นี่คือการแจกแจง: หากคุณไม่ชอบความเสี่ยงใช่มีความน่าจะเป็นเล็กน้อย (.03%) ที่xβ(s+1,(ns)+1)sn1/(1x)n=10s=5x
ป้อนคำอธิบายรูปภาพที่นี่
xน้อยกว่า 0.1 สำหรับการเร่งความเร็วน้อยกว่า 11% แต่การปรับสมดุลที่มีความน่าจะเป็นเท่ากับที่มากกว่า 0.9 สำหรับอัตราส่วนการเร่งความเร็วที่มากกว่า 10! หากคุณได้รับเงินตามสัดส่วนของความเร็วโปรแกรมนั่นก็ไม่ได้เลวร้ายอะไรx

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

เพิ่ม: ในการตอบสนองต่อความกังวลของโดรส์เกี่ยวกับผลบวกเท็จให้ฉันลองสร้างตัวอย่างที่อาจเกิดขึ้นได้ เราไม่เคยดำเนินการกับปัญหาที่อาจเกิดขึ้นเว้นแต่ว่าเราเห็นสองครั้งหรือมากกว่านั้นดังนั้นเราคาดหวังว่าผลบวกปลอมจะเกิดขึ้นเมื่อเราเห็นปัญหาในเวลาที่น้อยที่สุดที่เป็นไปได้โดยเฉพาะอย่างยิ่งเมื่อจำนวนตัวอย่างทั้งหมดมีขนาดใหญ่ สมมติว่าเราใช้ 20 ตัวอย่างและดูสองครั้ง นั่นคือประมาณการค่าใช้จ่าย 10% ของเวลาดำเนินการทั้งหมดซึ่งเป็นโหมดการกระจายสินค้า (ค่าเฉลี่ยของการแจกแจงสูงกว่า - คือ .) กราฟล่างในกราฟต่อไปนี้คือการแจกแจง:(s+1)/(n+2)=3/22=13.6%

ป้อนคำอธิบายรูปภาพที่นี่

พิจารณาว่าเราใช้ตัวอย่างมากถึง 40 ตัวอย่าง (มากกว่าที่ฉันเคยมีในคราวเดียว) และเห็นปัญหาเพียงสองอย่างเท่านั้น ค่าใช้จ่ายโดยประมาณ (โหมด) ของปัญหานั้นคือ 5% ดังที่แสดงบนเส้นโค้งที่สูงขึ้น

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

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

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

ฉันจะแนะนำให้ผู้ใช้งานโปรไฟล์ทำการรายงานปัจจัยเร่งความเร็วที่พวกเขาได้รับจริง ๆ


มีอีกจุดที่ต้องทำอีกครั้ง คำถามของเปโดรเกี่ยวกับผลบวกผิด ๆ

เขากล่าวว่าอาจมีปัญหาในการแก้ไขปัญหาเล็ก ๆ ในโค้ดที่ปรับให้เหมาะสมอย่างมาก (สำหรับฉันปัญหาเล็ก ๆ คือปัญหาที่เกิดขึ้น 5% หรือน้อยกว่าของเวลาทั้งหมด)

เนื่องจากเป็นไปได้ทั้งหมดที่จะสร้างโปรแกรมที่เหมาะสมที่สุดโดยสิ้นเชิงยกเว้น 5% จุดนี้สามารถแก้ไขได้ด้วยสังเกตุเท่านั้นเช่นเดียวกับในคำตอบนี้ ในการพูดคุยจากประสบการณ์เชิงประจักษ์มันจะเป็นเช่นนี้:

โดยทั่วไปโปรแกรมดังกล่าวจะมีโอกาสมากมายในการปรับให้เหมาะสม (เราสามารถเรียกพวกเขาว่า "ปัญหา" แต่พวกเขามักจะเป็นรหัสที่ดีอย่างสมบูรณ์แบบสามารถปรับปรุงได้มาก) แผนภาพนี้แสดงให้เห็นว่าโปรแกรมเทียมใช้เวลาระยะหนึ่ง (100 วินาทีพูด) และมีปัญหา A, B, C ... ที่เมื่อพบและแก้ไขให้ลด 30%, 21% และอื่น ๆ จาก 100s ต้นฉบับ

ป้อนคำอธิบายรูปภาพที่นี่

โปรดสังเกตว่าปัญหา F มีค่าใช้จ่าย 5% ของเวลาดั้งเดิมดังนั้นจึงเป็น "เล็ก" และหาได้ยากโดยไม่มีตัวอย่าง 40 ตัวอย่างขึ้นไป

อย่างไรก็ตาม 10 ตัวอย่างแรกพบปัญหา A ได้ง่าย ** เมื่อแก้ไขแล้วโปรแกรมจะใช้เวลาเพียง 70 วินาทีในการเร่งความเร็ว 100/70 = 1.43x ที่ไม่เพียง แต่ทำให้โปรแกรมเร็วขึ้นมันขยายตามอัตราส่วนนั้นเปอร์เซ็นต์ที่เกิดจากปัญหาที่เหลืออยู่ ตัวอย่างเช่นปัญหา B เดิมใช้ 21s ซึ่งเป็น 21% ของยอดรวม แต่หลังจากลบ A แล้ว B จะใช้ 21s จาก 70 หรือ 30% ดังนั้นจึงง่ายต่อการค้นหาเมื่อทำซ้ำกระบวนการทั้งหมด

เมื่อกระบวนการซ้ำแล้วซ้ำอีกห้าครั้งตอนนี้เวลาดำเนินการคือ 16.8 วินาทีซึ่งปัญหา F คือ 30% ไม่ใช่ 5% ดังนั้น 10 ตัวอย่างจึงหาได้ง่าย

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

หากพบปัญหาและแก้ไข A ถึง F การเร่งความเร็วคือ 100 / 11.8 = 8.5x หากพลาดหนึ่งในนั้นตัวอย่างเช่น D การเพิ่มความเร็วจะมีเพียง 100 / (11.8 + 10.3) = 4.5x นั่นคือราคาที่จ่ายสำหรับการปฏิเสธเชิงลบ

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

** ใช้เวลาในการค้นหาปัญหาอย่างน้อย 2 ครั้งเว้นแต่จะมีความรู้มาก่อนว่ามีวงวนอนันต์ (ใกล้) (เครื่องหมายถูกสีแดงแสดงถึงกลุ่มตัวอย่าง 10 ตัวอย่าง) จำนวนตัวอย่างเฉลี่ยที่จำเป็นในการรับจำนวนครั้งที่เข้าชม 2 ครั้งขึ้นไปเมื่อปัญหาคือ 30% คือ ( การกระจายแบบทวินามลบ ) 10 ตัวอย่างพบว่ามันมีความน่าจะเป็น 85%, 20 ตัวอย่าง - 99.2% ( การกระจายแบบทวินาม ) ที่จะได้รับความน่าจะเป็นของการหาปัญหาใน R ประเมินตัวอย่างเช่น:2/0.3=6.671 - pbinom(1, numberOfSamples, sizeOfProblem)1 - pbinom(1, 20, 0.3) = 0.9923627

เพิ่ม: เศษส่วนของเวลาที่บันทึกตามหลังการแจกแจงโดยที่คือจำนวนตัวอย่างและคือหมายเลขที่แสดงปัญหา อย่างไรก็ตามอัตราการเร่งความเร็วเท่ากับ (สมมติทั้งหมดของจะถูกบันทึกไว้) และมันจะน่าสนใจที่จะเข้าใจการกระจายของปีปรากฎว่าเป็นไปตามการกระจายBetaPrime ฉันจำลองด้วยตัวอย่าง 2 ล้านตัวอย่างมาถึงพฤติกรรมนี้:β ( s + 1 , ( n - s ) + 1 ) n s y 1 / ( 1 - x ) x y y - 1xβ(s+1,(ns)+1)nsy1/(1x)xyy1

         distribution of speedup
               ratio y

 s, n    5%-ile  95%-ile  mean
 2, 2    1.58    59.30   32.36
 2, 3    1.33    10.25    4.00
 2, 4    1.23     5.28    2.50
 2, 5    1.18     3.69    2.00
 2,10    1.09     1.89    1.37
 2,20    1.04     1.37    1.17
 2,40    1.02     1.17    1.08

 3, 3    1.90    78.34   42.94
 3, 4    1.52    13.10    5.00
 3, 5    1.37     6.53    3.00
 3,10    1.16     2.29    1.57
 3,20    1.07     1.49    1.24
 3,40    1.04     1.22    1.11

 4, 4    2.22    98.02   52.36
 4, 5    1.72    15.95    6.00
 4,10    1.25     2.86    1.83
 4,20    1.11     1.62    1.31
 4,40    1.05     1.26    1.14

 5, 5    2.54   117.27   64.29
 5,10    1.37     3.69    2.20
 5,20    1.15     1.78    1.40
 5,40    1.07     1.31    1.17

สองคอลัมน์แรกให้ช่วงความมั่นใจ 90% สำหรับอัตราส่วนความเร็ว อัตราส่วนเพิ่มความเร็วเฉลี่ยเท่ากับยกเว้นกรณีที่ n ในกรณีนั้นมันไม่ได้กำหนดและแน่นอนเมื่อฉันเพิ่มจำนวนของค่าจำลอง , ค่าเฉลี่ยเชิงประจักษ์จะเพิ่มขึ้นs = n y(n+1)/(ns)s=ny

นี่คือพล็อตของการแจกแจงของปัจจัยเร่งความเร็วและค่าเฉลี่ยสำหรับ 2 ตัวอย่างจาก 5, 4, 3 และ 2 ตัวอย่าง ตัวอย่างเช่นหากมีการสุ่มตัวอย่าง 3 รายการและมี 2 รายการที่พบปัญหาและสามารถลบปัญหานั้นได้ปัจจัยการเร่งความเร็วเฉลี่ยจะเป็น 4x หากมีการพบ 2 Hit ในตัวอย่างเพียง 2 ตัวอย่างความเร็วเฉลี่ยจะไม่ได้กำหนด - เนื่องจากแนวคิดของโปรแกรมที่มีลูปไม่สิ้นสุดมีความเป็นไปได้ที่ไม่ใช่ศูนย์

ป้อนคำอธิบายรูปภาพที่นี่


1
อืม ... คุณไม่ได้รับข้อมูลนี้อย่างแน่นอนดูกราฟการโทรของผู้สร้างโปรไฟล์หรือ "สรุปจากล่าง" ประเภทที่ให้ไว้โดย VTune?
Pedro

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

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

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

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

23

ไม่เพียง แต่คุณต้องมีความสนิทสนมของคุณคอมไพเลอร์คุณยังมีความสนิทสนมของคุณสถาปัตยกรรมเป้าหมายและระบบปฏิบัติการ

สิ่งที่มีผลต่อประสิทธิภาพ?

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

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

แม้ว่าสถาปัตยกรรมเป้าหมายจะไม่เปลี่ยนแปลง แต่การเปลี่ยนแปลงระดับต่ำไปยังระบบปฏิบัติการก็สามารถส่งผลกระทบต่อประสิทธิภาพได้เช่นกัน แพทช์บรรเทาผลกระทบ Spectre and Meltdown มีผลกระทบอย่างมากในปริมาณงานบางส่วนดังนั้นสิ่งเหล่านี้อาจบังคับให้ประเมินผลการเพิ่มประสิทธิภาพของคุณอีกครั้ง

ฉันจะรักษารหัสของฉันให้เหมาะสมได้อย่างไร

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

Modularity ยังหมายถึงความสามารถในการใช้ชุดทดสอบเดียวกันในทุกรุ่นที่ดีที่สุดและ unoptimised ของคุณช่วยให้คุณสามารถตรวจสอบว่าพวกเขาทั้งหมดมีพฤติกรรมเดียวกันและรายละเอียดแต่ละคนได้อย่างรวดเร็วในเช่นสำหรับเช่นการเปรียบเทียบ ฉันเข้าไปดูรายละเอียดเพิ่มเติมเล็กน้อยในคำตอบของฉันเกี่ยวกับวิธีการจัดทำเอกสารและสอนคนอื่น ๆ "เพิ่มประสิทธิภาพเกินการจดจำ" รหัสเข้มข้นแบบคำนวณได้? .

อ่านเพิ่มเติม

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

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


8

ฉันคิดว่าคุณวลีคำถามแคบเกินไป ในมุมมองของฉันทัศนคติที่มีประโยชน์คือการใช้ชีวิตภายใต้สมมติฐานที่ว่าการเปลี่ยนแปลงโครงสร้างข้อมูลและอัลกอริธึมเท่านั้นที่สามารถเพิ่มประสิทธิภาพการทำงานที่สำคัญในโค้ดที่มีมากกว่า 100 บรรทัดและฉันเชื่อว่าฉันยังไม่พบตัวอย่าง การอ้างสิทธิ์นี้


3
เห็นด้วยในหลักการ แต่ไม่ควรประมาทการทำงานร่วมกันระหว่างประสิทธิภาพของอัลกอริทึม / โครงสร้างข้อมูลและรายละเอียดของฮาร์ดแวร์ที่เกี่ยวข้อง เช่นต้นไม้ไบนารีที่สมดุลนั้นยอดเยี่ยมสำหรับการค้นหา / จัดเก็บข้อมูล แต่ขึ้นอยู่กับเวลาแฝงของหน่วยความจำระดับโลกตารางแฮชอาจดีกว่า
Pedro

1
ตกลง อัลกอริทึมและโครงสร้างข้อมูลสามารถให้การปรับปรุง O (10) ถึง O (100) อย่างไรก็ตามสำหรับปัญหาขอบเขตการคำนวณสองสามข้อ (เช่นในการคำนวณระดับโมเลกุล, ฟิสิกส์ดาราศาสตร์, การประมวลผลภาพและวิดีโอแบบเรียลไทม์, การเงิน) ห่วงที่มีการปรับสูงนั้นอาจทำให้แอพพลิเคชั่นโดยรวมเร็วขึ้น
fcruz

ฉันเคยเห็นลูปซ้อนกันสั่งไม่ดีในรหัส "การผลิต" ที่มีขนาดใหญ่มาก นอกจากนั้นฉันคิดว่าคุณพูดถูก
dmckee

8

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

ลินุกซ์

gprofนั้นค่อนข้างดี แต่มันบอกได้แค่ว่าแต่ละฟังก์ชั่นนั้นใช้เวลาเท่าไรมากกว่าแต่ละบรรทัด

Apple OS X

คุณอาจต้องการที่จะลองฉลาม มันมีอยู่ในเว็บไซต์ของผู้พัฒนาแอปเปิ้ลอยู่ภายใต้การดาวน์โหลด> เครื่องมือสำหรับนักพัฒนา> CHUD 4.6.2, รุ่นเก่าที่นี่ CHUD ยังมีเครื่องมือการทำโปรไฟล์อื่น ๆ เช่นส่วนหน้า BigTop, เครื่องมือค้นหาดัชนี PMC, โปรไฟล์ระดับฟังก์ชั่นของ Saturn และคำสั่งอื่น ๆ มากมาย ฉลามจะมาพร้อมกับรุ่น commandline


+1 โปรไฟล์ไหม ใช่ในทาง ... มันดีกว่าการคาดเดา แต่นี่คือรายการของปัญหาที่ใช้กับ gprof โดยเฉพาะและกับ profilers อื่น ๆ อีกมากมาย
Mike Dunlavey

Shark เป็นคำสั่งเก่าใน OS X หรือไม่ เพิ่มเติมที่นี่ ด้วย Mountain Lion ฉันควรใช้เครื่องมือหรือไม่
hhh

@hhh: มันเป็น GUI ตัวแปลภาษาสำหรับ macs แต่ดูเหมือนว่ามันจะไม่ได้รับการบำรุงรักษาอีกต่อไป ฉันไม่ได้ตั้งโปรแกรมบนเครื่องแอปเปิ้ลตั้งแต่ฉันเขียนคำตอบนี้ดังนั้นฉันไม่สามารถช่วยคุณได้มากนัก
ด่าน

1
มีอยู่ในไซต์ Apple Developer ภายใต้ดาวน์โหลด> เครื่องมือสำหรับนักพัฒนา> CHUD 4.6.2 รุ่นเก่ากว่าที่นี่และมีทุกประเภทการทำโปรไฟล์โชคไม่ดีที่การติดตั้งนี้ไม่ประสบความสำเร็จ: "ติดต่อผู้ผลิต" ไม่มีความคิดเกี่ยวกับข้อผิดพลาด Shark ถูกนำออกจาก Xcode อย่างเห็นได้ชัดหลังจาก Lion และต่อมากลับสู่ไซต์ Apple Dev หลังจากเป็นเครื่องมือฟรีใน MacUpdate
hhh

@hhh: ดูเหมือนว่าคุณมีคุณสมบัติที่จะตอบคำถามนี้ได้ดีกว่าฉัน อย่าลังเลที่จะแก้ไขคำตอบของฉันเพื่ออัปเดตหรือเขียนของคุณเอง
ด่าน

7

สำหรับประสิทธิภาพที่คุณจะได้รับให้นำผลลัพธ์จากการทำโปรไฟล์รหัสของคุณและสมมติว่าคุณระบุชิ้นส่วนที่ใช้เวลาเพียงเศษเสี้ยว "p" หากคุณต้องปรับปรุงประสิทธิภาพของชิ้นส่วนนั้นโดยใช้เพียงปัจจัย "s" การเร่งความเร็วโดยรวมของคุณจะเป็น 1 / ((1-p) + p / s) ดังนั้นคุณสามารถเพิ่มความเร็วได้สูงสุดเพียง 1 / (1-p) หวังว่าคุณจะมีพื้นที่สูง p! นี่คือกฎของAmdahlสำหรับการเพิ่มประสิทธิภาพแบบอนุกรม


5

การเพิ่มประสิทธิภาพรหัสของคุณจะต้องทำอย่างระมัดระวัง สมมติว่าคุณได้ดีบั๊กโค้ดเรียบร้อยแล้ว คุณสามารถประหยัดเวลาได้มากหากคุณทำตามลำดับความสำคัญเช่น:

  1. ใช้ไลบรารีที่ปรับให้เหมาะสมที่สุด (หรือปรับให้เหมาะสมที่สุดกับมืออาชีพ) หากเป็นไปได้ ตัวอย่างบางส่วนอาจรวมถึง FFTW, OpenBlas, Intel MKL, NAG ไลบรารี่เป็นต้นยกเว้นว่าคุณมีความสามารถสูง (เช่นนักพัฒนาของ GotoBLAS) คุณอาจไม่สามารถเอาชนะมืออาชีพได้

  2. ใช้ profiler (มีไม่กี่รายในรายการต่อไปนี้ที่มีชื่ออยู่ในเธรดนี้แล้ว - Intel Tune, valgrind, gprof, gcov, ฯลฯ ) เพื่อค้นหาว่าส่วนใดของรหัสของคุณใช้เวลามากที่สุด ไม่เสียเวลาในการปรับแต่งส่วนต่าง ๆ ของรหัสที่ไม่ค่อยมีใครเรียก

  3. จากผลลัพธ์ของ profiler ให้ดูที่ส่วนของรหัสของคุณที่ใช้เวลามากที่สุด กำหนดลักษณะของอัลกอริธึมของคุณคืออะไร - CPU นั้นถูกผูกไว้หรือมีหน่วยความจำถูกผูกไว้หรือไม่? แต่ละชุดต้องใช้เทคนิคการปรับให้เหมาะสมต่างกัน หากคุณพลาดแคชจำนวนมากหน่วยความจำอาจเป็นปัญหาคอขวดเพราะ CPU กำลังสูญเสียวงจรนาฬิกาเพื่อรอให้หน่วยความจำว่าง ลองคิดดูว่าการวนซ้ำนั้นเข้ากับแคช L1 / L2 / L3 ของระบบของคุณหรือไม่ หากคุณมีคำสั่ง "if" ในการวนซ้ำของคุณให้ตรวจสอบว่า profiler พูดอะไรที่เกี่ยวกับการคาดคะเนผิดสาขาหรือไม่? บทลงโทษสาขาที่ผิดในระบบของคุณคืออะไร? โดยวิธีการที่คุณสามารถรับข้อมูลการตีความผิดสาขาจากคู่มืออ้างอิงการเพิ่มประสิทธิภาพของ Intel [1] โปรดทราบว่าการลงโทษที่ผิดสาขานั้นขึ้นอยู่กับโปรเซสเซอร์โดยเฉพาะอย่างยิ่งคุณจะเห็นในคู่มือ Intel

  4. สุดท้ายแก้ไขปัญหาที่ระบุโดย profiler มีการพูดถึงเทคนิคจำนวนหนึ่งที่นี่ มีทรัพยากรที่ดีน่าเชื่อถือและครอบคลุมเกี่ยวกับการปรับให้เหมาะสมด้วย ในการตั้งชื่อเพียงสองฉบับมีคู่มืออ้างอิงการเพิ่มประสิทธิภาพของ Intel [1] และคู่มือการเพิ่มประสิทธิภาพทั้งห้าโดย Agner Fog [2] โปรดทราบว่ามีบางสิ่งที่คุณอาจไม่จำเป็นต้องทำถ้าคอมไพเลอร์ทำไปแล้ว - ตัวอย่างเช่นการวนลูปที่ยังไม่ได้เปิดการปรับหน่วยความจำ ฯลฯ อ่านเอกสารของคอมไพเลอร์ของคุณอย่างระมัดระวัง

อ้างอิง:

[1] คู่มืออ้างอิงการเพิ่มประสิทธิภาพสถาปัตยกรรม Intel 64 และ IA-32: http://www.intel.sg/content/dam/doc/manual/64-ia-32-architectures-optimization-manual.pdf

[2] Agner Fog, "ทรัพยากรการเพิ่มประสิทธิภาพซอฟต์แวร์": http://www.agner.org/optimize/

  • "ซอฟต์แวร์เพิ่มประสิทธิภาพใน C ++: คู่มือเพิ่มประสิทธิภาพสำหรับแพลตฟอร์ม Windows, Linux และ Mac"
  • "การปรับรูทีนย่อยให้เหมาะสมในภาษาแอสเซมบลี: คำแนะนำการปรับให้เหมาะสมสำหรับแพลตฟอร์ม x86"
  • "สถาปัตยกรรมไมโครของ Intel, AMD และ VIA CPU: คู่มือการปรับให้เหมาะสมสำหรับโปรแกรมเมอร์แอสเซมบลีและผู้ผลิตคอมไพเลอร์"
  • "ตารางคำสั่ง: รายการเวลาแฝงของคำสั่งปริมาณงานและการแบ่งย่อยการทำงานแบบไมโครสำหรับ Intel, AMD และ VIA CPU"
  • "การเรียกแบบแผนสำหรับคอมไพเลอร์ C ++ และระบบปฏิบัติการต่าง"

3

ฉันไม่ได้เป็นนักวิทยาศาสตร์การคำนวณเหมือนคนอื่น ๆ ที่นี่ (ดังนั้นฉันอาจผิด :)) แต่วันนี้มีจุดเล็ก ๆ ในการใช้เวลามากเกินไปในการทำงานแบบอนุกรมตราบใดที่เราใช้ libs มาตรฐาน มันอาจจะคุ้มค่ากว่าที่จะใช้เวลาเพิ่มเติม / ความพยายามในการทำให้โค้ดปรับขนาดได้มากขึ้น

ในกรณีใด ๆ ต่อไปนี้เป็นสองตัวอย่าง (หากคุณไม่ได้อ่าน) เกี่ยวกับการปรับปรุงประสิทธิภาพ (สำหรับปัญหา FE ที่ไม่มีโครงสร้าง)

Serial : ดูครึ่งหลังของบทคัดย่อและข้อความที่เกี่ยวข้อง

Parallel : ขั้นตอนการเริ่มต้นเป็นพิเศษในวินาที 4.2


3

นี่อาจเป็นคำตอบที่ดีกว่าคำตอบ ...

คุณต้องพัฒนาความคุ้นเคยกับคอมไพเลอร์ของคุณ คุณสามารถรับสิ่งนี้ได้อย่างมีประสิทธิภาพมากที่สุดโดยการอ่านคู่มือและทดลองกับตัวเลือกต่างๆ

คำแนะนำที่ดีส่วนใหญ่ที่ @Pedro การแจกจ่ายสามารถนำมาใช้โดยการปรับการรวบรวมมากกว่าโปรแกรม


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

1

วิธีการทำโปรไฟล์โปรแกรมอย่างง่าย (ใน Linux) คือการใช้perfในstatโหมด วิธีที่ง่ายที่สุดคือการใช้งาน

perf stat ./my_program args ...

และจะให้สถิติประสิทธิภาพที่เป็นประโยชน์กับคุณมากมาย:

Performance counter stats for './simd_test1':

     3884.559489 task-clock                #    1.000 CPUs utilized
              18 context-switches          #    0.005 K/sec
               0 cpu-migrations            #    0.000 K/sec
             383 page-faults               #    0.099 K/sec
  10,911,904,779 cycles                    #    2.809 GHz
 <not supported> stalled-cycles-frontend
 <not supported> stalled-cycles-backend
  14,346,983,161 instructions              #    1.31  insns per cycle
   2,143,017,630 branches                  #  551.676 M/sec
          28,892 branch-misses             #    0.00% of all branches

     3.885986246 seconds time elapsed

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

นอกจากนี้คุณยังสามารถลองใช้perf record ./my_program; perf reportซึ่งเป็นวิธีที่ง่ายในการสร้างโปรไฟล์ อ่าน man pages เพื่อเรียนรู้เพิ่มเติม

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