Evaluate the CppDepend metrics tool on Uefi firmware - shijunjing/edk2 GitHub Wiki

Evaluate the CppDepend metrics tool: https://www.cppdepend.com/

Collect build commands and generate report

Get your 14-day free CppDepend trial Today!

https://www.cppdepend.com/protected/CppDepend2020.1.zip

Use Build Monitor to collect MSVC toolchain's build commands with multi-thread enabled by default

C:\steven\edk2>C:\steven\Metrics\CppDepend\CppDepend2020.1\BuildMonitor64.exe -o OvmfPkgIa32X64.dsc.UsbKbDxe.VS2015x86.IA32.X64.build build -p OvmfPkg\OvmfPkgIa32X64.dsc -t VS2015x86 -a IA32 -a X64 -m MdeModulePkg\Bus\Usb\UsbKbDxe\UsbKbDxe.inf
  • Create new CppDepend project:

  • Set the CppDepend output dir:

  • Add build spec as OvmfPkgIa32X64.dsc.UsbKbDxe.VS2015x86.IA32.X64.build

  • Click "Run Full Analysis and Build Report"

Build Monitor Problem on MSVC toolchain with default multi-thread

  • Missing libs and files:

It looks that CppDepend collect all found files in outputdir\SourceFiles.zip. E.g. C:\steven\Metrics\CppDepend\Project\OvmfPkgIa32X64.dsc.UsbKbDxe.VS2015x86.IA32.X64\SourceFiles.zip

Below is the real libs used in the module UsbKbDxe, see it in C:\steven\edk2\Build\Ovmf3264\DEBUG_VS2015x86\X64\MdeModulePkg\Bus\Usb\UsbKbDxe\UsbKbDxe\OUTPUT\static_library_files.lst:

c:/steven/edk2/Build/Ovmf3264/DEBUG_VS2015x86/X64/MdePkg/Library/BaseLib/BaseLib/OUTPUT/BaseLib.lib
c:/steven/edk2/Build/Ovmf3264/DEBUG_VS2015x86/X64/MdePkg/Library/DxePcdLib/DxePcdLib/OUTPUT/DxePcdLib.lib
c:/steven/edk2/Build/Ovmf3264/DEBUG_VS2015x86/X64/MdePkg/Library/BaseMemoryLibRepStr/BaseMemoryLibRepStr/OUTPUT/BaseMemoryLibRepStr.lib
c:/steven/edk2/Build/Ovmf3264/DEBUG_VS2015x86/X64/MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib/OUTPUT/BaseDebugPrintErrorLevelLib.lib
c:/steven/edk2/Build/Ovmf3264/DEBUG_VS2015x86/X64/MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsicSev/OUTPUT/BaseIoLibIntrinsicSev.lib
c:/steven/edk2/Build/Ovmf3264/DEBUG_VS2015x86/X64/MdePkg/Library/BasePrintLib/BasePrintLib/OUTPUT/BasePrintLib.lib
c:/steven/edk2/Build/Ovmf3264/DEBUG_VS2015x86/X64/OvmfPkg/Library/PlatformDebugLibIoPort/PlatformDebugLibIoPort/OUTPUT/PlatformDebugLibIoPort.lib
c:/steven/edk2/Build/Ovmf3264/DEBUG_VS2015x86/X64/MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib/OUTPUT/UefiBootServicesTableLib.lib
c:/steven/edk2/Build/Ovmf3264/DEBUG_VS2015x86/X64/MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib/OUTPUT/UefiMemoryAllocationLib.lib
c:/steven/edk2/Build/Ovmf3264/DEBUG_VS2015x86/X64/MdePkg/Library/UefiDevicePathLibDevicePathProtocol/UefiDevicePathLibDevicePathProtocol/OUTPUT/UefiDevicePathLibDevicePathProtocol.lib
c:/steven/edk2/Build/Ovmf3264/DEBUG_VS2015x86/X64/MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib/OUTPUT/UefiRuntimeServicesTableLib.lib
c:/steven/edk2/Build/Ovmf3264/DEBUG_VS2015x86/X64/MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib/OUTPUT/UefiHiiServicesLib.lib
c:/steven/edk2/Build/Ovmf3264/DEBUG_VS2015x86/X64/MdePkg/Library/UefiLib/UefiLib/OUTPUT/UefiLib.lib
c:/steven/edk2/Build/Ovmf3264/DEBUG_VS2015x86/X64/MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint/OUTPUT/UefiDriverEntryPoint.lib
c:/steven/edk2/Build/Ovmf3264/DEBUG_VS2015x86/X64/MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib/OUTPUT/DxeReportStatusCodeLib.lib
c:/steven/edk2/Build/Ovmf3264/DEBUG_VS2015x86/X64/MdePkg/Library/UefiUsbLib/UefiUsbLib/OUTPUT/UefiUsbLib.lib
c:/steven/edk2/Build/Ovmf3264/DEBUG_VS2015x86/X64/MdeModulePkg/Library/UefiHiiLib/UefiHiiLib/OUTPUT/UefiHiiLib.lib
c:/steven/edk2/Build/Ovmf3264/DEBUG_VS2015x86/X64/MdeModulePkg/Bus/Usb/UsbKbDxe/UsbKbDxe/OUTPUT/UsbKbDxe.lib

