Làm thế nào để tôi đo hiệu suất của mã elisp?


26

Làm thế nào để tôi đo hiệu suất của mã elisp của tôi? Những công cụ / gói bên ngoài nào có sẵn để tôi đo thời gian thực hiện?

Ngoài tổng thời gian, tôi có thể xem một hồ sơ hiển thị thời gian thực hiện cho mỗi chức năng không? Tôi có thể cấu hình sử dụng bộ nhớ quá không?


1
Câu hỏi quá rộng. Những loại hiệu suất? Ở đâu? Khi nào? " Hiệu suất Emacs " có thể có nghĩa là bất cứ điều gì và tất cả mọi thứ.
vẽ

@Drew Nhiều ngôn ngữ lập trình khác có một bộ điểm chuẩn (ví dụ: Python: speed.pypy.org , JS: Sunspider, v.v.), và tôi đã hy vọng rằng có một trình thông dịch elisp tương đương.
Wilfred Hughes

Điểm chuẩn như được cung cấp bởi chức năng benchmarkvà trình lược tả không đo lường hiệu suất của Emacs . Nó đo hiệu suất đánh giá các biểu thức cụ thể. Nó rất hữu ích trong việc so sánh các màn trình diễn trong Emacs. Để đo hiệu suất của chính Emacs, bạn sẽ cần so sánh nó với hiệu suất của một thứ khác ngoài Emacs. Và đó là nơi mà bề rộng của Emacs phát huy tác dụng. Bạn có thể đo Emacs vs XYZ cho cái này hoặc cái kia, nhưng để đo hiệu suất của Emacs nói chung, bạn sẽ cần nhiều so sánh như vậy.
vẽ

Có lẽ bạn có nghĩa là " Làm thế nào để tôi đo hiệu suất trong Emacs "?
vẽ

2
OK, tôi đã mở emacs.stackexchange.com/q/655/304 để nói về điểm chuẩn Emacs và đặt lại câu hỏi này là về điểm chuẩn / hồ sơ các chương trình elisp.
Wilfred Hughes

Câu trả lời:


31

Điểm chuẩn

Các tùy chọn đơn giản nhất là benchmarkgói tích hợp. Cách sử dụng của nó rất đơn giản:

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

Nó được tải tự động, do đó bạn thậm chí không cần phải yêu cầu.

Hồ sơ

Điểm chuẩn là tốt trong các bài kiểm tra tổng thể, nhưng nếu bạn gặp vấn đề về hiệu năng thì nó không cho bạn biết chức năng nào đang gây ra sự cố. Cho rằng, bạn có (còn built-in) profiler .

  1. Bắt đầu với M-x profiler-start.
  2. Làm một số hoạt động tốn thời gian.
  3. Nhận báo cáo với M-x profiler-report.

Bạn nên được đưa đến một bộ đệm với một cây điều hướng các hàm gọi.
Ảnh chụp màn hình Profiler


benchmarkHàm dường như không hoạt động: khi tôi thực hiện trong một .ctệp đã mở (benchmark 100 (c-font-lock-fontify-region 0 17355)), tôi tiếp tục nhận được void-function jit-lock-bounds.
Hi-Angel

1
FTR: thay thế cho benchmarkcác chức năng benchmark-runbenchmark-run-compiled. Đối với tôi, sự khác biệt chính là cả hai chức năng thực sự hoạt động (xem phần bình luận trước) :
Hi-Angel

14

Ngoài câu trả lời của @ Malabara, tôi có xu hướng sử dụng with-timermacro được tạo tùy chỉnh để sử dụng vĩnh viễn các phần khác nhau trong mã của tôi (ví dụ: init.eltệp của tôi ).

Sự khác biệt là trong khi benchmarkcho phép nghiên cứu hiệu năng của một đoạn mã cụ thể mà bạn sử dụng, with-timerluôn cung cấp cho bạn thời gian dành cho từng phần của mã (không có nhiều chi phí cho các phần đủ lớn), cho bạn biết đầu vào để biết phần nào cần được điều tra thêm.

(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))))))

Ví dụ sử dụng:

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

mang lại đầu ra sau trong *Messages*bộ đệm:

Doing things... done (0.047s)

Tôi nên đề cập rằng điều này được truyền cảm hứng rất nhiều từ use-package-with-elapsed-timermacro của Jon Wiegley trong use-packagephần mở rộng tuyệt vời của anh ấy .


Nếu bạn đang đo init.el, có lẽ bạn sẽ quan tâm đến trình tạo hồ sơ khởi động emacs .
Wilfred Hughes

Macro là tuyệt vời. Điều này xứng đáng nhiều phiếu hơn.
Malabarba

2
Emacs ghi lại tổng thời gian init. Bạn có thể hiển thị nó với lệnh emacs-init-time.
Joe

1
@WilfredHughes vâng, tôi có sử dụng esupvà tôi thích nó. Nhưng một lần nữa, sự quan tâm của một thứ như with-timervậy không phải là quá nhiều để hồ sơ một cái gì đó mạnh mẽ. Sự quan tâm thực sự là bạn luôn có thông tin hồ sơ. Bất cứ khi nào tôi bắt đầu emacs, tôi có một dòng các dòng trong *Messages*bộ đệm của tôi cho tôi biết phần nào mất bao lâu. Nếu tôi phát hiện bất cứ điều gì bất thường, thì tôi có thể sử dụng bất kỳ công cụ nào đầy đủ hơn để lập hồ sơ và tối ưu hóa mọi thứ.
ffevotte

@JoeS Có, emacs-init-timekhông tạo ra thông tin thú vị. Tuy nhiên, nó chỉ đưa ra một thời gian bao gồm, mà không có khả năng phá vỡ các phần riêng lẻ của việc khởi tạo.
ffevotte

3

Ngoài câu trả lời của @ Malabarba, lưu ý rằng bạn có thể đo thời gian thực hiện được biên dịch của mã của mình với benchmark-run-compiled. Số liệu đó thường phù hợp hơn nhiều so với thời gian thực hiện được giải thíchM-x benchmark mang lại cho bạn:

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)

Ba con số là tổng thời gian đã trôi qua, số lần chạy GC và thời gian dành cho GC.


1

Điểm chuẩn không chỉ là về việc lấy số, mà còn là việc đưa ra quyết định dựa trên phân tích kết quả.

Có gói băng ghế dự bị trên MELPA mà bạn có thể sử dụng để có được các tính năng mà chương trình băng ghế dự bị cung cấp.

Nó thực hiện đo điểm chuẩn dựa trên so sánh nơi bạn kiểm tra Xcác thuộc tính hiệu suất Y.

Các chức năng của băng ghế dự bị có thể được xem như một benchmark-run-compiledtrình bao bọc không chỉ thu thập thông tin mà còn giúp nó dễ đọc định dạng phiên dịch. Nó bao gồm:

  • Thời gian đã trôi qua giữa XY
  • Thời gian trung bình trung bình
  • Số tiền phân bổ

Ví dụ sử dụng rất đơn giản:

(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)

Các benchstat-comparesẽ làm cho kết quả trong một bộ đệm tạm thời:

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)

Bạn sẽ cần benchstatchương trình nhị phân mặc dù. Nếu bạn đã sử dụng ngôn ngữ lập trình Go, rất có thể bạn đã có một ngôn ngữ trong hệ thống của mình. Nếu không, có một tùy chọn biên dịch nó từ các nguồn.

Nhị phân được biên dịch sẵn cho linux / amd64 có thể được tìm thấy tại trang phát hành github .

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.