Các lựa chọn thay thế cho gprof [đã đóng]


166

Những chương trình khác làm điều tương tự như gprof?


2
Những nền tảng bạn quan tâm?
osgx

2
Tôi quan tâm đến Linux.
neuromancer


13
@Gregory - Tôi có khuynh hướng đồng ý, và có lẽ anh ta nên đóng góp bằng câu trả lời của riêng mình, 229 so với 6, tất cả 6 câu trả lời đó là câu hỏi của chính anh ta ...
Jean-Bernard Pellerin

5
Làm thế nào câu hỏi này không mang tính xây dựng?
JohnTortugo

Câu trả lời:


73

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.


2
@Norman: ++ Sự nhầm lẫn đó về đệ quy dường như là đặc hữu đối với các hệ thống có khái niệm về thời gian di chuyển giữa các nút trong biểu đồ. Ngoài ra, tôi nghĩ rằng thời gian đồng hồ treo tường thường hữu ích hơn thời gian hướng dẫn của CPU và các dòng mã (hướng dẫn cuộc gọi) hữu ích hơn các quy trình. Nếu các mẫu ngăn xếp tại thời gian đồng hồ treo tường ngẫu nhiên được lấy, thì chi phí phân đoạn của một dòng (hoặc thủ tục hoặc bất kỳ mô tả nào khác bạn có thể thực hiện) được ước tính đơn giản bằng tỷ lệ của các mẫu thể hiện nó.
Mike Dunlavey

1
... Tôi đang nhấn mạnh hướng dẫn cuộc gọi, nhưng nó áp dụng cho bất kỳ hướng dẫn nào. Nếu ai đó có một nút cổ chai điểm nóng trung thực, chẳng hạn như một bong bóng gồm một dãy số lớn, thì các hướng dẫn so sánh / nhảy / hoán đổi / gia tăng của vòng lặp bên trong sẽ ở trên cùng / dưới cùng của gần như mọi mẫu ngăn xếp . Nhưng (đặc biệt là khi phần mềm trở nên lớn và hầu như không có thói quen nào có nhiều thời gian "tự"), nhiều vấn đề thực sự là hướng dẫn cuộc gọi, yêu cầu công việc, khi rõ ràng chi phí là bao nhiêu, thực sự không phải thực hiện.
Mike Dunlavey

3
... Kiểm tra này. Tôi nghĩ rằng họ gần như đang đi đúng hướng: rotateright.com/zoom.html
Mike Dunlavey

195

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 callhướ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ư:

  1. 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.

  2. 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.)

  3. đồ 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.

  4. đệ 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%.

  5. độ 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.

  6. 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.

  7. 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.

  8. 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.

  9. 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.)

  10. 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 vWxYzlần lượt là 1/2, 1/4, 1/8, 1/16, 1/32. Lấy mẫu vdễ 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ờ Wmấ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.


3
@Norman: Tôi đã tạo một hồ sơ dựa trên điều này, trong C cho DOS, khoảng '93. Tôi đã gọi nó là một máy phân tích hiệu suất khác, và đã giới thiệu nó xung quanh tại các cuộc họp của IEEE, nhưng đó là tất cả. Có một sản phẩm từ RotateRight có tên là Zoom không quá xa. Trên * nix, pstack tốt cho việc thực hiện thủ công. Danh sách việc cần làm của tôi cho công việc (dược điển trên Windows) dài khoảng một dặm, bao gồm các dự án thú vị, không đề cập đến gia đình. Điều này có thể hữu ích: stackoverflow.com/questions/1777669/ Kẻ
Mike Dunlavey

