Python: Đánh giá hiệu năng của code với cProfiler
Bài đăng này đã không được cập nhật trong 5 năm
Giới thiệu
Profiler là công cụ cho phép lập trình viên đánh giá hiệu năng của các đoạn code trong chương trình, từ đó tìm ra đoạn code chạy chậm hoặc tiêu tốn nhiều tài nguyên để optimize.
Từ phiên bản 2.5, Python cung cấp module cProfile
cho phép đo đạc thời gian tính toán, tài nguyên sử dụng của code.
cProfile
Trong phần này, ta xét một ví dụ đơn giản, đó là tính số hạng thứ n trong dãy Fibbonacci sử dụng đệ quy.
Tạo file fib.py
có nội dung như sau:
import sys
import functools
def fib(n):
if n < 2:
return n
return fib(n-1) + fib(n-2)
@functools.lru_cache()
def fib_cached(n):
if n < 2:
return n
return fib_cached(n-1) + fib_cached(n-2)
if __name__ == '__main__':
n = 32
if sys.argv[-1] == 'cached':
fib_cached(n)
else:
fib(n)
Cả 2 hàm đều tính dãy Fibonacci sử dụng đệ quy. Tuy nhiên, hàm
fib_cached
sử dụng thêm cache để ghi lại các giá trị được tính toán. Chi tiết về cách sử dụnglru_cache
trong Python, bạn đọc có thể xem tại đây.
Tiếp theo, ta thử đánh giá hiệu năng của chương trình trong trường hợp không sử dụng bộ nhớ cache. Chạy dòng sau trong terminal:
python3 -m cProfile -s calls fib.py
Kết quả nhận được:
7049175 function calls (21 primitive calls) in 1.468 seconds
Ordered by: call count
ncalls tottime percall cumtime percall filename:lineno(function)
7049155/1 1.468 0.000 1.468 1.468 fib.py:5(fib)
7 0.000 0.000 0.000 0.000 {built-in method builtins.getattr}
5 0.000 0.000 0.000 0.000 {built-in method builtins.setattr}
1 0.000 0.000 0.000 0.000 {method 'update' of 'dict' objects}
1 0.000 0.000 1.468 1.468 {built-in method builtins.exec}
1 0.000 0.000 0.000 0.000 {built-in method builtins.isinstance}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
1 0.000 0.000 1.468 1.468 fib.py:1(<module>)
1 0.000 0.000 0.000 0.000 functools.py:479(decorating_function)
1 0.000 0.000 0.000 0.000 functools.py:448(lru_cache)
1 0.000 0.000 0.000 0.000 functools.py:44(update_wrapper)
Các thông số trong kết quả:
ncalls
: tổng số lần gọi hàmtottime
: tổng thời gian sử dụng để thực hiện một hàm (không bao gồm thời gian gọi các hàm con)percall
: bằngtottime / ncalls
cumtime
: tổng thời gian tích luỹ để thực hiện xong phần code, từ khi được gọi cho đến khi kết thúcfilename:lineno(function)
: phần code được thực hiện Bây giờ, thử đánh giá chương trình trong trường hợp sử dụng cache:
python3 -m cProfile -s calls fib.py cached
Kết quả:
53 function calls (21 primitive calls) in 0.000 seconds
Ordered by: call count
ncalls tottime percall cumtime percall filename:lineno(function)
33/1 0.000 0.000 0.000 0.000 fib.py:11(fib_cached)
7 0.000 0.000 0.000 0.000 {built-in method builtins.getattr}
5 0.000 0.000 0.000 0.000 {built-in method builtins.setattr}
1 0.000 0.000 0.000 0.000 {method 'update' of 'dict' objects}
1 0.000 0.000 0.000 0.000 {built-in method builtins.exec}
1 0.000 0.000 0.000 0.000 {built-in method builtins.isinstance}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
1 0.000 0.000 0.000 0.000 fib.py:1(<module>)
1 0.000 0.000 0.000 0.000 functools.py:479(decorating_function)
1 0.000 0.000 0.000 0.000 functools.py:448(lru_cache)
1 0.000 0.000 0.000 0.000 functools.py:44(update_wrapper)
Trường hợp sử dụng cache, số lần gọi hàm giảm xuống còn 33, thời gian thực hiện xấp xỉ 0s (trường hợp không sử dụng cache, số lần gọi hàm là hơn 7 triệu ).
Visualization
Rõ ràng việc hiển thị kết quả trên terminal khá nhàm chán và khó theo dõi được kết quả. Do đó cần một công cụ để biểu diễn trực quan kết quả. Một trong các công cụ đó là KCachegrind. Với Ubuntu, KCachegrind có thể dễ dàng cài đặt chỉ bằng một câu lệnh
sudo apt-get install kcachegrind
Để biểu diễn kết quả trên KCachegrind, trước tiên cần lưu kết quả ra cProfile
file, sau đó cần đổi sang định dạng callgrind
file mà KCachegrind có thể hiểu được. Để làm dược việc này cần thêm module pyprof2calltree
của Python:
pip3 install pyprof2calltree --user
Ví dụ với chương trình tính dãy số Fibonacci:
- Lưu lại kết quả
python3 -m cProfile -o fib.profile fib.py
- Chuyển đổi kết quả sang định dạng file
callgrind
pyprof2calltree -i fib.profile -o fib.callgrind
- Visualize kết quả với KCachegrind
kcachegrind fib.callgrind
hoặc có thể mở chương trình KCachegrind, chọn File/Open, sau đó chọn đường dẫn đến file fib.callgrind
.
Kết quả thu được:
Kết luận
Trên đây là trình bày về cách sử dụng cơ bản công cụ cProfile
. Bài viết có thể còn nhiều thiếu sót, rất mong nhận được sự góp ý của mọi người.
Tài liệu tham khảo
All rights reserved