ฉันจะวัดประสิทธิภาพของรหัส elisp ได้อย่างไร


26

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

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


1
คำถามกว้างเกินไป ประสิทธิภาพแบบไหน ที่ไหน? เมื่อ? " ประสิทธิภาพ Emacs " อาจหมายถึงทุกสิ่ง
ดึง

@Drew ภาษาการเขียนโปรแกรมอื่น ๆ อีกมากมายมีชุดของมาตรฐาน (เช่น Python: speed.pypy.org , JS: Sunspider ฯลฯ ) และฉันหวังว่าจะมีล่ามแปลภาษา Elisp ที่เทียบเท่ากัน
Wilfred Hughes

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

บางทีคุณอาจหมายถึง " ฉันจะวัดประสิทธิภาพใน Emacs " ได้อย่างไร?
ดึง

2
ตกลงฉันได้เปิดemacs.stackexchange.com/q/655/304เกี่ยวกับการเปรียบเทียบ Emacs และการตั้งคำถามใหม่เกี่ยวกับคำถามนี้เป็นเรื่องเกี่ยวกับโปรแกรมการเปรียบเทียบ / ทำโปรไฟล์ elisp
Wilfred Hughes

คำตอบ:


31

เกณฑ์มาตรฐาน

ตัวเลือกที่ตรงไปตรงมาที่สุดคือbenchmarkแพ็คเกจในตัว การใช้งานง่ายอย่างน่าทึ่ง:

(benchmark 100 (form (to be evaluated)))

มันโหลดอัตโนมัติดังนั้นคุณไม่จำเป็นต้องใช้มัน

โปรไฟล์

เกณฑ์มาตรฐานนั้นดีในการทดสอบโดยรวม แต่ถ้าคุณประสบปัญหาด้านประสิทธิภาพก็ไม่ได้บอกคุณว่าฟังก์ชั่นใดเป็นสาเหตุของปัญหา เพื่อที่คุณจะมี (ยัง built-in) Profiler

  1. M-x profiler-startเริ่มต้นด้วย
  2. ดำเนินการบางครั้งต้องใช้เวลามาก
  3. M-x profiler-reportได้รับรายงานด้วย

คุณควรถูกนำไปที่บัฟเฟอร์ด้วยแผนผังการนำทางของการเรียกฟังก์ชัน
ภาพหน้าจอของ Profiler


benchmarkฟังก์ชั่นดูเหมือนจะไม่ทำงาน: เมื่อฉันทำใน.cไฟล์ที่เปิด(benchmark 100 (c-font-lock-fontify-region 0 17355))ฉันจะได้รับvoid-function jit-lock-boundsต่อไป
Hi-Angel

1
FTR: เป็นทางเลือกที่benchmarkมีฟังก์ชั่นและbenchmark-run benchmark-run-compiledสำหรับฉันความแตกต่างที่สำคัญคือฟังก์ชั่นทั้งสองใช้งานได้จริง(ดู prev. comment) : Ь
Hi-Angel

14

นอกเหนือจากคำตอบของ @ Malabara แล้วฉันมักจะใช้with-timerมาโครที่กำหนดเองเพื่อใช้กับส่วนต่างๆของรหัสของฉันอย่างถาวร (เช่นinit.elไฟล์ของฉัน)

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

