กลยุทธ์การเพิ่มประสิทธิภาพการทำงานของวิธีสุดท้าย [ปิด]


609

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

สมมติว่า:

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

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

ในอุดมคติแล้วให้พยายามตอบคำถามผู้ไม่เชื่อเรื่องภาษาและระบุข้อบกพร่องของกลยุทธ์ที่แนะนำหากมี

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

คำตอบ:


427

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

  • ปัญหาแรกที่พบคือการใช้ list clusters (ปัจจุบันเรียกว่า "iterators" และ "container classes") ซึ่งทำบัญชีมานานกว่าครึ่ง สิ่งเหล่านั้นถูกแทนที่ด้วยรหัสที่ค่อนข้างง่ายทำให้เวลาลดลงเหลือ 20 วินาที

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

  • ตอนนี้มันยากที่จะหาผู้กระทำความผิดที่เห็นได้ชัด แต่มีน้อยกว่าที่ฉันสามารถทำบางสิ่งบางอย่างและเวลาลดลงถึง 13 วินาที

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

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

  • การออกแบบนั้นเสร็จสิ้นแล้วลดขนาดซอร์สโค้ดลง 4 เท่าและเวลาจะลดลงเหลือ 10 วินาที

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

  • การวินิจฉัยเพิ่มเติมพบว่ามันใช้เวลาในการจัดการคิว ซับในเหล่านี้ช่วยลดเวลา 7 วินาที

  • ตอนนี้คนรับใหญ่คือการพิมพ์เพื่อการวินิจฉัยที่ฉันทำอยู่ ล้างออก - 4 วินาที

  • ตอนนี้ที่ใหญ่ที่สุดเวลาผู้รับสายจะmallocและฟรี วัตถุรีไซเคิล - 2.6 วินาที

  • ฉันยังพบการปฏิบัติการที่ไม่จำเป็นอย่างเคร่งครัด - 1.1 วินาที

อัตราเร่งรวม: 43.6

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

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

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

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

 /* IF ALL TASKS DONE, SEND ITC_ACKOP, AND DELETE OP */
