C ++ प्रोफाइलिंग तकनीकों का सर्वेक्षण
इस उत्तर में, मैं कुछ अलग-अलग सरल परीक्षण कार्यक्रमों का विश्लेषण करने के लिए कई अलग-अलग साधनों का उपयोग करूँगा, ताकि उन साधनों की तुलना कैसे की जा सके।
निम्नलिखित परीक्षण कार्यक्रम बहुत सरल है और निम्न कार्य करता है:
mainकॉल fastऔर maybe_slow3 बार, एक maybe_slowकॉल धीमी हो रही है
धीमी गति से कॉल maybe_slow10x लंबी है, और रनटाइम पर हावी हो जाती है अगर हम चाइल्ड फ़ंक्शन को कॉल पर विचार करते हैं common। आदर्श रूप से, प्रोफाइलिंग टूल हमें विशिष्ट धीमे कॉल पर इंगित करने में सक्षम होगा।
दोनों fastऔर maybe_slowकॉल करें common, जो कार्यक्रम के निष्पादन के थोक के लिए खाता है
कार्यक्रम इंटरफ़ेस है:
./main.out [n [seed]]
और कार्यक्रम O(n^2)कुल में लूप करता है । seedबस रनटाइम को प्रभावित किए बिना अलग-अलग आउटपुट प्राप्त करना है।
main.c
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
uint64_t __attribute__ ((noinline)) common(uint64_t n, uint64_t seed) {
for (uint64_t i = 0; i < n; ++i) {
seed = (seed * seed) - (3 * seed) + 1;
}
return seed;
}
uint64_t __attribute__ ((noinline)) fast(uint64_t n, uint64_t seed) {
uint64_t max = (n / 10) + 1;
for (uint64_t i = 0; i < max; ++i) {
seed = common(n, (seed * seed) - (3 * seed) + 1);
}
return seed;
}
uint64_t __attribute__ ((noinline)) maybe_slow(uint64_t n, uint64_t seed, int is_slow) {
uint64_t max = n;
if (is_slow) {
max *= 10;
}
for (uint64_t i = 0; i < max; ++i) {
seed = common(n, (seed * seed) - (3 * seed) + 1);
}
return seed;
}
int main(int argc, char **argv) {
uint64_t n, seed;
if (argc > 1) {
n = strtoll(argv[1], NULL, 0);
} else {
n = 1;
}
if (argc > 2) {
seed = strtoll(argv[2], NULL, 0);
} else {
seed = 0;
}
seed += maybe_slow(n, seed, 0);
seed += fast(n, seed);
seed += maybe_slow(n, seed, 1);
seed += fast(n, seed);
seed += maybe_slow(n, seed, 0);
seed += fast(n, seed);
printf("%" PRIX64 "\n", seed);
return EXIT_SUCCESS;
}
gprof
ग्रिफ़िट को इंस्ट्रूमेंटेशन के साथ सॉफ्टवेयर को फिर से स्थापित करने की आवश्यकता होती है, और यह उस इंस्ट्रूमेंटेशन के साथ एक नमूना दृष्टिकोण का भी उपयोग करता है। इसलिए यह सटीकता के बीच एक संतुलन बनाता है (नमूना हमेशा पूरी तरह से सटीक नहीं होता है और कार्यों को छोड़ सकता है) और निष्पादन मंदी (इंस्ट्रूमेंटेशन और नमूनाकरण अपेक्षाकृत तेज़ तकनीकें हैं जो निष्पादन को बहुत धीमा नहीं करती हैं)।
Gprof में GCC / binutils बनाया गया है, इसलिए हमें केवल इतना करना है -pgकि आप gitable को सक्षम करने के विकल्प के साथ संकलित करें। हम तब प्रोग्राम को सामान्य रूप से एक आकार सीएलआई पैरामीटर के साथ चलाते हैं जो कुछ सेकंड की उचित अवधि ( 10000) का उत्पादन करता है :
gcc -pg -ggdb3 -O3 -std=c99 -Wall -Wextra -pedantic -o main.out main.c
time ./main.out 10000
शैक्षिक कारणों के लिए, हम सक्षम किए बिना अनुकूलन के साथ एक रन भी करेंगे। ध्यान दें कि यह व्यवहार में बेकार है, क्योंकि आप आमतौर पर केवल अनुकूलित कार्यक्रम के प्रदर्शन का अनुकूलन करने के बारे में परवाह करते हैं:
gcc -pg -ggdb3 -O0 -std=c99 -Wall -Wextra -pedantic -o main.out main.c
./main.out 10000
सबसे पहले, timeहमें बताता है कि निष्पादन के समय के साथ और बिना -pgसमान थे, जो महान है: कोई मंदी नहीं! मैंने हालांकि जटिल सॉफ्टवेयर पर 2x - 3x की मंदी के खातों को देखा है, जैसे कि इस टिकट में दिखाया गया है ।
क्योंकि हमने संकलित किया है -pg, प्रोग्राम को चलाने से एक फ़ाइल gmon.outफ़ाइल तैयार होती है जिसमें प्रोफाइलिंग डेटा होता है।
हम उस फ़ाइल का ग्राफ़िकल gprof2dotरूप से निरीक्षण कर सकते हैं जैसा कि पूछा गया है: क्या यह संभावित परिणामों के चित्रमय प्रतिनिधित्व को प्राप्त करना संभव है?
sudo apt install graphviz
python3 -m pip install --user gprof2dot
gprof main.out > main.gprof
gprof2dot < main.gprof | dot -Tsvg -o output.svg
यहां, gprofटूल gmon.outट्रेस जानकारी को पढ़ता है , और एक मानव पठनीय रिपोर्ट उत्पन्न करता है main.gprof, जो gprof2dotतब एक ग्राफ़ उत्पन्न करने के लिए पढ़ता है।
Gprof2dot का स्रोत यहां है: https://github.com/jrfonseca/gprof2dot
हम -O0रन के लिए निम्नलिखित का पालन करते हैं:

और -O3रन के लिए:

-O0उत्पादन काफी आत्म व्याख्यात्मक है। उदाहरण के लिए, यह दर्शाता है कि 3 maybe_slowकॉल और उनके बच्चे कॉल कुल रनटाइम का 97.56% लेते हैं, हालांकि maybe_slowबच्चों के बिना खुद का निष्पादन कुल निष्पादन समय का 0.00% है, अर्थात उस फ़ंक्शन में खर्च किए गए लगभग सभी समय पर खर्च किया गया था बच्चा कहता है।
TODO: आउटपुट mainसे क्यों गायब है -O3, भले ही मैं इसे btGDB में देख सकता हूं ? जीप्रोफ आउटपुट से मिसिंग फंक्शन मुझे लगता है कि यह इसलिए है क्योंकि इसके संकलित इंस्ट्रूमेंटेशन के अलावा ग्राइपिट भी सैंपलिंग आधारित है, और -O3 mainयह सिर्फ बहुत तेज़ है और कोई सैंपल नहीं मिला है।
मैं पीएनजी के बजाय एसवीजी आउटपुट का चयन करता हूं क्योंकि एसवीजी Ctrl + F के साथ खोजा जा सकता है और फ़ाइल का आकार लगभग 10x छोटा हो सकता है। इसके अलावा, उत्पन्न छवि की चौड़ाई और ऊंचाई जटिल सॉफ़्टवेयर के लिए हजारों पिक्सेल के दसियों के साथ विनम्र हो सकती है, और eogPNGs के लिए उस मामले में GNOME 3.28.1 बग्स, जबकि SVGs मेरे ब्राउज़र द्वारा स्वचालित रूप से खुल जाते हैं। जिम्प 2.8 हालांकि अच्छी तरह से काम किया, यह भी देखें:
लेकिन फिर भी, आप जो चाहते हैं उसे खोजने के लिए छवि को बहुत चारों ओर खींच रहे हैं, उदाहरण के लिए इस टिकट से लिए गए "वास्तविक" सॉफ़्टवेयर उदाहरण से इस छवि को देखें :

