[llvm-dev] Using source-based code coverage on baremetal

Martin J. O'Riordan via llvm-dev llvm-dev at lists.llvm.org
Mon Sep 11 02:37:40 PDT 2017

I think that this proposal would be very useful, and I will describe our experiences of trying to do this for our embedded bare-metal target.

Recently we implemented support for just the '-fprofile-instr-generate' option and the 'compiler-rt/lib/profile' sources, and added the following to our LD scripts:

      /* Append the LLVM profiling sections */
      . = ALIGN(4);
      PROVIDE(__start___llvm_prf_cnts = .);
      PROVIDE(__stop___llvm_prf_cnts = .);

      . = ALIGN(4);
      PROVIDE(__start___llvm_prf_data = .);
      PROVIDE(__stop___llvm_prf_data = .);

      . = ALIGN(4);
      PROVIDE(__start___llvm_prf_names = .);
      PROVIDE(__stop___llvm_prf_names = .);

      . = ALIGN(4);
      PROVIDE(__start___llvm_prf_vnds = .);
      PROVIDE(__stop___llvm_prf_vnds = .);

This removed the need for the '.ctors' model for registering functions (which also reduces the run-time cost) and enabled our target to use the model described in 'InstrProfilingPlatformLinux.cpp' instead of 'InstrProfilingPlatformOther.cpp', adding our triple to 'lib/Transforms/Instrumentation/InstrProfiling.cpp'.

We use Newlib for our LibC so we have a reasonably complete ISO C library, but we do not have a file-system so the FILE based I/O cannot work.  And as there is no environment, dependence on environment variables is also meaningless.  I won't even bother discussing memory-mapped files ;-)

We also have to ensure that the basic instrumentation initialisation process normally handled by 'RegistrationRuntime Registration' is performed before the program is allowed execute, and that the data is subsequently dumped (taken off-chip) after execution.  This is done with a bit of smoke and mirrors as many programs in the embedded environment to not have support for running the '.ctors' functions before and the 'atexit' functions after execution (especially C programs).

But the Compiler-RT profile library also integrates the automatic merging and collation of data from multiple runs within the library implementation itself, and this is a really significant problem for base-metal system with no OS and no file-system.  It does this using "patterns" in the file name (derived from the environment), and the data collation performed by the system being profiled.

I think that to better facilitate bare-metal systems, this process of collating the results of multiple runs would be best provided by a separate stand-alone utility on the host system that would perform this logic offline rather than having it integrated online as it is currently defined.

Our implementation can now gather data for a single run ('default.profraw') but does not (yet) have the capability of collating the results from more than one profiling run.

We have not yet started supporting the other instrumentation such as coverage and ubsan, but hope to do so now that we have figured out how to do basic profiling for PGO.


-----Original Message-----
From: llvm-dev [mailto:llvm-dev-bounces at lists.llvm.org] On Behalf Of Jonathan Roelofs via llvm-dev
Sent: 06 September 2017 22:27
To: Friedman, Eli <efriedma at codeaurora.org>; Vedant Kumar <vsk at apple.com>; weimingz at codeaurora.org; llvm-dev <llvm-dev at lists.llvm.org>
Subject: Re: [llvm-dev] Using source-based code coverage on baremetal

On 9/5/17 7:55 PM, Friedman, Eli via llvm-dev wrote:

> Areas that required LLVM changes:
> 1. The copy of libclangrt_profile.a for the target.  Given that we 
> already were using builtins from compiler-rt, the primary changes 
> required are enabling the profile library and excluding a bunch of 
> files from the build (since baremetal doesn't have a filesystem, 
> system calls, etc.).  I'll look into posting patches when I have time, 
> but it might take me a little while for me to figure out how to 
> cleanly modify the build, and verify everything actually works on 
> trunk.  It looks like there's a CMake variable 
> COMPILER_RT_BAREMETAL_BUILD which is supposed to be turned on for this sort of environment?

Yes, that's exactly what that variable is for.

See also: clang/cmake/caches/BaremetalARM.cmake. I haven't taught this how to do the rest of the runtime bits (unwinder/libcxxabi/libcxx), but plan to at some point.

> 2. Changing the compiler and compiler-rt to use __start and __end 
> symbols to find the sections, rather than .init code.  This isn't 
> strictly necessary, but our linker supports __start and __end, and 
> this was easier than changing the baremetal image to handle a .init section.
> See needsRuntimeRegistrationOfSectionRange in 
> lib/Transforms/Instrumentation/InstrProfiling.cpp; we currently only 
> whitelist a few platforms.  Not sure what would be appropriate here; 
> maybe we could assume any *-none-* triple supports __start and __end 
> symbols?  Or maybe control it with a flag somehow? Or something else 
> I'm not thinking of?

A flag for this sounds great.


Jon Roelofs
jonathan at codesourcery.com
CodeSourcery / Mentor Embedded / Siemens _______________________________________________
LLVM Developers mailing list
llvm-dev at lists.llvm.org

More information about the llvm-dev mailing list