if (ptop->current_task >= ILST_LENGTH(ptop->tasklist){
. . .
/* FOR EACH OPERATION REQUEST */
for ( ptop = ILST_FIRST(oplist); ptop != NULL; ptop = ILST_NEXT(oplist, ptop)){
. . .
/* GET CURRENT TASK */
ptask = ILST_NTH(ptop->tasklist, ptop->current_task)

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

นี่คือปัญหาที่สองในสองบรรทัดแยกกัน:

 /* ADD TASK TO TASK LIST */
ILST_APPEND(ptop->tasklist, ptask)
. . .
/* ADD TRANSACTION TO TRANSACTION QUEUE */
ILST_APPEND(trnque, ptrn)

นี่คือรายการสร้างโดยการต่อท้ายรายการ (การแก้ไขคือการรวบรวมรายการในอาร์เรย์และสร้างรายการทั้งหมดในครั้งเดียว) สิ่งที่น่าสนใจคืองบเหล่านี้มีค่าใช้จ่ายเท่านั้น (เช่นอยู่ใน call stack) 3/48 ของเวลาเดิมดังนั้นจึงไม่ได้อยู่ใน ความเป็นจริงเป็นปัญหาใหญ่ที่จุดเริ่มต้น อย่างไรก็ตามหลังจากลบปัญหาแรกพวกเขาเสียค่าใช้จ่าย 3/20 ของเวลาและตอนนี้ก็เป็น "ปลาที่ใหญ่กว่า" โดยทั่วไปนั่นเป็นวิธีที่มันจะไป

ฉันอาจเพิ่มว่าโครงการนี้กลั่นจากโครงการจริงที่ฉันช่วย ในโครงการนั้นปัญหาด้านประสิทธิภาพมีความน่าทึ่งมาก (เช่นการเพิ่มความเร็ว) เช่นการเรียกรูทีนการเข้าถึงฐานข้อมูลภายในลูปด้านในเพื่อดูว่างานนั้นเสร็จสิ้นหรือไม่

เพิ่มการอ้างอิง: ซอร์สโค้ดทั้งต้นฉบับและการออกแบบสามารถพบได้ในwww.ddj.comสำหรับปี 1993 ในไฟล์ 9311.zip ไฟล์ slug.asc และ slug.zip

แก้ไข 2011/11/26: ขณะนี้มีโครงการ SourceForgeที่มีซอร์สโค้ดใน Visual C ++ และคำอธิบายแบบเป่าต่อเนื่องว่ามีการปรับจูนอย่างไร มันผ่านช่วงครึ่งแรกของสถานการณ์ที่อธิบายไว้ข้างต้นเท่านั้นและไม่เป็นไปตามลำดับเดียวกันทั้งหมด แต่ยังคงได้รับการเร่งความเร็วขนาด 2-3 ลำดับ


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

8
... ฉันยังเขียนหนังสือเล่มหนึ่งที่พิมพ์ออกมาแล้วดังนั้นมันจึงเป็นเรื่องไร้สาระสำหรับ Amazon - "การสร้างแอพพลิเคชั่นที่ดีขึ้น" ไอ 0442017405 โดยพื้นฐานแล้วเนื้อหาเดียวกันนั้นอยู่ในบทแรก
Mike Dunlavey

3
@ Mike Dunlavey ฉันขอแนะนำให้บอก Google ว่าคุณสแกนแล้ว พวกเขาอาจมีข้อตกลงกับใครก็ตามที่ซื้อผู้เผยแพร่ของคุณ
Thorbjørn Ravn Andersen

19
@ Thorbjørn: เพียงแค่ติดตามฉันได้ติดต่อกับ GoogleBooks กรอกแบบฟอร์มทั้งหมดและส่งสำเนาให้พวกเขา ฉันได้รับอีเมลกลับถามว่าฉันเป็นเจ้าของลิขสิทธิ์จริงๆหรือไม่ สำนักพิมพ์ Van Nostrand Reinhold ซึ่งซื้อโดย International Thompson ซึ่งซื้อโดย Reuters และเมื่อฉันพยายามโทรหรือส่งอีเมลถึงพวกเขามันก็เหมือนหลุมดำ ดังนั้นจึงอยู่ในบริเวณขอบรก - ฉันยังไม่ได้มีพลังงานในการไล่ล่ามันลง
Mike Dunlavey


188

ข้อเสนอแนะ:

  • คำนวณล่วงหน้าล่วงหน้าแทนการคำนวณซ้ำ : การวนซ้ำหรือการเรียกซ้ำที่มีการคำนวณที่มีช่วงของอินพุตค่อนข้าง จำกัด ลองทำการค้นหา (อาร์เรย์หรือพจนานุกรม) ที่มีผลลัพธ์ของการคำนวณนั้นสำหรับค่าทั้งหมดในช่วงที่ถูกต้องของ ปัจจัยการผลิต จากนั้นใช้การค้นหาอย่างง่ายภายในอัลกอริทึมแทน
    Down-side : หากใช้ค่าที่คำนวณล่วงหน้าเพียงไม่กี่ค่าสิ่งนี้อาจทำให้เรื่องแย่ลงการค้นหาอาจใช้หน่วยความจำที่สำคัญ
  • อย่าใช้วิธีห้องสมุด : ห้องสมุดส่วนใหญ่จะต้องเขียนเพื่อให้ทำงานอย่างถูกต้องภายใต้สถานการณ์ที่หลากหลายและทำการตรวจสอบค่าว่างจากพารามิเตอร์ ฯลฯ โดยการนำวิธีการมาใช้อีกครั้งคุณอาจสามารถขจัดตรรกะจำนวนมากที่ ใช้ไม่ได้ในกรณีที่คุณกำลังใช้งาน
    Down-sides : การเขียนรหัสเพิ่มเติมหมายถึงพื้นที่ผิวที่มากขึ้นสำหรับข้อบกพร่อง
  • ใช้วิธีการห้องสมุด : เพื่อโต้แย้งตัวเองห้องสมุดภาษาเขียนโดยคนที่ฉลาดกว่าคุณหรือฉัน อัตราต่อรองที่พวกเขาทำมันได้ดีขึ้นและเร็วขึ้น อย่าใช้ด้วยตัวคุณเองเว้นแต่ว่าคุณจะสามารถทำให้เร็วขึ้น (เช่น: วัดทุกครั้ง!)
  • โกง : ในบางกรณีถึงแม้ว่าการคำนวณที่แน่นอนอาจมีอยู่สำหรับปัญหาของคุณคุณอาจไม่จำเป็นต้อง 'แน่นอน' บางครั้งการประมาณอาจ 'ดีพอ' และเร็วกว่ามากในการจัดการ ถามตัวคุณเองมันสำคัญไหมถ้าคำตอบนั้นออกมา 1%? 5%? แม้แต่ 10%?
    Down-sides : เอ่อ ... คำตอบนั้นไม่แน่นอน

32
การคำนวณล่วงหน้าไม่ได้ช่วยอะไรเสมอไปและบางครั้งอาจทำให้เจ็บได้ - หากตารางการค้นหาของคุณใหญ่เกินไปก็สามารถทำลายประสิทธิภาพแคชของคุณได้
Adam Rosenfield

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

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

6
@Berteig: เพียงแค่ "แก้ไขให้ถูกต้อง" เป็นโอกาสสำหรับการเพิ่มประสิทธิภาพที่คนส่วนใหญ่คิดถึงในประสบการณ์ของฉัน
Martin Thompson

5
คุณไม่สามารถสรุปได้ว่าทุกคนฉลาดกว่าคุณ ในตอนท้ายเราทุกคนเป็นมืออาชีพ อย่างไรก็ตามคุณสามารถสันนิษฐานได้ว่ามีไลบรารีเฉพาะที่คุณใช้อยู่และได้มาถึงสภาพแวดล้อมของคุณเนื่องจากคุณภาพของมันดังนั้นการเขียนของไลบรารีนี้จะต้องละเอียดมากคุณไม่สามารถทำได้เช่นกันเพราะคุณไม่เชี่ยวชาญ และคุณไม่ต้องลงทุนในเวลาเดียวกัน ไม่ใช่เพราะคุณฉลาดน้อยกว่า มาเลย
v.oddou

164

เมื่อคุณไม่สามารถปรับปรุงประสิทธิภาพได้อีก - ดูว่าคุณสามารถปรับปรุงประสิทธิภาพที่รับรู้ได้หรือไม่

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

ตัวอย่างบางส่วน:

  • การคาดการณ์ว่าผู้ใช้จะขออะไรและเริ่มทำงานก่อนหน้านั้น
  • แสดงผลลัพธ์เมื่อพวกเขาเข้ามาแทนที่ทั้งหมดในครั้งเดียวในตอนท้าย
  • เครื่องวัดความก้าวหน้าที่แม่นยำ

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


27
แถบความคืบหน้าในการเร่งความเร็วในตอนท้ายอาจถูกมองว่าเร็วกว่าความเร็วที่แม่นยำอย่างแน่นอน ใน "ทบทวนแถบความคืบหน้าใหม่" (2007) Harrison, Amento, Kuznetsov และ Bell ทดสอบแถบหลายประเภทในกลุ่มผู้ใช้รวมทั้งพูดคุยถึงวิธีการหลายวิธีในการจัดเรียงการดำเนินการเพื่อให้ความคืบหน้าเร็วขึ้น
Emil Vikström

9
ตอนนี้, แถบความคืบหน้าส่วนใหญ่เป็นของปลอมเพราะการทำนายขั้นตอนที่แตกต่างกันหลายขั้นตอนของการไหลเข้าสู่เปอร์เซ็นต์เดียวนั้นยากหรือเป็นไปไม่ได้บางครั้ง. เพียงแค่ดูแท่งเหล่านั้นทั้งหมดที่ติดอยู่ที่ 99% :-(
Emil Vikström

138

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

  • แคช Data cache เป็นแผงขายสินค้าอันดับ 1 ในโปรแกรมส่วนใหญ่ ปรับปรุงอัตราการเข้าถึงแคชโดยจัดโครงสร้างโครงสร้างข้อมูลใหม่เพื่อให้มีตำแหน่งที่ดีขึ้น โครงสร้างของแพ็คและประเภทที่เป็นตัวเลขลงเพื่อกำจัดไบต์ที่ถูกสิ้นเปลือง (ดังนั้นการดึงแคชที่สูญเปล่า); ดึงข้อมูลล่วงหน้าเพื่อลดแผงลอย
  • โหลดตีร้านค้า ข้อสันนิษฐานของคอมไพเลอร์เกี่ยวกับ aliasing ของตัวชี้และกรณีที่ข้อมูลถูกย้ายระหว่างชุดรีจิสเตอร์ที่ไม่ได้เชื่อมต่อผ่านหน่วยความจำสามารถทำให้เกิดพฤติกรรมทางพยาธิวิทยาบางอย่างที่ทำให้ไพพ์ไลน์ของ CPU ทั้งหมดเคลียร์โหลดโหลด ค้นหาสถานที่ที่ลอยเวกเตอร์และ ints ถูกโยนเข้าหากันแล้วกำจัดมัน ใช้__restrictอย่างอิสระเพื่อสัญญากับคอมไพเลอร์เกี่ยวกับนามแฝง
  • การดำเนินงาน microcoded โปรเซสเซอร์ส่วนใหญ่มีการดำเนินการบางอย่างที่ไม่สามารถไปป์ไลน์ได้ แต่ให้เรียกใช้รูทีนย่อยขนาดเล็กที่เก็บไว้ใน ROM แทน ตัวอย่างบน PowerPC คือจำนวนเต็มคูณหารและเปลี่ยนโดยจำนวนตัวแปร ปัญหาคือว่าไปป์ไลน์ทั้งหมดหยุดทำงานในขณะที่การดำเนินการนี้กำลังดำเนินการอยู่ พยายามกำจัดการใช้งานการดำเนินการเหล่านี้หรืออย่างน้อยก็แบ่งพวกมันออกเป็น ops pipelined ที่เป็นส่วนประกอบเพื่อให้คุณได้รับประโยชน์จาก superscalar dispatch ในสิ่งที่เหลืออยู่ในโปรแกรมของคุณ
  • mispredicts สาขา ท่อเหล่านี้ว่างเปล่าเกินไป ค้นหากรณีที่ CPU ใช้เวลานานในการเติมท่อหลังสาขาและใช้คำใบ้สาขาถ้ามีเพื่อให้คาดเดาได้ถูกต้องบ่อยขึ้น หรือดีกว่าให้เปลี่ยนกิ่งก้านด้วยการเลื่อนตามเงื่อนไขทุกที่ที่ทำได้โดยเฉพาะอย่างยิ่งหลังจากการดำเนินการจุดลอยตัวเนื่องจากท่อของพวกมันมักจะลึกกว่าและการอ่านค่าสถานะเงื่อนไขหลังจาก fcmp อาจทำให้แผงลอย
  • ลำดับ Ops ทำ SIMD เหล่านี้

และอีกหนึ่งสิ่งที่ฉันชอบทำ:

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

8
ฉันใช้ Intel VTune และ PIX เป็นส่วนใหญ่ ไม่มีความคิดถ้าพวกเขาสามารถปรับให้เข้ากับ C # แต่จริงๆแล้วเมื่อคุณมีเลเยอร์นามธรรม JIT ที่การเพิ่มประสิทธิภาพเหล่านี้ส่วนใหญ่อยู่นอกเหนือการเข้าถึงของคุณยกเว้นการปรับปรุงท้องถิ่นแคชและอาจหลีกเลี่ยงบางสาขา
Crashworks

6
ถึงกระนั้นก็ตามการตรวจสอบผลลัพธ์ของ post-JIT อาจช่วยในการพิจารณาว่ามีสิ่งก่อสร้างใดที่ไม่สามารถปรับให้เหมาะสมได้ดีในขั้นตอน JIT ... การสอบสวนไม่สามารถทำร้ายได้แม้ว่าจะกลายเป็นจุดสิ้นสุด
jerryjvl

5
ฉันคิดว่าคนจำนวนมากรวมถึงตัวฉันเองจะสนใจ "wtf assembly" นี้ที่ผลิตโดย gcc คุณฟังดูเหมือนงานที่น่าสนใจมาก :)
BlueRaja - Danny Pflughoeft

1
Examples on the PowerPC ...<- นั่นคือการใช้งานบางอย่างของ PowerPC PowerPC เป็น ISA ไม่ใช่ CPU
Billy ONeal

1
@BillyONeal แม้ในฮาร์ดแวร์ x86 ที่ทันสมัย ​​imul สามารถปิดกั้นไปป์ไลน์; โปรดดูที่ "คู่มืออ้างอิงการเพิ่มประสิทธิภาพสถาปัตยกรรมIntel® 64 และ IA-32" .313.3.2.3: "คำสั่งการคูณจำนวนเต็มใช้เวลาหลายรอบในการดำเนินการพวกเขาจะถูกไพพ์ไลน์ซึ่งคำสั่งจำนวนเต็มทวีคูณและคำสั่งแฝงอื่น ๆ ขั้นตอนการดำเนินการอย่างไรก็ตามคำแนะนำการคูณจำนวนเต็มจะบล็อกคำสั่งจำนวนเต็มรอบเดียวอื่น ๆ ไม่ให้ออกเนื่องจากความต้องการของคำสั่งของโปรแกรม " leaที่ว่าทำไมมันมักจะดีกว่าที่จะใช้คำชิดขนาดอาร์เรย์และ
Crashworks

78

ขว้างฮาร์ดแวร์มากขึ้น!


30
ฮาร์ดแวร์ไม่ได้เป็นตัวเลือกเสมอไปเมื่อคุณมีซอฟต์แวร์ที่คาดว่าจะทำงานบนฮาร์ดแวร์ที่มีอยู่ในฟิลด์
Doug T.

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

19
@ Crashworks หรือสำหรับระบบฝังตัว เมื่อคุณลักษณะสุดท้ายคือในที่สุดและชุดแรกของผ้าปั่นแล้วไม่ได้เป็นช่วงเวลาที่จะพบว่าคุณควรจะใช้ CPU ที่เร็วขึ้นในสถานที่แรก ...
RBerteig

71
ฉันเคยต้องดีบักโปรแกรมที่มีการรั่วไหลของหน่วยความจำขนาดใหญ่ - ขนาด VM ของมันเพิ่มขึ้นประมาณ 1Mb ต่อชั่วโมง เพื่อนร่วมงานติดตลกว่าทั้งหมดที่ฉันต้องการจะทำหน่วยความจำเพิ่มเป็นในอัตราคงที่ :)
j_random_hacker

9
ฮาร์ดแวร์เพิ่มเติม: ใช่แล้วเส้นชีวิตของนักพัฒนาธรรมดา ฉันไม่รู้กี่ครั้งที่ฉันได้ยิน "เพิ่มเครื่องอื่นและเพิ่มความจุเป็นสองเท่า!"
Olof Forshell

58

คำแนะนำเพิ่มเติม:

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

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

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

  • เธรด I / O : สำหรับผู้ที่กล้าพอให้รวม 'I / O ล่วงหน้า' หรือ 'Delay I / O' กับการคำนวณจริงโดยย้ายการโหลดลงในเธรดขนานดังนั้นในขณะที่คุณกำลังโหลดข้อมูลเพิ่มเติมคุณสามารถทำงานได้ ในการคำนวณข้อมูลที่คุณมีอยู่หรือในขณะที่คุณคำนวณชุดข้อมูลถัดไปคุณสามารถเขียนผลลัพธ์จากชุดข้อมูลล่าสุดพร้อมกันได้


3
โปรดทราบว่า "การย้าย IO ไปยังเธรดขนาน" ควรทำในลักษณะ asynchronous IO บนหลาย ๆ แพลตฟอร์ม (เช่น Windows NT)
Billy ONeal

2
I / O นั้นเป็นจุดวิกฤติเพราะมันช้าและมีความล่าช้ามากและคุณสามารถได้เร็วขึ้นด้วยคำแนะนำนี้ แต่ก็ยังมีข้อบกพร่องพื้นฐาน: ประเด็นคือความล่าช้า (ซึ่งจะต้องซ่อนอยู่) และเหนือศีรษะ syscall ( ซึ่งจะต้องลดลงโดยการลดจำนวนการโทร I / O) คำแนะนำที่ดีที่สุดคือ: ใช้mmap()สำหรับการป้อนข้อมูลทำการmadvise()โทรที่เหมาะสมและใช้aio_write()ในการเขียนเอาต์พุตขนาดใหญ่ (= ไม่กี่ MiB)
cmaster - คืนสถานะโมนิก้า

1
ตัวเลือกสุดท้ายนี้ค่อนข้างง่ายต่อการนำไปใช้ใน Java โดยเฉพาะ มันให้ประสิทธิภาพที่เพิ่มขึ้นอย่างมากสำหรับแอปพลิเคชันที่ฉันเขียน อีกจุดที่สำคัญ (มากกว่าการเลื่อน I / O ล่วงหน้า) คือการทำให้เป็นลำดับและ I / O บล็อกขนาดใหญ่ การอ่านขนาดเล็กจำนวนมากมีราคาแพงกว่าขนาดใหญ่ 1 อันเนื่องจากเวลาในการค้นหาดิสก์
BobMcGee

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

48

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

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

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

หลีกเลี่ยงการใช้เคียวรีย่อยที่สัมพันธ์กัน ใช้การรวม (รวมการรวมเข้ากับตารางที่ได้รับหากเป็นไปได้) (ฉันรู้ว่านี่เป็นจริงสำหรับ Microsoft SQL Server แต่ทดสอบคำแนะนำเมื่อใช้แบ็กเอนด์ differnt)

ดัชนี, ดัชนี, ดัชนี และอัปเดตสถิติเหล่านั้นหากมีผลกับฐานข้อมูลของคุณ

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

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

ไม่เคยใส่วนใด ๆ เข้าไปในทริกเกอร์!

ฐานข้อมูลส่วนใหญ่มีวิธีการตรวจสอบวิธีการดำเนินการค้นหา ใน Microsoft SQL Server สิ่งนี้เรียกว่าแผนการดำเนินการ ตรวจสอบสิ่งเหล่านั้นก่อนเพื่อดูว่าพื้นที่ปัญหาอยู่ที่ใด

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

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

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


29

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

นี่คือเอฟเฟกต์ที่คุณต้องจัดการ บางครั้งผ่าน micro การจัดการโค้ดของคุณ แต่บางครั้งผ่านการพิจารณาอย่างรอบคอบและการปรับโครงสร้างใหม่

ความคิดเห็นมากมายพูดถึงโค้ดที่เป็นมิตรกับแคชแล้ว มีอย่างน้อยสองรสชาติที่แตกต่างของสิ่งนี้:

  • หลีกเลี่ยงการดึงข้อมูลหน่วยความจำ
  • ลดแรงดันบัสของหน่วยความจำ (แบนด์วิดท์)

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

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

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


25
  • คุณใช้ฮาร์ดแวร์อะไรอยู่ คุณสามารถใช้การเพิ่มประสิทธิภาพเฉพาะแพลตฟอร์ม (เช่น vectorization) ได้หรือไม่
  • คุณจะได้รับคอมไพเลอร์ที่ดีกว่า เช่นเปลี่ยนจาก GCC เป็น Intel?
  • คุณสามารถทำให้อัลกอริทึมของคุณทำงานแบบขนานได้หรือไม่?
  • คุณสามารถลดการพลาดแคชโดยจัดระเบียบข้อมูลใหม่ได้หรือไม่?
  • คุณสามารถปิดการใช้งาน asserts ได้หรือไม่?
  • Micro-optimization สำหรับคอมไพเลอร์และแพลตฟอร์มของคุณ ในรูปแบบของ "ที่ if / else ให้ใส่คำสั่งที่พบบ่อยที่สุดเป็นอันดับแรก"

4
ควรจะเป็น "เปลี่ยนจาก GCC จะ LLVM" :)
Zifre

4
คุณสามารถทำให้อัลกอริทึมของคุณทำงานแบบขนานได้หรือไม่? - การผกผันยังใช้
justin

4
จริงที่การลดจำนวนเธรดสามารถเป็นการปรับให้เหมาะสมดีเท่ากัน
Johan Kotlinski

Re: การปรับให้เหมาะสมแบบไมโคร: ถ้าคุณตรวจสอบเอาต์พุต asm ของคอมไพเลอร์คุณสามารถปรับแต่งซอร์สเพื่อจับมือไว้เพื่อสร้าง asm ที่ดีขึ้น ดูเหตุใดรหัส C ++ นี้เร็วกว่าชุดประกอบที่เขียนด้วยมือของฉันสำหรับทดสอบการคาดคะเนของ Collatz สำหรับข้อมูลเพิ่มเติมเกี่ยวกับการช่วยเหลือหรือเอาชนะคอมไพเลอร์ใน x86 ที่ทันสมัย
Peter Cordes

17

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

ค้นหาสิ่งที่ต้องใช้เวลามากที่สุดก่อนและเข้าใจว่าทำไม

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

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

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

HPH, asoudmove


16

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

ในทางกลับกัน Google folks เป็นที่รู้จักกันในเรื่องการใช้กำลังคนและทรัพยากรจำนวนมากในการแก้ปัญหาบางอย่างในโครงการเครื่องมือและโครงสร้างพื้นฐานที่ใช้เช่นการเพิ่มประสิทธิภาพโปรแกรมทั้งหมดสำหรับ gccโดยมีทีมวิศวกรที่ทุ่มเท การแฮ็ก gcc internals เพื่อเตรียมความพร้อมสำหรับกรณีการใช้งานทั่วไปของ Google

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


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

2
อุปกรณ์ของ IIRC Duff นั้นเร็วกว่ามาก เฉพาะเมื่อสหกรณ์สั้นมาก (เช่นการแสดงออกทางคณิตศาสตร์เล็ก ๆ คนเดียว)
BCS

12
  • เมื่อคุณมาถึงจุดที่คุณใช้อัลกอริธึมที่มีประสิทธิภาพคำถามของสิ่งที่คุณต้องการความเร็วหรือหน่วยความจำเพิ่มเติม ใช้การแคชเพื่อ "จ่าย" ในหน่วยความจำเพื่อความเร็วที่มากขึ้นหรือใช้การคำนวณเพื่อลดขนาดหน่วยความจำ
  • ถ้าเป็นไปได้ (และมีประสิทธิภาพมากขึ้น) โยนฮาร์ดแวร์ที่มีปัญหา - CPU ที่เร็วขึ้นหน่วยความจำเพิ่มเติมหรือ HD สามารถแก้ปัญหาได้เร็วขึ้นจากนั้นลองรหัสมัน
  • ใช้การขนานถ้าเป็นไปได้ - รันส่วนหนึ่งของรหัสบนหลายเธรด
  • ใช้เครื่องมือที่เหมาะสมสำหรับงาน ภาษาการเขียนโปรแกรมบางภาษาสร้างโค้ดที่มีประสิทธิภาพมากขึ้นโดยใช้โค้ดที่มีการจัดการ (เช่น Java / .NET) จะช่วยเร่งการพัฒนา แต่ภาษาการเขียนโปรแกรมดั้งเดิมจะสร้างโค้ดที่รันได้เร็วขึ้น
  • เพิ่มประสิทธิภาพไมโคร มีเพียงคุณเท่านั้นที่สามารถใช้ชุดประกอบที่ได้รับการปรับปรุงเพื่อเพิ่มความเร็วให้กับโค้ดขนาดเล็กโดยใช้การเพิ่มประสิทธิภาพ SSE / เวกเตอร์ในสถานที่ที่เหมาะสมสามารถเพิ่มประสิทธิภาพได้อย่างมาก

12

แบ่งและพิชิต

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


9
+1 สำหรับเสียง "smack" ของ flyswatter ที่ฉันได้ยินในขณะที่อ่านประโยคสุดท้าย
Bryan Boettcher

11

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

  • ... ถ้าเป็นความทรงจำ - หาหนังสือเล่มหนึ่งที่เขียนมานานแล้วโดย Knuth หนึ่งในซีรี่ส์ "The Art of Computer Programming" เป็นไปได้ว่าเป็นเรื่องเกี่ยวกับการเรียงลำดับและค้นหา - หากหน่วยความจำของฉันผิดคุณจะต้องค้นหาว่าเขาพูดถึงวิธีจัดการกับการจัดเก็บข้อมูลเทปที่ช้า เปลี่ยนหน่วยความจำ /คู่เทปของเขาให้เป็นคู่ของแคช / หน่วยความจำหลัก (หรือเป็นคู่ของ L1 / L2 แคช) ตามลำดับ ศึกษาเทคนิคทั้งหมดที่เขาอธิบาย - หากคุณไม่พบสิ่งที่สามารถแก้ปัญหาของคุณได้ให้จ้างนักวิทยาศาสตร์คอมพิวเตอร์มืออาชีพเพื่อทำการวิจัยมืออาชีพ หากปัญหาหน่วยความจำของคุณเกิดขึ้นโดยบังเอิญกับ FFT (แคชหายไปที่ดัชนีย้อนกลับแบบบิตเมื่อทำ Radix-2 butterflies) จากนั้นอย่าจ้างนักวิทยาศาสตร์ - แทนให้เพิ่มประสิทธิภาพด้วยตนเองผ่านแบบตัวต่อหนึ่งจนกว่าคุณจะ ไม่ว่าจะเป็นชนะหรือไปถึงจุดจบ คุณพูดถึงบีบออกไปไม่กี่เปอร์เซ็นต์ใช่ไหม? ถ้ามันมีน้อยจริง ๆ คุณจะชนะ

  • ... ถ้าเป็นโปรเซสเซอร์ - เปลี่ยนเป็นภาษาแอสเซมบลี ศึกษาข้อมูลจำเพาะของโปรเซสเซอร์ - สิ่งใดที่ใช้เห็บ , VLIW, SIMD ฟังก์ชั่นการโทรเป็นไปได้มากที่สุดเห็บกิน - เปลี่ยน เรียนรู้การแปลงลูป - ไปป์, unroll การคูณและการหารอาจถูกแทนที่ / สอดแทรกด้วยการเลื่อนบิต (การคูณด้วยจำนวนเต็มขนาดเล็กอาจเปลี่ยนได้ด้วยการเพิ่มเติม) ลองเล่นกลกับข้อมูลที่สั้นกว่า - หากคุณโชคดีที่คำสั่งหนึ่งคำสั่งที่มี 64 บิตอาจเปลี่ยนได้โดยใช้สองใน 32 หรือ 4 ใน 16 หรือ 8 หรือ 8 ลองอีกต่อไปข้อมูล - เช่นการคำนวณแบบลอยของคุณอาจช้ากว่าการคำนวณแบบสองเท่าที่ตัวประมวลผลเฉพาะ หากคุณมีสิ่งที่เกี่ยวกับวิชาตรีโกณมิติให้ต่อสู้กับตารางที่คำนวณล่วงหน้า โปรดระลึกไว้ว่าไซน์ที่มีค่าน้อยอาจถูกแทนที่ด้วยค่านั้นหากการสูญเสียความแม่นยำอยู่ภายในขีด จำกัด ที่อนุญาต

  • ... ถ้าเป็นเครือข่ายลองนึกถึงการบีบอัดข้อมูลที่คุณส่งผ่าน แทนที่การถ่ายโอน XML ด้วยไบนารี โปรโตคอลการศึกษา ลองใช้ UDP แทน TCP หากคุณสามารถจัดการกับข้อมูลสูญหายได้

  • ... ถ้าเป็นฐานข้อมูลไปที่ฟอรัมฐานข้อมูลและขอคำแนะนำ In-memory data-grid, การปรับแผนคิวรี ฯลฯ ให้เหมาะสม ฯลฯ

HTH :)