क्या आप उन सभी छोटी अनसुलझी स्पेगेटी लाइनों के साथ एक दूसरे पर जाने वाली सबसे महत्वपूर्ण कॉल स्टैक आसानी से पा सकते हैं? वहाँ बेहतर dotविकल्प हो सकता है मुझे यकीन है, लेकिन मैं अब वहां नहीं जाना चाहता। हमें वास्तव में इसके लिए एक उचित समर्पित दर्शक चाहिए, लेकिन मुझे अभी तक यह नहीं मिला है:
हालाँकि आप उन समस्याओं को थोड़ा कम करने के लिए रंगीन मानचित्र का उपयोग कर सकते हैं। उदाहरण के लिए, पिछली विशाल छवि पर, मैंने आखिरकार बाईं ओर महत्वपूर्ण पथ खोजने में कामयाबी हासिल की जब मैंने शानदार कटौती की जो कि हरे रंग के बाद आती है, उसके बाद अंत में गहरा और गहरा नीला होता है।
वैकल्पिक रूप से, हम gprofबिल्ट-इन बिनुटिल्स टूल के टेक्स्ट आउटपुट का भी निरीक्षण कर सकते हैं, जिसे हमने पहले बचाया था:
cat main.gprof
डिफ़ॉल्ट रूप से, यह एक अत्यंत क्रिया आउटपुट उत्पन्न करता है जो बताता है कि आउटपुट डेटा का क्या अर्थ है। चूंकि मैं इससे बेहतर व्याख्या नहीं कर सकता, इसलिए मैं आपको इसे स्वयं पढ़ने दूंगा।
एक बार जब आप डेटा आउटपुट प्रारूप को समझ जाते हैं, तो आप -bविकल्प के साथ ट्यूटोरियल के बिना सिर्फ डेटा दिखाने के लिए वर्बोसिटी को कम कर सकते हैं :
gprof -b main.out
हमारे उदाहरण में, आउटपुट -O0निम्न थे :
Flat profile:
Each sample counts as 0.01 seconds.
% cumulative self self total
time seconds seconds calls s/call s/call name
100.35 3.67 3.67 123003 0.00 0.00 common
0.00 3.67 0.00 3 0.00 0.03 fast
0.00 3.67 0.00 3 0.00 1.19 maybe_slow
Call graph
granularity: each sample hit covers 2 byte(s) for 0.27% of 3.67 seconds
index % time self children called name
0.09 0.00 3003/123003 fast [4]
3.58 0.00 120000/123003 maybe_slow [3]
[1] 100.0 3.67 0.00 123003 common [1]
-----------------------------------------------
<spontaneous>
[2] 100.0 0.00 3.67 main [2]
0.00 3.58 3/3 maybe_slow [3]
0.00 0.09 3/3 fast [4]
-----------------------------------------------
0.00 3.58 3/3 main [2]
[3] 97.6 0.00 3.58 3 maybe_slow [3]
3.58 0.00 120000/123003 common [1]
-----------------------------------------------
0.00 0.09 3/3 main [2]
[4] 2.4 0.00 0.09 3 fast [4]
0.09 0.00 3003/123003 common [1]
-----------------------------------------------
Index by function name
[1] common [4] fast [3] maybe_slow
और इसके लिए -O3:
Flat profile:
Each sample counts as 0.01 seconds.
% cumulative self self total
time seconds seconds calls us/call us/call name
100.52 1.84 1.84 123003 14.96 14.96 common
Call graph
granularity: each sample hit covers 2 byte(s) for 0.54% of 1.84 seconds
index % time self children called name
0.04 0.00 3003/123003 fast [3]
1.79 0.00 120000/123003 maybe_slow [2]
[1] 100.0 1.84 0.00 123003 common [1]
-----------------------------------------------
<spontaneous>
[2] 97.6 0.00 1.79 maybe_slow [2]
1.79 0.00 120000/123003 common [1]
-----------------------------------------------
<spontaneous>
[3] 2.4 0.00 0.04 fast [3]
0.04 0.00 3003/123003 common [1]
-----------------------------------------------
Index by function name
[1] common
प्रत्येक अनुभाग के लिए एक बहुत ही त्वरित सारांश के रूप में:
0.00 3.58 3/3 main [2]
[3] 97.6 0.00 3.58 3 maybe_slow [3]
3.58 0.00 120000/123003 common [1]
फ़ंक्शन के आसपास केंद्र जो इंडेंटेड ( maybe_flow) छोड़ दिए गए हैं । [3]उस फ़ंक्शन की आईडी है। फ़ंक्शन के ऊपर, इसके कॉलर्स हैं, और इसके नीचे कैलिस हैं।
इसके लिए -O3, यहां देखें कि चित्रमय आउटपुट में क्या है maybe_slowऔर fastएक ज्ञात माता-पिता नहीं है, जो कि प्रलेखन का <spontaneous>मतलब है।
मुझे यकीन नहीं है कि वहाँ एक अच्छा तरीका है लाइन-बाय-लाइन प्रोफाइलिंग को ग्रिट के साथ करना है: `gprof` समय कोड की विशेष लाइनों में बिताया
वेलग्रिंड कॉलग्रिंड
valgrind वर्चुअल मशीन के माध्यम से प्रोग्राम चलाता है। यह प्रोफाइलिंग को बहुत सटीक बनाता है, लेकिन यह प्रोग्राम की एक बहुत बड़ी मंदी भी पैदा करता है। मैंने पहले भी kcachegrind पर उल्लेख किया है: उपकरण एक चित्रमय फ़ंक्शन कोड के ग्राफ़ को प्राप्त करने के लिए
कॉलग्रिंड प्रोफाइल कोड के लिए वैलग्राइंड का उपकरण है और kcachegrind एक केडीई प्रोग्राम है जो कैशेग्रिंड आउटपुट की कल्पना कर सकता है।
पहले हमें -pgसामान्य संकलन पर वापस जाने के लिए ध्वज को निकालना होगा , अन्यथा रन वास्तव में विफल हो जाता है Profiling timer expired, और हां, यह इतना सामान्य है कि मैंने किया और इसके लिए एक स्टैक ओवरफ्लो प्रश्न था।
इसलिए हम संकलित करते हैं:
sudo apt install kcachegrind valgrind
gcc -ggdb3 -O3 -std=c99 -Wall -Wextra -pedantic -o main.out main.c
time valgrind --tool=callgrind valgrind --dump-instr=yes \
--collect-jumps=yes ./main.out 10000
मैं सक्षम करता हूं --dump-instr=yes --collect-jumps=yesक्योंकि यह उन सूचनाओं को भी डंप करता है जो हमें एक अपेक्षाकृत छोटे जोड़े गए ओवरहेड लागत पर प्रदर्शन के प्रति असेंबली लाइन टूटने को देखने में सक्षम बनाता है।
बल्ले से, timeहमें बताता है कि कार्यक्रम को निष्पादित करने में 29.5 सेकंड लगे, इसलिए हमारे पास इस उदाहरण पर लगभग 15x की मंदी थी। जाहिर है, यह मंदी बड़े काम के बोझ के लिए एक गंभीर सीमा होने जा रही है। यहां वर्णित "वास्तविक विश्व सॉफ्टवेयर उदाहरण" पर , मैंने 80x की मंदी देखी।
रन मेरे मामले में callgrind.out.<pid>उदाहरण के लिए एक प्रोफाइल डेटा फ़ाइल उत्पन्न करता है callgrind.out.8554। हम उस फ़ाइल को इसके साथ देखते हैं:
kcachegrind callgrind.out.8554
जो एक जीयूआई दिखाता है जिसमें टेक्स्ट ग्राइप आउटपुट के समान डेटा होता है:

इसके अलावा, अगर हम नीचे दाईं ओर "कॉल ग्राफ़" टैब पर जाते हैं, तो हमें एक कॉल ग्राफ़ दिखाई देता है, जिसे हम राइट क्लिक करके निर्यात कर सकते हैं, ताकि सफेद सीमा के अनुचित मात्रा के साथ निम्नलिखित छवि प्राप्त कर सकें :-)

मुझे लगता fastहै कि उस ग्राफ़ पर नहीं दिख रहा है क्योंकि kcachegrind ने विज़ुअलाइज़ेशन को सरल बना दिया होगा क्योंकि उस कॉल में बहुत कम समय लगता है, यह संभवतः वह व्यवहार होगा जो आप एक वास्तविक प्रोग्राम पर चाहते हैं। राइट क्लिक मेनू में ऐसे नोड्स को खींचने के लिए नियंत्रित करने के लिए कुछ सेटिंग्स हैं, लेकिन मैं इसे एक त्वरित प्रयास के बाद इतनी कम कॉल दिखाने के लिए नहीं मिला। अगर मैं fastबाईं विंडो पर क्लिक करता हूं , तो यह एक कॉल ग्राफ दिखाता है fast, जिससे स्टैक वास्तव में कैप्चर किया गया था। किसी को अभी तक पूर्ण ग्राफ़ कॉल ग्राफ़ दिखाने का कोई तरीका नहीं मिला था : कॉलग्रिंड शो करें सभी फ़ंक्शन कॉल kcachegrat कॉल ग्राफ़ में दिखाएँ
TODO जटिल C ++ सॉफ्टवेयर पर, मुझे कुछ प्रकार की प्रविष्टियाँ दिखाई देती हैं <cycle N>, उदाहरण के लिए, <cycle 11>जहाँ मैं फ़ंक्शन नामों की अपेक्षा करूँगा, इसका क्या मतलब है? मैंने देखा कि वहाँ "टॉगल डिटेक्शन" बटन है जो चालू और बंद है, लेकिन इसका क्या मतलब है?
perf से linux-tools
perfविशेष रूप से लिनक्स कर्नेल सैंपलिंग तंत्र का उपयोग करने लगता है। यह सेटअप करने के लिए बहुत सरल है, लेकिन यह भी पूरी तरह से सटीक नहीं है।
sudo apt install linux-tools
time perf record -g ./main.out 10000
इसने 0.2s को निष्पादन में जोड़ा है, इसलिए हम समय के हिसाब से ठीक हैं, लेकिन मैं अभी भी बहुत दिलचस्पी नहीं देख रहा हूं, commonकीबोर्ड के मुख्य तीर के साथ नोड का विस्तार करने के बाद :
Samples: 7K of event 'cycles:uppp', Event count (approx.): 6228527608
Children Self Command Shared Object Symbol
- 99.98% 99.88% main.out main.out [.] common
common
0.11% 0.11% main.out [kernel] [k] 0xffffffff8a6009e7
0.01% 0.01% main.out [kernel] [k] 0xffffffff8a600158
0.01% 0.00% main.out [unknown] [k] 0x0000000000000040
0.01% 0.00% main.out ld-2.27.so [.] _dl_sysdep_start
0.01% 0.00% main.out ld-2.27.so [.] dl_main
0.01% 0.00% main.out ld-2.27.so [.] mprotect
0.01% 0.00% main.out ld-2.27.so [.] _dl_map_object
0.01% 0.00% main.out ld-2.27.so [.] _xstat
0.00% 0.00% main.out ld-2.27.so [.] __GI___tunables_init
0.00% 0.00% main.out [unknown] [.] 0x2f3d4f4944555453
0.00% 0.00% main.out [unknown] [.] 0x00007fff3cfc57ac
0.00% 0.00% main.out ld-2.27.so [.] _start
तो फिर मैं यह देखने के लिए -O0प्रोग्राम को बेंचमार्क करने की कोशिश करता हूं कि क्या कुछ दिखाता है, और केवल अब, आखिर में, क्या मुझे कॉल ग्राफ़ दिखाई देता है:
Samples: 15K of event 'cycles:uppp', Event count (approx.): 12438962281
Children Self Command Shared Object Symbol
+ 99.99% 0.00% main.out [unknown] [.] 0x04be258d4c544155
+ 99.99% 0.00% main.out libc-2.27.so [.] __libc_start_main
- 99.99% 0.00% main.out main.out [.] main
- main
- 97.54% maybe_slow
common
- 2.45% fast
common
+ 99.96% 99.85% main.out main.out [.] common
+ 97.54% 0.03% main.out main.out [.] maybe_slow
+ 2.45% 0.00% main.out main.out [.] fast
0.11% 0.11% main.out [kernel] [k] 0xffffffff8a6009e7
0.00% 0.00% main.out [unknown] [k] 0x0000000000000040
0.00% 0.00% main.out ld-2.27.so [.] _dl_sysdep_start
0.00% 0.00% main.out ld-2.27.so [.] dl_main
0.00% 0.00% main.out ld-2.27.so [.] _dl_lookup_symbol_x
0.00% 0.00% main.out [kernel] [k] 0xffffffff8a600158
0.00% 0.00% main.out ld-2.27.so [.] mmap64
0.00% 0.00% main.out ld-2.27.so [.] _dl_map_object
0.00% 0.00% main.out ld-2.27.so [.] __GI___tunables_init
0.00% 0.00% main.out [unknown] [.] 0x552e53555f6e653d
0.00% 0.00% main.out [unknown] [.] 0x00007ffe1cf20fdb
0.00% 0.00% main.out ld-2.27.so [.] _start
TODO: -O3फांसी पर क्या हुआ ? क्या यह केवल इतना है maybe_slowऔर fastबहुत तेज़ थे और कोई नमूना नहीं मिला? क्या यह -O3बड़े कार्यक्रमों पर अच्छी तरह से काम करता है जिन्हें निष्पादित करने में अधिक समय लगता है? क्या मुझे कुछ सीएलआई विकल्प याद आया? मुझे -Fहर्ट्ज में नमूना आवृत्ति को नियंत्रित करने के बारे में पता चला , लेकिन मैंने इसे डिफ़ॉल्ट रूप से अधिकतम अनुमति के लिए बदल दिया -F 39500(इसके साथ बढ़ाया जा सकता है sudo) और मुझे अभी भी स्पष्ट कॉल नहीं दिख रहे हैं।
एक अच्छी बात है perfब्रेंडन ग्रेग का फ्लेमग्राफ टूल है जो कॉल स्टैक के समय को बहुत साफ तरीके से प्रदर्शित करता है जो आपको बड़ी कॉल को जल्दी से देखने की अनुमति देता है। यह टूल यहां उपलब्ध है: https://github.com/brendangregg/FlameGraph और इसका पूर्ण ट्यूटोरियल पर भी उल्लेख किया गया है: http://www.brendangregg.com/perf.html#FlameGraphs जब मैं perfबिना भाग sudoगया ERROR: No stack counts foundतो मुझे इसके लिए मिला अब मैं इसके साथ करूँगा sudo:
git clone https://github.com/brendangregg/FlameGraph
sudo perf record -F 99 -g -o perf_with_stack.data ./main.out 10000
sudo perf script -i perf_with_stack.data | FlameGraph/stackcollapse-perf.pl | FlameGraph/flamegraph.pl > flamegraph.svg
लेकिन इस तरह के एक सरल कार्यक्रम में आउटपुट को समझना बहुत आसान नहीं है, क्योंकि हम आसानी से न तो उस ग्राफ पर देख सकते हैं और न maybe_slowही fast:

अधिक जटिल उदाहरण पर यह स्पष्ट हो जाता है कि ग्राफ़ का क्या अर्थ है:

TODO [unknown]उस उदाहरण में कार्यों का एक लॉग है , ऐसा क्यों है?
एक और परिपूर्ण जीयूआई इंटरफेस जो इसके लायक हो सकता है:
ग्रहण ट्रेस कम्पास प्लगइन: https://www.eclipse.org/tracecompass/
लेकिन इसका नकारात्मक पहलू यह है कि आपको सबसे पहले डेटा को कॉमन ट्रेस फॉर्मेट में बदलना होगा, जिसके साथ किया जा सकता है perf data --to-ctf , लेकिन इसे बिल्ड समय पर सक्षम करने की आवश्यकता है / perfनए पर्याप्त होने चाहिए , जिनमें से किसी एक के लिए पूर्णता की स्थिति नहीं है। उबुन्टु 18.04
https://github.com/KDAB/hotspot
इसका नकारात्मक पक्ष यह है कि उबंटू पैकेज नहीं है, और इसके निर्माण के लिए Qt 5.10 की आवश्यकता है जबकि Ubuntu 18.04 Qt 5.9 पर है।
gperftools
पहले "Google प्रदर्शन उपकरण" कहा जाता था, स्रोत: https://github.com/gperftools/gperftools नमूना आधारित।
पहले gperftools स्थापित करें:
sudo apt install google-perftools
फिर, हम gperftools CPU प्रोफाइलर को दो तरह से सक्षम कर सकते हैं: रनटाइम पर, या बिल्ड टाइम पर।
रनटाइम के दौरान, हमें LD_PRELOADइंगित करने के लिए सेट करना होगा libprofiler.so, जिसे आप locate libprofiler.soमेरे सिस्टम पर देख सकते हैं , जैसे:
gcc -ggdb3 -O3 -std=c99 -Wall -Wextra -pedantic -o main.out main.c
LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libprofiler.so \
CPUPROFILE=prof.out ./main.out 10000
वैकल्पिक रूप से, हम लायब्रेरी को लिंक टाइम पर बना सकते हैं, LD_PRELOADरनटाइम में पासिंग को वितरित करते हुए:
gcc -Wl,--no-as-needed,-lprofiler,--as-needed -ggdb3 -O3 -std=c99 -Wall -Wextra -pedantic -o main.out main.c
CPUPROFILE=prof.out ./main.out 10000
यह भी देखें: gperftools - प्रोफ़ाइल फ़ाइल को डंप नहीं किया गया
इस डेटा को देखने का सबसे अच्छा तरीका यह है कि मैं pprof आउटपुट को उसी प्रारूप में बना सकता हूं जिसे kcachegrind इनपुट के रूप में लेता है (हां, Valgrind-project-दर्शक-उपकरण) और देखने के लिए kcachegrind का उपयोग करें:
google-pprof --callgrind main.out prof.out > callgrind.out
kcachegrind callgrind.out
उन विधियों में से किसी एक के साथ चलने के बाद, हमें prof.outआउटपुट के रूप में एक प्रोफाइल डेटा फ़ाइल मिलती है । हम उस फ़ाइल को एसवीजी के रूप में रेखांकन के साथ देख सकते हैं:
google-pprof --web main.out prof.out

जो अन्य उपकरणों की तरह एक परिचित कॉल ग्राफ के रूप में देता है, लेकिन सेकंड के बजाय नमूनों की संख्या की क्लंकी इकाई के साथ।
वैकल्पिक रूप से, हम कुछ पाठ्य सामग्री भी प्राप्त कर सकते हैं:
google-pprof --text main.out prof.out
जो देता है:
Using local file main.out.
Using local file prof.out.
Total: 187 samples
187 100.0% 100.0% 187 100.0% common
0 0.0% 100.0% 187 100.0% __libc_start_main
0 0.0% 100.0% 187 100.0% _start
0 0.0% 100.0% 4 2.1% fast
0 0.0% 100.0% 187 100.0% main
0 0.0% 100.0% 183 97.9% maybe_slow
इसे भी देखें: google perf टूल का उपयोग कैसे करें
Ubuntu 18.04 में परीक्षण किया गया, gprof2dot 2019.11.30, valgrind 3.13.0, perf 4.15.18, Linux कर्नेल 4.15.0, FlameGraph 1a0dc6985aad06e76857f2a354bd5ba0c9ce96b, gperftools 2.5-2।