#include <fstream>
#include <stdlib>
#include <thread>

extern "C" {
#include <unistd.h>					// sysconf
#include <sys/times.h>					// times
#include <time.h>
}

inline unsigned long long int Time() {
    timespec ts;
    clock_gettime(
#if defined( __linux__ )
	 CLOCK_THREAD_CPUTIME_ID,
#elif defined( __freebsd__ )
	 CLOCK_PROF,
#elif defined( __solaris__ )
	 CLOCK_HIGHRES,
#else
    #error uC++ : internal error, unsupported architecture
#endif
	 &ts );
    return 1000000000LL * ts.tv_sec + ts.tv_nsec;
} // Time

struct GreatSuspender {
	coroutine_desc __cor;
};

DECL_COROUTINE(GreatSuspender);

void ?{}( GreatSuspender * this ) {
	prime(this);
}

void main( GreatSuspender * this )
{
	while( true ) {
		suspend();
	}
}

void resumer( GreatSuspender * this, const unsigned int NoOfTimes ) {
	for ( volatile unsigned int i = 0; i < NoOfTimes; i += 1 ) {
		resume( this );
	}
}

#ifndef N
#define N 100000000
#endif



long long int measure_coroutine() {
	const unsigned int NoOfTimes = N;
	long long int StartTime, EndTime;

	GreatSuspender s;

	StartTime = Time();
	// for ( volatile unsigned int i = 0; i < NoOfTimes; i += 1 ) {
	// 	resume( this_coroutine() );
	// 	// resume( &s );
	// }
	resumer( &s, NoOfTimes );
	EndTime = Time();

	return ( EndTime - StartTime ) / NoOfTimes;
}

long long int measure_thread() {
	const unsigned int NoOfTimes = N;
	long long int StartTime, EndTime;

	StartTime = Time();
	for ( volatile unsigned int i = 0; i < NoOfTimes; i += 1 ) {
		yield();
	}
	EndTime = Time();

	return ( EndTime - StartTime ) / NoOfTimes;
}

int main()
{
	sout | time(NULL) | ',' | measure_coroutine() | ',' | measure_thread() | endl;
}