9

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

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


8

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

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

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


8

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

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

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

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

  • Parallelise : ค้นหาธุรกรรมที่เป็นลำดับซึ่งไม่จำเป็นต้องมีการออกอย่างเป็นเหตุเป็นผลตามลำดับอย่างเคร่งครัดและนำระบบกลับมาใช้ซ้ำ ฉันจัดการกับกรณีหนึ่งที่คำขอแบบ end-to-end มีความล่าช้าของเครือข่ายโดยธรรมชาติที่ ~ 2s ซึ่งไม่ใช่ปัญหาสำหรับการทำธุรกรรมเดียว แต่เมื่อต้องการการเดินทางไปกลับ 6 ครั้งต่อเนื่องกัน 6 ครั้งก่อนที่ผู้ใช้จะสามารถควบคุมแอปพลิเคชันไคลเอนต์ได้ มันกลายเป็นแหล่งใหญ่ของแห้ว การค้นพบว่าการทำธุรกรรมเหล่านี้เป็นอิสระอย่างอิสระอนุญาตให้ดำเนินการแบบคู่ขนานซึ่งช่วยลดความล่าช้าของผู้ใช้ปลายทางให้ใกล้เคียงกับค่าใช้จ่ายในการเดินทางไปกลับครั้งเดียว

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

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

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

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


