/* val1.c  2013-01-04 09:35
   Reference executable for validating application profiling tools.
   val1:  triangular distribution of time among N functions.

   With default values of the parameters, the expected distribution of
   time (both self and total) is approximately
     function1  5x
     function2  4x
     function3  3x
     function4  2x
     function5   x
     main        0
   for x = 6.67 %.

   Language -std=gnu99 (with gcc-specific attributes).
   Uses Boost preprocessor library.
   Original versions tested:  gcc 4.7.2, Boost 1.51.0.
*/

// Configurable NUMFUN:  how many leaf functions to create.
#ifndef NUMFUN
#define NUMFUN 5
#endif

// Configurable INNERLOOP:  how many iterations in leaf functions.
#ifndef INNERLOOP
#define INNERLOOP 256
#endif

// Configurable OUTERLOOP:  how many iterations in main program.
#ifndef OUTERLOOP
#define OUTERLOOP (200000000/INNERLOOP)
#endif

// Configurable REVERSE:  define to reverse order of function invocations
// #define REVERSE

#include <inttypes.h>
#include <math.h>
#include <stdio.h>
#include <boost/preprocessor/repetition/repeat_from_to.hpp>

uint64_t accumulator=1;
double   adder=0;

// Define NUMFUN functions.
#define funnam(n) BOOST_PP_CAT(function,n)
#define defun(z,n,data) __attribute__((noinline)) void funnam(n)() { \
  for (uint64_t looper=0; looper<INNERLOOP; ++looper)                \
    adder += M_PI*3, accumulator = accumulator*3 + adder;            \
}
BOOST_PP_REPEAT_FROM_TO (1, BOOST_PP_INC(NUMFUN), defun, "unused")

// The number of invocations forms a triangular distribution.
#ifdef REVERSE
#define callfun(z,n,data) \
  if (loopmod < BOOST_PP_INC(n)) funnam(BOOST_PP_SUB(NUMFUN,n))();
#else
#define callfun(z,n,data) \
  if (loopmod < BOOST_PP_SUB(NUMFUN,n)) funnam(BOOST_PP_INC(n))();
#endif

int main() {
  for (uint64_t looper=0; looper<OUTERLOOP; ++looper) {
    const uint64_t loopmod = looper % NUMFUN;
    BOOST_PP_REPEAT (NUMFUN, callfun, "unused")
  }
  printf ("%" PRIu64 " %f\n", accumulator, adder);
  return 0;
}