(defmacro with-timer (title &rest forms)
  "Run the given FORMS, counting the elapsed time.
A message including the given TITLE and the corresponding elapsed
time is displayed."
  (declare (indent 1))
  (let ((nowvar (make-symbol "now"))
        (body   `(progn ,@forms)))
    `(let ((,nowvar (current-time)))
       (message "%s..." ,title)
       (prog1 ,body
         (let ((elapsed
                (float-time (time-subtract (current-time) ,nowvar))))
           (message "%s... done (%.3fs)" ,title elapsed))))))

ตัวอย่างการใช้:

(with-timer "Doing things"
  (form (to (be evaluated))))

ให้ผลลัพธ์ต่อไปนี้ใน*Messages*บัฟเฟอร์:

Doing things... done (0.047s)

ฉันควรพูดถึงว่านี่เป็นแรงบันดาลใจอย่างมากจากuse-package-with-elapsed-timerมาโครของ Jon Wiegley ในการuse-packageต่อยอดเยี่ยมของเขา


หากคุณกำลังวัด init.el คุณอาจจะสนใจในemacs เริ่มต้น Profiler
Wilfred Hughes

มาโครสุดยอดมาก สมควรได้รับคะแนนมากขึ้น
Malabarba

2
Emacs บันทึกเวลาเริ่มต้นทั้งหมด emacs-init-timeคุณสามารถแสดงด้วยคำสั่ง
Joe

1
@ วิลเฟรดฮิวจ์ใช่ฉันใช้esupและฉันชอบมัน แต่อีกครั้งความสนใจของสิ่งต่าง ๆ ที่with-timerไม่มากพอที่จะเล่าเรื่องอะไร ความสนใจที่แท้จริงคือคุณมีข้อมูลการทำโปรไฟล์อยู่เสมอ เมื่อใดก็ตามที่ฉันเริ่ม emacs ฉันมีเส้นเล็ก ๆ ใน*Messages*บัฟเฟอร์ของฉันที่บอกฉันว่าส่วนไหนใช้เวลานานแค่ไหน หากฉันตรวจพบสิ่งผิดปกติฉันสามารถใช้เครื่องมือที่เพียงพอเพื่อทำโปรไฟล์และปรับให้เหมาะสม
ffevotte

@ JoeS ใช่emacs-init-timeสร้างข้อมูลที่น่าสนใจ อย่างไรก็ตามมันให้เวลาที่ผ่านไปโดยรวมเท่านั้นโดยไม่มีความเป็นไปได้ที่จะแยกย่อยแต่ละส่วนของการเริ่มต้น
ffevotte

3

นอกจากคำตอบของ @ Malabarba โปรดทราบว่าคุณสามารถวัดเวลาดำเนินการที่คอมไพล์ด้วยรหัสของคุณbenchmark-run-compiledได้ ตัวชี้วัดนั้นมักจะเกี่ยวข้องมากกว่าเวลาดำเนินการตีความที่M-x benchmarkให้คุณ:

ELISP> (benchmark-run (cl-loop for i below (* 1000 1000) sum i))
(0.79330082 6 0.2081620540000002)

ELISP> (benchmark-run-compiled (cl-loop for i below (* 1000 1000) sum i))
(0.047896284 0 0.0)

ตัวเลขสามตัวคือเวลาที่ผ่านไปทั้งหมดจำนวนการรัน GC และเวลาที่ใช้ใน GC


1

การเปรียบเทียบไม่เพียง แต่เกี่ยวกับการรับตัวเลขเท่านั้น แต่ยังเกี่ยวกับการตัดสินใจโดยอาศัยการวิเคราะห์ผลลัพธ์

มีแพ็คเกจbenchstat.elใน MELPA ซึ่งคุณสามารถใช้เพื่อรับคุณสมบัติที่โปรแกรมbenchstatจัดหาให้

จะดำเนินการเปรียบเทียบตามการเปรียบเทียบที่คุณตรวจสอบคุณสมบัติประสิทธิภาพการทำงานกับXY

ฟังก์ชั่น Benchstat สามารถดูได้เป็นbenchmark-run-compiledwrapper ที่ไม่เพียง แต่รวบรวมข้อมูล แต่ให้กลับมาอ่านง่ายในรูปแบบตีความ มันรวมถึง:

  • เวลาที่ผ่านไประหว่างXและY
  • เวลาเฉลี่ยโดยเฉลี่ย
  • จำนวนการจัดสรร

ตัวอย่างการใช้งานที่ง่ายมาก:

(require 'benchstat)

;; Decide how much repetitions is needed.
;; This is the same as `benchmark-run-compiled` REPETITIONS argument.
(defconst repetitions 1000000)

;; Collect old code profile.
(benchstat-run :old repetitions (list 1 2))
;; Collect new code profile.
(benchstat-run :new repetitions (cons 1 2))

;; Display the results.
;; Can be run interactively by `M-x benchstat-compare'.
(benchstat-compare)

benchstat-compareจะแสดงผลลัพธ์ในบัฟเฟอร์ชั่วคราว:

name   old time/op    new time/op    delta
Emacs    44.2ms ± 6%    25.0ms ±15%  -43.38%  (p=0.000 n=10+10)

name   old allocs/op  new allocs/op  delta
Emacs      23.0 ± 0%      11.4 ± 5%  -50.43%  (p=0.000 n=10+10)

คุณจะต้องใช้benchstatโปรแกรมไบนารี หากคุณใช้ภาษาโปรแกรม Go เป็นไปได้ว่าคุณมีภาษาหนึ่งในระบบ มิฉะนั้นจะมีตัวเลือกในการรวบรวมจากแหล่งที่มา

ไบนารี precompiled สำหรับลินุกซ์ / amd64 สามารถพบได้ที่หน้าปล่อย GitHub

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