blob: 4669d16270862d96a91e890777f5010c4db8b744 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <unistd.h>
#include <time.h>
#include <sys/time.h>
#define INIT_RETRIES 5
void usage(void);
void send_buffer(int fd, char* buffer, int bytes);
void print_headers(void);
double subtractTimeOfDay(struct timeval* begin, struct timeval* end);
int main(int argc, char** argv)
{
int socketFd;
int retVal;
int c;
int i;
int displayHeaders = 1;
int serverPort = 0;
int duration = 60;
double actual_duration;
char* hostname = NULL;
char* sendBuffer = NULL;
int kilobytesBufSize = 32;
int bytesBufSize;
struct sockaddr_in address;
struct hostent* host_entry;
time_t start_time;
time_t end_time;
unsigned int buffers_sent = 0;
double megaBytesSent;
double megaBytesPerSecond;
struct timeval beginTimeDetails;
struct timeval endTimeDetails;
while ((c = getopt (argc, argv, "p:l:b:P:H:f:t:h")) != -1)
{
switch (c)
{
case 'p':
serverPort = atoi(optarg);
break;
case 'l':
duration = atoi(optarg);
break;
case 'b':
kilobytesBufSize = atoi(optarg);
break;
case 'P':
displayHeaders = atoi(optarg);
if (displayHeaders)
displayHeaders = 1;
break;
case 'H':
hostname = optarg;
break;
case 'f':
// backward compat
break;
case 't':
// backward compat
break;
case 'h':
case '?':
default:
usage();
return 1;
}
}
if (!serverPort)
{
fprintf(stdout, "-p port not specified\n");
usage();
return 1;
}
if (!hostname)
{
fprintf(stdout, "-H hostname not specified\n");
usage();
return 1;
}
// validate a sensible value for duration
if (duration < 5 || duration > 3600)
{
fprintf(stdout, "duration must be between 5 and 3600 seconds\n");
return 1;
}
// validate a sensible value for buffer size
if (kilobytesBufSize < 1 || kilobytesBufSize > 10240)
{
fprintf(stdout, "buffer size for sending must be between 1 and 10240 KB\n");
return 1;
}
bytesBufSize = kilobytesBufSize * 1024;
sendBuffer = malloc(bytesBufSize);
memset(sendBuffer, 0, bytesBufSize);
socketFd = socket(PF_INET, SOCK_STREAM, 0);
if (socketFd < 0)
{
fprintf(stdout, "socket call failed\n");
return 1;
}
host_entry = gethostbyname(hostname);
memset(&address, 0, sizeof(struct sockaddr_in));
address.sin_family = AF_INET;
memcpy((char *)&address.sin_addr,(char *)host_entry->h_addr, host_entry->h_length);
address.sin_port = htons(serverPort);
for (i = 0; i < INIT_RETRIES; ++i)
{
retVal = connect(socketFd,(struct sockaddr *)&address, sizeof(address));
if (retVal == 0)
break;
sleep(1);
}
if (retVal < 0)
{
fprintf(stdout, "Could not connect to server after %d retries\n", INIT_RETRIES);
return 1;
}
printf("Connected to server\n");
start_time = time(NULL);
end_time = start_time + duration;
gettimeofday(&beginTimeDetails, NULL);
while (time(NULL) < end_time)
{
send_buffer(socketFd, sendBuffer, bytesBufSize);
buffers_sent++;
}
gettimeofday(&endTimeDetails, NULL);
actual_duration = subtractTimeOfDay(&beginTimeDetails, &endTimeDetails);
megaBytesSent = buffers_sent * (double)bytesBufSize / (1024.0*1024.0);
megaBytesPerSecond = megaBytesSent / actual_duration;
if (displayHeaders)
print_headers();
printf("0 0 %d %.2f %.2f\n", bytesBufSize, (double)actual_duration, megaBytesPerSecond);
return 0;
}
void usage()
{
fprintf(stdout, "usage: gpnetbench -p PORT -H HOST [-l SECONDS] [-t EXPERIMENT] [-f UNITS] [-P HEADERS] [-b KB] [-h]\n");
fprintf(stdout, "where\n");
fprintf(stdout, " PORT is the port to connect to for the server\n");
fprintf(stdout, " HOST is the hostname to connect to for the server\n");
fprintf(stdout, " SECONDS is the number of seconds to sample the network, where the default is 60\n");
fprintf(stdout, " EXPERIMENT is the experiment name to run, where the default is TCP_STREAM\n");
fprintf(stdout, " UNITS is the output units, where the default is M megabytes\n");
fprintf(stdout, " HEADERS is 0 (don't) or 1 (do) display headers in the output\n");
fprintf(stdout, " KB is the size of the send buffer in kilobytes, where the default is 32\n");
fprintf(stdout, " -h shows this help message\n");
}
void send_buffer(int fd, char* buffer, int bytes)
{
ssize_t retval;
while(bytes > 0)
{
retval = send(fd, buffer, bytes, 0);
if (retval < 0)
{
perror("error on send call");
exit(1);
}
if (retval > bytes)
{
fprintf(stdout, "unexpected large return code from send %d with only %d bytes in send buffer\n", (int)retval, bytes);
}
// advance the buffer by number of bytes sent and reduce number of bytes remaining to be sent
bytes -= retval;
buffer += retval;
}
}
double subtractTimeOfDay(struct timeval* begin, struct timeval* end)
{
double seconds;
if (end->tv_usec < begin->tv_usec)
{
end->tv_usec += 1000000;
end->tv_sec -= 1;
}
seconds = end->tv_usec - begin->tv_usec;
seconds /= 1000000.0;
seconds += (end->tv_sec - begin->tv_sec);
return seconds;
}
void print_headers()
{
printf(" Send\n");
printf(" Message Elapsed\n");
printf(" Size Time Throughput\n");
printf("n/a n/a bytes secs. MBytes/sec\n");
}