#include <math.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <time.h>
#include <sys/time.h>
#include <sys/fcntl.h>
#include <asm/unistd.h>
#include <sys/stat.h>
#include <stdio.h>
#include <netinet/ip.h>
#include <string.h>
#include <sys/socket.h>

void setnonblock(int sock)
{
  int flags=fcntl(sock,F_GETFL,0);    
  fcntl(sock, F_SETFL,flags|O_NONBLOCK);
}

#define rdtsc() ({ unsigned long a, d; asm volatile("rdtsc":"=a" (a), "=d" (d)); a; })

int main(int argc, char** argv)
{
	unsigned long tsc1, tsc2;
	int ret, delay, i, j;
#if 0
	int fd=open("/dev/null", O_RDONLY);
	if(fd < 0) {
		perror("opening /dev/null");
		exit(1);
	}
	for(i=0 ; i < 20; ++i) {
		tsc1=rdtsc();
		read(fd, &ret, 0);
		tsc2=rdtsc();
		printf("%f, ", (tsc2-tsc1)/3000.0);
		sleep(1);
	}
	printf("\n");
	close(fd);
#endif

	struct sockaddr_in local;
	memset(&local, 0, sizeof(local));
	local.sin_family=AF_INET;
	local.sin_port=htons(5000);
	int recvsock=socket(AF_INET, SOCK_DGRAM, 0);
	setnonblock(recvsock);
	bind(recvsock, (struct sockaddr*)&local, sizeof(local));
	
	int sendsock=socket(AF_INET, SOCK_DGRAM, 0);

	char buf[100];
	memset(buf, 0, sizeof(buf));
	
	struct sockaddr_in remote;
	socklen_t remotelen=sizeof(remote);

	volatile uint32_t dummy=0;
	size_t buflen=sizeof(buf);

	for(delay=100000; delay < 400000000U; delay *= 1.2) {
		uint64_t totcycles=0, totcyclesSquared=0;
		
		for(i=0; i < 10; ++i) {
			for(j=0; j < 10; ++j) 
				sendto(sendsock, buf, sizeof(buf), 0, (struct sockaddr*)&local, sizeof(local));
			
			for(j=0; j < 10; ++j) {
				tsc1=rdtsc();
				ret=recvfrom(recvsock, buf, buflen, 0, (struct sockaddr*)&remote, &remotelen);
				tsc2=rdtsc();
				
				if(ret < 0) {
					perror("recvfrom");
					exit(1);
				}
				
				if(ret!=buflen) {
					fprintf(stderr, "Strange length: %d\n", ret);
					break;
				}
				
				totcycles+=(tsc2-tsc1);
				totcyclesSquared += (tsc2-tsc1)*(tsc2-tsc1);
				for(dummy=0; dummy < delay; ++dummy)
					;
			}
		}
		printf("%u %f %f\n", delay, (totcycles)/(3000.0*10*10), sqrt((totcyclesSquared - totcycles * totcycles / 100)/99)/(3000.0*10*10));
		fflush(stdout);
		usleep(10000);
	}
}
