| /* |
| * 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"); |
| } |
| |