7

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


7

ไม่กี่% สุดท้ายคือ CPU และแอพพลิเคชั่นที่ขึ้นกับ ....

  • สถาปัตยกรรมแคชแตกต่างกันชิปบางตัวมีแรมบนชิปที่คุณสามารถแมปโดยตรง ARM (บางครั้ง) มีหน่วยเวกเตอร์ SH4 เป็นเมทริกซ์เมทริกซ์ที่มีประโยชน์ มีGPUอยู่หรือเปล่าบางทีเงาอาจจะเป็นหนทางไป TMS320มีความอ่อนไหวมากต่อกิ่งก้านสาขาภายในลูป (ดังนั้นแยกลูปและย้ายสภาพภายนอกถ้าเป็นไปได้)

รายการดำเนินไป .... แต่สิ่งต่าง ๆ เหล่านี้เป็นทางเลือกสุดท้าย ...

สร้างสำหรับ x86 และเรียกใช้Valgrind / Cachegrind กับรหัสสำหรับการทำโปรไฟล์ประสิทธิภาพที่เหมาะสม หรือCCStudioของ Texas Instruments มีผู้สร้างโปรไฟล์ที่น่ารัก ถ้าอย่างนั้นคุณจะรู้ว่าจะโฟกัสที่ไหน ...


7

