#include <stdio.h> /* for printf() and fprintf() */
#include <sys/socket.h> /* for socket(), connect(), send(), and recv() */
#include <arpa/inet.h> /* for sockaddr_in and inet_addr() */
#include <stdlib.h> /* for atoi() and exit() */
#include <string.h> /* for memset() */
#include <unistd.h> /* for close() */
#include <netinet/in.h>
#include <sys/time.h>
#include <netinet/tcp.h>
#include <assert.h>
#include <stdlib.h>
#include <errno.h>
#include <mach/mach_time.h>
#define ORWL_NANO (+1.0E-9)
#define ORWL_GIGA UINT64_C(1000000000)
/*#define HOST "img901.imageshack.us"*/
/*#define HOSTIP "208.94.1.133"*/
#define HOSTIP "127.0.0.1"
/*#define PORT 3000*/
#define PORT 8080
/*#define PATH "/validate?token=%s"*/
#define PATH "/verify?key=%s"
int timecmp(const void* a, const void* b)
{
return *((const size_t*)a) - *((const size_t*)b);
}
static double orwl_timebase = 0.0;
static uint64_t orwl_timestart = 0;
inline struct timespec orwl_gettime(void)
{
// be more careful in a multithreaded environement
if (!orwl_timestart)
{
mach_timebase_info_data_t tb = { 0 };
mach_timebase_info(&tb);
orwl_timebase = tb.numer;
orwl_timebase /= tb.denom;
orwl_timestart = mach_absolute_time();
}
struct timespec t;
double diff = (mach_absolute_time() - orwl_timestart) * orwl_timebase;
t.tv_sec = diff * ORWL_NANO;
t.tv_nsec = diff - (t.tv_sec * ORWL_GIGA);
return t;
}
#include <time.h>
#include <sys/time.h>
#ifdef __MACH__
#include <mach/clock.h>
#include <mach/mach.h>
#endif
inline struct timespec gettime()
{
struct timespec ts;
#ifdef __MACH__ // OS X does not have clock_gettime, use clock_get_time
clock_serv_t cclock;
mach_timespec_t mts;
host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
clock_get_time(cclock, &mts);
mach_port_deallocate(mach_task_self(), cclock);
ts.tv_sec = mts.tv_sec;
ts.tv_nsec = mts.tv_nsec;
return ts;
#else
return clock_gettime(CLOCK_REALTIME, &ts);
#endif
}
inline uint64_t gettime_ns()
{
struct timespec ts = gettime();
return ts.tv_sec * (1000000000) + ts.tv_nsec;
}
inline uint64_t getns()
{
struct timespec time = orwl_gettime();
return time.tv_sec * ORWL_NANO + time.tv_nsec;
}
inline uint64_t getus()
{
struct timeval now;
gettimeofday(&now, NULL);
return now.tv_usec;
}
void shuffle(size_t* array, size_t n)
{
if (n > 1)
{
size_t i;
for (i = 0; i < n - 1; i++)
{
size_t j = i + rand() / (RAND_MAX / (n - i) + 1);
size_t t = array[j];
array[j] = array[i];
array[i] = t;
}
}
}
int main(int argc, char* argv[])
{
setbuf(stdout, NULL);
const size_t repeats = atoi(argv[1]);
const size_t keysCount = argc - 2;
char** keys = &argv[2];
printf("Using %lu keys, repeating test %lu times\n", keysCount, repeats);
uint64_t results[keysCount];
memset(results, 0, sizeof(results));
char* headers[keysCount];
const char* requestTemplate = "GET " PATH " HTTP/1.1\r\nConnection: keep-alive\r\n\r\n";
for (size_t i = 0; i < keysCount; ++i)
{
size_t length = strlen(requestTemplate) - strlen("%s") + strlen(keys[i]) + 1;
headers[i] = (char*)malloc(length);
sprintf(headers[i], requestTemplate, keys[i]);
}
int sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
int flag = 1;
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char*)&flag, sizeof(flag));
struct sockaddr_in serverAddress =
{
.sin_family = AF_INET,
.sin_addr = {
.s_addr = inet_addr(HOSTIP)
},
.sin_port = htons(PORT)
};
if (0 != connect(sock, (struct sockaddr*)&serverAddress, sizeof(serverAddress)))
{
printf("Failed to connect\n");
return 1;
}
printf("Socket connected\n");
char buf[1024];
long start;
long end;
size_t responseLength;
size_t keysOrder[keysCount];
for (size_t i = 0; i < keysCount; ++i)
{
keysOrder[i] = i;
}
size_t testsDone = 0;
for (int i = 0; i < 10; ++i)
{
printf("%d\t", i);
}
printf("\n");
size_t tests = 0;
RUN_TEST:
tests++;
shuffle(keysOrder, keysCount);
size_t slowestTime = 0;
size_t slowestKey = 0;
size_t roundTimes[keysCount];
memset(roundTimes, 0, sizeof(roundTimes));
size_t roundResults[keysCount];
memset(roundResults, 0, sizeof(roundResults));
for (size_t i = 0; i < keysCount; ++i)
{
const char* key = keys[keysOrder[i]];
char* header = headers[keysOrder[i]];
/*printf("sending reques: %s\n", header);*/
size_t keyRepeats = 0;
uint64_t averageTime = 0;
uint64_t minTime = 99999999999;
uint64_t maxTime = 0;
uint64_t timeSum = 0;
PERFORM_REQUEST:
keyRepeats += 1;
responseLength = 0;
fd_set readset;
FD_ZERO(&readset);
FD_SET(sock, &readset);
/*start = getus();*/
start = gettime_ns();
ssize_t sent = send(sock, header, strlen(header), 0);// MSG_DONTWAIT);
if (sent < 0)
{
fprintf(stderr, "Failed to write data to socket: %s", strerror(errno));
return 1;
}
/*write(sock, header, strlen(header));*/
do
{
if (0 > select(sock + 1, &readset, NULL, NULL, NULL))
{
fprintf(stderr, "select() failed: %s", strerror(errno));
return 1;
}
}
while (!FD_ISSET(sock, &readset));
end = gettime_ns();
/*
while (responseLength < 10)
{
responseLength += read(sock, buf + responseLength, sizeof(buf) - responseLength);
}
*/
/*end = clock();*/
/*end = getus();*/
/*printf("%llu %llu %llu\n", start, end, time);*/
/*assert(buf[9] == '2' || buf[9] == '3');*/
/*int verificationResult = (buf[9] == '2');*/
/*if (verificationResult)*/
/*{*/
/*printf("VALID: %s\n", key);*/
/*return 0;*/
/*}*/
while (strncmp(buf + responseLength - 7, "\r\n0\r\n\r\n", 7) != 0)
/*while (*(buf + responseLength - 1) != '}')*/
{
/*printf("\n\nloop\n");*/
/*printf("%d %d %d\n", *(buf + responseLength - 1) == '}', *(buf + responseLength - 2), *(buf + responseLength - 3));*/
ssize_t bytesReceived = read(sock, buf + responseLength, sizeof(buf) - responseLength);
if (bytesReceived < 0)
{
fprintf(stderr, "read() failed: %s", strerror(errno));
return 1;
}
responseLength += bytesReceived;
}
/*printf("\n\nrequest finished\n");*/
uint64_t time = end - start;
timeSum += time;
/*
if (averageTime == 0)
{
averageTime = time;
}
else
{
averageTime = averageTime + time / 2;
}
*/
if (time < minTime)
{
minTime = time;
}
if (time > maxTime)
{
maxTime = time;
}
if (keyRepeats < 10)
{
goto PERFORM_REQUEST;
}
/*averageTime = timeSum / 3;*/
/*roundResults[keysOrder[i]] = averageTime;*/
roundResults[keysOrder[i]] = minTime;
if (averageTime > slowestTime)
{
slowestTime = averageTime;
slowestKey = keysOrder[i];
}
/*printf("Got response: %s\n", buf);*/
}
size_t sortedRoundResults[keysCount];
memcpy(sortedRoundResults, roundResults, sizeof(roundResults));
qsort(sortedRoundResults, keysCount, sizeof(sortedRoundResults[0]), timecmp);
/*
printf("\n");
for(int i =0;i<keysCount;++i)
{
printf("%llu ", roundResults[i]);
}
printf("\n");
printf("round results: ");
for(int i =0;i<keysCount;++i)
{
printf("%llu ", sortedRoundResults[i]);
}
printf("\n");
*/
for (size_t i = 0; i < keysCount; ++i)
{
size_t keyResult = roundResults[i];
for (ssize_t j = keysCount - 1; j >= 0; --j)
{
if (sortedRoundResults[j] == keyResult)
{
/*printf("key %ld gets %ld points\n", i, j);*/
results[i] += j;
break;
}
}
}
/*results[slowestKey]++;*/
testsDone++;
printf("\r");
size_t maxResult = 0;
for (size_t i = 0; i < keysCount; ++i)
{
if (results[i] > maxResult)
{
maxResult = results[i];
}
}
for (size_t i = 0; i < keysCount; ++i)
{
#define BOLD_ON "\x1b[1;31m"
#define BOLD_OFF "\x1b[0m"
if (results[i] == maxResult)
{
printf(BOLD_ON "%.02lf\t" BOLD_OFF, ((double)results[i]) / testsDone);
}
else
{
printf("%.02f\t", ((double)results[i]) / testsDone);
}
}
/*printf("\n");*/
if (testsDone < repeats)
{
goto RUN_TEST;
}
close(sock);
return 0;
}