In this section:
Introduction
The asminfer tool applies additional inference modules to the static data file (.pail) that has been merged with dynamic data. An inference module provides additional analysis of the coverage information.
In this section, we assume that you've already installed Parasoft ASMTools and that they are on your system path. Refer to Parasoft ASMTools for information about the full tool chain, including installation and requirements.
Basic Usage
Run asminfer
and specify the static data file and inference module you want to apply:
$ asminfer --input-file /path/to/static-data-file.pail --inference-module <module>
Use the --input-file
flag ( or -i
) to specify the static data file. This file is created by instrumenting objects, archives, and executables using the Asminst and merged with a dynamic data file (.padd) with the Asmcovbuf to output coverage.
Use the --inference-module
flag (or -m
) to specify the name of the inference module you want to apply. This flag is optional. If not included or if a module name is not specified, all available modules will be be invoked.
You can run asminfer
multiple times on the same .pail file.
Examples
$ asminfer --input-file C:\path\to\static\data\example.pail --inference-module switch_tracking
$ asminfer --input-file /path/to/static/data/example.pail --inference-module switch_tracking
Options
--blacklist <path-to-file> -b <path-to-file> --excluded-function-file <path-to-file> | Specifies a file that contains a list of functions to be excluded from instrumentation in the current translation unit. You can use this option multiple times to specify several lists. |
---|---|
--help -h | Prints the descriptions of the options for asminfer |
--inference-module=<module name> -m | Specifies the name of the inference module to be applied to the specified static data file |
--input-file=<path/to/static/data/file.pail> -i | Specifies the static data to be processed by the specified inference module |
--list-modules -l | Prints available inference modules. |
--output-file <path-and-name> -o <path-and-name> | Specifies the name/location of the output file. |
--version -v | Print out the version header of the too.l |
--whitelist <path-to-file> -w <path-to-file> --include-function-file <path-to-file> | Specifies a file that contains a list of functions to be included for instrumentation in the current translation unit. You can use this option multiple times to specify several lists. |
Known Issues
Switch tracking omits switch cases that have been removed by the compiler during optimization.
Some compiler optimizations, such as -Ospace/-Osize
from the ppc_ghs_2017_1 compiler, remove cases from a switch to save space. This change is reflected in the interleaved output of the compiler by not associating the case with any assembly code.
Since the compiler has optimized the case away, there is no way to identify that the case was taken or not taken. It will not show up in the switch statistics because of this.
The following C example demonstrates the issue:
int foo(int a) { switch(a) { case 1: a++; break; case 2: a--; break; case 3: a = 0; break; case 4: a += 2; break; case 5: a -= 2; break; case 6: a = 1000; break; case 7: a = 50; break; case 8: a = a * a; break; default: a += a; } return a; }
The following output shows the results with interleaving when using the -Ospace
/-Osize
optimization for the ppc_ghs_2017_1
compiler:
#Version: C-POWERPC 2017.1.4 RELEASE VERSION #Release: Compiler v2017.1.4 #Revision Date: Sun Apr 9 19:41:34 2017 #Release Date: Sun Apr 9 17:00:05 2017 .text .align 2 .global simpleSwitch7_50 simpleSwitch7_50: #1: int simpleSwitch7_50(int a) #2: { #3: switch(a) addi r12, r3, -2 cmplwi r12, 6 bgt .L13 slwi r12, r12, 1 addis r12, r12, %hiadj(.L95) lhzu r11, %lo(.L95)(r12) add r12, r12, r11 mtctr r12 bctr .L95: .short .L6-.L95-0 .short .L7-.L95-2 .short .L8-.L95-4 .short .L9-.L95-6 .short .L10-.L95-8 .short .L11-.L95-10 .short .L12-.L95-12 .short 0-0-0 .L6: #4: { #5: case 1: #6: a++; #7: break; #8: case 2: #9: a--; subi r3, r3, 1 blr #10: break; #11: case 3: .L7: #12: a = 0; li r3, 0 blr #13: break; #14: case 4: .L8: #15: a += 2; addi r3, r3, 2 blr #16: break; #17: case 5: .L9: #18: a -= 2; subi r3, r3, 2 blr #19: break; #20: case 6: .L10: #21: a = 1000; li r3, 1000 blr #22: break; #23: case 7: .L11: #24: a = 50; li r3, 50 blr #25: break; #26: case 8: .L12: #27: a = a * a; mullw r3, r3, r3 blr #28: break; #29: default: .L13: #30: a += a; slwi r3, r3, 1 #31: } #32: return a; blr .type simpleSwitch7_50,@function .size simpleSwitch7_50,$-simpleSwitch7_50 .align 2 #33: }
The assembly performs a subtraction in lines 30-38. This is because case 1
, which performs addition, has been optimized out. The compiler has determined that a+=a
in the default
case yields the same behavior as a++
when a == 1
. Thus, when a == 1
, the default
case is taken because they are equivalent. This is a function of the compiler, not asminfer.
There is no generated code available for case 1
, so it cannot have independent coverage because it can no longer be distinguished from the default
case in this scenario.
Because the compiler optmized out case 1
, there is no code associated with case 1
. Asminfer will correctly ignore case 1
because there is no actual code associated with it. This is expected known behavior with asminfer.
If case 1
contained more code, e.g., if source coverage was applied, then the compiler would have deemed the case to be different from the default and thus would not have been optimized out. The following table describes the behavior:
#3: switch(a) ---> ---------------------------------------------------------- Switch statement overview: ---------------------------------------------------------- Name: Code was: Branch was: ASM equivalent: default: Covered Taken Label: .L13 case 2: Covered Taken Label: .L6 case 3: Covered Taken Label: .L7 case 4: Covered Taken Label: .L8 case 5: Not Covered Not Taken Label: .L9 case 6: Not Covered Not Taken Label: .L10 case 7: Covered Taken Label: .L11 case 8: Not Covered Not Taken Label: .L12 ----------------------------------------------------------
The compiler was able to save space by optimizing out paths of execution. The tradeoff, however, was that tracking the code much more difficult. The only way to actually verify the results with this level of optimization enabled is to manually analyze the assembly code line by line to determine the code's function.
When using other optimization styles. such as -Ospeed
, the compiler is free to optimize cases away, as well. Asminfer will report the data as it sees it.