Did you know that a CAT6 cable is capable of 10x better shielding off extrenal inteferences than a default Cat5e UTP cable?

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


7

ไม่ใกล้เคียงกับความลึกหรือความซับซ้อนเหมือนคำตอบก่อนหน้า แต่จะไปที่: (นี่เป็นระดับเริ่มต้น / ระดับกลาง)

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

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

1
ในกรณีส่วนใหญ่ AFAIK เครื่องมือเพิ่มประสิทธิภาพที่เหมาะสมจะทำอะไรได้ดีกับลูปโดยที่โปรแกรมเมอร์ไม่จำเป็นต้องย้อนกลับอย่างชัดเจน ทั้งเครื่องมือเพิ่มประสิทธิภาพจะย้อนกลับวนกลับเองหรือมีวิธีอื่นที่ดีเท่ากัน ฉันได้บันทึกเอาท์พุท ASM ที่เหมือนกันสำหรับลูป (ค่อนข้างเป็นที่ยอมรับง่าย) ที่เขียนทั้งจากน้อยไปมากเทียบกับสูงสุดและจากมากไปน้อยเทียบกับ 0 และแน่นอนว่า Z80 วันของฉันมีฉัน ปลาเฮอริ่งแดง / การปรับให้เหมาะสมก่อนกำหนดเมื่อรหัสที่สามารถอ่านได้และการเรียนรู้การปฏิบัติที่สำคัญยิ่งขึ้นควรจัดลำดับความสำคัญ
underscore_d

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

