/*****************************************************
 * DIFlow                                            *
 *                                                   *
 * Simple backend to show the call trace of a module *
 *****************************************************/

#include <stdio.h>

/* high resolution clock macros */
#include "../kit/map_clock.h"

#define MAX_FUNCS 500
static char *funcs[MAX_FUNCS];
static long func_calls[MAX_FUNCS];
static int idf = 0;

typedef union
{
  struct {
    long lo;
    long hi;
  } time;
  long long ll;
} ll;

static ll start_time;

#define MAX_EVENTS 120000
static long events[MAX_EVENTS];
static ll time[MAX_EVENTS];
static long reps[MAX_EVENTS];
static long evcnt=0;

/*****************************************************
 * Called before main()                              *
 * Initialize your stuff here                        *
 *****************************************************/
int
di_init_backend (int num)
{
  HI_RES_TIME(start_time.time.lo, start_time.time.hi);
#ifdef VERBOSE 
  fprintf (stderr, "DIFlow: start_time = 0x%llx\n", start_time.ll);
#endif
  return 1;
}

/*****************************************************
 * Called before main()                              *
 * Reply to the DIRuntime                            *
 * 0 -> if you don't want to receive a callback when *
 *      "n" is entered/exited                        *
 * x -> if you want to receive a callback when "n"   *
 *      is entered/exited (x = arg2 of callback)     *
 *****************************************************/
int 
di_callback_required (char *n)
{
  if ((idf < MAX_FUNCS) && fok) {
#ifdef VERBOSE 
    fprintf (stderr, "DIFlow: %s is event %d\n", n, idf);
#endif
    idf++;
    funcs[idf] = n;
    func_calls[idf] = 0;
    return idf;
  } else {
    return 0;
  }
}

/*****************************************************
 * Called before entering an instrumented function   *
 * a = thread id                                     *
 * b = event id                                      *
 * c = first arg of call                             *
 * d = second arg of call                            *
 * e = third arg of call                             *
 * This routine fills our trace buffer               *
 *****************************************************/
void
di_pre_event_callback (long a, long b, long c, long d, long e)
{
  func_calls[b]++;
  if (evcnt<MAX_EVENTS) {
  	HI_RES_TIME(time[evcnt].time.lo, time[evcnt].time.hi);
	reps[evcnt]=1;
  	events[evcnt++]=b;
  }
}

/*****************************************************
 * Called at program termination                     *
 * Process our trace buffer                          *
 *****************************************************/
void 
di_fini_backend ()
{
  long i;

  fprintf (stderr, "DIFlow: evcnt is %ld (max is %ld)\n", evcnt, MAX_EVENTS);
  for(i=0; i<evcnt; i++) {
    fprintf(stderr, "%ld 0x%llx %s\n", i, time[i].ll - start_time.ll, funcs[events[i]]);
  }
  for(i=1; i<idf; i++)
    if (func_calls[i]) fprintf(stderr, "%ld \t%s\n", func_calls[i], funcs[i]);
}
