/*
    Copyright 2005-2010 Intel Corporation.  All Rights Reserved.

    This file is part of Threading Building Blocks.

    Threading Building Blocks is free software; you can redistribute it
    and/or modify it under the terms of the GNU General Public License
    version 2 as published by the Free Software Foundation.

    Threading Building Blocks is distributed in the hope that it will be
    useful, but WITHOUT ANY WARRANTY; without even the implied warranty
    of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Threading Building Blocks; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

    As a special exception, you may use this file as part of a free software
    library without restriction.  Specifically, if other files instantiate
    templates or use macros or inline functions from this file, or you compile
    this file and link it with other files to produce an executable, this
    file does not by itself cause the resulting executable to be covered by
    the GNU General Public License.  This exception does not however
    invalidate any other reasons why the executable file might be covered by
    the GNU General Public License.
*/

// Thread level recorder
#ifndef __THREAD_LEVEL_H
#define __THREAD_LEVEL_H
#include <cstdio>
#include <omp.h>
#include <assert.h>
#include "tbb/atomic.h"
#include "tbb/tick_count.h"

//#define LOG_THREADS // use this to ifdef out calls to this class 
//#define NO_BAIL_OUT // continue execution after detecting oversubscription

using namespace tbb;

typedef enum {tbb_outer, tbb_inner, omp_outer, omp_inner} client_t;

class ThreadLevelRecorder {
  tbb::atomic<int> tbb_outer_level;
  tbb::atomic<int> tbb_inner_level;
  tbb::atomic<int> omp_outer_level;
  tbb::atomic<int> omp_inner_level;
  struct record {
    tbb::tick_count time;
    int n_tbb_outer_thread;
    int n_tbb_inner_thread;
    int n_omp_outer_thread;
    int n_omp_inner_thread;
  };
  tbb::atomic<unsigned> next;
  /** Must be power of two */
  static const unsigned max_record_count = 1<<20;
  record array[max_record_count];
  int max_threads;
  bool fail;
 public:
  void change_level(int delta, client_t whichClient);
  void dump();
  void init();
};

void ThreadLevelRecorder::change_level(int delta, client_t whichClient) {
  int tox=tbb_outer_level, tix=tbb_inner_level, oox=omp_outer_level, oix=omp_inner_level;
  if (whichClient == tbb_outer) {
    tox = tbb_outer_level+=delta;
  } else if (whichClient == tbb_inner) {
    tix = tbb_inner_level+=delta;
  } else if (whichClient == omp_outer) {
    oox = omp_outer_level+=delta;
  } else if (whichClient == omp_inner) {
    oix = omp_inner_level+=delta;
  } else {
    printf("WARNING: Bad client type; ignoring.\n");
    return;
  }
  // log non-negative entries
  tbb::tick_count t = tbb::tick_count::now();
  unsigned k = next++;
  if (k<max_record_count) {
    record& r = array[k];
    r.time = t;
    r.n_tbb_outer_thread = tox>=0?tox:0;
    r.n_omp_outer_thread = oox>=0?oox:0;
    r.n_tbb_inner_thread = tix>=0?tix:0;
    r.n_omp_inner_thread = oix>=0?oix:0;
  }
  char errStr[100];
  int tot_threads;
  tot_threads = tox+tix+oox+oix;
  sprintf(errStr, "ERROR: Number of threads (%d+%d+%d+%d=%d) in use exceeds maximum (%d).\n", 
	  tox, tix, oox, oix, tot_threads, max_threads);
  if (tot_threads > max_threads) {
#ifdef NO_BAIL_OUT
    if (!fail) {
      printf("%sContinuing...\n", errStr);
      fail = true;
    }
#else
    dump();
    printf("%s\n", errStr);
    assert(tot_threads <= max_threads);
#endif
  }
}

void ThreadLevelRecorder::dump() {
  FILE* f = fopen("time.txt","w");
  if (!f) {
    perror("fopen(time.txt)\n");
    exit(1);
  }
  unsigned limit = next;
  if (limit>max_record_count) { // Clip
    limit = max_record_count;
  }
  for (unsigned i=0; i<limit; ++i) {
    fprintf(f,"%f\t%d\t%d\t%d\t%d\n",(array[i].time-array[0].time).seconds(), array[i].n_tbb_outer_thread,
	    array[i].n_tbb_inner_thread, array[i].n_omp_outer_thread, array[i].n_omp_inner_thread);
  }
  fclose(f);
  int tox=tbb_outer_level, tix=tbb_inner_level, oox=omp_outer_level, oix=omp_inner_level;
  int tot_threads;
  tot_threads = tox+tix+oox+oix;
  if (!fail) printf("INFO: Passed.\n");
  else printf("INFO: Failed.\n");
}

void ThreadLevelRecorder::init() {
  fail = false;
  max_threads = omp_get_max_threads();
  printf("INFO: Getting maximum hardware threads... %d.\n", max_threads);
}

ThreadLevelRecorder TotalThreadLevel;
#endif
