| 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 یک ابزار پوشش آزمون (test coverage) است. از آن در کنار GCC برای تجزیهوتحلیل برنامههایتان استفاده کنید تا به ایجاد کدهای بهینهتر و سریعتر و همچنین کشف بخشهای آزمایشنشدهٔ برنامه کمک نمایید. میتوانید از gcov بهعنوان یک ابزار پروفایلسازی (profiling) برای یافتن بخشهایی که تلاشهای بهینهسازی بیشترین تأثیر را روی کد دارند استفاده کنید. همچنین میتوانید gcov را همراه با ابزار پروفایلسازی دیگر، یعنی gprof، برای ارزیابی اینکه کدام بخشهای کد بیشترین زمان پردازش را مصرف میکنند به کار ببرید.
ابزارهای پروفایلسازی به شما در تحلیل عملکرد کد کمک میکنند. با استفاده از یک ابزار تحلیل عملکرد مانند gcov یا gprof، میتوانید برخی از آمارهای پایه عملکرد را به دست آورید، از قبیل:
- هر خط از کد چند بار اجرا میشود
- کدام خطوط از کد واقعاً اجرا شدهاند
- هر بخش از کد چه مقدار زمان محاسباتی مصرف میکند
هنگامی که این اطلاعات را دربارهٔ نحوهٔ اجرای کد کامپایلشده به دست آوردید، میتوانید به بررسی هر ماژول بپردازید تا مشخص شود کدام ماژولها باید بهینهسازی شوند. gcov به شما کمک میکند تا بخشهای نیازمند بهینهسازی را شناسایی کنید.
توسعهدهندگان نرمافزار همچنین از آزمون پوشش در هماهنگی با مجموعههای آزمون (testsuites) استفاده میکنند تا مطمئن شوند نرمافزار واقعاً برای انتشار به اندازه کافی خوب است. مجموعههای آزمون میتوانند بررسی کنند که برنامه طبق انتظار کار میکند؛ ابزار پوشش کد نیز بررسی میکند چه مقدار از برنامه توسط مجموعه آزمون پوشش داده شده است. سپس توسعهدهندگان میتوانند تشخیص دهند که چه مواردی از آزمون (test cases) باید به مجموعههای آزمون اضافه شود تا هم آزمون دقیقتری انجام گیرد و هم محصول نهایی بهتری تولید شود.
اگر قصد استفاده از 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 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) در آن کامپایل شده است
- 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 شامل پارامترهای قالب (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: در صورتی که شاخه از نوع عبور مستقیم (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
- استفاده از رنگها برای خطوط کدی که پوشش صفر دارند. از رنگ قرمز برای خطوط غیراستثنایی (non-exceptional) و از فیروزهای برای خطوط استثنایی استفاده میشود. همین رنگها برای بلوکهای پایه همراه با گزینهٔ -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، یا نام مسیر شیء (object). فایلهای دادهٔ .gcno و .gcda با استفاده از این گزینه جستجو میشوند. اگر یک دایرکتوری مشخص شود، فایلهای داده در آن دایرکتوری قرار داشته و بر اساس نام فایل ورودی، بدون پسوند آن، نامگذاری میشوند. اگر یک فایل در اینجا مشخص شود، فایلهای داده بر اساس نام آن فایل، بدون پسوند آن، نامگذاری خواهند شد.
- -p
- --preserve-paths
- حفظ اطلاعات کامل مسیر در نام فایلهای .gcov تولیدشده. بدون این گزینه، فقط بخش نام فایل استفاده میشود. با این گزینه، تمام دایرکتوریها استفاده میشوند، به طوری که نویسههای / به نویسههای # تبدیل میشوند، بخشهای دایرکتوری . حذف شده و بخشهای غیرقابلحذف .. به ^ تغییر نام مییابند. این مورد زمانی مفید است که فایلهای منبع در چندین دایرکتوری مختلف قرار داشته باشند.
- -q
- --use-hotness-colors
- تولید خروجی رنگی شبیه به perf برای خطوط پرکاربرد (hot lines). راهنمای مقیاس رنگ در ابتدای فایل خروجی چاپ میشود.
- -r
- --relative-only
- تنها اطلاعات مربوط به فایلهای منبع با نام مسیر نسبی (پس از حذف پیشوند منبع) را خروجی میدهد. مسیرهای مطلق معمولاً فایلهای سرآیند سیستم هستند و پوشش هر گونه توابع درونخطی (inline) در آنها معمولاً اهمیتی ندارد.
- -s directory
- --source-prefix directory
- پیشوندی برای نام فایلهای منبع جهت حذف شدن هنگام تولید فایلهای خروجی پوشش. این گزینه هنگام ساخت (build) در یک دایرکتوری جداگانه مفید است، یعنی زمانی که نمیخواهید مسیر دایرکتوری منبع در تعیین نام فایلهای خروجی لحاظ شود. توجه داشته باشید که این تشخیص پیشوند پیش از بررسی این که آیا فایل منبع مطلق است یا نه اعمال میشود.
- -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 را با چندین فایل ورودی فراخوانی کنید، مشارکتهای هر فایل ورودی با هم جمع میشوند. معمولاً آن را با همان فهرست فایلهایی فراخوانی میکنید که در پیوند (link) نهایی فایل اجرایی خود به کار بردهاید..PP فایلهای .gcov شامل فیلدهایی جدا شده با : به همراه کد منبع برنامه هستند. قالب به این صورت است:
<execution_count>:<line_number>:<source line text>
در صورت درخواست از طریق گزینهٔ خط فرمان، ممکن است اطلاعات بلوک اضافی پس از هر خط بیاید. مقدار execution_count برای خطوطی که فاقد کد هستند - است. خطوط اجرا نشده بسته به اینکه آیا به ترتیب از طریق مسیرهای غیراستثنایی یا فقط مسیرهای استثنایی مانند گردانندههای استثنای C++ قابل دسترسی هستند، با ##### یا ===== علامتگذاری میشوند. با تعیین گزینهٔ -a، بلوکهای اجرا نشده بسته به اینکه آیا یک بلوک پایه از طریق مسیرهای غیراستثنایی یا استثنایی قابل دسترسی است، با $$$$$ یا %%%%% مشخص میشوند. بلوکهای پایهٔ اجرا شدهای که عبارتی با execution_count برابر صفر دارند، با نویسهٔ * خاتمه مییابند و با گزینهٔ -k با رنگ ارغوانی (magenta) نمایش داده میشوند. این قابلیت در Ada پشتیبانی نمیشود.
توجه داشته باشید که GCC میتواند بدنهٔ توابعی را که مورد نیاز نیستند کاملاً حذف کند -- برای نمونه اگر در همهجا بهصورت درونخطی (inlined) قرار گرفته باشند. چنین توابعی با - علامتگذاری میشوند که میتواند گیجکننده باشد. از گزینههای -fkeep-inline-functions و -fkeep-static-functions برای حفظ این توابع و توانمندسازی gcov جهت نمایش صحیح execution_count آنها استفاده کنید.
برخی از خطوط اطلاعاتی در ابتدا، دارای line_number با مقدار صفر هستند. این خطوط مقدماتی به شکل زیر هستند:
-:0:<tag>:<value>
با پیشرفت توسعهٔ gcov، ترتیب و تعداد این خطوط مقدماتی افزایش خواهد یافت --- به بدون تغییر ماندن آنها تکیه نکنید. از tag برای یافتن یک خط مقدماتی خاص استفاده کنید.
اطلاعات تکمیلی بلوک به این شکل است:
<tag> <information>
بخش information برای انسان خوانا است، اما بهگونهای طراحی شده که برای تجزیه توسط ماشین (machine parsing) نیز به اندازهٔ کافی ساده باشد.
هنگام چاپ درصدها، 0% و 100% تنها زمانی چاپ میشوند که مقادیر به ترتیب دقیقاً 0% و 100% باشند. سایر مقادیری که بهطور معمول به 0% یا 100% گرد میشوند، در عوض بهعنوان نزدیکترین مقدار غیرمرزی چاپ میشوند.
هنگام استفاده از gcov، ابتدا باید برنامهٔ خود را با گزینهٔ ویژهٔ GCC یعنی --coverage کامپایل کنید. این کار به کامپایلر اعلام میکند تا اطلاعات اضافی مورد نیاز gcov (اساساً یک گراف جریان از برنامه) را تولید کند و همچنین کدهای تکمیلی را برای تولید اطلاعات پروفایلینگ بیشتری که gcov به آنها نیاز دارد، در فایلهای شیء (object files) قرار دهد. این فایلهای اضافی در دایرکتوریای که فایل شیء در آن قرار دارد، ذخیره میشوند.
اجرای برنامه باعث ایجاد خروجی پروفایل خواهد شد. به ازای هر فایل منبع کامپایل شده با -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 فراخوانیها را مجهز (instrument) میکند، تعداد فراخوانی ممکن است پس از خطی بدون هیچ بلوک مجزایی نشان داده شود. همانطور که مشاهده میکنید، خط 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:}
برای هر تابع، خطی چاپ میشود که نشان میدهد تابع چند بار فراخوانی شده، چند بار بازگشته، و چند درصد از بلوکهای تابع اجرا شدهاند.
برای هر بلوک پایه، خطی پس از آخرین خط بلوک پایه چاپ میشود که انشعاب یا فراخوانی خاتمهدهندهٔ آن بلوک پایه را توصیف میکند. در صورتی که چندین بلوک پایه در یک خط پایان یابند، ممکن است چندین انشعاب و فراخوانی برای آن خط مبدأ فهرست شوند. در این حالت، به هر یک از انشعابها و فراخوانیها یک شماره داده میشود. روش سادهای برای نگاشت این انشعابها و فراخوانیها به ساختارهای کد مبدأ وجود ندارد. با این حال، به طور کلی، انشعاب یا فراخوانی با کمترین شماره با چپترین ساختار در خط مبدأ متناظر خواهد بود.
برای یک انشعاب، اگر حداقل یک بار اجرا شده باشد، درصدی چاپ خواهد شد که نشاندهندهٔ تعداد دفعات طیشدن انشعاب تقسیم بر تعداد دفعات اجرای آن است. در غیر این صورت، پیام "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 است.
یک برآمد زمانی پوششدادهشده محسوب میشود که اثر مستقلی روی تصمیم بگذارد، که با نام ماسککردن 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". این حالت برای کاربران انسانی در نظر گرفته شده و برای درک اینکه چه کدهایی در طول آزمون یا با ورودیهای دادهشده اجرا شدهاند، مناسب است. این خروجی بسیار پرجزئیات است، و برای تمرکز بر توابع خاص میتوان آن را با فیلترهای --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، کد پروفایلسازی ابتدا تلاش میکند یک فایل .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)، روی نامهای درهمریخته تطبیق انجام دهید، و برعکس. برای گزارشدهی دربارهٔ نمونهسازی "int" از "Foo" با تطبیق روی نامهای درهمریخته و سادهشده:
$ 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 یعنی
--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) از تابع را در هر فایل شیئی که به آن نیاز دارد تولید کند. اگر fileA.o و fileB.o هر دو حاوی بدنهٔ برونخطیِ یک تابع درونخطیپذیر خاص باشند، هر دوی آنها شامل شمارشهای پوشش برای آن تابع نیز خواهند بود. هنگامی که fileA.o و fileB.o با یکدیگر پیوند داده میشوند، پیونددهنده در بسیاری از سیستمها، یکی از آن بدنههای برونخطی را برای تمام فراخوانیهای آن تابع انتخاب کرده و دیگری را حذف یا نادیده میگیرد. متأسفانه، پیونددهنده شمارندههای پوشش را برای بدنهٔ استفادهنشدهٔ تابع حذف نمیکند. از این رو در هنگام مجهزسازی کد، تمام کاربردهای آن تابع به جز یکی، شمارش صفر را نشان خواهند داد.
اگر تابع در چندین مکان درونخطی شود، ساختار بلوک در هر مکان ممکن است یکسان نباشد. برای نمونه، ممکن است یک شرط در برخی موارد در زمان کامپایل قابل محاسبه باشد. از آنجا که پوشش تمام استفادههای تابع درونخطی برای همان خطوط منبع یکسان نمایش داده خواهد شد، شمارش خطوط ممکن است به خودی خود متناقض به نظر برسد.
برنامههای با زمان اجرای طولانی میتوانند از امکانات "__gcov_reset" و "__gcov_dump" استفاده کنند تا جمعآوری نمایه را به بخش مورد نظر برنامه محدود نمایند. فراخوانی "__gcov_reset(void)" تمام شمارندههای نمایهٔ زمان اجرا را صفر میکند، و فراخوانی "__gcov_dump(void)" باعث میشود اطلاعات نمایهٔ جمعآوریشده در آن نقطه در فایلهای خروجی .gcda ذخیره شود. برنامههای مجهزشده از یک تخریبکنندهٔ ایستا (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 Free Documentation License)، نسخهٔ ۱.۳ یا هر نسخهٔ متأخر دیگری که توسط بنیاد نرمافزار آزاد (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.
| 2025-08-08 | gcc-15.2.0 |