| GCOV(1) | GNU | GCOV(1) |
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 یک برنامهٔ سنجش پوشش آزمون است. از آن به همراه GCC برای تحلیل برنامههای خود استفاده کنید تا بتوانید کدهایی بهینهتر و با اجرای سریعتر تولید کرده و بخشهای آزمایشنشدهٔ برنامهٔ خود را کشف کنید. میتوانید از gcov به عنوان ابزاری برای پروفایلینگ استفاده کنید تا مشخص شود تلاشهای شما برای بهینهسازی، بیشترین تأثیر را در کدام قسمتهای کد خواهد داشت. همچنین میتوانید از gcov به همراه ابزار دیگر پروفایلینگ، یعنی gprof، استفاده کنید تا ارزیابی کنید کدام بخشهای کد بیشترین مقدار زمان پردازشی را مصرف میکنند.
ابزارهای پروفایلینگ به شما در تحلیل کارایی کدتان کمک میکنند. با استفاده از یک ابزار پروفایلینگ مانند gcov یا gprof، میتوانید برخی از آمارهای پایهای کارایی را به دست آورید؛ از جمله:
- هر خط از کد چند بار اجرا میشود
- کدام خطوط از کد واقعاً اجرا میشوند
- هر بخش از کد چه مقدار زمان پردازشی مصرف میکند
هنگامی که این موارد را دربارهٔ نحوهٔ کارکرد کد کامپایلشدهٔ خود دانستید، میتوانید هر ماژول را بررسی کنید تا ببینید کدام ماژولها باید بهینهسازی شوند. gcov به شما کمک میکند تعیین کنید کار بهینهسازی را از کجا شروع کنید.
توسعهدهندگان نرمافزار همچنین از سنجش پوشش آزمون در کنار مجموعههای آزمون (testsuiteها) استفاده میکنند تا مطمئن شوند نرمافزار واقعاً کیفیت لازم برای انتشار را دارد. مجموعههای آزمون میتوانند بررسی کنند که برنامه طبق انتظار عمل میکند یا خیر؛ یک برنامهٔ سنجش پوشش آزمون بررسی میکند چه مقدار از برنامه توسط این مجموعه آزمون اجرا و سنجیده شده است. سپس توسعهدهندگان میتوانند تعیین کنند چه نوع آزمونهای جدیدی باید به مجموعههای آزمون اضافه شوند تا هم آزمون بهتری انجام شود و هم محصول نهایی باکیفیتتری تولید گردد.
اگر قصد استفاده از gcov را دارید، باید کد خود را بدون بهینهسازی کامپایل کنید؛ زیرا بهینهسازی ممکن است از طریق ترکیب چندین خط کد در یک تابع، اطلاعات مورد نیاز شما را برای یافتن «نقاط بحرانی» (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
- بسامد (فرکانس) شاخهها را در فایل خروجی، و اطلاعات خلاصهٔ شاخهها را در خروجی استاندارد مینویسد. این گزینه به شما امکان میدهد ببینید هر شاخه در برنامه شما چند بار طی شده است. شاخههای بدون شرط نمایش داده نخواهند شد، مگر اینکه گزینهٔ -u مشخص شده باشد.
- -c
- --branch-counts
- بسامد شاخهها را به جای درصد، بهصورت تعداد شاخههای طیشده مینویسد.
- -g
- --conditions
- پوشش شرطها (condition coverage) را در فایل خروجی، و اطلاعات خلاصهٔ شرط را در خروجی استاندارد مینویسد. این گزینه به شما اجازه میدهد ببینید آیا شرطها در برنامه شما دستکم یک بار تأثیر مستقلی بر نتیجهٔ عبارت بولی داشتهاند یا خیر (پوشش شرط/تصمیم اصلاحشده یا MC/DC). این گزینه نیازمند کامپایل کد مبدأ با -fcondition-coverage است.
- -e
- --prime-paths
- پوشش مسیر (path coverage) را در فایل خروجی، و اطلاعات خلاصهٔ مسیر را در خروجی استاندارد مینویسد. این گزینه امکان مشاهدهٔ تعداد مسیرهای اولیهای (prime paths) که دستکم یک بار طی شدهاند را فراهم میکند. یک مسیر دنبالهای از بلوکهای پایهای است. یک مسیر در صورتی ساده است که هیچ بلوک تکراری (هیچ حلقهای) جز احتمالاً بلوک اول و آخر نداشته باشد، و در صورتی اولیه (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 مطابقت داشته باشد، آخرین مورد اعمال میشود. بهطور پیشفرض gcov تمام توابع را گزارش میدهد، اما اگر از --include استفاده شود، تنها توابع منطبق با آن گزارش خواهند شد.
- --exclude regex
- توابع منطبق با regex را مستثنی میکند. این گزینه باعث میشود gcov توابعی را که با عبارت منظم گسترشیافتهٔ regex مطابقت دارند گزارش نکند. این پرچم میتواند با --include ترکیب شود. اگر تابعی هم با 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: دایرکتوری کاری که واحد کامپایل در آن کامپایل شده است
- 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: نام سادهشده (demangled) تابع
- end_column: ستونی در فایل منبع که تابع در آن پایان مییابد
- end_line: خطی در فایل منبع که تابع در آن پایان مییابد
- execution_count: تعداد دفعات اجرای تابع
- name: نام تابع
- start_column: ستونی در فایل منبع که تابع در آن آغاز میشود
- start_line: خطی در فایل منبع که تابع در آن آغاز میشود
توجه داشته باشید که شماره خطوط و ستونها از ۱ آغاز میشوند. در پیادهسازی فعلی، start_line و start_column شامل پارامترهای قالب و نوع بازگشتی ابتدایی نمیشوند، اما احتمالاً این مورد در آینده برطرف خواهد شد.
هر 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: در صورتی که شاخه یک شاخه گذر مستقیم (fall through) باشد، true است
- throw: در صورتی که شاخه یک شاخه استثنا (exceptional) باشد، true است
- isource_block_id: شناسه (ID) بلوک پایهای که این شاخه در آن رخ میدهد
- destination_block_id: شناسه (ID) بلوک پایهای که این شاخه به آن میپرد
هر call دارای ساختار زیر است:
{
"destination_block_id": 1,
"returned": 11,
"source_block_id": 13
}
فیلدهای عنصر call دارای معانی زیر هستند:
- returned: تعداد دفعاتی که یک فراخوانی تابع بازگشته است (تعداد فراخوانی برابر است با line::count)
- isource_block_id: شناسه (ID) بلوک پایهای که این فراخوانی در آن رخ میدهد
- destination_block_id: شناسه (ID) بلوک پایهای که این فراخوانی پس از بازگشت در آن ادامه مییابد
هر condition دارای ساختار زیر است:
{
"count": 4,
"covered": 2,
"not_covered_false": [],
"not_covered_true": [0, 1],
}
فیلدهای عنصر condition دارای معانی زیر هستند:.IP "*" 4 count: تعداد نتایج شرط در این عبارت
- covered: تعداد نتایج شرطِ پوششدادهشده در این عبارت
- not_covered_true: جملهها، بر اساس اندیس، که در این عبارت بهصورت درست (true) دیده نشدهاند
- not_covered_false: جملهها، بر اساس اندیس، که در این عبارت بهصورت نادرست (false) دیده نشدهاند
- -H
- --human-readable
- شمارشها را در قالبی خوانا برای انسان بنویس (مانند 24.6k).
- -k
- --use-colors
- برای خطوط کدی که پوشش صفر دارند از رنگها استفاده کن. از رنگ قرمز برای خطوط غیراستثنایی و رنگ فیروزهای برای خطوط استثنایی استفاده میشود. همین رنگها برای بلوکهای پایه با گزینهٔ -a نیز استفاده میشوند.
- -l
- --long-file-names
- برای فایلهای منبع گنجاندهشده (included)، نامهای فایل طولانی بساز. برای نمونه، اگر فایل سرآیند x.h حاوی کد باشد و در فایل a.c گنجانده شده باشد، اجرای gcov روی فایل a.c فایلی خروجی به نام a.c##x.h.gcov بهجای x.h.gcov تولید میکند. این ویژگی زمانی مفید است که x.h در چندین فایل منبع گنجانده شده باشد و بخواهید سهم هر یک را بهصورت مجزا مشاهده کنید. اگر از گزینهٔ -p استفاده کنید، هم نام فایل گنجاننده و هم فایل گنجاندهشده مسیرهای کامل خواهند بود.
- -m
- --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 یا مسیر فایل آبجکت را مشخص کن. فایلهای دادهٔ .gcno و .gcda با استفاده از این گزینه جستجو میشوند. اگر یک دایرکتوری مشخص شود، فایلهای داده در آن دایرکتوری قرار داشته و نام آنها بر اساس نام فایل ورودی (بدون پسوند آن) خواهد بود. اگر فایلی در اینجا مشخص شود، فایلهای داده بر اساس نام آن فایل، بدون پسوند آن، نامگذاری میشوند.
- -p
- --preserve-paths
- حفظ کامل اطلاعات مسیر در نام فایلهای .gcov تولیدشده. بدون این گزینه، فقط جزء نام فایل استفاده میشود. با این گزینه، تمام دایرکتوریها استفاده میشوند، بهطوری که نویسههای / به نویسههای # تبدیل میشوند، اجزای دایرکتوری . حذف شده و اجزای غیرقابلحذف .. به ^ تغییر نام مییابند. این ویژگی زمانی مفید است که فایلهای منبع در چندین دایرکتوری مختلف قرار داشته باشند.
- -q
- --use-hotness-colors
- تولید خروجی رنگی شبیه به perf برای خطوط پرتکرار (hot lines). راهنمای طیف رنگی در ابتدای فایل خروجی چاپ میشود.
- -r
- --relative-only
- فقط اطلاعات مربوط به فایلهای منبعی با مسیر نسبی را در خروجی درج کن (پس از حذف پیشوند منبع). مسیرهای مطلق معمولاً فایلهای سرآیند سیستمی هستند و پوشش توابع درونخطی (inline) در آنها معمولاً اهمیتی ندارد.
- -s directory
- --source-prefix directory
- یک پیشوند برای نامهای فایلهای منبع جهت حذف هنگام تولید فایلهای خروجی پوشش. این گزینه هنگام ساخت در یک دایرکتوری جداگانه مفید است، زمانی که تمایلی به حضور مسیر دایرکتوری منبع در تعیین نام فایلهای خروجی وجود ندارد. توجه داشته باشید که این تشخیص پیشوند قبل از تعیین مطلق بودن یا نبودن فایل منبع اعمال میشود.
- -t
- --stdout
- ارسال خروجی به خروجی استاندارد بهجای فایلهای خروجی.
- -u
- --unconditional-branches
- هنگامی که احتمالات شاخهها ارائه میشود، شاخههای غیرشرطی را نیز در نظر بگیر. شاخههای غیرشرطی معمولاً جالب توجه نیستند.
- -v
- --version
- نمایش شماره نسخهٔ gcov (در خروجی استاندارد) و خروج بدون انجام هیچ پردازش دیگری.
- -w
- --verbose
- چاپ اطلاعات تفصیلی مربوط به بلوکهای پایه و کمانها (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 را با چندین فایل ورودی فراخوانی کنید، مشارکتهای حاصل از هر فایل ورودی جمع میشوند. معمولاً آن را با همان فهرست فایلهایی فراخوانی میکنید که در پیوند نهایی برنامهٔ اجراییتان استفاده شدهاند..PP فایلهای .gcov شامل فیلدهایی هستند که با : از یکدیگر جدا شدهاند و در کنار کد منبع برنامه قرار دارند. قالب به این صورت است:
<execution_count>:<line_number>:<source line text>
در صورت درخواست از طریق گزینههای خط فرمان، ممکن است اطلاعات تکمیلیِ بلوک پس از هر خط قرار گیرد. مقدار execution_count برای خطوط فاقد کد، - است. خطوط اجرانشده با ##### یا ===== مشخص میشوند؛ بسته به اینکه آیا به ترتیب از طریق مسیرهای غیراستثنایی قابل دسترسی هستند یا صرفاً از طریق مسیرهای استثنایی مانند مدیریتکنندههای استثنای (exception handlers) C++. با تعیین گزینهٔ -a، بلوکهای اجرانشده بسته به اینکه از طریق مسیرهای غیراستثنایی یا استثنایی در دسترس باشند، به ترتیب با $$$$$ یا %%%%% علامتگذاری میشوند. بلوکهای پایهای اجراشدهای که دارای عبارتی با execution_count صفر باشند، با نویسهٔ * پایان مییابند و با گزینهٔ -k با رنگ سرخابی (magenta) نمایش داده میشوند. این قابلیت در Ada پشتیبانی نمیشود.
توجه داشته باشید که GCC میتواند بدنهٔ توابعی را که مورد نیاز نیستند کاملاً حذف کند -- برای نمونه اگر در همهجا درونخطی (inlined) شده باشند. اینگونه توابع با - مشخص میشوند که میتواند گمراهکننده باشد. از گزینههای -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 (اساساً یک گراف جریان از برنامه) را ایجاد کند و همچنین کد اضافهای را در فایلهای شیء (object files) برای تولید دادههای تحلیل کارایی (profiling) اضافیِ مورد نیاز gcov بگنجاند. این فایلهای اضافی در دایرکتوریای قرار میگیرند که فایل شیء در آن واقع شده است.
اجرای برنامه باعث ایجاد خروجی تحلیل کارایی خواهد شد. به ازای هر فایل منبع که با -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، تعداد انشعابها و فراخوانیهای
آن بلوک نمایش داده خواهد شد.
به دلیل روشی که GCC برای ابزارگذاری (instrumentation) فراخوانیها استفاده میکند، ممکن است تعداد فراخوانی پس از خطی بدون هیچ بلوک مجزایی نشان داده شود. همانطور که مشاهده میکنید، خط 33 حاوی یک بلوک پایه است که اجرا نشده است.
هنگامی که از گزینهٔ -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:}
برای هر تابع، خطی چاپ میشود که نشان میدهد تابع چند بار فراخوانی شده، چند بار بازگشته و چه درصدی از بلوکهای تابع اجرا شدهاند.
برای هر بلوک پایه، خطی پس از آخرین خط بلوک پایه چاپ میشود که انشعاب یا فراخوانی پایاندهندهٔ آن بلوک پایه را توصیف میکند. در صورتی که چندین بلوک پایه در یک خط مبدأ پایان یابند، ممکن است چندین انشعاب و فراخوانی برای آن خط فهرست شوند. در این حالت، به هر یک از انشعابها و فراخوانیها یک شماره اختصاص داده میشود. راه سادهای برای نگاشت مجدد این انشعابها و فراخوانیها به سازههای کد مبدأ وجود ندارد. با این حال، به طور کلی، کمشمارهترین انشعاب یا فراخوانی با چپترین سازه در خط کد مبدأ مطابقت دارد.
برای یک انشعاب، اگر حداقل یک بار اجرا شده باشد، درصدی چاپ خواهد شد که نشاندهندهٔ تعداد دفعات پیموده شدن (taken) انشعاب تقسیم بر تعداد دفعات اجرای انشعاب است. در غیر این صورت، پیام "never executed" چاپ میشود.
برای یک فراخوانی، اگر حداقل یک بار اجرا شده باشد، درصدی چاپ خواهد شد که نشاندهندهٔ تعداد دفعات بازگشت فراخوانی تقسیم بر تعداد دفعات اجرای فراخوانی است. این مقدار معمولاً 100% خواهد بود، اما ممکن است برای توابعی که "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:}
برای هر شرط، تعداد برآمدهای پیمودهشده و کل برآمدها چاپ میشود، و در صورتی که برآمدهای پوششدادهنشده وجود داشته باشند، خطی برای هر شرط چاپ میشود که برآمد پوششدادهنشده را در پرانتز نشان میدهد. شرطها بر اساس نمایهٔ (اندیس) خود شناسایی میشوند -- نمایهٔ 0 چپترین شرط است. در "a || (b && c)"، نماد a شرط 0، b شرط 1، و c شرط 2 است.
یک برآمد در صورتی پوششدادهشده در نظر گرفته میشود که تأثیر مستقلی بر تصمیمگیری داشته باشد، که به عنوان masking MC/DC (پوشش شرط/تصمیم اصلاحشده) نیز شناخته میشود. در این مثال، تصمیم به 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 اجرا شود، تعداد دفعات اجرای هر سطر در کد منبع به نتایج اجرا(های) قبلی افزوده خواهد شد. این قابلیت از چندین جهت میتواند سودمند باشد. برای نمونه، میتواند برای تجمیع دادهها در طول چندین بار اجرای برنامه به عنوان بخشی از یک مجموعهآزمون اعتبارسنجی استفاده شود، یا اطلاعات دقیقتر و درازمدتتری را در طول شمار زیادی از اجراهای برنامه ارائه دهد.
دادههای درون فایلهای .gcda بلافاصله پیش از خروج برنامه ذخیره میشوند. برای هر فایل منبع که با -fprofile-arcs کامپایل شده باشد، کد ارزیابی کارایی (profiling) ابتدا تلاش میکند تا یک فایل .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 کنترل کنید. توجه داشته باشید که تطبیق و گزارشدهی مستقل هستند، بنابراین میتوانید بر اساس نامهای mangled تطبیق را انجام دهید در حالی که نامهای demangled را چاپ میکنید، و برعکس. برای گزارشگیری از نمونهسازی (instantiation) نوع "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"، در حالی که سازندهٔ (constructor) "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 یعنی
--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) میتوانند باعث ایجاد شمارشهای غیرمنتظره برای خطوط شوند. شمارش خطوط برای کد منبع تابع درونخطیپذیر نمایش داده میشود، اما آنچه نشان داده میشود به این بستگی دارد که تابع در کجا درونخطی (inline) شده باشد، یا اینکه اصلاً درونخطی نشده باشد.
اگر تابع درونخطی نشود، کامپایلر باید یک نسخهٔ برونخط (out-of-line) از تابع را در هر فایل شیء (object file) که به آن نیاز دارد صادر کند. اگر هر دو فایل fileA.o و fileB.o شامل بدنهٔ برونخط یک تابع درونخطیپذیر خاص باشند، هر دو نیز شامل شمارش پوشش کد برای آن تابع خواهند بود. هنگامی که fileA.o و fileB.o به یکدیگر پیوند داده میشوند، پیونددهنده در بسیاری از سیستمها یکی از آن بدنههای برونخط را برای تمام فراخوانیهای آن تابع انتخاب کرده و دیگری را حذف یا نادیده میگیرد. متأسفانه، شمارندههای پوشش مربوط به بدنهٔ استفادهنشدهٔ تابع حذف نخواهند شد. از این رو هنگام ابزار دقیقسازی، به جز یکی، تمام موارد استفاده از آن تابع شمارش صفر را نشان خواهند داد.
اگر تابع در چندین مکان درونخطی شود، ساختار بلوک در هر مکان ممکن است یکسان نباشد. برای نمونه، ممکن است در برخی موارد یک شرط در زمان کامپایل قابل محاسبه باشد. از آنجا که پوشش تمام موارد استفاده از تابع درونخطی برای همان خطوط منبع یکسان نمایش داده میشود، خود شمارش خطوط ممکن است متناقض به نظر برسد.
برنامههای طولانیمدت میتوانند از امکانات "__gcov_reset" و "__gcov_dump" برای محدود کردن جمعآوری دادههای پروفایل به بخشهای مدنظر برنامه استفاده کنند. فراخوانی "__gcov_reset(void)" تمام شمارندههای پروفایل زمان اجرا را صفر میکند، و فراخوانی "__gcov_dump(void)" موجب تخلیه اطلاعات پروفایل جمعآوریشده تا آن نقطه در فایلهای خروجی .gcda میشود. برنامههای مجهز شده به ابزار دقیق، از یک تخریبکنندهٔ ایستا (static destructor) با اولویت ۹۹ برای فراخوانی تابع "__gcov_dump" استفاده میکنند. بدین ترتیب "__gcov_dump" پس از تمام تخریبکنندههای ایستای تعریفشده توسط کاربر و همچنین گردانندههای ثبتشده با "atexit" اجرا میشود.
اگر یک فایل اجرایی شیء اشتراکی پویا را از طریق سازوکار dlopen بارگذاری کند، برای تخلیهٔ تمام دادههای پروفایل به گزینهٔ -Wl,--dynamic-list-data نیاز است.
کتابخانهٔ زمان اجرای پروفایلگیری خطاهای مختلف مربوط به دستکاری و ذخیرهسازی دادههای پروفایل را گزارش میدهد. خطاها در خروجی خطای استاندارد یا در صورت تنظیم متغیر محیطی، در فایل GCOV_ERROR_FILE چاپ میشوند. به منظور پایان دادن فوری به برنامه پس از رخ دادن خطا، متغیر محیطی GCOV_EXIT_AT_ERROR را تنظیم کنید. این کار به کاربران کمک میکند تا تداخل دادههای پروفایل را که منجر به ایجاد نمایهای گمراهکننده میشود، پیدا کنند.
همچنین ببینید (SEE ALSO)
gpl(7)، gfdl(7)، fsf-funding(7)، gcc(1) و مدخل Info برای gcc..SH "کپیرایت و تکثیر (COPYRIGHT)" Copyright (c) 1996-2025 Free Software Foundation, Inc.
مجوز کپی، توزیع و/یا تغییر این سند تحت شرایط «مجوز مستندات آزاد GNU»، نسخهٔ 1.3 یا هر نسخهٔ متأخرتر منتشرشده توسط بنیاد نرمافزارهای آزاد اعطا میشود؛ با بخشهای تغییرناپذیرِ "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.
| 2025-08-08 | gcc-15.2.0 |