| GCOV(1) | GNU | GCOV(1) |
نام (NAME)
gcov - ابزار بررسی پوشش آزمون
خلاصه دستور (SYNOPSIS)
gcov [-v|--version] [-h|--help]
[-a|--all-blocks]
[-b|--branch-probabilities]
[-c|--branch-counts]
[-g|--conditions]
[-e|--prime-paths]
[--prime-paths-lines[=type]]
[--prime-paths-source[=type]]
[-d|--display-progress]
[-f|--function-summaries]
[--include regex]
[--exclude regex]
[-j|--json-format]
[-H|--human-readable]
[-k|--use-colors]
[-l|--long-file-names]
[-m|--demangled-names]
[-M|--filter-on-demangled]
[-n|--no-output]
[-o|--object-directory directory|file]
[-p|--preserve-paths]
[-q|--use-hotness-colors]
[-r|--relative-only]
[-s|--source-prefix directory]
[-t|--stdout]
[-u|--unconditional-branches]
[-x|--hash-filenames]
files
توضیحات (DESCRIPTION)
دستور gcov برنامهای برای بررسی پوشش آزمون (test coverage) است. از آن در هماهنگی با GCC برای تحلیل برنامههایتان استفاده کنید تا بتوانید کدهایی کارآمدتر با اجرای سریعتر بنویسید و بخشهای آزمودهنشده برنامه خود را بیابید. میتوانید از gcov به عنوان ابزاری برای پروفایلینگ (profiling) استفاده کنید تا کشف کنید تلاشهای بهینهسازیتان کجا بیشترین تأثیر را بر کد خواهد گذاشت. همچنین میتوانید gcov را همراه با ابزار پروفایلینگ دیگر، یعنی gprof، به کار ببرید تا ارزیابی کنید کدام بخشهای کد بیشترین میزان زمان پردازش را مصرف میکنند.
ابزارهای پروفایلینگ به شما در تحلیل کارایی کد کمک میکنند. با استفاده از یک پروفایلر مانند gcov یا gprof، میتوانید برخی از آمارهای پایه کارایی را به دست آورید، از قبیل:
- هر خط از کد هر چند وقت یکبار اجرا میشود
- کدام خطوط از کد واقعاً اجرا میشوند
- هر بخش از کد چه میزان زمان پردازشی مصرف میکند
هنگامی که این موارد را درباره نحوه عملکرد کد کامپایلشده خود دانستید، میتوانید هر ماژول را بررسی کنید تا ببینید کدام ماژولها باید بهینهسازی شوند. دستور gcov به شما کمک میکند تعیین کنید روی بهینهسازی کدام قسمتها کار کنید.
توسعهدهندگان نرمافزار همچنین از آزمون پوشش همراه با مجموعههای آزمون (testsuites) استفاده میکنند تا مطمئن شوند نرمافزار واقعاً برای انتشار به اندازه کافی خوب است. مجموعههای آزمون میتوانند بررسی کنند که آیا برنامه طبق انتظار عمل میکند یا خیر؛ یک برنامه تحلیل پوشش، بررسی میکند که چه میزان از برنامه توسط مجموعه آزمون پوشش داده شده و اجرا شده است. سپس توسعهدهندگان میتوانند مشخص کنند چه نوع نمونههای آزمونی (test cases) باید به مجموعههای آزمون اضافه شوند تا هم آزمونهای بهتری حاصل شود و هم محصول نهایی بهتری تولید گردد.
اگر قصد استفاده از gcov را دارید، باید کد خود را بدون بهینهسازی (optimization) کامپایل کنید؛ زیرا بهینهسازی از طریق ادغام برخی خطوط کد در یک تابع، ممکن است اطلاعات کافی را که برای یافتن «نقاط داغ» (hot spots) — بخشهایی از کد که زمان زیادی از پردازنده را میگیرند — نیاز دارید در اختیارتان نگذارد. به همین ترتیب، از آنجا که gcov آمارها را بر پایه خط (در پایینترین وضوح) جمعآوری میکند، با سبک برنامهنویسیای که در هر خط تنها یک دستور قرار میدهد، بهترین عملکرد را دارد. اگر از ماکروهای پیچیدهای استفاده کنید که به حلقهها یا ساختارهای کنترلی دیگر گسترش مییابند، آمارها کمتر مفید خواهند بود؛ چرا که آنها تنها وضعیت خطی را گزارش میکنند که فراخوانی ماکرو در آن رخ داده است. چنانچه ماکروهای پیچیده شما رفتاری شبیه به توابع دارند، میتوانید برای حل این مشکل، آنها را با توابع inline جایگزین کنید.
دستور gcov یک فایل گزارش لاگ به نام sourcefile.gcov میسازد که مشخص میکند هر خط از یک فایل مبدأ مانند sourcefile.c چند بار اجرا شده است. میتوانید از این فایلهای لاگ به همراه gprof برای تنظیم دقیق کارایی برنامههای خود بهره ببرید. ابزار gprof اطلاعات زمانبندی را در اختیارتان میگذارد که میتوانید آن را در کنار دادههای دریافتی از gcov استفاده کنید.
دستور gcov تنها روی کدهایی کار میکند که با GCC کامپایل شده باشند. این ابزار با هیچیک از سازوکارهای دیگر پروفایلینگ یا پوشش آزمون سازگار نیست..SH "گزینهها (OPTIONS)"
- -a
- --all-blocks
- تعداد دفعات اجرای هر بلوک پایهای (basic block) را بهصورت جداگانه بنویس. بهطور معمول gcov شمارشهای اجرا را تنها برای بلوکهای اصلی یک خط خروجی میدهد. با این گزینه میتوانید تعیین کنید که آیا بلوکهای درون یک خط اجرا نشدهاند یا خیر.
- -b
- --branch-probabilities
- تکرار شاخهها (branch frequencies) را در فایل خروجی بنویس و اطلاعات خلاصهٔ شاخه را در خروجی استاندارد چاپ کن. این گزینه به شما امکان میدهد ببینید هر شاخه در برنامه شما چند بار طی شده است. شاخههای بدون شرط نمایش داده نخواهند شد، مگر اینکه گزینهٔ -u مشخص شده باشد.
- -c
- --branch-counts
- تکرار شاخهها را بهجای درصد شاخههای طیشده، بهصورت تعداد شاخههای طیشده بنویس.
- -g
- --conditions
- پوشش شرط (condition coverage) را در فایل خروجی بنویس و اطلاعات خلاصهٔ شرط را در خروجی استاندارد چاپ کن. این گزینه به شما امکان میدهد ببینید آیا شرایط در برنامه شما حداقل یکبار تأثیر مستقلی بر نتیجهٔ عبارت بولی داشتهاند یا خیر (پوشش تصمیم/شرط اصلاحشده یا MC/DC). این کار نیازمند آن است که کد منبع را با -fcondition-coverage کامپایل کنید.
- -e
- --prime-paths
- پوشش مسیر (path coverage) را در فایل خروجی بنویس و اطلاعات خلاصهٔ مسیر را در خروجی استاندارد چاپ کن. این گزینه به شما اجازه میدهد ببینید چه تعداد مسیر اول (prime path) حداقل یکبار طی شدهاند. یک مسیر، دنبالهای از بلوکهای پایهای است. یک مسیر در صورتی ساده است که هیچ بلوک تکراری نداشته باشد (بدون حلقه) بهجز احتمالاً اولین و آخرین بلوک، و زمانی «اول» (prime) است که یک مسیر ساده با حداکثر طول ممکن باشد. برای خروجی عادی، این گزینه فقط شامل تعداد مسیرهای پوششدادهشده است. برای جزئیات دقیقتر دربارهٔ مسیرها میتوانید از --prime-paths-lines یا --prime-paths-source استفاده کنید. با --json-format تمام جزئیات مسیر در خروجی گنجانده میشود. این کار نیازمند آن است که کد منبع را با -fpath-coverage کامپایل کنید.
- --prime-paths-lines [=type]
- پوشش مسیر را در فایل خروجی بنویس و اطلاعات خلاصهٔ مسیر را در خروجی استاندارد چاپ کن. این گزینه به شما امکان میدهد ببینید چه تعداد مسیر اول حداقل یکبار طی شدهاند، و گزارشی فشرده از مسیرهای پوششیافته یا پوششنیافته و نحوهٔ پوشش دادن آنها ارائه میدهد. این حالت برای گزارشدهی خودکار و پیگیری پیشرفت مفید است. type میتواند حذف شود، یا یکی از مقادیر زیر باشد:
- uncovered - شامل مسیرهای پوششنیافته (طینشده). این مقدار پیشفرض است.
- covered - شامل مسیرهای پوششیافته (طیشده).
- both - شامل همهٔ مسیرها. این معادل استفاده از هر دو مقدار covered و uncovered است.
این یک نمونه از خروجی --prime-paths-lines است:
paths covered 12 of 15 path 2 not covered: lines 8 8(false) 11(true) 11 13(true) 13(true) 14 17 path 3 not covered: lines 8 8(false) 11(true) 11 13(true) 13(false) 16 17 path 4 not covered: lines 8 8(false) 11(true) 11 13(false) 16 17
این بدان معناست که برای پوشش مسیر ۲ باید خطهای ۸، ۱۱، ۱۳، ۱۴ و ۱۷ اجرا شوند، در حالی که تصمیم در خط ۸ برابر با false و تصمیمها در خطهای ۱۱ و ۱۳ برابر با "false" ارزیابی شوند.
- --prime-paths-source [=type]
- پوشش مسیر را در فایل خروجی بنویس و اطلاعات خلاصهٔ مسیر را در خروجی استاندارد چاپ کن. این گزینه به شما امکان میدهد ببینید چه تعداد مسیر اول حداقل یکبار طی شدهاند، و گزارشی دقیق از مسیرهای پوششنیافته و چگونگی پوشش آنها ارائه میدهد. این حالت برای درک مسیرها و تعاملات میان بخشهای مختلف برنامه شما مفید است. type میتواند حذف شود، یا یکی از مقادیر زیر باشد:
- uncovered - شامل مسیرهای پوششنیافته (طینشده). این مقدار پیشفرض است.
- covered - شامل مسیرهای پوششیافته (طیشده).
- both - شامل همهٔ مسیرها. این معادل استفاده از هر دو مقدار covered و uncovered است.
این یک نمونه از خروجی --prime-paths-source است:
path 10 not covered:
BB 3: 8: for (i = 0; i < 10; i++)
BB 3: 9: total += i;
BB 4: (false) 8: for (i = 0; i < 10; i++)
BB 5: (true) 11: int v = total > 100 ? 1 : 2;
BB 6: 11: int v = total > 100 ? 1 : 2;
BB 8: (false) 13: if (total != 45 && v == 1)
BB 11: 16: printf ("Success\n");
BB 12: 17: return 0;
ستون نخست (BB) دنبالهٔ بلوکهای پایهای است (به -w مراجعه کنید). ستون میانی (true/false) تصمیم برای آن خط است. ستون سوم شمارهٔ خط است. ستون چهارم خودِ خط کد است. این خطوط باید با همین ترتیب اجرا شوند تا مسیر ۱۰ پوشش داده شود.
- -d
- --display-progress
- نمایش میزان پیشرفت در خروجی استاندارد.
- -f
- --function-summaries
- علاوه بر خلاصهٔ آماری در سطح فایل، خلاصهٔ آماری مربوط به هر تابع را نیز خروجی بده.
- --include regex
- توابع منطبق با regex را شامل شود. این گزینه سبب میشود که gcov تنها دربارهٔ توابعی گزارش دهد که با عبارت منظم توسعهیافتهٔ regex تطابق دارند. این پرچم میتواند با --exclude ترکیب شود. اگر تابعی هم با include و هم با exclude مطابقت داشته باشد، آخرین include/exclude اعمال خواهد شد. بهطور پیشفرض gcov تمام توابع را گزارش میدهد، اما اگر --include استفاده شود، تنها توابع منطبق بر آن گزارش داده میشوند.
- --exclude regex
- توابع منطبق با regex را مستثنی کن. این گزینه سبب میشود که gcov دربارهٔ توابعی که با عبارت منظم توسعهیافتهٔ regex تطابق دارند گزارش ندهد. این پرچم میتواند با --include ترکیب شود. اگر تابعی هم با include و هم با exclude مطابقت داشته باشد، آخرین include/exclude اعمال خواهد شد. بهطور پیشفرض gcov تمام توابع را گزارش میدهد، و اگر --exclude به کار رود، توابع منطبق بر آن نادیده گرفته میشوند.
- -h
- --help
- نمایش راهنمای استفاده از gcov (در خروجی استاندارد)، و خروج بدون انجام هرگونه پردازش بیشتر.
- -j
- --json-format
- فایل gcov را در
یک قالب
میانی JSON با
پردازش
آسان خروجی
بده که برای
تولید
نیازی به کد
منبع ندارد.
فایل JSON با
الگوریتم
فشردهسازی
gzip فشرده
میشود و
فایلها
دارای
پسوند .gcov.json.gz
خواهند بود.
ساختار JSON به صورت زیر است:
{ "current_working_directory": "foo/bar", "data_file": "a.out", "format_version": "2", "gcc_version": "11.1.1 20210510" "files": ["$file"] }فیلدهای عنصر ریشه دارای معانی زیر هستند:
- current_working_directory: دایرکتوری کاری که واحد ترجمه (compilation unit) در آن کامپایل شده است.IP * 4 data_file: نام فایل داده (GCDA)
- format_version: نگارش
معنایی
قالب
تغییرات در نگارش 2:
- *
- calls: اطلاعات مربوط به فراخوانیهای تابع افزوده شده است
- *
- gcc_version: نگارش کامپایلر GCC
هر file شکل زیر را دارد:
{
"file": "a.c",
"functions": ["$function"],
"lines": ["$line"]
}
میدانهای عنصر file دارای معانی زیر هستند:
- *
- file_name: نام فایل مبدأ
هر function شکل زیر را دارد:
{
"blocks": 2,
"blocks_executed": 2,
"demangled_name": "foo",
"end_column": 1,
"end_line": 4,
"execution_count": 1,
"name": "foo",
"start_column": 5,
"start_line": 1
}
میدانهای عنصر function دارای معانی زیر هستند:
- blocks: تعداد بلوکهای موجود در تابع
- blocks_executed: تعداد بلوکهای اجراشدهی تابع
- demangled_name: نام سرهمبندیزداییشده تابع
- end_column: ستونی در فایل مبدأ که تابع در آن پایان مییابد
- end_line: خطی در فایل مبدأ که تابع در آن پایان مییابد
- execution_count: تعداد دفعات اجرای تابع
- name: نام تابع
- start_column: ستونی در فایل مبدأ که تابع از آن آغاز میشود
- start_line: خطی در فایل مبدأ که تابع از آن آغاز میشود
توجه داشته باشید که شماره خطوط و شماره ستونها از ۱ آغاز میشوند. در پیادهسازی فعلی، start_line و start_column شامل پارامترهای قالب (template) و نوع بازگشتی ابتدایی نمیشوند، اما این مورد احتمالاً در آینده اصلاح خواهد شد.
هر line شکل زیر را دارد:
{
"block_ids": ["$block_id"],
"branches": ["$branch"],
"calls": ["$call"],
"count": 2,
"conditions": ["$condition"],
"line_number": 15,
"unexecuted_block": false,
"function_name": "foo",
}
شاخهها و فراخوانیها تنها با گزینه -b موجود هستند. میدانهای عنصر line دارای معانی زیر هستند:
- block_ids: شناسه بلوکهای پایهای که متعلق به این خط هستند
- count: تعداد دفعات اجرای خط
- line_number: شماره خط
- unexecuted_block: پرچمی برای مشخص کردن اینکه آیا خط شامل بلوک اجرانشده است یا خیر (همه دستورات روی این خط اجرا نشدهاند)
- function_name: نام تابعی که این line متعلق به آن است (برای خطی دارای دستورات درونخطی (inlined) ممکن است تنظیم نشده باشد)
هر branch شکل زیر را دارد:
{
"count": 11,
"destination_block_id": 17,
"fallthrough": true,
"source_block_id": 13,
"throw": false
}
میدانهای عنصر branch دارای معانی زیر هستند:
- count: تعداد دفعات اجرای شاخه
- fallthrough: مقدار true هنگامی که شاخه از نوع سرریز (fall through) باشد
- throw: مقدار true هنگامی که شاخه از نوع استثنا (exceptional) باشد
- isource_block_id: شناسه بلوک پایهای که این شاخه در آن رخ میدهد
- destination_block_id: شناسه بلوک پایهای که این شاخه به آن میپرد
هر call شکل زیر را دارد:
{
"destination_block_id": 1,
"returned": 11,
"source_block_id": 13
}
میدانهای عنصر call دارای معانی زیر هستند:
- returned: تعداد دفعاتی که فراخوانی تابع بازگشته است (تعداد فراخوانی برابر با line::count است)
- isource_block_id: شناسه بلوک پایهای که این فراخوانی در آن رخ میدهد
- destination_block_id: شناسه بلوک پایهای که این فراخوانی پس از بازگشت در آن ادامه مییابد
هر condition شکل زیر را دارد:
{
"count": 4,
"covered": 2,
"not_covered_false": [],
"not_covered_true": [0, 1],
}
میدانهای عنصر condition دارای معانی زیر هستند:
- count: تعداد برآمدهای شرط در این عبارت
- covered: تعداد برآمدهای پوششدادهشدهی شرط در این عبارت
- not_covered_true: عبارتها، بر اساس نمایه، که در این عبارت مقدار درست (true) نداشتهاند
- not_covered_false: عبارتها، بر اساس نمایه، که در این عبارت مقدار نادرست (false) نداشتهاند
- -H
- --human-readable
- شمارشها را در قالبی خوانا برای انسان مینویسد (مانند 24.6k).
- -k
- --use-colors
- از رنگها برای خطوط کدی که پوشش صفر دارند استفاده میکند. ما از رنگ قرمز برای خطوط غیراستثنایی و فیروزهای برای خطوط استثنایی استفاده میکنیم. همین رنگها برای بلوکهای پایه با گزینه -a نیز استفاده میشوند.
- -l
- --long-file-names
- نامهای فایلی طولانی برای فایلهای مبدأ گنجاندهشده ایجاد میکند. برای نمونه، اگر فایل سرایند x.h حاوی کد باشد و در فایل a.c گنجانده شده باشد، اجرای gcov روی فایل a.c یک فایل خروجی با نام a.c##x.h.gcov به جای x.h.gcov تولید خواهد کرد. این ویژگی میتواند زمانی مفید باشد که x.h در چندین فایل مبدأ گنجانده شده باشد و بخواهید مشارکتهای هر کدام را جداگانه ببینید. اگر از گزینه -p استفاده کنید، هر دو نام فایل گنجاننده و گنجاندهشده نامهای کامل مسیر خواهند بود..IP -m 4
- --demangled-names
- نمایش نامهای غیردرهمریخته (demangled) توابع در خروجی. حالت پیشفرض بر نمایش نامهای درهمریخته (mangled) توابع است.
- -M
- --filter-on-demangled
- باعث میشود گزینههای --include و --exclude با نامهای demangled مطابقت داده شوند. این گزینه فقط بر تطبیق نامها تأثیر میگذارد و به معنای فعال شدن خودکار --demangled-names نیست، اما میتوان بدون مشکل آن را با این گزینه ترکیب کرد.
- -n
- --no-output
- فایل خروجی gcov ایجاد نشود.
- -o directory|file
- --object-directory directory
- --object-file file
- مشخص کردن دایرکتوری حاوی فایلهای داده gcov، یا مسیر فایل شیء (object). فایلهای داده .gcno و .gcda با استفاده از این گزینه جستجو میشوند. اگر یک دایرکتوری مشخص شود، فایلهای داده در آن دایرکتوری قرار دارند و همنام با نام فایل ورودی (بدون پسوند آن) نامگذاری میشوند. اگر یک فایل مشخص شود، فایلهای داده همنام با آن فایل (بدون پسوند آن) نامگذاری خواهند شد.
- -p
- --preserve-paths
- حفظ اطلاعات کامل مسیر در نام فایلهای .gcov تولیدشده. بدون این گزینه، تنها بخش نام فایل استفاده میشود. با فعال بودن این گزینه، تمام دایرکتوریها استفاده میشوند، به طوری که نویسههای / به نویسههای # تبدیل شده، مؤلفههای دایرکتوری . حذف گردیده و مؤلفههای غیرقابلحذف .. به ^ تغییر نام مییابند. این گزینه زمانی که فایلهای مبدأ در چندین دایرکتوری مختلف قرار دارند مفید است.
- -q
- --use-hotness-colors
- تولید خروجی رنگی شبیه به perf برای خطوط داغ و پرتکرار. راهنمای مقیاس رنگها در ابتدای فایل خروجی چاپ میشود.
- -r
- --relative-only
- تنها اطلاعات مربوط به فایلهای مبدأ با نام مسیر نسبی (پس از حذف پیشوند مبدأ) در خروجی آورده شود. مسیرهای مطلق معمولاً فایلهای سرآیند سیستمی هستند و بررسی پوشش هرگونه تابع درونخطی (inline) در آنها عموماً حائز اهمیت نیست.
- -s directory
- --source-prefix directory
- پیشوندی برای نام فایلهای مبدأ جهت حذف هنگام تولید فایلهای پوشش خروجی. این گزینه زمانی کاربرد دارد که فرآیند ساخت در یک دایرکتوری جداگانه انجام میشود و نیازی به ذکر مسیر دایرکتوری مبدأ در نامگذاری فایلهای خروجی نیست. توجه داشته باشید که این تشخیص پیشوند، پیش از بررسی مطلق بودن مسیر فایل مبدأ اعمال میشود.
- -t
- --stdout
- ارسال خروجی به خروجی استاندارد به جای ایجاد فایلهای خروجی.
- -u
- --unconditional-branches
- هنگام ارائه احتمالات انشعاب، انشعابهای بدون شرط نیز لحاظ شوند. انشعابهای بدون شرط معمولاً چندان حائز اهمیت نیستند.
- -v
- --version
- نمایش شماره نسخه gcov (در خروجی استاندارد) و خروج بدون انجام هیچ پردازش دیگری.
- -w
- --verbose
- چاپ اطلاعات تفصیلی مربوط به بلوکهای پایهای (basic blocks) و یالها (arcs).
- -x
- --hash-filenames
- هنگام استفاده از --preserve-paths، ابزار gcov از نام مسیر کامل فایلهای مبدأ برای ایجاد نام فایل خروجی استفاده میکند. این کار میتواند منجر به ایجاد نامهای طولانی شود که از محدودیتهای سیستمفایل فراتر میروند. این گزینه نامهایی به شکل source-file##md5.gcov ایجاد میکند، که در آن بخش source-file همان نام پایانی فایل است و مؤلفه md5 از نام کامل دستکاریشدهای که در غیر این صورت به کار میرفت محاسبه میشود. این گزینه در سیستمهایی با محدودیت در طول نام سیستمفایل، جایگزینی برای --preserve-paths است.
gcov باید در همان دایرکتوری جاری اجرا شود که کامپایلر در آن فراخوانی شده بود. در غیر این صورت قادر به مکانیابی فایلهای مبدأ نخواهد بود. gcov فایلهایی موسوم به mangledname.gcov در دایرکتوری جاری تولید میکند. این فایلها حاوی اطلاعات پوشش مربوط به فایل مبدأ متناظرشان هستند. برای هر فایل مبدأ (یا سرآیند) حاوی کد که جهت تولید فایلهای داده کامپایل شده است، یک فایل .gcov تولید میشود. بخش mangledname از نام فایل خروجی معمولاً همان نام فایل مبدأ است، اما در صورت مشخص شدن گزینههای -l یا -p میتواند ساختار پیچیدهتری داشته باشد. برای جزئیات به توضیحات این گزینهها مراجعه کنید.
اگر gcov را با چندین فایل ورودی اجرا کنید، مقادیر مربوط به هر فایل ورودی با هم جمع میشوند. معمولاً آن را با همان فهرست فایلهایی که در پیوند (link) نهایی فایل اجرایی شما حضور داشتهاند اجرا میکنید.
فایلهای .gcov حاوی فیلدهایی هستند که با : از هم جدا شده و در کنار کد مبدأ برنامه قرار گرفتهاند. قالب به صورت زیر است:
<execution_count>:<line_number>:<source line text>
در صورت درخواست از طریق گزینههای خط فرمان، ممکن است اطلاعات تکمیلی بلوک پس از هر خط آورده شود. برای خطوط فاقد کد، مقدار execution_count به صورت - درج میشود. خطوط اجرا نشده بسته به اینکه به ترتیب از طریق مسیرهای غیراستثنایی یا فقط از طریق مسیرهای استثنایی (مانند مدیریتکنندههای استثنای ++C) در دسترس باشند، با ##### یا ===== علامتگذاری میشوند. با تعیین گزینه -a، بلوکهای اجرا نشده بسته به دسترسیپذیری از طریق مسیرهای غیراستثنایی یا استثنایی، با $$$$$ یا %%%%% مشخص میگردند. بلوکهای پایهای اجرا شده که دستوری با execution_count برابر صفر دارند، با نویسه * خاتمه مییابند و با گزینه -k به رنگ ارغوانی نمایش داده میشوند. این قابلیت در Ada پشتیبانی نمیشود.
توجه داشته باشید که GCC میتواند بدنه توابعی را که به آنها نیازی نیست بهطور کامل حذف کند -- برای نمونه توابعی که در تمام نقاط درونخطی (inline) شدهاند. چنین توابعی با علامت - مشخص میشوند که ممکن است گمراهکننده باشد. از گزینههای -fkeep-inline-functions و -fkeep-static-functions استفاده کنید تا این توابع حفظ شوند و gcov بتواند مقدار execution_count آنها را بهدرستی نمایش دهد.
برخی از خطوط اطلاعاتی در ابتدای فایل، دارای line_number با مقدار صفر هستند. این خطوط مقدماتی (preamble) به شکل زیر هستند:
-:0:<tag>:<value>
ترتیب و تعداد این خطوط مقدماتی با پیشرفت توسعه gcov دستخوش تغییر و افزایش خواهد شد --- روی ثابت ماندن آنها حساب نکنید. از tag برای یافتن یک خط مقدماتی مشخص استفاده کنید.
اطلاعات تکمیلی بلوکها به شکل زیر است:
<tag> <information>
بخش information برای انسان خوانا است، اما طوری طراحی شده که به اندازه کافی برای پردازش ماشینی نیز ساده باشد.
هنگام چاپ درصدها، مقادیر 0% و 100% تنها زمانی چاپ میشوند که مقادیر به ترتیب دقیقاً 0% و 100% باشند. سایر مقادیری که طبق قاعده معمول به 0% یا 100% گرد میشوند، در عوض به عنوان نزدیکترین مقدار غیرمرزی چاپ خواهند شد.
هنگام استفاده از gcov، باید ابتدا برنامه خود را با گزینه ویژه کامپایلر GCC یعنی --coverage کامپایل کنید. این گزینه به کامپایلر اعلام میکند که اطلاعات تکمیلی مورد نیاز gcov (اساساً یک نمودار جریان برنامه یا flow graph) را تولید کند و همچنین کدهای اضافی لازم را جهت گردآوری دادههای پروفایلینگ در فایلهای شیء بگنجاند. این فایلهای الحاقی در دایرکتوری محل قرارگیری فایل شیء ذخیره میشوند..PP اجرای برنامه باعث ایجاد خروجی پروفایل خواهد شد. به ازای هر فایل مبدأ کامپایلشده با -fprofile-arcs، یک فایل همراه .gcda در دایرکتوری فایل شیء قرار خواهد گرفت.
اکنون اجرای gcov با نامهای فایل مبدأ برنامه بهعنوان آرگومان، فهرستی از کد را به همراه بسامد اجرای هر سطر تولید خواهد کرد. برای مثال، اگر نام برنامهٔ شما tmp.cpp باشد، با استفاده از قابلیتهای پایهٔ gcov چنین خروجیای را مشاهده خواهید کرد:
$ g++ --coverage tmp.cpp -c $ g++ --coverage tmp.o $ a.out $ gcov tmp.cpp -m File 'tmp.cpp' Lines executed:92.86% of 14 Creating 'tmp.cpp.gcov'
فایل tmp.cpp.gcov حاوی خروجی gcov است. در اینجا یک نمونه آورده شده است:
-: 0:Source:tmp.cpp
-: 0:Working directory:/home/gcc/testcase
-: 0:Graph:tmp.gcno
-: 0:Data:tmp.gcda
-: 0:Runs:1
-: 0:Programs:1
-: 1:#include <stdio.h>
-: 2:
-: 3:template<class T>
-: 4:class Foo
-: 5:{
-: 6: public:
1*: 7: Foo(): b (1000) {}
------------------
Foo<char>::Foo():
#####: 7: Foo(): b (1000) {}
------------------
Foo<int>::Foo():
1: 7: Foo(): b (1000) {}
------------------
2*: 8: void inc () { b++; }
------------------
Foo<char>::inc():
#####: 8: void inc () { b++; }
------------------
Foo<int>::inc():
2: 8: void inc () { b++; }
------------------
-: 9:
-: 10: private:
-: 11: int b;
-: 12:};
-: 13:
-: 14:template class Foo<int>;
-: 15:template class Foo<char>;
-: 16:
-: 17:int
1: 18:main (void)
-: 19:{
-: 20: int i, total;
1: 21: Foo<int> counter;
-: 22:
1: 23: counter.inc();
1: 24: counter.inc();
1: 25: total = 0;
-: 26:
11: 27: for (i = 0; i < 10; i++)
10: 28: total += i;
-: 29:
1*: 30: int v = total > 100 ? 1 : 2;
-: 31:
1: 32: if (total != 45)
#####: 33: printf ("Failure\n");
-: 34: else
1: 35: printf ("Success\n");
1: 36: return 0;
-: 37:}
توجه داشته باشید که سطر ۷ چندین بار در گزارش نشان داده شده است. نخستین مورد، تعداد کل دفعات اجرای آن سطر را نمایش میدهد و دو مورد بعدی متعلق به نمونههای سازندهٔ کلاس Foo هستند. همچنین همانطور که میبینید، سطر ۳۰ شامل چند بلوک پایهٔ اجرانشده است و از این رو شمارش اجرا دارای نماد ستاره است.
هنگامی که از گزینهٔ -a استفاده میکنید، شمارش بلوکها را بهطور جداگانه دریافت خواهید کرد و خروجی شبیه به این خواهد بود:
-: 0:Source:tmp.cpp
-: 0:Working directory:/home/gcc/testcase
-: 0:Graph:tmp.gcno
-: 0:Data:tmp.gcda
-: 0:Runs:1
-: 0:Programs:1
-: 1:#include <stdio.h>
-: 2:
-: 3:template<class T>
-: 4:class Foo
-: 5:{
-: 6: public:
1*: 7: Foo(): b (1000) {}
------------------
Foo<char>::Foo():
#####: 7: Foo(): b (1000) {}
------------------
Foo<int>::Foo():
1: 7: Foo(): b (1000) {}
------------------
2*: 8: void inc () { b++; }
------------------
Foo<char>::inc():
#####: 8: void inc () { b++; }
------------------
Foo<int>::inc():
2: 8: void inc () { b++; }
------------------
-: 9:
-: 10: private:
-: 11: int b;
-: 12:};
-: 13:
-: 14:template class Foo<int>;
-: 15:template class Foo<char>;
-: 16:
-: 17:int
1: 18:main (void)
-: 19:{
-: 20: int i, total;
1: 21: Foo<int> counter;
1: 21-block 0
-: 22:
1: 23: counter.inc();
1: 23-block 0
1: 24: counter.inc();
1: 24-block 0
1: 25: total = 0;
-: 26:
11: 27: for (i = 0; i < 10; i++)
1: 27-block 0
11: 27-block 1
10: 28: total += i;
10: 28-block 0
-: 29:
1*: 30: int v = total > 100 ? 1 : 2;
1: 30-block 0
%%%%%: 30-block 1
1: 30-block 2
-: 31:
1: 32: if (total != 45)
1: 32-block 0
#####: 33: printf ("Failure\n");
%%%%%: 33-block 0
-: 34: else
1: 35: printf ("Success\n");
1: 35-block 0
1: 36: return 0;
1: 36-block 0
-: 37:}
در این حالت، هر بلوک پایه تنها در یک سطر نمایش داده میشود -- آخرین سطر از آن بلوک. یک بلوک چندسطری تنها در شمارش اجرای همان سطر آخر لحاظ خواهد شد، و سطرهای دیگر بهعنوان سطرهای حاوی کد نشان داده نمیشوند، مگر اینکه بلوکهای قبلی در آن سطرها پایان یابند. تعداد کل دفعات اجرای یک سطر نشان داده میشود و سطرهای پس از آن تعداد اجرای بلوکهای مجزایی را نمایش میدهند که در آن سطر پایان مییابند. در صورت استفاده از گزینهٔ -b، پس از هر بلوک، تعداد انشعابها و فراخوانیهای آن بلوک نیز نشان داده خواهد شد.
به دلیل نحوهٔ ابزارگذاری (instrumentation) فراخوانیها در GCC، ممکن است شمارش فراخوانی پس از سطری نمایش داده شود که هیچ بلوک مجزایی ندارد. همانطور که میبینید، سطر ۳۳ شامل یک بلوک پایه است که اجرا نشده است.
هنگامی که از گزینهٔ -b استفاده میکنید، خروجی بدین شکل خواهد بود:
-: 0:Source:tmp.cpp
-: 0:Working directory:/home/gcc/testcase
-: 0:Graph:tmp.gcno
-: 0:Data:tmp.gcda
-: 0:Runs:1
-: 0:Programs:1
-: 1:#include <stdio.h>
-: 2:
-: 3:template<class T>
-: 4:class Foo
-: 5:{
-: 6: public:
1*: 7: Foo(): b (1000) {}
------------------
Foo<char>::Foo():
function Foo<char>::Foo() called 0 returned 0% blocks executed 0%
#####: 7: Foo(): b (1000) {}
------------------
Foo<int>::Foo():
function Foo<int>::Foo() called 1 returned 100% blocks executed 100%
1: 7: Foo(): b (1000) {}
------------------
2*: 8: void inc () { b++; }
------------------
Foo<char>::inc():
function Foo<char>::inc() called 0 returned 0% blocks executed 0%
#####: 8: void inc () { b++; }
------------------
Foo<int>::inc():
function Foo<int>::inc() called 2 returned 100% blocks executed 100%
2: 8: void inc () { b++; }
------------------
-: 9:
-: 10: private:
-: 11: int b;
-: 12:};
-: 13:
-: 14:template class Foo<int>;
-: 15:template class Foo<char>;
-: 16:
-: 17:int
function main called 1 returned 100% blocks executed 81%
1: 18:main (void)
-: 19:{
-: 20: int i, total;
1: 21: Foo<int> counter;
call 0 returned 100%
branch 1 taken 100% (fallthrough)
branch 2 taken 0% (throw)
-: 22:
1: 23: counter.inc();
call 0 returned 100%
branch 1 taken 100% (fallthrough)
branch 2 taken 0% (throw)
1: 24: counter.inc();
call 0 returned 100%
branch 1 taken 100% (fallthrough)
branch 2 taken 0% (throw)
1: 25: total = 0;
-: 26:
11: 27: for (i = 0; i < 10; i++)
branch 0 taken 91% (fallthrough)
branch 1 taken 9%
10: 28: total += i;
-: 29:
1*: 30: int v = total > 100 ? 1 : 2;
branch 0 taken 0% (fallthrough)
branch 1 taken 100%
-: 31:
1: 32: if (total != 45)
branch 0 taken 0% (fallthrough)
branch 1 taken 100%
#####: 33: printf ("Failure\n");
call 0 never executed
branch 1 never executed
branch 2 never executed
-: 34: else
1: 35: printf ("Success\n");
call 0 returned 100%
branch 1 taken 100% (fallthrough)
branch 2 taken 0% (throw)
1: 36: return 0;
-: 37:}
برای هر تابع، خطی چاپ میشود که نشان میدهد آن تابع چند بار فراخوانی شده، چند بار بازگشته و چند درصد از بلوکهای تابع اجرا شدهاند.
برای هر بلوک پایه (basic block)، خطی پس از آخرین خط آن بلوک چاپ میشود که شاخه یا فراخوانیِ پایانبخش آن بلوک را توصیف میکند. اگر چندین بلوک پایه در یک خط مبدأ به پایان برسند، ممکن است چندین شاخه و فراخوانی برای آن تکخط مبدأ فهرست شود. در این حالت، به هر یک از شاخهها و فراخوانیها یک شماره اختصاص داده میشود. راه سادهای برای نگاشت معکوس این شاخهها و فراخوانیها به ساختارهای کد مبدأ وجود ندارد. با این حال، بهطور کلی، شاخه یا فراخوانی با کمترین شماره، متناظر با چپترین ساختار در خط مبدأ خواهد بود.
برای یک شاخه، اگر حداقل یک بار اجرا شده باشد، درصدی چاپ میشود که بیانگر تعداد دفعات طی شدن شاخه تقسیم بر تعداد دفعات اجرای آن شاخه است. در غیر این صورت، پیام «never executed» چاپ میشود.
برای یک فراخوانی، اگر حداقل یک بار اجرا شده باشد، درصدی چاپ میشود که نشاندهندهٔ تعداد دفعات بازگشت فراخوانی تقسیم بر تعداد دفعات اجرای آن فراخوانی است. این مقدار معمولاً ۱۰۰٪ خواهد بود، اما ممکن است برای توابعی که "exit" یا "longjmp" را فراخوانی میکنند کمتر باشد؛ چرا که ممکن است پس از هر بار فراخوانی بازنگردند.
هنگامی که از گزینهٔ -g استفاده میکنید، خروجی شما شبیه به این خواهد بود:
$ gcov -t -m -g tmp
-: 0:Source:tmp.cpp
-: 0:Graph:tmp.gcno
-: 0:Data:tmp.gcda
-: 0:Runs:1
-: 1:#include <stdio.h>
-: 2:
-: 3:int
1: 4:main (void)
-: 5:{
-: 6: int i, total;
1: 7: total = 0;
-: 8:
11: 9: for (i = 0; i < 10; i++)
condition outcomes covered 2/2
10: 10: total += i;
-: 11:
1*: 12: int v = total > 100 ? 1 : 2;
condition outcomes covered 1/2
condition 0 not covered (true)
-: 13:
1*: 14: if (total != 45 && v == 1)
condition outcomes covered 1/4
condition 0 not covered (true)
condition 1 not covered (true false)
#####: 15: printf ("Failure\n");
-: 16: else
1: 17: printf ("Success\n");
1: 18: return 0;
-: 19:}
برای هر شرط، تعداد نتایج رخداده و کل نتایج چاپ میشود، و در صورت وجود نتایج پوششدادهنشده، برای هر شرط خطی چاپ خواهد شد که نتیجهٔ پوششدادهنشده را در پرانتز نشان میدهد. شرطها بر اساس اندیس خود مشخص میشوند -- اندیس ۰ چپترین شرط است. در "a || (b && c)"، a شرط ۰، b شرط ۱، و c شرط ۲ است.
یک نتیجه زمانی پوششدادهشده در نظر گرفته میشود که اثر مستقلی بر تصمیم داشته باشد؛ که به آن پوشش پنهانساز MC/DC (یا Modified Condition/Decision Coverage) نیز میگویند. در این مثال، تصمیم به true ارزیابی میشود و a ارزیابی میگردد، اما پوشش داده نمیشود. دلیل این امر آن است که a نمیتواند بهطور مستقل بر تصمیم تأثیر بگذارد -- هر دو متغیر a و b باید مقدارشان تغییر کند تا تصمیم تغییر یابد.
$ gcov -t -m -g tmp
-: 0:Source:tmp.c
-: 0:Graph:tmp.gcno
-: 0:Data:tmp.gcda
-: 0:Runs:1
-: 1:#include <stdio.h>
-: 2:
1: 3:int main()
-: 4:{
1: 5: int a = 1;
1: 6: int b = 0;
-: 7:
1: 8: if (a && b)
condition outcomes covered 1/4
condition 0 not covered (true false)
condition 1 not covered (true)
#####: 9: printf ("Success!\n");
-: 10: else
1: 11: printf ("Failure!\n");
-: 12:}
هنگامی که برنامه را با --coverage -fpath-coverage کامپایل کرده و از گزینهٔ -e استفاده میکنید، خروجی شما شبیه به این خواهد بود:
$ gcov -t -e tmp
-: 0:Source:tmp.cpp
-: 0:Graph:tmp.gcno
-: 0:Data:tmp.gcda
-: 0:Runs:1
-: 1:#include <stdio.h>
-: 2:
paths covered 4 of 15
1: 3:int main ()
-: 4:{
-: 5: int i, total;
1: 6: total = 0;
-: 7:
11: 8: for (i = 0; i < 10; i++)
10: 9: total += i;
-: 10:
1*: 11: int v = total > 100 ? 1 : 2;
-: 12:
1*: 13: if (total != 45 && v == 1)
#####: 14: printf ("Failure\n");
-: 15: else
1: 16: printf ("Success\n");
1: 17: return 0;
-: 18:}
این خروجی برای درک تقریبی بخشهایی که فاقد پوشش هستند و آزمایش اینکه ورودیهای مختلف چگونه پوشش را تغییر میدهند، مفید است. گزینهٔ --prime-paths-source ابزاری کارآمد برای درک مسیرهاست.
$ gcov -t --prime-paths-source tmp
-: 0:Source:tmp.cpp
-: 0:Graph:tmp.gcno
-: 0:Data:tmp.gcda
-: 0:Runs:1
-: 1:#include <stdio.h>
-: 2:
paths covered 4 of 15
path 1:
BB 2: 3:int main ()
BB 2: 6: total = 0;
BB 2: 8: for (i = 0; i < 10; i++)
BB 4: (false) 8: for (i = 0; i < 10; i++)
BB 5: (true) 11: int v = total > 100 ? 1 : 2;
BB 6: 11: int v = total > 100 ? 1 : 2;
BB 8: (true) 13: if (total != 45 && v == 1)
BB 9: (true) 13: if (total != 45 && v == 1)
BB 10: 14: printf ("Failure\n");
BB 12: 17: return 0;
در این حالت، gcov جزئیات مربوط به مسیرهای ازدسترفته را چاپ میکند. ستون نخست، توالی بلوکهای پایه (BB) را فهرست میکند. ستون دوم تصمیمی است که باید در آن خط اتخاذ شود (اگر تصمیمی وجود داشته باشد). ستونهای پایانی، شمارهٔ خط و خود خط کد هستند. این ویژگی برای درک مسیرها، بهویژه آنهایی که پوششدادنشان دشوار یا حتی دستنیافتنی است، مفید میباشد. اگر یک خط بخشی از چندین بلوک پایه باشد، ممکن است خطوط تکرار شوند؛ برای نمونه حلقهٔ "for". این حالت برای خواندن انسان طراحی شده و برای درک اینکه چه کدی در حین آزمون یا برای ورودیهای دادهشده اجرا شده است، مناسب است. این خروجی بسیار پرجزئیات (verbose) است، و برای تمرکز بر روی توابع خاص میتوان آن را با فیلترهای --include و --exclude ترکیب کرد.
خروجی فشردهتری با --prime-paths-lines در دسترس است که به این صورت خواهد بود:
-: 0:Source:tmp.cpp
-: 0:Graph:tmp.gcno
-: 0:Data:tmp.gcda
-: 0:Runs:1
-: 1:#include <stdio.h>
-: 2:
paths covered 4 of 15
path 1 not covered: lines 8 8(false) 11(true) 11 13(true) 13(true) 14 17
path 2 not covered: lines 8 8(false) 11(true) 11 13(true) 13(false) 16 17
path 3 not covered: lines 8 8(false) 11(true) 11 13(false) 16 17
path 4 not covered: lines 8 8(false) 11(false) 11 13(true) 13(true) 14 17
path 5 not covered: lines 8 8(false) 11(false) 11 13(true) 13(false) 16 17
path 6 not covered: lines 8 8(false) 11(false) 11 13(false) 16 17
path 8 not covered: lines 9 8(false) 11(true) 11 13(true) 13(true) 14 17
path 9 not covered: lines 9 8(false) 11(true) 11 13(true) 13(false) 16 17
path 10 not covered: lines 9 8(false) 11(true) 11 13(false) 16 17
path 11 not covered: lines 9 8(false) 11(false) 11 13(true) 13(true) 14 17
path 12 not covered: lines 9 8(false) 11(false) 11 13(true) 13(false) 16 17
1: 3:int main ()
-: 4:{
در این حالت، هر مسیر ازدسترفته با استفاده از خطوط و تصمیمها همانند --prime-paths-source بسط داده میشود، اما در یک خط منفرد چاپ میگردد. این حالت نمای کلیِ مناسبی از مسیرها فراهم ساخته و برای ردگیری چگونگی آزموده شدن کد توسط آزمونها و ورودیهای مختلف کارآمد است.
شمارندههای اجرا انباشتهشونده هستند. اگر برنامهٔ نمونه بدون حذف فایل .gcda دوباره اجرا شود، تعداد دفعات اجرای هر خط از کد مبدأ به نتایج اجرای (یا اجراهای) پیشین افزوده خواهد شد. این موضوع میتواند از چندین جهت کاربردی باشد؛ برای نمونه، میتوان از آن برای گردآوری دادهها طی چندین بار اجرای برنامه به عنوان بخشی از یک مجموعهآزمون اعتبارسنجی استفاده کرد، یا اطلاعات درازمدت و دقیقتری را در طول تعداد زیادی از اجراهای برنامه به دست آورد..PP دادهها در فایلهای .gcda بلافاصله پیش از خروج برنامه ذخیره میشوند. برای هر فایل مبدأ کامپایلشده با -fprofile-arcs، کد پروفایلسازی ابتدا تلاش میکند یک فایل .gcda موجود را بخواند؛ اگر فایل با فایل اجرایی مطابقت نداشته باشد (تعداد متفاوتی از شمارش بلوکهای پایه)، محتویات فایل را نادیده میگیرد. سپس تعداد دفعات اجرای جدید را افزوده و در نهایت دادهها را در فایل مینویسد.
میتوانید با استفاده از --include و --exclude گزارشی از زیرمجموعهای از توابع تهیه کنید. این قابلیت هنگامی که با --stdout ترکیب شود، برای درک رفتار و میزان پوشش یک تابع خاص از طریق اجرای آزمون، بررسی خروجی gcov، آزمودن ورودی دیگر و اجرای مجدد gcov بسیار مفید است.
$ gcov -m --stdout --include inc tmp
-: 0:Source:tmp.cpp
-: 0:Graph:tmp.gcno
-: 0:Data:tmp.gcda
-: 0:Runs:1
2*: 8: void inc () { b++; }
------------------
Foo<char>::inc():
#####: 8: void inc () { b++; }
------------------
Foo<int>::inc():
2: 8: void inc () { b++; }
------------------
ابزار gcov بهطور پیشفرض با نامهای mangled تطبیق میدهد، که میتوانید آن را با پرچم -M کنترل کنید. توجه داشته باشید که تطبیق و گزارشدهی مستقل از یکدیگر هستند، بنابراین میتوانید در حین چاپ نامهای demangled، با نامهای mangled تطبیق دهید و برعکس. برای گزارشدهی روی نمونهسازی "int" از "Foo" با تطبیق روی نامهای mangled و demangled:
$ gcov -t -m -M tmp --include 'Foo<int>'
-: 0:Source:tmp.cpp
-: 0:Graph:tmp.gcno
-: 0:Data:tmp.gcda
-: 0:Runs:1
1: 7: Foo(): b (1000) {}
2: 8: void inc () { b++; }
$ gcov -t -m tmp --include 'FooIi'
-: 0:Source:tmp.cpp
-: 0:Graph:tmp.gcno
-: 0:Data:tmp.gcda
-: 0:Runs:1
1: 7: Foo(): b (1000) {}
2: 8: void inc () { b++; }
آرگومانهای --include و --exclude عبارات باقاعدهٔ توسعهیافته هستند (مانند grep -E)، بنابراین الگوی "in.?" هم با "inc" و هم با "main" تطبیق مییابد. در صورت استفاده به همراه -M، تمام نمونهسازیهای "int" از "Foo" نیز تطبیق داده میشوند. گزینههای --include و --exclude را میتوان چند بار استفاده کرد، و اگر نامی با چند فیلتر مطابقت داشته باشد، آخرین مورد تطبیقیافته اولویت خواهد داشت. برای مثال، برای تطبیق با "main" و نمونهسازی "int" از "inc"، در حالی که سازندهٔ "Foo" نادیده گرفته میشود:
$ gcov -t -m -M --include in --exclude Foo --include '<int>::inc' tmp
-: 0:Source:tmp.cpp
-: 0:Graph:tmp.gcno
-: 0:Data:tmp.gcda
-: 0:Runs:1
2: 8: void inc () { b++; }
1: 18:main (void)
-: 19:{
-: 20: int i, total;
1: 21: Foo<int> counter;
-: 22:
1: 23: counter.inc();
1: 24: counter.inc();
1: 25: total = 0;
-: 26:
11: 27: for (i = 0; i < 10; i++)
10: 28: total += i;
-: 29:
1*: 30: int v = total > 100 ? 1 : 2;
-: 31:
1: 32: if (total != 45)
#####: 33: printf ("Failure\n");
-: 34: else
1: 35: printf ("Success\n");
1: 36: return 0;
استفاده از gcov با بهینهسازی GCC (Using gcov with GCC Optimization)
اگر قصد دارید از gcov برای کمک به بهینهسازی کد خود استفاده کنید، ابتدا باید برنامهٔ خود را با گزینهٔ ویژهٔ GCC یعنی --coverage کامپایل کنید. بهجز آن، میتوانید از هر گزینهٔ دیگر GCC نیز استفاده کنید؛ اما اگر میخواهید اثبات کنید که تکتک خطوط برنامهٔ شما اجرا شدهاند، نباید همزمان با بهینهسازی کامپایل کنید. در برخی ماشینها، بهینهساز میتواند برخی از خطوط سادهٔ کد را با ترکیب آنها با سایر خطوط حذف کند. برای مثال، کدی مانند این:
if (a != b) c = 1; else c = 0;
روی برخی ماشینها میتواند به یک دستورالعمل واحد ترجمه شود. در این حالت، هیچ راهی برای gcov وجود ندارد که شمارش اجرای جداگانهای را برای هر خط محاسبه کند، زیرا برای هر خط کد جداگانهای وجود ندارد. بنابراین اگر برنامه را با بهینهسازی کامپایل کرده باشید، خروجی gcov به این شکل خواهد بود:
100: 12:if (a != b) 100: 13: c = 1; 100: 14:else 100: 15: c = 0;
خروجی نشان میدهد که این بلوک کد، که از طریق بهینهسازی ترکیب شده است، ۱۰۰ بار اجرا شده است. به یک معنا این نتیجه درست است، زیرا تنها یک دستورالعمل وجود داشت که هر چهار خط را نمایندگی میکرد. با این حال، خروجی نشان نمیدهد که چند بار نتیجه 0 و چند بار نتیجه 1 بوده است.
توابع درونخطیشدنی (Inlineable) میتوانند شمارش خطوط غیرمنتظرهای ایجاد کنند. شمارش خطوط برای کد منبع تابع درونخطیشدنی نمایش داده میشود، اما آنچه نشان داده میشود بستگی به این دارد که تابع در کجا درونخطی شده است یا اینکه اصلاً درونخطی نشده باشد.
اگر تابع درونخطی نشود، کامپایلر باید یک نسخهٔ برونخطی (out of line) از تابع را در هر فایل شیء (object file) که به آن نیاز دارد تولید کند. اگر fileA.o و fileB.o هر دو شامل بدنهٔ برونخطی یک تابع درونخطیشدنی خاص باشند، هر دو نیز شامل شمارندههای پوشش آن تابع خواهند بود. هنگامی که fileA.o و fileB.o با یکدیگر پیوند داده میشوند، پیونددهنده (linker) در بسیاری از سیستمها یکی از آن بدنههای برونخطی را برای تمام فراخوانیهای آن تابع انتخاب کرده و دیگری را حذف یا نادیده میگیرد. متأسفانه، شمارندههای پوشش برای بدنهٔ استفادهنشدهٔ تابع حذف نخواهند شد. بنابراین در حالت سنجشگذاریشده (instrumented)، تمام موارد استفاده از آن تابع به جز یکی، شمارش صفر را نشان خواهند داد.
اگر تابع در چندین مکان درونخطی شود، ممکن است ساختار بلوک در هر مکان یکسان نباشد. برای نمونه، ممکن است یک شرط در برخی موارد در زمان کامپایل قابل محاسبه باشد. از آنجا که پوشش تمام استفادههای تابع درونخطی برای همان خطوط مبدأ یکسان نشان داده میشود، ممکن است شمارش خطوط بهخودیخود متناقض به نظر برسد.
برنامههای با مدت اجرای طولانی (Long-running) میتوانند از امکانات "__gcov_reset" و "__gcov_dump" برای محدود کردن جمعآوری دادههای پروفایل به بخش مورد نظر از برنامه استفاده کنند. فراخوانی "__gcov_reset(void)" تمام شمارندههای پروفایل زمان اجرا را به صفر بازنشانی میکند، و فراخوانی "__gcov_dump(void)" باعث میشود اطلاعات پروفایل جمعآوریشده در آن نقطه، در فایلهای خروجی .gcda ذخیره شوند. برنامههای سنجشگذاریشده از یک مخرب ایستا (static destructor) با اولویت ۹۹ برای فراخوانی تابع "__gcov_dump" استفاده میکنند. بنابراین "__gcov_dump" پس از تمام مخربهای ایستای تعریفشده توسط کاربر و همچنین گردانندههای ثبتشده با "atexit" اجرا میشود.
اگر یک فایل اجرایی یک شیء اشتراکی پویا (dynamic shared object) را از طریق قابلیت dlopen بارگیری کند، گزینهٔ -Wl,--dynamic-list-data برای تخلیهٔ تمام دادههای پروفایل لازم است.
کتابخانهٔ زمان اجرای پروفایلسازی، خطاهای مختلف مربوط به دستکاری و ذخیرهٔ پروفایل را گزارش میکند. خطاها در خروجی خطای استاندارد یا در صورت استفاده از متغیر محیطی، در فایل GCOV_ERROR_FILE چاپ میشوند. به منظور خروج فوری پس از وقوع خطا، متغیر محیطی GCOV_EXIT_AT_ERROR را تنظیم کنید. این کار میتواند به کاربران در یافتن تداخل پروفایلها (clashing) که منجر به یک پروفایل گمراهکننده میشود، کمک کند..SH "همچنین ببینید (SEE ALSO)" gpl(7)، gfdl(7)، fsf-funding(7)، gcc(1) و مدخل Info برای gcc.
کپیرایت و تکثیر (COPYRIGHT)
Copyright (c) 1996-2026 Free Software Foundation, Inc.
اجازه کپی، توزیع و/یا تغییر این سند تحت شرایط مجوز مستندات آزاد گنو (GNU Free Documentation License)، نسخه 1.3 یا هر نسخهٔ بعدی منتشرشده توسط بنیاد نرمافزارهای آزاد (Free Software Foundation) اعطا میشود؛ با این شرط که بخشهای تغییرناپذیر «GNU General Public License» و «Funding Free Software»، متنهای روی جلد (a) (زیر را ببینید) و متنهای پشت جلد (b) (زیر را ببینید) باشند. یک نسخه از این مجوز در صفحه راهنمای gfdl(7) گنجانده شده است.
(a) متن روی جلد FSF عبارت است از:
A GNU Manual
(b) متن پشت جلد FSF عبارت است از:
You have freedom to copy and modify this GNU Manual, like GNU software. Copies published by the Free Software Foundation raise funds for GNU development.
| 2026-08-10 | gcc-16.2.1 |