[llvm-dev] Profiling data structure

Roger Pau Monné via llvm-dev llvm-dev at lists.llvm.org
Fri Oct 27 03:28:19 PDT 2017


On Thu, Oct 26, 2017 at 11:07:51AM -0700, Xinliang David Li wrote:
> On Thu, Oct 26, 2017 at 1:31 AM, Roger Pau Monné <roger.pau at citrix.com>
> wrote:
> 
> > On Wed, Oct 25, 2017 at 09:13:54AM -0700, Xinliang David Li wrote:
> > > On Wed, Oct 25, 2017 at 12:26 AM, Roger Pau Monné via llvm-dev <
> > > >  - The "Values" field in __llvm_profile_data always seems to be NULL.
> > > >    Is this expected? What/why could cause this?
> > > >
> > >
> > > This is for value profiling. For now there are only two kinds:  indirect
> > > call targets and memcpy/memset size. If the function body does not have
> > any
> > > value sites, the field will be null.
> >
> > You will have to bear with me because my knowledge of compiler
> > internals is very limited. What is exactly a "value site"?
> >
> >
> It refers to a location in a function where the compiler inserts the value
> profiling hook.
> 
> 
> 
> > Can you give me some code examples that trigger this in C?
> >
> 
> 
> typedef void (*FP)(void);
> 
> void test (FP fp) {
> 
>      fp();        /* a value site */
> }
> 
> 
> There are two ways to turn on value profiling:
> 
> 1) using instrumentation for PGO (we call it IR-PGO):
> 
>    -fprofile-generate
> 
> 
> 2) using Front-end based instrumentation which is used for coverage testing:
> 
>    -fprofile-instr-generate -mllvm -enable-value-profiling=true

I'm currently using -fprofile-instr-generate -fcoverage-mapping which
are the options specified in [0]. ATM I'm only interested in getting
coverage data.

I've created the following simple example:

static void foo(void)
{
  int foo = 1;
}

static void bar(void)
{
  int bar = 1;
}

static void exec(void (*fp)(void))
{
  fp();
}

int main(int argc, char **argv)
{
  int count = 0;

  while ( count++ < 10000 )
    exec(rand() % 2 ? foo : bar);

  return 0;
}

Then I've used my custom made runtime and checked that both Values and
NumValueSites inside of __llvm_profile_data are still NULL.

I've also dumped the coverage data using my own runtime (which ignores
Values and NumValueSites), and got the following profile, which looks
right:

     |static void foo(void)
4.95k|{
4.95k|  int foo = 1;
4.95k|}
     |
     |static void bar(void)
5.04k|{
5.04k|  int bar = 1;
5.04k|}
     |
     |static void exec(void (*fp)(void))
10.0k|{
10.0k|  fp();
10.0k|}
     |
     |int main(int argc, char **argv)
    1|{
    1|  int count = 0;
    1|
10.0k|  while ( count++ < 10000 )
10.0k|    exec(rand() % 2 ? foo : bar);
    1|
    1|  return 0;
    1|}

So can Values and NumValueSites be safely ignored in order to obtain
the coverage data?

> >
> > > >
> > > >  - Since what I'm coding is a decoupled replacement for the profiling
> > > >    runtime inside of compiler_rt, is there anyway that at compile or
> > > >    run time I can fetch the version of the profiling data?
> > > >
> > >
> > >  At compile time, it is the macro: INST_PROF_RAW_VERSION. At runtime, it
> > is
> > > the second field of the raw profile header.
> >
> > I'm not able to use INST_PROF_RAW_VERSION at compile time. Are you
> > sure this is exported? If I do:
> >
> > cc -fprofile-instr-generate -fcoverage-mapping -dM -E - < /dev/null
> >
> >
> Ok.  The macro is defined for building the compiler itself, but not passed
> down to the user program when compiling it.
> 
> If you use IR-PGO (turned on with -fprofile-generate), the information is
> stored in a symbol in rodata: __llvm_profile_raw_version -- the least
> significant 32bits has the value of the raw version. Unfortunately, the
> front-end based instrumentation currently does not emit such a symbol.

That's right, __llvm_profile_raw_version cannot be used in my case
because it's exported by the runtime, and here I'm not using the
compiler_rt runtime at all.

Would it be possible to export this as a compile time define when
-fprofile-instr-generate -fcoverage-mapping is used?

Does that sound sensible?

> > I don't see INST_PROF_RAW_VERSION neither any similar defines.
> >
> > >    I'm mostly worried that at some point llvm will bump the version
> > > >    and change the layout, and then I will have to update my runtime
> > > >    accordingly, but without llvm reporting the version used by the
> > > >    compiler it's going to be very hard to keep backwards
> > > >    compatibility or to detect version bumps.
> > > >
> > > >
> > > yes, the raw profile format can change anytime. We only try to keep
> > > backward compatibility for indexed format.
> > >
> > > At runtime with in-process profile merging, if the source raw profile
> > > data's format version is different from the current runtime version, an
> > > error will be emitted.
> >
> > Keep in mind this is a kernel, so the source is compiled with
> > "-fprofile-instr-generate -fcoverage-mapping", but the profiling
> > runtime in compiler_rt is not linked against the kernel.
> >
> > I would like to have a reliable way that I could use to detect version
> > bumps in the internal coverage data, so that I can implement the
> > required changes in my in-kernel coverage code.
> >
> > I have a series ready for Xen in order to implement this, I will send
> > the patch with the in-kernel profiling implementation to this list for
> > review.
> >
> 
> 
> The right way for this is to define __llvm_profile_raw_version variable
> with FE instrumentation as is done by IR-PGO.   I have cc'ed Vedant who may
> help with this.

Wouldn't it be better to export an internal compiler define rather
than creating a symbol with the profile version?

Thanks, Roger.

[0] https://clang.llvm.org/docs/SourceBasedCodeCoverage.html


More information about the llvm-dev mailing list