[llvm-commits] [llvm] r80712 - in /llvm/trunk: include/llvm/Analysis/ProfileInfoTypes.h lib/Transforms/Instrumentation/CMakeLists.txt lib/Transforms/Instrumentation/OptimalEdgeProfiling.cpp runtime/libprofile/OptimalEdgeProfiling.c runtime/libprofile/exported_symbols.lst

Andreas Neustifter astifter-llvm at gmx.at
Tue Sep 1 13:17:54 PDT 2009


Hi,

since this is quite a big patch, I will give a quick walk-trough.

Andreas Neustifter wrote:
> [...[
> Modified: llvm/trunk/include/llvm/Analysis/ProfileInfoTypes.h
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Analysis/ProfileInfoTypes.h?rev=80712&r1=80711&r2=80712&view=diff
> 
> ==============================================================================
> --- llvm/trunk/include/llvm/Analysis/ProfileInfoTypes.h (original)
> +++ llvm/trunk/include/llvm/Analysis/ProfileInfoTypes.h Tue Sep  1 14:03:44 2009
> @@ -22,7 +22,8 @@
>    BlockInfo     = 3,   /* Block profiling information     */
>    EdgeInfo      = 4,   /* Edge profiling information      */
>    PathInfo      = 5,   /* Path profiling information      */
> -  BBTraceInfo   = 6    /* Basic block trace information   */
> +  BBTraceInfo   = 6,   /* Basic block trace information   */
> +  OptEdgeInfo   = 7    /* Edge profiling information, optimal version */
>  };
>  
>  #endif /* LLVM_ANALYSIS_PROFILEINFOTYPES_H */
> 

This simply adds a new ID for the fields in the llvmprof.out (the
profiling output).

> [...]
> Added: llvm/trunk/lib/Transforms/Instrumentation/OptimalEdgeProfiling.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Instrumentation/OptimalEdgeProfiling.cpp?rev=80712&view=auto
> 
> [...]
> +inline static void printEdgeCounter(ProfileInfo::Edge e,
> +                                    BasicBlock* b,
> +                                    unsigned i) {
> +  DEBUG(errs() << "--Edge Counter for " << (e) << " in " \
> +               << ((b)?(b)->getNameStr():"0") << " (# " << (i) << ")\n");
> +}

A function to print out debug info, this is used several times in the
code so its factored out.

> +bool OptimalEdgeProfiler::runOnModule(Module &M) {
> +  Function *Main = M.getFunction("main");
> +  if (Main == 0) {
> +    errs() << "WARNING: cannot insert edge profiling into a module"
> +           << " with no main function!\n";
> +    return false;  // No main, no instrumentation!
> +  }
> +
> +  std::set<BasicBlock*> BlocksToInstrument;
> +  unsigned NumEdges = 0;
> +  for (Module::iterator F = M.begin(), E = M.end(); F != E; ++F) {
> +    if (F->isDeclaration()) continue;
> +    // Reserve space for (0,entry) edge.
> +    ++NumEdges;
> +    for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) {
> +      // Keep track of which blocks need to be instrumented.  We don't want to
> +      // instrument blocks that are added as the result of breaking critical
> +      // edges!
> +      BlocksToInstrument.insert(BB);
> +      if (BB->getTerminator()->getNumSuccessors() == 0) {
> +        // Reserve space for (BB,0) edge.
> +        ++NumEdges;
> +      } else {
> +        NumEdges += BB->getTerminator()->getNumSuccessors();
> +      }
> +    }
> +  }

Okay, so here it gets interessting:
The BlocksToInstrument stores all blocks that are in the function prior
to instrumenting, since the spliting of critical edges adds new blocks
(which have not to be instrumented), we have to remember them for later.
NumEdges counts all the edges that may be instrumented. Later on its
decided which edges to actually instrument, to achieve optimal profiling.
For the entry block a virtual edge (0,entry) is reserved, for each block
with no successors an edge (BB,0) is reserved. These edges are necessary
to calculate a truly optimal maximum spanning tree and thus an optimal
instrumentation.

> +  const Type *Int32 = Type::getInt32Ty(M.getContext());
> +  const ArrayType *ATy = ArrayType::get(Int32, NumEdges);
> +  GlobalVariable *Counters =
> +    new GlobalVariable(M, ATy, false, GlobalValue::InternalLinkage,
> +                       Constant::getNullValue(ATy), "OptEdgeProfCounters");
> +  NumEdgesInserted = 0;
> +
> +  std::vector<Constant*> Initializer(NumEdges);
> +  Constant* zeroc = ConstantInt::get(Int32, 0);
> +  Constant* minusonec = ConstantInt::get(Int32, ProfileInfo::MissingValue);

In the profiling output a counter for each edge is reserved, but only
few are used. This is done to be able to read in the profile without
calulating the maximum spanning tree again, instead each edge counter
that is not used is initialised with -1 to signal that this edge counter
has to be calculated from other edge counters on reading the profile
info back in.

> +  // Instrument all of the edges not in MST...
> +  unsigned i = 0;
> +  for (Module::iterator F = M.begin(), E = M.end(); F != E; ++F) {
> +    if (F->isDeclaration()) continue;
> +    DEBUG(errs()<<"Working on "<<F->getNameStr()<<"\n");
> +
> +    PI = &getAnalysisID<ProfileInfo>(ProfileEstimatorPassID,*F);
> +    MaximumSpanningTree MST = MaximumSpanningTree(&(*F),PI,true);

Calculate a Maximum Spanning Tree with the edge weights determined by
ProfileEstimator. ProfileEstimator also assign weights to the virtual
edges (0,entry) and (BB,0) (for blocks with no successors) and this
edges also participate in the maximum spanning tree calculation. The
third parameter of MaximumSpanningTree() has the effect that not the
actual MST is returned but the edges _not_ in the MST.

> +    // Create counter for (0,entry) edge.
> +    BasicBlock *entry = &(F->getEntryBlock());
> +    ProfileInfo::Edge edge = ProfileInfo::getEdge(0,entry);
> +    if (std::binary_search(MST.begin(),MST.end(),edge)) {
> +      printEdgeCounter(edge,entry,i);
> +      IncrementCounterInBlock(entry, i, Counters); NumEdgesInserted++;
> +      Initializer[i++] = (zeroc);
> +    } else{
> +      Initializer[i++] = (minusonec);
> +    }

Check if (0,entry) not in the MST (and thus its in the MST set). If not,
instrument edge (IncrementCounterInBlock()) and set the counter
initially to zero, if the edge is in the MST the counter is initialised
to -1.
(Note to self: Okay, this source code is really hard to read, I have to
change that.)

> +    for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) {
> +      if (!BlocksToInstrument.count(BB)) continue; // Don't count new blocks

Here its checked if the block was in the function initially or if it was
introduced by SplitCriticalEdge().
(Note to self: Maybe its easier to store blocks that are introduced
instead of the initial blocks in the function.)

> +      // Okay, we have to add a counter of each outgoing edge not in MST. If
> +      // the outgoing edge is not critical don't split it, just insert the
> +      // counter in the source or destination of the edge.
> +      TerminatorInst *TI = BB->getTerminator();
> +      if (TI->getNumSuccessors() == 0) {
> +        // Create counter for (BB,0), edge.
> +        ProfileInfo::Edge edge = ProfileInfo::getEdge(BB,0);
> +        if (std::binary_search(MST.begin(),MST.end(),edge)) {
> +          printEdgeCounter(edge,BB,i);
> +          IncrementCounterInBlock(BB, i, Counters); NumEdgesInserted++;
> +          Initializer[i++] = (zeroc);
> +        } else{
> +          Initializer[i++] = (minusonec);
> +        }

Same as for (0,entry) but for (BB,0) in case the block has no successors.

> +      }
> +      for (unsigned s = 0, e = TI->getNumSuccessors(); s != e; ++s) {

Iterate for each Block over the exiting edges, this ensures that each
edge is visited.

> +        BasicBlock *Succ = TI->getSuccessor(s);
> +        ProfileInfo::Edge edge = ProfileInfo::getEdge(BB,Succ);
> +        if (std::binary_search(MST.begin(),MST.end(),edge)) {
> +
> +          // If the edge is critical, split it.
> +          SplitCriticalEdge(TI,s,this);
> +          Succ = TI->getSuccessor(s);
> +
> +          // Okay, we are guaranteed that the edge is no longer critical.  If we
> +          // only have a single successor, insert the counter in this block,
> +          // otherwise insert it in the successor block.
> +          if (TI->getNumSuccessors() == 1) {
> +            // Insert counter at the start of the block
> +            printEdgeCounter(edge,BB,i);
> +            IncrementCounterInBlock(BB, i, Counters); NumEdgesInserted++;
> +          } else {
> +            // Insert counter at the start of the block
> +            printEdgeCounter(edge,Succ,i);
> +            IncrementCounterInBlock(Succ, i, Counters); NumEdgesInserted++;
> +          }
> +          Initializer[i++] = (zeroc);
> +        } else {
> +          Initializer[i++] = (minusonec);
> +        }
> +      }

Each edge that is not in MST (and thus in set MST, how weird is
that...), has to be checked if its an critical edge. If yes, it is split
because we need a block right on this edge to put the counter in,
otherwise the counter is placed in the source or destination block.

> +    }
> +  }
> +
> +  // check if indeed all counters have been used
> +  assert(i==NumEdges && "the number of edges in counting array is wrong");