5

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

สถานที่แคชที่ดีกว่า, การคลี่วงออก, พยายามกำจัดโซ่การพึ่งพาระยะยาว, เพื่อให้ได้ระดับการขนานที่ดีขึ้น ชอบการเคลื่อนไหวแบบมีเงื่อนไขมากกว่าสาขาเมื่อเป็นไปได้ ใช้ประโยชน์จากคำแนะนำ SIMD เมื่อเป็นไปได้

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

ถ้าอย่างนั้นและ "แสดงรหัสบน SO และขอคำแนะนำในการปรับให้เหมาะสมสำหรับชิ้นส่วนของรหัสนั้น"


5

หากฮาร์ดแวร์ที่ดีกว่าเป็นตัวเลือกให้เลือกตัวเลือกนี้ มิฉะนั้น

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

ฉันจะเพิ่มหุ้นครั้งแรกของคุณ .: อย่าลืมปิดทุกข้อมูลการแก้จุดบกพร่องในตัวเลือกของคอมไพเลอร์ของคุณ
varnie

5

วิธี google เป็นตัวเลือกหนึ่ง "แคชมัน .. หากเป็นไปได้อย่าแตะต้องดิสก์"


5

นี่คือเทคนิคการเพิ่มประสิทธิภาพที่รวดเร็วและสกปรกที่ฉันใช้ ฉันคิดว่านี่เป็นการเพิ่มประสิทธิภาพ 'ผ่านครั้งแรก'

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