6
Tôi luôn thấy các trình biên dịch không hữu ích cho việc sửa mã chậm, và thay vào đó sử dụng các đoạn mã gỡ lỗi có chọn lọc để đo thời gian thực hiện bởi một nhóm các câu lệnh tôi chọn, thường được hỗ trợ bởi một số macro nhỏ tầm thường hoặc bất cứ điều gì. Tôi không bao giờ mất quá nhiều thời gian để tìm ra thủ phạm, nhưng tôi luôn bối rối với cách tiếp cận "da gấu và dao đá" của mình khi "mọi người khác" (theo như tôi biết) sử dụng các công cụ ưa thích. Cảm ơn bạn đã cho tôi thấy lý do tại sao tôi không bao giờ có thể nhận được thông tin tôi cần từ hồ sơ. Đây là một trong những ý tưởng quan trọng nhất tôi từng thấy trên SO. Làm tốt!
Wayne Conrad

7
@osgx: Tôi không có ý định xé toạc bất cứ thứ gì. Nó giống như một chiếc ô tô cũ yêu thích, đơn giản và chắc chắn, nhưng có những thứ nó không làm được, và chúng ta cần phải nhận thức được những điều đó, và không chỉ vậy, chúng ta cần phải thức dậy khỏi những huyền thoại. Tôi đánh giá cao rằng trên một số nền tảng có thể khó lấy mẫu ngăn xếp, nhưng nếu một vấn đề là gprof sẽ không tìm thấy nó, thì thực tế đó là công cụ duy nhất là sự thoải mái nhỏ.
Mike Dunlavey

2
@Andrew: ... nếu lý do đó áp dụng cho một số phần đáng kể của các mẫu (như hơn 1), thì (các) dòng mã có thể loại bỏ hoạt động đó nằm trên các mẫu đó. Một biểu đồ có thể cung cấp cho bạn một gợi ý về điều này, nhưng một số lượng lớn các mẫu ngăn xếp sẽ chỉ hiển thị chúng cho bạn.
Mike Dunlavey

2
@Matt: Ví dụ về các vấn đề về hiệu suất IO được tìm thấy theo cách này: 1) in các thông điệp nhật ký vào một tệp hoặc bảng điều khiển, được cho là không đáng kể. 2) Chuyển đổi giữa văn bản và nhân đôi trong IO số. 3) IO trích xuất các chuỗi quốc tế hóa trong quá trình khởi động, các chuỗi mà hóa ra không cần phải được quốc tế hóa. Tôi đã nhấn rất nhiều ví dụ như thế này.
Mike Dunlavey

63

Vì tôi không thấy ở đây bất cứ điều gì về perfmộ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 perfnếu Linux Kernel của bạn lớn hơn 2.6.32 hoặc oprofilenế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ư gprofyêu cầu). Tuy nhiên để có được biểu đồ cuộc gọi chính xác, perfbạ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.sovì nó được biên dịch -fno-omit-frame-pointertrong 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;
}

Tôi chỉ chạy ví dụ của bạn và lấy 5 stackshots. Đây là những gì họ tìm thấy: 40% (khoảng) thời gian 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.
Mike Dunlavey

stackshotgì Có phải đó là pstackđầu ra?

2
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.

2
Đối với # 1. Đôi khi khách hàng gọi và nói rằng chương trình của bạn hoạt động chậm. Bạn không thể nói ngay điều đó 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.

2
Đối với # 2. Đơn giản hóa là một cách tiếp cận tốt, tôi đồng ý. Đôi khi nó hoạt động. Nếu sự cố hiệu suất chỉ xảy ra trên máy chủ của khách hàng và bạn không thể sao chép chúng trên máy chủ của mình thì hồ sơ sẽ được sử dụng.

21

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.


2
Như đã đề cập trong câu trả lời valgrind, Zoom từ RotateRight ( rotateright.com ) cung cấp giao diện đẹp hơn nhiều và cho phép định hình từ xa.
JanePhanie

không thích oprofile, nó có vẻ ngớ ngẩn
Matt Joiner

@Matt điểm nào cụ thể?
Anycorn

Nó không thể đối phó với hơn 10 giây thực thi trước khi tạo ra tràn stat, đầu ra không đặc biệt hữu ích và tài liệu này rất khủng khiếp.
Matt Joiner

1
@Tho OProfile: ARM, POWER, ia64, ...
Anycorn



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.