Check if the number of edges counted at first was the number of edges we
considered for instrumentation.

> +  // assign initialiser to array
> +  Constant *init = ConstantArray::get(ATy, Initializer);
> +  Counters->setInitializer(init);

At last the created initialiser is assigned to the counter array.
> +
> +  // Add the initialization call to main.
> +  InsertProfilingInitCall(Main, "llvm_start_opt_edge_profiling", Counters);

This places the call to the runtime library into the byte code that
manages the initialisation and writing of the llvmprof.out file.

> [...]
> Added: llvm/trunk/runtime/libprofile/OptimalEdgeProfiling.c
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/runtime/libprofile/OptimalEdgeProfiling.c?rev=80712&view=auto

This adds wrappers around the generic functions in CommonProfiling.c in
the runtime library.

> [...]
> Modified: llvm/trunk/runtime/libprofile/exported_symbols.lst
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/runtime/libprofile/exported_symbols.lst?rev=80712&r1=80711&r2=80712&view=diff

Add the OptimalEdgeProfiling to the exported symbols of the profiling
library.

So thats it, I will plan on commenting the other commits tomorrow.

Andi

-- 
==========================================================================
This email is signed, for more information see
http://web.student.tuwien.ac.at/~e0325716/gpg.html




More information about the llvm-commits mailing list