รู้สภาพแวดล้อมของคุณ รู้ว่าการปรับให้เหมาะสมมักขึ้นอยู่กับสภาพแวดล้อมการพัฒนา ยกตัวอย่างเช่นใน VB6 การส่งโดยการอ้างอิงนั้นช้ากว่าการส่งผ่านค่า แต่ใน C และ C ++ โดยการอ้างอิงนั้นเร็วกว่าอย่างมาก ใน C มีเหตุผลที่จะลองทำบางสิ่งและทำสิ่งที่แตกต่างหากรหัสส่งคืนบ่งชี้ถึงความล้มเหลวในขณะที่ใน Dot Net การจับข้อยกเว้นนั้นช้ากว่าการตรวจสอบสภาพที่ถูกต้องก่อนทำการทดลอง

ดัชนีสร้างดัชนีในเขตข้อมูลฐานข้อมูลที่สืบค้นบ่อย คุณสามารถแลกเปลี่ยนพื้นที่เพื่อความเร็วได้ตลอดเวลา

หลีกเลี่ยงการค้นหา ภายในวงเพื่อปรับให้เหมาะสมฉันหลีกเลี่ยงการค้นหาใด ๆ ค้นหาออฟเซ็ตและ / หรือดัชนีด้านนอกของลูปและนำข้อมูลภายในมาใช้ซ้ำ

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

