Phương pháp phân tích động
Ở đây tôi mô tả một vài phương pháp phân tích động.
Các phương thức động thực sự chạy chương trình để xác định đồ thị cuộc gọi.
Đối lập với các phương thức động là các phương thức tĩnh, cố gắng xác định nó từ nguồn một mình mà không cần chạy chương trình.
Ưu điểm của phương pháp động:
- bắt con trỏ hàm và lệnh gọi C ++ ảo. Chúng hiện diện với số lượng lớn trong bất kỳ phần mềm không tầm thường nào.
Nhược điểm của phương pháp động:
- bạn phải chạy chương trình, chương trình này có thể chậm hoặc yêu cầu thiết lập mà bạn không có, ví dụ: biên dịch chéo
- chỉ các hàm thực sự được gọi mới hiển thị. Ví dụ: một số hàm có thể được gọi hoặc không tùy thuộc vào các đối số dòng lệnh.
KcacheGrind
https://kcachegrind.github.io/html/Home.html
Chương trình kiểm tra:
int f2(int i) { return i + 2; }
int f1(int i) { return f2(2) + i + 1; }
int f0(int i) { return f1(1) + f2(2); }
int pointed(int i) { return i; }
int not_called(int i) { return 0; }
int main(int argc, char **argv) {
int (*f)(int);
f0(1);
f1(1);
f = pointed;
if (argc == 1)
f(1);
if (argc == 2)
not_called(1);
return 0;
}
Sử dụng:
sudo apt-get install -y kcachegrind valgrind
# Compile the program as usual, no special flags.
gcc -ggdb3 -O0 -o main -std=c99 main.c
# Generate a callgrind.out.<PID> file.
valgrind --tool=callgrind ./main
# Open a GUI tool to visualize callgrind data.
kcachegrind callgrind.out.1234
Bây giờ bạn đang ở bên trong một chương trình GUI tuyệt vời chứa nhiều dữ liệu hiệu suất thú vị.
Ở dưới cùng bên phải, chọn tab "Biểu đồ cuộc gọi". Điều này hiển thị một biểu đồ cuộc gọi tương tác tương quan với số liệu hiệu suất trong các cửa sổ khác khi bạn nhấp vào các chức năng.
Để xuất biểu đồ, hãy nhấp chuột phải vào biểu đồ đó và chọn "Xuất biểu đồ". PNG được xuất trông giống như sau:
Từ đó chúng ta có thể thấy rằng:
- nút gốc là
_start
, là điểm vào ELF thực và chứa bảng soạn khởi tạo glibc
f0
, f1
Và f2
được gọi là như mong đợi từ người khác
pointed
cũng được hiển thị, mặc dù chúng tôi đã gọi nó bằng một con trỏ hàm. Nó có thể không được gọi nếu chúng ta đã truyền một đối số dòng lệnh.
not_called
không được hiển thị vì nó không được gọi trong quá trình chạy, vì chúng tôi không chuyển đối số dòng lệnh bổ sung.
Điều thú vị valgrind
là nó không yêu cầu bất kỳ tùy chọn biên dịch đặc biệt nào.
Do đó, bạn có thể sử dụng nó ngay cả khi bạn không có mã nguồn, chỉ có tệp thực thi.
valgrind
quản lý để làm điều đó bằng cách chạy mã của bạn thông qua một "máy ảo" nhẹ. Điều này cũng làm cho việc thực thi cực kỳ chậm so với thực thi gốc.
Như có thể thấy trên biểu đồ, thông tin thời gian về mỗi lệnh gọi hàm cũng được thu thập và thông tin này có thể được sử dụng để lập cấu hình chương trình, đây có thể là trường hợp sử dụng ban đầu của thiết lập này, không chỉ để xem biểu đồ cuộc gọi: Làm cách nào để tôi lập cấu hình Mã C ++ chạy trên Linux?
Đã thử nghiệm trên Ubuntu 18.04.
gcc -finstrument-functions
+ vân vân
https://github.com/elcritch/etrace
-finstrument-functions
thêm các lệnh gọi lại , etrace phân tích cú pháp tệp ELF và triển khai tất cả các lệnh gọi lại.
Tuy nhiên, thật không may, tôi không thể làm cho nó hoạt động: Tại sao `-f kinh nguyệt-chức năng` không hoạt động cho tôi?
Đầu ra đã xác nhận có định dạng:
\-- main
| \-- Crumble_make_apple_crumble
| | \-- Crumble_buy_stuff
| | | \-- Crumble_buy
| | | \-- Crumble_buy
| | | \-- Crumble_buy
| | | \-- Crumble_buy
| | | \-- Crumble_buy
| | \-- Crumble_prepare_apples
| | | \-- Crumble_skin_and_dice
| | \-- Crumble_mix
| | \-- Crumble_finalize
| | | \-- Crumble_put
| | | \-- Crumble_put
| | \-- Crumble_cook
| | | \-- Crumble_put
| | | \-- Crumble_bake
Có thể là phương pháp hiệu quả nhất bên cạnh hỗ trợ theo dõi phần cứng cụ thể, nhưng có nhược điểm là bạn phải biên dịch lại mã.