Những chương trình khác làm điều tương tự như gprof?
Những chương trình khác làm điều tương tự như gprof?
Câu trả lời:
Valgrind có một hồ sơ đếm số hướng dẫn với một trình hiển thị rất đẹp có tên là KCacheGrind . Như Mike Dunlavey khuyến nghị, Valgrind đếm một phần các hướng dẫn mà một thủ tục được thực hiện trên ngăn xếp, mặc dù tôi rất tiếc phải nói rằng nó dường như bị lẫn lộn khi có sự đệ quy lẫn nhau. Nhưng visualizer là rất tốt đẹp và ánh sáng năm trước gprof
.
gprof (đọc bài báo) tồn tại vì lý do lịch sử. Nếu bạn nghĩ rằng nó sẽ giúp bạn tìm thấy các vấn đề về hiệu suất, nó không bao giờ được quảng cáo như vậy. Đây là những gì tờ báo nói:
Chương trình có thể được sử dụng để so sánh và đánh giá chi phí thực hiện khác nhau.
Nó không nói rằng nó có thể được sử dụng để xác định các triển khai khác nhau được đánh giá, mặc dù nó ngụ ý rằng nó có thể, trong những trường hợp đặc biệt:
đặc biệt là nếu các phần nhỏ của chương trình được tìm thấy để chi phối thời gian thực hiện của nó.
Còn những vấn đề không được bản địa hóa thì sao? Làm những điều không quan trọng? Đừng đặt kỳ vọng vào gprof chưa bao giờ được yêu cầu cho nó. Nó chỉ là một công cụ đo lường và chỉ hoạt động gắn với CPU.
Hãy thử điều này thay thế.
Đây là một ví dụ về việc tăng tốc 44 lần.
Đây là một bản tăng tốc 730x.
Đây là một video trình diễn dài 8 phút.
Đây là một lời giải thích về số liệu thống kê.
Đây là một câu trả lời cho các bài phê bình.
Có một quan sát đơn giản về các chương trình. Trong một thực thi nhất định, mọi hướng dẫn chịu trách nhiệm cho một phần nhỏ của tổng thời gian (đặc biệt là các call
hướng dẫn), theo nghĩa là nếu nó không ở đó, thời gian sẽ không được sử dụng. Trong thời gian đó, hướng dẫn là trên ngăn xếp **. Khi điều đó được hiểu, bạn có thể thấy rằng -
gprof là hiện thân của những huyền thoại nhất định về hiệu suất, chẳng hạn như:
chương trình lấy mẫu truy cập là hữu ích.
Nó chỉ hữu ích nếu bạn có một nút cổ chai điểm nóng không cần thiết, chẳng hạn như một bong bóng của một mảng lớn các giá trị vô hướng. Ví dụ, ngay khi bạn thay đổi nó thành một loại bằng cách sử dụng so sánh chuỗi, nó vẫn là một nút cổ chai, nhưng việc lấy mẫu bộ đếm chương trình sẽ không thấy điều đó bởi vì bây giờ điểm nóng đang ở trong so sánh chuỗi. Mặt khác, nếu nó là để lấy mẫu bộ đếm chương trình mở rộng (ngăn xếp cuộc gọi), điểm mà tại đó so sánh chuỗi được gọi, vòng lặp sắp xếp, được hiển thị rõ ràng. Trên thực tế, gprof là một nỗ lực khắc phục những hạn chế của việc lấy mẫu chỉ bằng máy tính.
rằng các hàm thời gian quan trọng hơn việc nắm bắt các dòng mã tốn thời gian.
Lý do cho huyền thoại đó là gprof không thể chụp các mẫu ngăn xếp, vì vậy thay vào đó, nó nhân các hàm, đếm số lần gọi của chúng và cố gắng ghi lại biểu đồ cuộc gọi. Tuy nhiên, một khi chức năng tốn kém được xác định, bạn vẫn cần xem bên trong nó để biết các dòng chịu trách nhiệm về thời gian. Nếu có các mẫu ngăn xếp mà bạn không cần phải tìm, các dòng đó sẽ nằm trên các mẫu. (Một chức năng thông thường có thể có 100 - 1000 hướng dẫn. Cuộc gọi chức năng là 1 hướng dẫn, do đó, một số thứ định vị các cuộc gọi tốn kém chính xác hơn 2-3 bậc.)
đồ thị cuộc gọi là quan trọng.
Những gì bạn cần biết về một chương trình không phải là nơi nó dành thời gian, mà là tại sao. Khi nó đang dành thời gian trong một hàm, mỗi dòng mã trên ngăn xếp sẽ đưa ra một liên kết trong chuỗi lý do tại sao nó lại ở đó. Nếu bạn chỉ có thể thấy một phần của ngăn xếp, bạn chỉ có thể thấy một phần lý do tại sao, vì vậy bạn không thể biết chắc chắn rằng thời gian đó có thực sự cần thiết hay không. Biểu đồ cuộc gọi cho bạn biết điều gì? Mỗi cung cho bạn biết rằng một số hàm A đang trong quá trình gọi một số hàm B trong một phần nhỏ thời gian. Ngay cả khi A chỉ có một dòng mã như vậy gọi B, thì dòng đó chỉ đưa ra một phần nhỏ lý do tại sao. Nếu bạn đủ may mắn, có thể dòng đó có lý do kém. Thông thường, bạn cần phải xem nhiều dòng đồng thời để tìm một lý do kém nếu nó ở đó. Nếu A gọi B ở nhiều nơi, thì nó sẽ cho bạn biết ít hơn.
đệ quy đó là một vấn đề khó hiểu.
Điều đó chỉ bởi vì gprof và các trình định hình khác nhận thấy cần phải tạo một biểu đồ cuộc gọi và sau đó thời gian thuộc tính cho các nút. Nếu một người có các mẫu của ngăn xếp, thì chi phí thời gian của mỗi dòng mã xuất hiện trên các mẫu là một con số rất đơn giản - tỷ lệ của các mẫu được đặt trên đó. Nếu có đệ quy, thì một dòng nhất định có thể xuất hiện nhiều lần trên một mẫu.
Không vấn đề. Giả sử các mẫu được lấy mỗi N ms và dòng xuất hiện trên F% trong số chúng (đơn lẻ hoặc không). Nếu dòng đó có thể được thực hiện để không mất thời gian (chẳng hạn như bằng cách xóa nó hoặc phân nhánh xung quanh nó), thì các mẫu đó sẽ biến mất và thời gian sẽ giảm F%.
độ chính xác của phép đo thời gian (và do đó một số lượng lớn mẫu) rất quan trọng.
Hãy suy nghĩ về nó trong một giây. Nếu một dòng mã nằm trên 3 mẫu trong số năm mẫu, thì nếu bạn có thể bắn nó ra như một bóng đèn, thì đó sẽ là khoảng 60% thời gian ít hơn sẽ được sử dụng. Bây giờ, bạn biết rằng nếu bạn đã lấy 5 mẫu khác nhau, bạn có thể chỉ nhìn thấy nó 2 lần hoặc nhiều nhất là 4. Vì vậy, phép đo 60% giống như một phạm vi chung từ 40% đến 80%. Nếu chỉ có 40%, bạn có nói vấn đề không đáng để sửa không? Vì vậy, điểm chính xác của thời gian là gì, khi điều bạn thực sự muốn là tìm ra vấn đề ? 500 hoặc 5000 mẫu sẽ đo được vấn đề với độ chính xác cao hơn, nhưng sẽ không tìm thấy nó chính xác hơn.
việc đếm các câu lệnh hoặc hàm gọi là hữu ích.
Giả sử bạn biết một hàm đã được gọi 1000 lần. Bạn có thể nói từ đó chi phí thời gian là bao nhiêu? Bạn cũng cần biết trung bình mất bao lâu để chạy, nhân nó với số đếm và chia cho tổng thời gian. Thời gian gọi trung bình có thể thay đổi từ nano giây đến giây, do đó, chỉ riêng số lượng không nói lên nhiều. Nếu có các mẫu ngăn xếp, chi phí của một thói quen hoặc của bất kỳ câu lệnh nào chỉ là một phần của các mẫu mà nó được bật. Phần nhỏ thời gian đó về nguyên tắc có thể được lưu lại nếu quy trình hoặc câu lệnh có thể được thực hiện để không mất thời gian, vì vậy đó là điều có mối quan hệ trực tiếp nhất với hiệu suất.
rằng các mẫu không cần phải được thực hiện khi bị chặn
Lý do cho huyền thoại này có hai mặt: 1) rằng lấy mẫu PC là vô nghĩa khi chương trình đang chờ và 2) mối bận tâm với độ chính xác của thời gian. Tuy nhiên, đối với (1) chương trình rất có thể đang chờ đợi một cái gì đó mà nó yêu cầu, chẳng hạn như tệp I / O, mà bạn cần biết , và mẫu ngăn xếp nào tiết lộ. (Rõ ràng là bạn muốn loại trừ các mẫu trong khi chờ đầu vào của người dùng.) Đối với (2) nếu chương trình đang chờ đơn giản vì cạnh tranh với các quy trình khác, điều đó có lẽ xảy ra theo cách khá ngẫu nhiên trong khi nó đang chạy. Vì vậy, trong khi chương trình có thể mất nhiều thời gian hơn, điều đó sẽ không ảnh hưởng lớn đến số liệu thống kê có vấn đề, phần trăm thời gian mà các câu lệnh nằm trên ngăn xếp.
rằng vấn đề "thời gian tự" Thời gian
tự chỉ có ý nghĩa nếu bạn đang đo ở cấp độ chức năng, không phải cấp độ dòng và bạn nghĩ rằng bạn cần trợ giúp sáng suốt nếu thời gian chức năng hoàn toàn tính toán cục bộ so với các thói quen được gọi. Nếu tóm tắt ở cấp độ dòng, một dòng biểu thị thời gian tự nếu nó ở cuối ngăn xếp, nếu không, nó đại diện cho thời gian bao gồm. Dù bằng cách nào, cái giá phải trả là tỷ lệ phần trăm của các mẫu ngăn xếp, do đó, nó sẽ định vị nó cho bạn trong cả hai trường hợp.
rằng các mẫu phải được lấy ở tần số cao
Điều này xuất phát từ ý tưởng rằng một vấn đề về hiệu suất có thể xảy ra nhanh và các mẫu đó phải thường xuyên để đạt được nó. Nhưng, nếu vấn đề gây tốn kém, 20%, ví dụ, trong tổng thời gian chạy là 10 giây (hoặc bất cứ điều gì), thì mỗi mẫu trong tổng thời gian đó sẽ có 20% cơ hội đánh vào nó, bất kể sự cố xảy ra trong một mảnh như thế này
.....XXXXXXXX...........................
.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^
(20 mẫu, 4 lần truy cập)
hoặc trong nhiều mảnh nhỏ như thế này
X...X...X.X..X.........X.....X....X.....
.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^
(20 mẫu, 3 lần truy cập)
Dù bằng cách nào, số lần truy cập sẽ trung bình khoảng 1 trên 5, bất kể có bao nhiêu mẫu được lấy, hoặc làm thế nào ít (Trung bình = 20 * 0,2 = 4. Độ lệch chuẩn = +/- sqrt (20 * 0,2 * 0,8) = 1,8.)
mà bạn đang cố gắng tìm các nút cổ chai
như thể chỉ có một ở đó. Xem xét dòng thời gian thực hiện sau: vxvWvzvWvxvWvYvWvxvWv.vWvxvWvYvW
Nó bao gồm các công việc thực sự hữu ích, được đại diện bởi .
. Có các vấn đề về hiệu suất vWxYz
lần lượt là 1/2, 1/4, 1/8, 1/16, 1/32. Lấy mẫu v
dễ dàng tìm thấy . Nó được gỡ bỏ, để lại
xWzWxWYWxW.WxWYW
Bây giờ chương trình mất một nửa thời gian để chạy, và bây giờ W
mất một nửa thời gian, và được tìm thấy dễ dàng. Nó được gỡ bỏ, để lại
xzxYx.xY
quá trình này tiếp tục, mỗi lần loại bỏ vấn đề hiệu suất lớn nhất, theo tỷ lệ phần trăm, cho đến khi không thể tìm thấy gì để loại bỏ. Bây giờ điều duy nhất được thực hiện là .
, nó thực thi trong 1/32 thời gian được sử dụng bởi chương trình gốc. Đây là hiệu ứng phóng đại, bằng cách loại bỏ bất kỳ vấn đề nào làm cho phần còn lại lớn hơn, theo phần trăm, vì mẫu số bị giảm.
Một điểm quan trọng khác là mọi vấn đề đều phải được tìm thấy - không thiếu bất kỳ vấn đề nào trong số 5. Bất kỳ vấn đề nào không được tìm thấy và khắc phục đều làm giảm nghiêm trọng tỷ lệ tăng tốc cuối cùng. Chỉ tìm một số, nhưng không phải tất cả, không "đủ tốt".
THÊM: Tôi muốn chỉ ra một lý do tại sao gprof lại phổ biến - nó được dạy, có lẽ vì nó miễn phí, dễ dạy và đã có từ lâu. Một tìm kiếm nhanh của Google định vị một số tổ chức học thuật dạy nó (hoặc xuất hiện):
ber ở bu clemson colorado duke Earmham
** Ngoại trừ các cách khác để yêu cầu công việc được thực hiện, điều đó không để lại dấu vết cho biết tại sao , chẳng hạn như bằng cách gửi tin nhắn.
Vì tôi không thấy ở đây bất cứ điều gì về perf
một công cụ tương đối mới để cấu hình kernel và các ứng dụng người dùng trên Linux, tôi đã quyết định thêm thông tin này.
Trước hết - đây là hướng dẫn về cấu hình Linux vớiperf
Bạn có thể sử dụng perf
nếu Linux Kernel của bạn lớn hơn 2.6.32 hoặc oprofile
nếu nó cũ hơn. Cả hai chương trình không yêu cầu bạn thiết bị chương trình của bạn (như gprof
yêu cầu). Tuy nhiên để có được biểu đồ cuộc gọi chính xác, perf
bạn cần xây dựng chương trình cho mình -fno-omit-frame-pointer
. Ví dụ : g++ -fno-omit-frame-pointer -O2 main.cpp
.
Bạn có thể xem phân tích "trực tiếp" của ứng dụng của mình với perf top
:
sudo perf top -p `pidof a.out` -K
Hoặc bạn có thể ghi dữ liệu hiệu suất của một ứng dụng đang chạy và phân tích chúng sau đó:
1) Để ghi dữ liệu hiệu suất:
perf record -p `pidof a.out`
hoặc để ghi lại trong 10 giây:
perf record -p `pidof a.out` sleep 10
hoặc để ghi với biểu đồ cuộc gọi ()
perf record -g -p `pidof a.out`
2) Để phân tích dữ liệu được ghi lại
perf report --stdio
perf report --stdio --sort=dso -g none
perf report --stdio -g none
perf report --stdio -g
Hoặc bạn có thể ghi lại dữ liệu hiệu suất của ứng dụng và phân tích chúng sau đó chỉ bằng cách khởi chạy ứng dụng theo cách này và chờ cho nó thoát ra:
perf record ./a.out
Đây là một ví dụ về hồ sơ chương trình thử nghiệm
Chương trình thử nghiệm nằm trong tệp main.cpp (Tôi sẽ đặt main.cpp ở cuối thư):
Tôi biên dịch nó theo cách này:
g++ -m64 -fno-omit-frame-pointer -g main.cpp -L. -ltcmalloc_minimal -o my_test
Tôi sử dụng libmalloc_minimial.so
vì nó được biên dịch -fno-omit-frame-pointer
trong khi libc malloc dường như được biên dịch mà không có tùy chọn này. Sau đó, tôi chạy chương trình thử nghiệm của mình
./my_test 100000000
Sau đó, tôi ghi lại dữ liệu hiệu suất của một quy trình đang chạy:
perf record -g -p `pidof my_test` -o ./my_test.perf.data sleep 30
Sau đó, tôi phân tích tải trên mỗi mô-đun:
báo cáo hoàn hảo --stdio -g none --sort comm, dso -i ./my_test.perf.data
# Overhead Command Shared Object
# ........ ....... ............................
#
70.06% my_test my_test
28.33% my_test libtcmalloc_minimal.so.0.1.0
1.61% my_test [kernel.kallsyms]
Sau đó, tải cho mỗi chức năng được phân tích:
báo cáo hoàn hảo --stdio -g none -i ./my_test.perf.data | dịch lọc c ++
# Overhead Command Shared Object Symbol
# ........ ....... ............................ ...........................
#
29.30% my_test my_test [.] f2(long)
29.14% my_test my_test [.] f1(long)
15.17% my_test libtcmalloc_minimal.so.0.1.0 [.] operator new(unsigned long)
13.16% my_test libtcmalloc_minimal.so.0.1.0 [.] operator delete(void*)
9.44% my_test my_test [.] process_request(long)
1.01% my_test my_test [.] operator delete(void*)@plt
0.97% my_test my_test [.] operator new(unsigned long)@plt
0.20% my_test my_test [.] main
0.19% my_test [kernel.kallsyms] [k] apic_timer_interrupt
0.16% my_test [kernel.kallsyms] [k] _spin_lock
0.13% my_test [kernel.kallsyms] [k] native_write_msr_safe
and so on ...
Sau đó, chuỗi cuộc gọi được phân tích:
báo cáo hoàn hảo --stdio -g đồ thị -i ./my_test.perf.data | dịch lọc c ++
# Overhead Command Shared Object Symbol
# ........ ....... ............................ ...........................
#
29.30% my_test my_test [.] f2(long)
|
--- f2(long)
|
--29.01%-- process_request(long)
main
__libc_start_main
29.14% my_test my_test [.] f1(long)
|
--- f1(long)
|
|--15.05%-- process_request(long)
| main
| __libc_start_main
|
--13.79%-- f2(long)
process_request(long)
main
__libc_start_main
15.17% my_test libtcmalloc_minimal.so.0.1.0 [.] operator new(unsigned long)
|
--- operator new(unsigned long)
|
|--11.44%-- f1(long)
| |
| |--5.75%-- process_request(long)
| | main
| | __libc_start_main
| |
| --5.69%-- f2(long)
| process_request(long)
| main
| __libc_start_main
|
--3.01%-- process_request(long)
main
__libc_start_main
13.16% my_test libtcmalloc_minimal.so.0.1.0 [.] operator delete(void*)
|
--- operator delete(void*)
|
|--9.13%-- f1(long)
| |
| |--4.63%-- f2(long)
| | process_request(long)
| | main
| | __libc_start_main
| |
| --4.51%-- process_request(long)
| main
| __libc_start_main
|
|--3.05%-- process_request(long)
| main
| __libc_start_main
|
--0.80%-- f2(long)
process_request(long)
main
__libc_start_main
9.44% my_test my_test [.] process_request(long)
|
--- process_request(long)
|
--9.39%-- main
__libc_start_main
1.01% my_test my_test [.] operator delete(void*)@plt
|
--- operator delete(void*)@plt
0.97% my_test my_test [.] operator new(unsigned long)@plt
|
--- operator new(unsigned long)@plt
0.20% my_test my_test [.] main
0.19% my_test [kernel.kallsyms] [k] apic_timer_interrupt
0.16% my_test [kernel.kallsyms] [k] _spin_lock
and so on ...
Vì vậy, tại thời điểm này, bạn biết nơi chương trình của bạn dành thời gian.
Và đây là main.cpp cho bài kiểm tra:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
time_t f1(time_t time_value)
{
for (int j =0; j < 10; ++j) {
++time_value;
if (j%5 == 0) {
double *p = new double;
delete p;
}
}
return time_value;
}
time_t f2(time_t time_value)
{
for (int j =0; j < 40; ++j) {
++time_value;
}
time_value=f1(time_value);
return time_value;
}
time_t process_request(time_t time_value)
{
for (int j =0; j < 10; ++j) {
int *p = new int;
delete p;
for (int m =0; m < 10; ++m) {
++time_value;
}
}
for (int i =0; i < 10; ++i) {
time_value=f1(time_value);
time_value=f2(time_value);
}
return time_value;
}
int main(int argc, char* argv2[])
{
int number_loops = argc > 1 ? atoi(argv2[1]) : 1;
time_t time_value = time(0);
printf("number loops %d\n", number_loops);
printf("time_value: %d\n", time_value );
for (int i =0; i < number_loops; ++i) {
time_value = process_request(time_value);
}
printf("time_value: %ld\n", time_value );
return 0;
}
f1
đang gọi delete
. 40% (khoảng) thời gian process_request
được gọi delete
. Một phần tốt của phần còn lại đã được sử dụng new
. Các phép đo là thô, nhưng các điểm nóng được xác định chính xác.
As in my answer, you run it under a debugger and hit ^C at a random time and capture the stack trace
. 1) Tôi nghĩ rằng kỹ thuật của bạn không hữu ích khi bạn cần phân tích các vấn đề về hiệu suất cho một chương trình đang chạy trên máy chủ của khách hàng. 2) Tôi không chắc cách bạn áp dụng kỹ thuật này để lấy thông tin cho một chương trình có nhiều luồng xử lý các yêu cầu khác nhau. Ý tôi là khi bức tranh chung khá phức tạp.
the problem is outside your code
, phải không? Vì bạn có thể cần một số thông tin để hỗ trợ quan điểm của mình. Trong tình huống này, tại một số điểm bạn có thể cần phải lập hồ sơ cho ứng dụng của mình. Bạn không thể yêu cầu khách hàng của mình bắt đầu gdb và nhấn ^ C và nhận ngăn xếp cuộc gọi. Đây là quan điểm của tôi. Đây là một ví dụ spielwiese.fontein.de/2012/01/22/ . Tôi đã có vấn đề này và hồ sơ đã giúp rất nhiều.
Hãy thử OProfile . Nó là một công cụ tốt hơn nhiều để định hình mã của bạn. Tôi cũng sẽ đề nghị Intel VTune .
Hai công cụ trên có thể thu hẹp thời gian dành cho một dòng mã cụ thể, chú thích mã của bạn, hiển thị lắp ráp và bao nhiêu hướng dẫn cụ thể. Bên cạnh số liệu thời gian, bạn cũng có thể truy vấn các bộ đếm cụ thể, ví dụ: lần truy cập bộ đệm, v.v.
Không giống như gprof, bạn có thể cấu hình bất kỳ quá trình / nhị phân nào đang chạy trên hệ thống của bạn bằng cách sử dụng một trong hai.
Các công cụ hiệu suất của Google bao gồm một trình lược tả đơn giản để sử dụng. CPU cũng như heap profiler có sẵn.
Hãy xem Sysprof .
Phân phối của bạn có thể có nó rồi.
http://lttng.org/ nếu bạn muốn một trình theo dõi hiệu suất cao