ลด Abstractionsยิ่งมีการใช้รหัสนามธรรมในการทำงานมากเท่าไหร่ก็จะยิ่งช้าลงเท่านั้น ภายในลูปที่สำคัญลดบทคัดย่อ (เช่นเปิดเผยวิธีการระดับล่างที่หลีกเลี่ยงรหัสพิเศษ)

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

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


5

หากคุณมีเลขทศนิยมที่ขนานกันอย่างมากโดยเฉพาะอย่างยิ่งความแม่นยำเดี่ยวลองถ่ายไปยังโปรเซสเซอร์กราฟิก (ถ้ามี) โดยใช้ OpenCL หรือ (สำหรับชิป NVidia) CUDA GPU มีพลังการคำนวณจุดลอยตัวอันยิ่งใหญ่ใน shaders ของพวกเขาซึ่งมากกว่า CPU มาก


5

การเพิ่มคำตอบนี้เนื่องจากฉันไม่เห็นมันรวมอยู่ในคำอื่น ๆ ทั้งหมด

ลดการแปลงโดยนัยระหว่างประเภทและเครื่องหมายย่อ:

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

GCC spesific: คุณสามารถทดสอบได้โดยเพิ่ม pragmas verbose รอบ ๆ โค้ดของคุณ

#ifdef __GNUC__
#  pragma GCC diagnostic push
#  pragma GCC diagnostic error "-Wsign-conversion"
#  pragma GCC diagnostic error "-Wdouble-promotion"
#  pragma GCC diagnostic error "-Wsign-compare"
#  pragma GCC diagnostic error "-Wconversion"
#endif

/* your code */

#ifdef __GNUC__
#  pragma GCC diagnostic pop
#endif

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

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


นี่คือเหตุผลที่ฉันชอบสิ่งนั้นใน OCaml การคัดเลือกประเภทตัวเลขจะต้องเป็น xplicit
ออกุสตุส

@Gaius fair point - แต่ในหลายกรณีการเปลี่ยนภาษาไม่ใช่ทางเลือกที่สมจริง เนื่องจาก C / C ++ ใช้กันอย่างแพร่หลายมีประโยชน์เพื่อให้สามารถเข้มงวดมากขึ้นแม้ว่าคอมไพเลอร์เฉพาะ
ideasman42

4

บางครั้งการเปลี่ยนเค้าโครงของข้อมูลของคุณสามารถช่วยได้ ใน C คุณอาจเปลี่ยนจากอาร์เรย์หรือโครงสร้างเป็นโครงสร้างของอาร์เรย์หรือในทางกลับกัน


4

ปรับแต่งระบบปฏิบัติการและกรอบ

อาจฟังดูเกินความจริง แต่ลองคิดดูเช่นนี้ระบบปฏิบัติการและกรอบการทำงานได้รับการออกแบบมาเพื่อทำสิ่งต่างๆ แอปพลิเคชันของคุณทำสิ่งที่เฉพาะเจาะจงมากเท่านั้น หากคุณสามารถทำให้ระบบปฏิบัติการทำตามที่แอปพลิเคชันของคุณต้องการและทำให้แอปพลิเคชันของคุณเข้าใจว่าเฟรมเวิร์ก (php, .net, java) ทำงานอย่างไรคุณสามารถปรับปรุงฮาร์ดแวร์ของคุณได้ดีขึ้นมาก

ตัวอย่างเช่น Facebook เปลี่ยนบางสิ่งที่ระดับเคอร์เนลใน Linux เปลี่ยนการทำงานของ memcached (ตัวอย่างเช่นพวกเขาเขียนพร็อกซี memcached และใช้ udp แทน tcp )

อีกตัวอย่างสำหรับสิ่งนี้คือ Window2008 Win2K8 มีรุ่นที่คุณสามารถติดตั้งได้เพียงระบบปฏิบัติการพื้นฐานที่จำเป็นในการใช้งาน X application (เช่น Web-Apps, Server Apps) สิ่งนี้ช่วยลดค่าใช้จ่ายส่วนใหญ่ที่ระบบปฏิบัติการใช้ในกระบวนการทำงานและให้ประสิทธิภาพที่ดีขึ้น

แน่นอนคุณควรโยนฮาร์ดแวร์เพิ่มเติมเป็นขั้นตอนแรก ...


2
นั่นจะเป็นวิธีการที่ถูกต้องหลังจากวิธีการอื่น ๆ ทั้งหมดล้มเหลวหรือหากระบบปฏิบัติการหรือคุณลักษณะเฉพาะของกรอบรับผิดชอบการลดลงอย่างเห็นได้ชัด แต่ระดับของความเชี่ยวชาญและการควบคุมที่จำเป็นในการดึงออกนั้นอาจไม่สามารถใช้ได้กับทุกโครงการ
Andrew Neely
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.