#include <mutex>
#include <thread>
#include <condition_variable>
#include <time.h>
#include <stdio.h>


//Measure overhead of calling std::condition_variable::notify_one() if noone is waiting

#define NUM_CALLS 1000000

static std::mutex mtx;
static std::condition_variable cv;
static bool exit_touch_thread = false;

static void touch_thread() {
	std::unique_lock<std::mutex> ul(mtx);
	while(!exit_touch_thread)
		cv.wait(ul);
}


int main(void) {
	//First spawn a thread and make it wait on the CV. This is to
	//ensure that any user/kernel resources lazily allocated is done.
	std::thread t(touch_thread);
	
	timespec ts_wait{0,1000000000};
	nanosleep(&ts_wait,nullptr);
	
	{
		std::unique_lock<std::mutex> ul(mtx);
		exit_touch_thread = true;
		cv.notify_one();
	}
	
	t.join();
	
	timespec ts_start;
	clock_gettime(CLOCK_REALTIME,&ts_start);
	
	//then call notify_one() a million times
	for(int i=0; i<NUM_CALLS; i++)
		cv.notify_one();
	
	timespec ts_end;
	clock_gettime(CLOCK_REALTIME,&ts_end);
	
	double time_taken = (ts_end.tv_sec-ts_start.tv_sec) +
	                    (ts_end.tv_nsec-ts_start.tv_nsec)/1000000000.0;
	
	printf("%.3f seconds to 1000000 notify_one() calls\n", time_taken);
	printf(" = %.6f nanoseconds/call\n", time_taken/NUM_CALLS*1000000000.0);
	
	return 0;
}