Unzip SourceFiles.zip and show all CppDepend found lib folders:

C:\steven\Metrics\CppDepend\Project\OvmfPkgIa32X64.dsc.UsbKbDxe.VS2015x86.IA32.X64\SourceFiles>tree steven
Folder PATH listing for volume XPx64
Volume serial number is 280A-7EC6
C:\STEVEN\METRICS\CPPDEPEND\PROJECT\OVMFPKGIA32X64.DSC.USBKBDXE.VS2015X86.IA32.X64\SOURCEFILES\STEVEN
└───edk2
    ├───build
    │   └───ovmf3264
    │       └───debug_vs2015x86
    │           └───x64
    │               └───mdemodulepkg
    │                   └───bus
    │                       └───usb
    │                           └───usbkbdxe
    │                               └───usbkbdxe
    │                                   └───debug
    ├───mdemodulepkg
    │   ├───bus
    │   │   └───usb
    │   │       └───usbkbdxe
    │   ├───include
    │   │   └───library
    │   └───library
    │       ├───uefihiilib
    │       └───uefihiiserviceslib
    └───mdepkg
        ├───include
        │   └───library
        └───library
            ├───basedebugprinterrorlevellib
            ├───baseiolibintrinsic
            ├───baselib
            │   └───x64
            ├───basememorylibrepstr
            ├───baseprintlib
            ├───dxepcdlib
            ├───uefilib
            ├───uefimemoryallocationlib
            └───uefiusblib

After compare above library directories, we can see below 6 libraries are missing in CppDepend, total 6/18= 33% missing rate.

OvmfPkg/Library/PlatformDebugLibIoPort/PlatformDebugLibIoPort/OUTPUT/PlatformDebugLibIoPort.lib
MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib/OUTPUT/UefiBootServicesTableLib.lib
MdePkg/Library/UefiDevicePathLibDevicePathProtocol/UefiDevicePathLibDevicePathProtocol/OUTPUT/UefiDevicePathLibDevicePathProtocol.lib
MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib/OUTPUT/UefiRuntimeServicesTableLib.lib
MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint/OUTPUT/UefiDriverEntryPoint.lib
MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib/OUTPUT/DxeReportStatusCodeLib.lib

Use Build Monitor to collect MSVC toolchain's build commands with multi-thread disabled (single thread: -n 1)

  • Clean build the UsbKbDxe again with -n 1 option
C:\steven\edk2>C:\steven\Metrics\CppDepend\CppDepend2020.1\BuildMonitor64.exe build -p OvmfPkg\OvmfPkgIa32X64.dsc -t VS2015x86 -a IA32 -a X64 -m MdeModulePkg\Bus\Usb\UsbKbDxe\UsbKbDxe.inf -o OvmfPkgIa32X64.dsc.UsbKbDxe.VS2015x86.IA32.X64.p1.build -n 1
  • Create new CppDepend project: OvmfPkgIa32X64.dsc.UsbKbDxe.VS2015x86.IA32.X64.p1.
  1. Set Project Name as OvmfPkgIa32X64.dsc.UsbKbDxe.VS2015x86.IA32.X64.p1
  2. Set ProjectFile as C:\steven\Metrics\CppDepend\Project\OvmfPkgIa32X64.dsc.UsbKbDxe.VS2015x86.IA32.X64.p1.cdproj
  3. Set Output Directories as C:\steven\Metrics\CppDepend\Project\OvmfPkgIa32X64.dsc.UsbKbDxe.VS2015x86.IA32.X64.p1
  • Unzip SourceFiles.zip and check all CppDepend found lib folders again:
C:\steven\Metrics\CppDepend\Project\OvmfPkgIa32X64.dsc.UsbKbDxe.VS2015x86.IA32.X64.p1\SourceFiles>tree steven
Folder PATH listing for volume XPx64
Volume serial number is 280A-7EC6
C:\STEVEN\METRICS\CPPDEPEND\PROJECT\OVMFPKGIA32X64.DSC.USBKBDXE.VS2015X86.IA32.X64.P1\SOURCEFILES\STEVEN
└───edk2
    ├───build
    │   └───ovmf3264
    │       └───debug_vs2015x86
    │           └───x64
    │               └───mdemodulepkg
    │                   └───bus
    │                       └───usb
    │                           └───usbkbdxe
    │                               └───usbkbdxe
    │                                   └───debug
    ├───mdemodulepkg
    │   ├───bus
    │   │   └───usb
    │   │       └───usbkbdxe
    │   ├───include
    │   │   └───library
    │   └───library
    │       ├───dxereportstatuscodelib
    │       ├───uefihiilib
    │       └───uefihiiserviceslib
    ├───mdepkg
    │   ├───include
    │   │   └───library
    │   └───library
    │       ├───basedebugprinterrorlevellib
    │       ├───baseiolibintrinsic
    │       ├───baselib
    │       │   └───x64
    │       ├───basememorylibrepstr
    │       ├───baseprintlib
    │       ├───dxepcdlib
    │       ├───uefibootservicestablelib
    │       ├───uefidevicepathlibdevicepathprotocol
    │       ├───uefidriverentrypoint
    │       ├───uefilib
    │       ├───uefimemoryallocationlib
    │       ├───uefiruntimeservicestablelib
    │       └───uefiusblib
    └───ovmfpkg
        └───library
            └───platformdebuglibioport

OK, this time all the libraries are found by CppDepend!

  • See the usbkbdxe driver all libraries dependency graph here. More details usage: Dependency Graph

  • But CppDepend looks cannot completely convert the MSVC command to clang parser command. There are +3400 Clang Parsing Errors in the final result:

Use Build Monitor to collect file build commands with CLANGPDB toolchain (single thread: -n 1)

Use the BuildMonitor64.exe to clean build the UsbKbDxe module and OvmfPkgIa32X64 platform with CLANGPDB toolchain:

C:\steven\edk2>set CLANG_HOST_BIN=n 
C:\steven\edk2>set CLANG_BIN=C:\Program Files\LLVM\bin\
C:\steven\edk2>C:\steven\Metrics\CppDepend\CppDepend2020.1\BuildMonitor64.exe build -p OvmfPkg\OvmfPkgIa32X64.dsc -t CLANGPDB -a IA32 -a X64 -m MdeModulePkg\Bus\Usb\UsbKbDxe\UsbKbDxe.inf -o OvmfPkgIa32X64.dsc.UsbKbDxe.CLANGPDB.IA32.X64.p1.build -n 1
C:\steven\edk2>rmdir Build /s /q
C:\steven\edk2>C:\steven\Metrics\CppDepend\CppDepend2020.1\BuildMonitor64.exe build -p OvmfPkg\OvmfPkgIa32X64.dsc -t CLANGPDB -a IA32 -a X64 -o OvmfPkgIa32X64.dsc.CLANGPDB.IA32.X64.p1.build -n 1   
  • Create new CppDepend projects for the UsbKbDxe module and OvmfPkgIa32X64 platform. There are almost no Clang Parsing Error (+3400 --> only 7 in whole OVMF platform), the CLANGPDB clang build&link commands perfectly match the CppDepend, great!!

Comment Problems:

The tool report the comment percentage is 57%, which looks very high.

Dependency (reference) Query Example:

Method reference: Select methods that are using me directly:

from m in Methods where m.IsUsing ("edk2/UefiCpuPkg/CpuDxe/CpuMp.c/__Globals/GetGdtr(void*)")
select new { m, m.NbLinesOfCode }

Method reference: Select methods that are using me (directly or indirectly):

from m in Methods 
let depth0 = m.DepthOfIsUsing("edk2/UefiCpuPkg/CpuDxe/CpuMp.c/__Globals/GetGdtr(void*)")
where depth0  >= 0 orderby depth0
select new { m, depth0 }

Global Variable reference: Select Types that are using me directly:

from t in Types where t.IsUsing ("edk2/UefiCpuPkg/CpuDxe/CpuMp.c/__Globals/mMpServiceHandle")
select new { t, t.NbLinesOfCode }

Global Variable reference: Select methods that is assigning me (directly or indirectly):

from m in Methods 
let depth0 = m.DepthOfAssignField("edk2/UefiCpuPkg/CpuDxe/CpuMp.c/__Globals/mMpServiceHandle")
where depth0  >= 0 orderby depth0
select new { m, depth0 }

File reference: Select files that are using me directly:

from f in Files where f.IsUsing ("edk2/UefiCpuPkg/CpuDxe/CpuMp.c") select new { f, f.NbLinesOfCode }

File reference: Select methods that are using me (directly or indirectly):

from m in Methods where m.IsUsing ("edk2/UefiCpuPkg/CpuDxe/CpuMp.c")
select new { m, m.NbLinesOfCode }

See more reference query pictures here: https://github.com/shijunjing/WikiDoc/tree/master/CppDepend