/*
 *  DebugProfiling.cpp
 *  iphone-gl-app
 *
 *  Created by John Ryland on 16/06/09.
 *  Copyright 2009 InvertedLogic. All rights reserved.
 *
 */

#include <stdlib.h>
#include <stdarg.h>
#include "String.h"
#include "DebugProfiling.h"


DebugProfiling::AutoEnter::AutoEnter(const char *f) : func(f)
{
}


DebugProfiling::AutoEnter::~AutoEnter()
{
}


DebugProfiling::AutoEnter DebugProfiling::enter(const char *func)
{
	return DebugProfiling::AutoEnter(func);
}


#if 0

void *insideSampleList[10*60*1000];
void *totalSampleList[10*60*1000*5];
int insideSampleListPos = 0;
int totalSampleListPos = 0;


static void profilerSignalHandler(int signal, siginfo_t *, void *context)
{
	if (signal != SIGPROF)
		return;
/*
	if (active_sampler_ == NULL) return;
	TickSample sample;
	// If profiling, we extract the current pc and sp.
	if (active_sampler_->IsProfiling()) {
		// Extracting the sample from the context is extremely machine dependent.
	ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
	mcontext_t& mcontext = ucontext->uc_mcontext;
#if __DARWIN_UNIX03
		sample.pc = mcontext->__ss.__eip;
		sample.sp = mcontext->__ss.__esp;
		sample.fp = mcontext->__ss.__ebp;
#else  // !__DARWIN_UNIX03
		sample.pc = mcontext->ss.eip;
		sample.sp = mcontext->ss.esp;
		sample.fp = mcontext->ss.ebp;
#endif  // __DARWIN_UNIX03
	}	
	// We always sample the VM state.
	sample.state = Logger::state();
	active_sampler_->Tick(&sample);
*/
	ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
	mcontext_t& mcontext = ucontext->uc_mcontext;
	insideSampleList[insideSampleListPos] = mcontext->ss.eip;
	insideSampleListPos++;
}


DebugProfiling::DebugProfiling()
	//: interval_(interval), profiling_(profiling), active_(false)
{
	signal_handler_installed_ = false;
}


DebugProfiling::~DebugProfiling()
{
}


void DebugProfiling::start()
{
	// There can only be one active sampler at the time on POSIX
	// platforms.
	if (active_sampler_ != NULL)
		return;
	
	// Request profiling signals.
	struct sigaction sa;
	sa.sa_sigaction = ProfilerSignalHandler;
	sigemptyset(&sa.sa_mask);
	sa.sa_flags = SA_SIGINFO;
	if (sigaction(SIGPROF, &sa, &data_->old_signal_handler_) != 0)
		return;
	data_->signal_handler_installed_ = true;
	
	// Set the itimer to generate a tick for each interval.
	itimerval itimer;
	itimer.it_interval.tv_sec = interval_ / 1000;
	itimer.it_interval.tv_usec = (interval_ % 1000) * 1000;
	itimer.it_value = itimer.it_interval;
	setitimer(ITIMER_PROF, &itimer, &data_->old_timer_value_);
	
	// Set this sampler as the active sampler.
	active_sampler_ = this;
	active_ = true;
}


void DebugProfiling::stop()
{
	// Restore old signal handler
	if (data_->signal_handler_installed_) {
		setitimer(ITIMER_PROF, &data_->old_timer_value_, NULL);
		sigaction(SIGPROF, &data_->old_signal_handler_, 0);
		data_->signal_handler_installed_ = false;
	}
	
	// This sampler is no longer the active sampler.
	active_sampler_ = NULL;
	active_ = false;
}



#ifdef ENABLE_LOGGING_AND_PROFILING

static Sampler* active_sampler_ = NULL;


+static void
+SIG_HANDLER_SIGNATURE (sigprof_signal_handler)
+{
	+	int pos;
	+
	+	GET_CONTEXT;
	+
	+	if (prof_counts >= MAX_PROF_SAMPLES)
		+		return;
	+	pos = InterlockedIncrement (&prof_counts);
	+	prof_addresses [pos - 1] = mono_arch_ip_from_context (ctx);
+}
+
static void
SIG_HANDLER_SIGNATURE (sigquit_signal_handler)
{
	@@ -8178,6 +8274,25 @@ mono_runtime_install_handlers (void)
#endif /* PLATFORM_WIN32 */
}

+static void
+setup_profiler (void)
+{
	+	struct itimerval itval;
	+	static int inited = 0;
	+
	+	/* about 10 minutes of samples */
	+	prof_addresses = g_new0 (gpointer, MAX_PROF_SAMPLES);
	+	itval.it_interval.tv_usec = 1000;
	+	itval.it_interval.tv_sec = 0;
	+	itval.it_value = itval.it_interval;
	+	setitimer (ITIMER_PROF, &itval, NULL);
	+	if (inited)
		+		return;
	+	inited = 1;
	+	prof_table = g_hash_table_new (g_str_hash, g_str_equal);
	+	add_signal_handler (SIGPROF, sigprof_signal_handler);
+}
+

#endif

