diff --git a/a.out b/a.out index 193102b..37154d7 100755 Binary files a/a.out and b/a.out differ diff --git a/evBuild.out b/evBuild.out index 4e41ae5..679aaa5 100755 Binary files a/evBuild.out and b/evBuild.out differ diff --git a/event_builder.cxx b/event_builder.cxx index 9c0f8f2..ea35e72 100644 --- a/event_builder.cxx +++ b/event_builder.cxx @@ -10,6 +10,11 @@ #include #include +#include + +#include +#include + int makeSocket() { int sockfd; @@ -44,6 +49,7 @@ void startListening(int server_fd) { int acceptConnection(int server_fd) { int client_fd; struct sockaddr_in remoteAddr; + size_t addrlen = sizeof(remoteAddr); if ((client_fd = accept(server_fd, (struct sockaddr *)&remoteAddr, (socklen_t *)&addrlen)) < 0) { perror("accept"); @@ -91,8 +97,6 @@ int main(int argc, char const *argv[]) { #define TRUE 1 #define FALSE 0 - - int main(int argc, char const *argv[]) { signal(SIGTERM, term_handler); @@ -139,9 +143,90 @@ int main(int argc, char const *argv[]) { FD_SET(master_socket, &readfds); max_sd = master_socket; + //add child sockets to set + for ( i = 0 ; i < max_clients ; i++) + { + //socket descriptor + sd = client_socket[i]; + + //if valid socket descriptor then add to read list + if(sd > 0) + FD_SET( sd , &readfds); + + //highest file descriptor number, need it for the select function + if(sd > max_sd) + max_sd = sd; + } + + //wait for an activity on one of the sockets , timeout is NULL , + //so wait indefinitely + activity = select( max_sd + 1 , &readfds , NULL , NULL , NULL); + + if ((activity < 0) && (errno!=EINTR)) + { + printf("select error"); + } + + //If something happened on the master socket , + //then its an incoming connection + if (FD_ISSET(master_socket, &readfds)) + { + new_socket = acceptConnection(master_socket); + + //add new socket to array of sockets + for (i = 0; i < max_clients; i++) + { + //if position is empty + if( client_socket[i] == 0 ) + { + client_socket[i] = new_socket; + printf("Adding to list of sockets as %d\n" , i); + + break; + } + } + } + + //else its some IO operation on some other socket + for (i = 0; i < max_clients; i++) + { + sd = client_socket[i]; + + if (FD_ISSET( sd , &readfds)) + { + //Check if it was for closing , and also read the + //incoming message + uint32_t word; + if ((valread = recv( sd , &word, 4, 0)) == 0) + { + struct sockaddr_in address; + int addrlen; + //Somebody disconnected , get his details and print + getpeername(sd , (struct sockaddr*)&address , \ + (socklen_t*)&addrlen); + printf("Host disconnected , ip %s , port %d \n" , + inet_ntoa(address.sin_addr) , ntohs(address.sin_port)); + + printf("Disconnected fd %d", sd); + + //Close the socket and mark as 0 in list for reuse + close( sd ); + client_socket[i] = 0; + } + + //Echo back the message that came in + else + { + printf("[RICEVUTO]\t0x%x FROM %d\n", word, sd); + } + } + } + } + /* + int client_fd = acceptConnection(server_fd); while (true) { @@ -152,7 +237,7 @@ int main(int argc, char const *argv[]) { exit(EXIT_FAILURE); } printf("[RICEVUTO]\t0x%x\n", word); - } + }*/ return 0; diff --git a/provider.cxx b/provider.cxx index e2686ae..f5086d9 100644 --- a/provider.cxx +++ b/provider.cxx @@ -133,7 +133,7 @@ int main(int argc, char* argv[]) { encode_fragment(buffer, fragment); ssize_t bytes = send(socket, reinterpret_cast(buffer), sizeof(buffer), 0); if (bytes != header.fragmentSize * sizeof(uint32_t)) { - perror("Send failed: nub bytes not matching"); + perror("Send failed: num bytes not matching"); exit(EXIT_FAILURE); } diff --git a/spawn_clients.sh b/spawn_clients.sh new file mode 100755 index 0000000..57caa28 --- /dev/null +++ b/spawn_clients.sh @@ -0,0 +1,12 @@ +#!/bin/bash +echo "Usage: $0 host port runNumber numberOfProviders" + +if [ $# -eq 4 ] +then + echo "Selected host: $1:$2 runNumber: $3 numberOfProviders: $4" + for i in $(seq 1 $4); + do + echo "Spawning provider number $i" + ./prov.out $1 $2 $3 & + done +fi diff --git a/testing/buffer_size/client.out b/testing/buffer_size/client.out new file mode 100755 index 0000000..ac74467 Binary files /dev/null and b/testing/buffer_size/client.out differ diff --git a/testing/buffer_size/client_buffer_size.cxx b/testing/buffer_size/client_buffer_size.cxx new file mode 100644 index 0000000..d50d818 --- /dev/null +++ b/testing/buffer_size/client_buffer_size.cxx @@ -0,0 +1,105 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include +#include + +int makeSocket() { + int sockfd; + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + perror("socket failed"); + exit(EXIT_FAILURE); + } + return sockfd; +} + +void connectTo(int sock, const char* host, int port) { + struct sockaddr_in serv_addr; + serv_addr.sin_family = AF_INET; + serv_addr.sin_addr.s_addr = inet_addr(host); + serv_addr.sin_port = htons(port); + + if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { + perror("Connection failed"); + exit(EXIT_FAILURE); + } + + printf("Connected to %s: %d\n", host, port); +} + +int main(int argc, char* argv[]) { + + int socket = makeSocket(); + connectTo(socket, "127.0.0.1", 7777); + + //allocating 100 megabytes of memory + uint64_t* chunky_boy = new uint64_t[13107200]; + size_t chunky_boy_size = 13107200 * sizeof(uint64_t); + printf("chonky size %d", static_cast(chunky_boy_size)); + sleep(5); + + //setting memory to verify non-emptyness + memset(chunky_boy, 45678832, chunky_boy_size); + + std::vector sizes; + std::vector times; + + + for ( int i = 1; i < 1e6 + 2; i += 1e3) { + + printf("Selected buffer size: %d\n", i); + auto start = std::chrono::high_resolution_clock::now(); + int kilos = 0; + for ( int j = 0; j < chunky_boy_size; ) { + + ssize_t bytes = send(socket, reinterpret_cast(chunky_boy) + j, std::min(static_cast(chunky_boy_size) - j, i), 0); + j += i; + if (j%1024 == 0) { + kilos++; + } + } + + + auto end = std::chrono::high_resolution_clock::now(); + double time_taken = std::chrono::duration_cast(end - start).count(); + + time_taken *= 1e-9; + + times.push_back(time_taken); + sizes.push_back(i); + + std::cout << "Time taken by program is : " << std::fixed + << time_taken << std::setprecision(9); + std::cout << " sec" << std::endl; + } + + std::ofstream fout; + fout.open("send_data_buffer"); + fout << "buffer_size;time;\n"; + auto iter_sizes = sizes.begin(); + auto iter_times = times.begin(); + + for ( ; (iter_sizes != sizes.end()) && (iter_times != times.end()) ; (++iter_sizes, ++iter_times) ) { + fout << *iter_sizes << ";" << *iter_times << ";\n"; + } + + fout.close(); + + + return 0; +} \ No newline at end of file diff --git a/testing/buffer_size/server.out b/testing/buffer_size/server.out new file mode 100755 index 0000000..3657290 Binary files /dev/null and b/testing/buffer_size/server.out differ diff --git a/testing/buffer_size/server_consume_data.cxx b/testing/buffer_size/server_consume_data.cxx new file mode 100644 index 0000000..e325abd --- /dev/null +++ b/testing/buffer_size/server_consume_data.cxx @@ -0,0 +1,91 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +int makeSocket() { + int sockfd; + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + perror("socket failed"); + exit(EXIT_FAILURE); + } + return sockfd; +} + +void bindSocketPort(int server_fd, int port) { + struct sockaddr_in localAddr; + localAddr.sin_family = AF_INET; + localAddr.sin_addr.s_addr = INADDR_ANY; + localAddr.sin_port = htons(port); + + if (bind(server_fd, (struct sockaddr *)&localAddr, sizeof(localAddr)) < 0) { + perror("bind failed"); + exit(EXIT_FAILURE); + } + printf("FD %d bound to port %d\n", server_fd, port); +} + +void startListening(int server_fd) { + if (listen(server_fd, 3) < 0) { + perror("listen"); + exit(EXIT_FAILURE); + } + printf("FD %d listening to new connections\n", server_fd); +} + +int acceptConnection(int server_fd) { + int client_fd; + struct sockaddr_in remoteAddr; + size_t addrlen = sizeof(remoteAddr); + if ((client_fd = accept(server_fd, (struct sockaddr *)&remoteAddr, (socklen_t *)&addrlen)) < 0) { + perror("accept"); + exit(EXIT_FAILURE); + } + printf("Connection from host %s, port %d, FD %d\n", inet_ntoa(remoteAddr.sin_addr), ntohs(remoteAddr.sin_port), client_fd); + return client_fd; +} + + +int main(int argc, char* argv[]) { + if (argc != 2) { + printf("Usage: %s portNumber \n", argv[0]); + exit(EXIT_FAILURE); + } + int port = atoi(argv[1]); + printf("Start socket port %d\n", port); + + int server_fd = makeSocket(); + bindSocketPort(server_fd, port); + startListening(server_fd); + int client_fd = acceptConnection(server_fd); + + uint64_t bytes_read = 0; + uint64_t kbytes_read = 0; + + while (true) { + char buffer[32 * 1024] = {0}; + ssize_t bytes = read(client_fd, &buffer, sizeof(buffer)); + + bytes_read += static_cast(bytes); + //printf("tot bytos %lu\n", bytes_read); + + if (uint64_t newkb = (bytes_read / 1024) > 0) { + //printf("before: %lu", bytes_read); + bytes_read -= (1024 * newkb); + //printf("after: %lu", bytes_read); + kbytes_read += newkb; + //printf("Read %d kbytes\n", static_cast(kbytes_read)); + } + } + + return 0; +} \ No newline at end of file diff --git a/testing/connection_method/epoll_data_stats_100.csv b/testing/connection_method/epoll_data_stats_100.csv new file mode 100644 index 0000000..7f3ed08 --- /dev/null +++ b/testing/connection_method/epoll_data_stats_100.csv @@ -0,0 +1,19 @@ +buffer_size;time;total_received_data; +1;30000;45817; +500;30000;16688512; +1000;30000;26801219; +2000;30004.1;40979357; +3000;30000.2;49705756; +4000;30000.1;56029482; +5000;30000.1;60047108; +10000;30000.2;99444868; +20000;30000.2;106228515; +30000;30000.6;103007812; +40000;30000.5;112140625; +50000;30000.8;104677734; +100000;30002.8;119785156; +200000;30001.2;117539062; +300000;30002.7;127939453; +400000;30010.1;121523437; +500000;30004.6;125390625; +1000000;30036.4;126757812; diff --git a/testing/connection_method/epoll_data_stats_1000.csv b/testing/connection_method/epoll_data_stats_1000.csv new file mode 100644 index 0000000..f22d032 --- /dev/null +++ b/testing/connection_method/epoll_data_stats_1000.csv @@ -0,0 +1,19 @@ +buffer_size;time;total_received_data; +1;30000.5;26535; +500;30000.9;12931772; +1000;30000.8;20953270; +2000;30000.7;30575921; +3000;30000.2;37463270; +4000;30003.3;42943248; +5000;30000.4;47972201; +10000;30003.9;57650021; +20000;30001.7;70555676; +30000;30006.6;66315379; +40000;30000.8;64524353; +50000;30006.4;80692139; +100000;30008.4;93501600; +200000;30002.2;103220112; +300000;30010;108385843; +400000;30002.3;110109484; +500000;30041.3;106363740; +1000000;30000;103425306; diff --git a/testing/connection_method/epoll_data_stats_1000_TIMEOUT.csv b/testing/connection_method/epoll_data_stats_1000_TIMEOUT.csv new file mode 100644 index 0000000..be1d0cd --- /dev/null +++ b/testing/connection_method/epoll_data_stats_1000_TIMEOUT.csv @@ -0,0 +1,19 @@ +buffer_size;time;total_received_data; +1;30001.7;23972; +500;30001.1;16452118; +1000;30000;28659540; +2000;30000;43843616; +3000;30000;53965134; +4000;30000;78146535; +5000;30000;81098297; +10000;30000.1;104959571; +20000;30000;103154410; +30000;30000.1;98912274; +40000;30000.2;106528334; +50000;30000;108412018; +100000;30000.1;99869795; +200000;30001.9;113863135; +300000;30006.9;113726256; +400000;30003.6;113588963; +500000;30004.1;124238792; +1000000;30005.3;127730003; diff --git a/testing/connection_method/epoll_data_stats_1000_TIMEOUT_HARD.csv b/testing/connection_method/epoll_data_stats_1000_TIMEOUT_HARD.csv new file mode 100644 index 0000000..7b4d947 --- /dev/null +++ b/testing/connection_method/epoll_data_stats_1000_TIMEOUT_HARD.csv @@ -0,0 +1,19 @@ +buffer_size;time;total_received_data; +1;30000.7;32735; +500;30000;18563821; +1000;30000;33321199; +2000;30000;57600348; +3000;30000;72226712; +4000;30000;80548950; +5000;30000;92428421; +10000;30000;125112074; +20000;30000;130615660; +30000;30000;133488130; +40000;30000;149347337; +50000;30000;141748519; +100000;30000;145676700; +200000;30000.1;167065891; +300000;30000.1;180569049; +400000;30000;186854294; +500000;30000;191359610; +1000000;30000;187503120; diff --git a/testing/connection_method/epoll_data_stats_500.csv b/testing/connection_method/epoll_data_stats_500.csv new file mode 100644 index 0000000..c79d663 --- /dev/null +++ b/testing/connection_method/epoll_data_stats_500.csv @@ -0,0 +1,19 @@ +buffer_size;time;total_received_data; +1;30000.3;38239; +500;30000.3;15008694; +1000;30000.5;24572299; +2000;30000.1;34510344; +3000;30001;41199235; +4000;30000.9;45359880; +5000;30000.5;48985625; +10000;30003.5;59779061; +20000;30003.2;66210747; +30000;30000.4;70755300; +40000;30002.9;91266308; +50000;30005.9;112726855; +100000;30002;120034453; +200000;30004.6;120310170; +300000;30011.9;110168294; +400000;30017;103690777; +500000;30023.6;106875799; +1000000;30065.7;111296658; diff --git a/testing/connection_method/ev_builder_epoll.out b/testing/connection_method/ev_builder_epoll.out new file mode 100755 index 0000000..e81bf2d Binary files /dev/null and b/testing/connection_method/ev_builder_epoll.out differ diff --git a/testing/connection_method/ev_builder_select.out b/testing/connection_method/ev_builder_select.out new file mode 100755 index 0000000..b27f09a Binary files /dev/null and b/testing/connection_method/ev_builder_select.out differ diff --git a/testing/connection_method/event_builder_epoll.cxx b/testing/connection_method/event_builder_epoll.cxx new file mode 100644 index 0000000..abb52ed --- /dev/null +++ b/testing/connection_method/event_builder_epoll.cxx @@ -0,0 +1,283 @@ +#include +#include +#include +#include +#include // for fprintf() +#include // for close(), read() +#include // for epoll_create1(), epoll_ctl(), struct epoll_event +#include // for strncmp + +//my addition to the online guide +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define MAX_EVENTS 20000 + +int makeSocket() { + int sockfd; + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + perror("socket failed"); + exit(EXIT_FAILURE); + } + return sockfd; +} + +void bindSocketPort(int server_fd, int port) { + struct sockaddr_in localAddr; + localAddr.sin_family = AF_INET; + localAddr.sin_addr.s_addr = INADDR_ANY; + localAddr.sin_port = htons(port); + + if (bind(server_fd, (struct sockaddr *)&localAddr, sizeof(localAddr)) < 0) { + perror("bind failed"); + exit(EXIT_FAILURE); + } + printf("FD %d bound to port %d\n", server_fd, port); +} + +void startListening(int server_fd) { + if (listen(server_fd, 20000) < 0) { + perror("listen"); + exit(EXIT_FAILURE); + } + printf("FD %d listening to new connections\n", server_fd); +} + +int acceptConnection(int server_fd) { + int client_fd; + struct sockaddr_in remoteAddr; + + size_t addrlen = sizeof(remoteAddr); + if ((client_fd = accept(server_fd, (struct sockaddr *)&remoteAddr, (socklen_t *)&addrlen)) < 0) { + perror("accept"); + exit(EXIT_FAILURE); + } else { + int flags = fcntl(client_fd, F_GETFL); + fcntl(client_fd, F_SETFL, flags | O_NONBLOCK); + } + printf("Connection from host %s, port %d, FD %d\n", inet_ntoa(remoteAddr.sin_addr), ntohs(remoteAddr.sin_port), client_fd); + return client_fd; +} + +void acceptConnectionEpollStyle(int server_fd, int &efd) { + struct sockaddr_in new_remoteAddr; + int addrlen = sizeof(struct sockaddr_in); + + while (true) { + int conn_sock = accept(server_fd, (struct sockaddr*)&new_remoteAddr, (socklen_t*)&addrlen); + + if (conn_sock == -1) { + // All incoming connections have been processed + if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) { + break; + } else { + perror("accept"); + break; + } + } + + // make new connection non-blocking + int flags = fcntl(conn_sock, F_GETFL, 0); + fcntl(conn_sock, F_SETFL, flags | O_NONBLOCK); + + // monitor new connection for read events, always in edge triggered + struct epoll_event event; + event.events = EPOLLIN;// | EPOLLET; + event.data.fd = conn_sock; + + // Allow epoll to monitor the new connection + if (epoll_ctl(efd, EPOLL_CTL_ADD, conn_sock, &event) == -1) { + perror("epoll_ctl: conn_sock"); + break; + } + printf("Accepted epoll style connection from %s:%d from fd: %d\n", inet_ntoa(new_remoteAddr.sin_addr), ntohs(new_remoteAddr.sin_port), conn_sock); + + } +} + +void term_handler(int signal) { + printf("Terminated, received SIGNAL %d", signal); + exit(EXIT_SUCCESS); +} + + +int main(int argc, char const *argv[]) { + + signal(SIGTERM, term_handler); + + + if (argc != 2) { + printf("Usage: %s portNumber \n", argv[0]); + exit(EXIT_FAILURE); + } + int port = atoi(argv[1]); + printf("Start socket port %d\n", port); + + int master_socket; + const int opt = 1; + + + master_socket = makeSocket(); + + //set master socket to allow multiple connections , + //this is just a good habit, it will work without this + if( setsockopt(master_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, + sizeof(opt)) < 0 ) + { + perror("setsockopt"); + exit(EXIT_FAILURE); + } + + bindSocketPort(master_socket, port); + startListening(master_socket); + + int flags = fcntl(master_socket, F_GETFL, 0); + fcntl(master_socket, F_SETFL, flags | O_NONBLOCK); + + struct epoll_event ev, events[MAX_EVENTS]; + + //create the epoll instance + int epoll_fd = epoll_create1(0); + if (epoll_fd == -1) { + printf("Failed to create epoll file descriptor\n"); + exit(EXIT_FAILURE); + } + + ev.data.fd = master_socket; + // Reading events with edge triggered mode + ev.events = EPOLLIN;// | EPOLLET; + + // Allowing epoll to monitor the master_socket + if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, master_socket, &ev) == -1){ + perror("epoll_ctl"); + exit(EXIT_FAILURE); + } + + std::vector sizes; + std::vector tot_received_data; + std::vector times; + + int increment = 499; + + for (int buf_size = 1; buf_size < 1e6 + 1; ) { + switch (buf_size) { + case 500: + increment = 500; + break; + case (int) 1e3: + increment = 1e3; + break; + case (int) 5e3: + increment = 5e3; + break; + case (int) 1e4: + increment = 1e4; + break; + case (int) 5e4: + increment = 5e4; + break; + case (int) 1e5: + increment = 1e5; + break; + case (int) 5e5: + increment = 5e5; + break; + } + printf("Next increment %d with current i: %d\n", increment, buf_size); + + uint64_t bytes_read = 0; + uint64_t kBytes_read = 0; + double total_time_taken = 0; + + while (true) { + // Time measurements + auto start = std::chrono::high_resolution_clock::now(); + + // Returns only the sockets for which there are events + //printf("Before wait\n"); + int nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, -1); + //printf("After wait\n"); + if (nfds == -1) { + perror("epoll_wait"); + exit(EXIT_FAILURE); + } + + // Iterate on the sockets having events + for (int i = 0; i < nfds; i++) { + //printf("Tot fds = %d reading from %d\n", nfds, i); + int fd = events[i].data.fd; + if (fd == master_socket) { + // If the activity is on the master socket, than it's a new connection request + acceptConnectionEpollStyle(master_socket, epoll_fd); + } else if ((events[i].events & EPOLLERR) || (events[i].events & EPOLLHUP) || (!(events[i].events & EPOLLIN))) { + // Than the client connection is closed, so I close it + printf("Closing %d", fd); + close(fd); + } else { + // Than we received data from one of the monitored sockets + char buffer[buf_size]; + int valread = 0; + //while (valread != EAGAIN) { + valread = recv(fd, &buffer, buf_size, 0); + if (valread > 0) { + //printf("[RICEVUTO]\t FROM %d\n", fd); + bytes_read += valread; + int kilos = 0; + if ((kilos = bytes_read / 1024) > 0) { + kBytes_read += kilos; + bytes_read -= (kilos * 1024); + //printf("reade bites %lu", bytes_read); + } + } + //} + + } + } + + auto end = std::chrono::high_resolution_clock::now(); + double time_taken = std::chrono::duration_cast(end - start).count(); + //time taken in milliseconds + time_taken *= 1e-6; + total_time_taken += time_taken; + + if (total_time_taken > 3e4) { + times.push_back(total_time_taken); + sizes.push_back(buf_size); + tot_received_data.push_back(kBytes_read); + break; + } + } + + buf_size += increment; + + } + + std::ofstream fout; + fout.open("epoll_data_stats_1000_TIMEOUT.csv"); + //the time is in milliseconds and the data in kbytes + fout << "buffer_size;time;total_received_data;\n"; + auto iter_sizes = sizes.begin(); + auto iter_times = times.begin(); + auto iter_data = tot_received_data.begin(); + + for ( ; (iter_sizes != sizes.end()) && (iter_times != times.end()) && (iter_data != tot_received_data.end()) ; (++iter_sizes, ++iter_times, ++iter_data) ) { + fout << *iter_sizes << ";" << *iter_times << ";" << *iter_data << ";\n"; + } + + fout.close(); + + if (close(epoll_fd)) { + printf("Failed to close epoll file descriptor"); + exit(EXIT_FAILURE); + } + + return 0; +} \ No newline at end of file diff --git a/testing/connection_method/event_builder_select.cxx b/testing/connection_method/event_builder_select.cxx new file mode 100644 index 0000000..b343853 --- /dev/null +++ b/testing/connection_method/event_builder_select.cxx @@ -0,0 +1,301 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + + +int makeSocket() { + int sockfd; + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + perror("socket failed"); + exit(EXIT_FAILURE); + } + return sockfd; +} + +void bindSocketPort(int server_fd, int port) { + struct sockaddr_in localAddr; + localAddr.sin_family = AF_INET; + localAddr.sin_addr.s_addr = INADDR_ANY; + localAddr.sin_port = htons(port); + + if (bind(server_fd, (struct sockaddr *)&localAddr, sizeof(localAddr)) < 0) { + perror("bind failed"); + exit(EXIT_FAILURE); + } + printf("FD %d bound to port %d\n", server_fd, port); +} + +void startListening(int server_fd) { + if (listen(server_fd, 1024) < 0) { + perror("listen"); + exit(EXIT_FAILURE); + } + printf("FD %d listening to new connections\n", server_fd); +} + +int acceptConnection(int server_fd) { + int client_fd; + struct sockaddr_in remoteAddr; + + size_t addrlen = sizeof(remoteAddr); + if ((client_fd = accept(server_fd, (struct sockaddr *)&remoteAddr, (socklen_t *)&addrlen)) < 0) { + perror("accept"); + exit(EXIT_FAILURE); + } else { + int flags = fcntl(client_fd, F_GETFL); + fcntl(client_fd, F_SETFL, flags | O_NONBLOCK); + } + printf("Connection from host %s, port %d, FD %d\n", inet_ntoa(remoteAddr.sin_addr), ntohs(remoteAddr.sin_port), client_fd); + return client_fd; +} + +void term_handler(int signal) { + printf("Terminated, received SIGNAL %d", signal); + exit(EXIT_SUCCESS); +} + +#define TRUE 1 +#define FALSE 0 + +int main(int argc, char const *argv[]) { + + signal(SIGTERM, term_handler); + + if (argc != 2) { + printf("Usage: %s portNumber \n", argv[0]); + exit(EXIT_FAILURE); + } + int port = atoi(argv[1]); + printf("Start socket port %d\n", port); + + int opt = TRUE; + int master_socket , addrlen , new_socket , client_socket[1024] , + max_clients = 1024 , activity, i , valread , sd; + int max_sd; + + //set of socket descriptors + fd_set readfds; + + //initialise all client_socket[] to 0 so not checked + for (i = 0; i < max_clients; i++) + { + client_socket[i] = 0; + } + + master_socket = makeSocket(); + + //set master socket to allow multiple connections , + //this is just a good habit, it will work without this + if( setsockopt(master_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, + sizeof(opt)) < 0 ) + { + perror("setsockopt"); + exit(EXIT_FAILURE); + } + + bindSocketPort(master_socket, port); + startListening(master_socket); + + int flags = fcntl(master_socket, F_GETFL, 0); + fcntl(master_socket, F_SETFL, flags | O_NONBLOCK); + + std::vector sizes; + std::vector tot_received_data; + std::vector times; + + int increment = 499; + + for (int kikko = 1; kikko < 1e6 + 1;) { + switch (kikko) { + case 500: + increment = 500; + break; + case (int) 1e3: + increment = 1e3; + break; + case (int) 5e3: + increment = 5e3; + break; + case (int) 1e4: + increment = 1e4; + break; + case (int) 5e4: + increment = 5e4; + break; + case (int) 1e5: + increment = 1e5; + break; + case (int) 5e5: + increment = 5e5; + break; + } + printf("Next increment %d with current i: %d\n", increment, kikko); + + uint64_t bytes_read = 0; + uint64_t kBytes_read = 0; + double total_time_taken = 0; + + while (true) { + auto start = std::chrono::high_resolution_clock::now(); + //clear the socket set + FD_ZERO(&readfds); + + //add master socket to set + FD_SET(master_socket, &readfds); + max_sd = master_socket; + + //add child sockets to set + for ( i = 0 ; i < max_clients ; i++) + { + //socket descriptor + sd = client_socket[i]; + + //if valid socket descriptor then add to read list + if(sd > 0) + FD_SET( sd , &readfds); + + //highest file descriptor number, need it for the select function + if(sd > max_sd) + max_sd = sd; + } + + //wait for an activity on one of the sockets , timeout is NULL , + //so wait indefinitely + activity = select( max_sd + 1 , &readfds , NULL , NULL , NULL); + + if ((activity < 0) && (errno!=EINTR)) + { + printf("select error"); + } + + //If something happened on the master socket , + //then its an incoming connection + if (FD_ISSET(master_socket, &readfds)) + { + new_socket = acceptConnection(master_socket); + + //add new socket to array of sockets + for (i = 0; i < max_clients; i++) + { + //if position is empty + if( client_socket[i] == 0 ) + { + client_socket[i] = new_socket; + printf("Adding to list of sockets as %d\n" , i); + + break; + } + } + } + + //else its some IO operation on some other socket + for (i = 0; i < max_clients; i++) + { + sd = client_socket[i]; + + if (FD_ISSET( sd , &readfds)) + { + //Check if it was for closing , and also read the + //incoming message + char buffer[kikko]; + /*if ((valread = recv( sd , &buffer, kikko, 0)) >= 0) + { + printf("[RICEVUTO]\t FROM %d valread: %d\n", sd, valread); + bytes_read += valread; + int kilos = 0; + if ((kilos = bytes_read / 1024) > 0) { + kBytes_read += kilos; + bytes_read -= (kilos * 1024); + //printf("reade bites %lu", bytes_read); + } + }*/ + + if ((valread = recv( sd , &buffer, kikko, 0)) == 0) + { + struct sockaddr_in address; + int addrlen; + //Somebody disconnected , get his details and print + getpeername(sd , (struct sockaddr*)&address , \ + (socklen_t*)&addrlen); + printf("Host disconnected , ip %s , port %d \n" , + inet_ntoa(address.sin_addr) , ntohs(address.sin_port)); + + printf("Disconnected fd %d", sd); + + //Close the socket and mark as 0 in list for reuse + close( sd ); + client_socket[i] = 0; + } + + //Echo back the message that came in + else + { + if (valread > 0) { + //printf("[RICEVUTO]\t FROM %d\n", sd); + bytes_read += valread; + int kilos = 0; + if ((kilos = bytes_read / 1024) > 0) { + kBytes_read += kilos; + bytes_read -= (kilos * 1024); + //printf("reade bites %lu", bytes_read); + } + } + } + } + } + + auto end = std::chrono::high_resolution_clock::now(); + double time_taken = std::chrono::duration_cast(end - start).count(); + //time taken in milliseconds + time_taken *= 1e-6; + total_time_taken += time_taken; + + if (total_time_taken > 3e4) { + times.push_back(total_time_taken); + sizes.push_back(kikko); + tot_received_data.push_back(kBytes_read); + break; + } + + //sleep(3); + + + } + + kikko += increment; + + } + + std::ofstream fout; + fout.open("select_data_stats_1000desc_NOBLOCK_TIMEOUT_HARD.csv"); + //the time is in milliseconds and the data in kbytes + fout << "buffer_size;time;total_received_data;\n"; + auto iter_sizes = sizes.begin(); + auto iter_times = times.begin(); + auto iter_data = tot_received_data.begin(); + + for ( ; (iter_sizes != sizes.end()) && (iter_times != times.end()) && (iter_data != tot_received_data.end()) ; (++iter_sizes, ++iter_times, ++iter_data) ) { + fout << *iter_sizes << ";" << *iter_times << ";" << *iter_data << ";\n"; + } + + fout.close(); + + + + return 0; +} \ No newline at end of file diff --git a/testing/connection_method/fragment_dataformat.h b/testing/connection_method/fragment_dataformat.h new file mode 100644 index 0000000..cbecd89 --- /dev/null +++ b/testing/connection_method/fragment_dataformat.h @@ -0,0 +1,56 @@ +#include +#include +#include + +#define START_OF_HEADER_MARKER 0xee1234ee + +typedef struct Header { + uint32_t startOfHeaderMarker = START_OF_HEADER_MARKER; + uint32_t headerSize; + uint32_t fragmentSize; + uint32_t sourceIdentifier; + uint32_t runNumber; + uint32_t detectorEventNumber; + uint32_t numberOfStatusElements; + uint32_t *statusElementsArray; + /*friend std::ostream& operator <<(std::ostream& os, Header const& header) + { + return os << std::setw(8) << std::setfill('0') << header.startOfHeaderMarker << '\n' + << std::setw(8) << std::setfill('0') << header.headerSize << '\n' + << std::setw(8) << std::setfill('0') << header.fragmentSize << '\n' + << std::setw(8) << std::setfill('0') << header.runNumber << '\n' + << std::setw(8) << std::setfill('0') << header.detectorEventNumber << '\n' + << std::setw(8) << std::setfill('0') << header.numberOfStatusElements << '\n'; + }*/ +} Header; + +typedef struct Fragment { + Header header; + uint32_t *payloadElements; +} Fragment; + +enum ERROR_CODES { + INCORRECT_ERROR = (1 << 0), + CORRUPTED_ERROR = (1 << 1), + MISSING_DATA_ERROR = (1 << 2), + TIMEOUT_ERROR = (1 << 3) +}; + +void encode_header(uint32_t *buffer, const Header &header) { + buffer[0] = header.startOfHeaderMarker; + buffer[1] = header.headerSize; + buffer[2] = header.fragmentSize; + buffer[3] = header.sourceIdentifier; + buffer[4] = header.runNumber; + buffer[5] = header.detectorEventNumber; + buffer[6] = header.numberOfStatusElements; + + std::memcpy(&buffer[7], header.statusElementsArray, header.numberOfStatusElements * sizeof(uint32_t)); +} + +void encode_fragment(uint32_t *buffer, const Fragment &fragment){ + encode_header(buffer, fragment.header); + std::memcpy(&buffer[fragment.header.headerSize], fragment.payloadElements, (fragment.header.fragmentSize - fragment.header.headerSize) * sizeof(uint32_t)); +} + + diff --git a/testing/connection_method/notes_on_connection_method.md b/testing/connection_method/notes_on_connection_method.md new file mode 100644 index 0000000..6dd19c6 --- /dev/null +++ b/testing/connection_method/notes_on_connection_method.md @@ -0,0 +1,46 @@ +# Important notes on why to use level triggered mode in this scenario +For monitoring multiple clients sending data frequently, you should generally use level-triggered mode with epoll() for simplicity and reliability. + +Level-Triggered Mode: In this mode, the epoll_wait() function returns whenever there is data available to read or write on a socket, as long as the socket remains ready. You use recv() or send() to read or write the data. This mode is more suitable for handling frequent data transmission, as the socket remains in the ready state until all available data is processed. + +Edge-Triggered Mode: In this mode, the epoll_wait() function returns only when the socket transitions from not ready to ready. You need to process data until EAGAIN is received, at which point you should exit the loop and re-register the socket with EPOLLONESHOT to be notified again when the socket becomes ready again. This mode requires more careful management, as you must handle the data until no more is available, and it can lead to more complex code. + +Given your description of continuous data transmission causing the application to hang in edge-triggered mode, and considering your preference for handling frequent data transmission, level-triggered mode seems like the better choice. It allows you to focus on processing data without worrying about handling the edge conditions and re-registering the socket. + +From a theoretical standpoint: + +Edge Triggered: This mode provides more fine-grained control and can potentially be more efficient, especially in scenarios where data arrival might be infrequent and you want to be notified only when there's a change in socket readiness. + +Level Triggered: This mode simplifies handling continuous data flow, as the socket remains in the ready state as long as data is available, which is often more suitable for high-frequency data streams. + +Ultimately, your choice should depend on the nature of your application and how you want to manage the data flow. While edge-triggered mode can be used with careful handling, level-triggered mode is generally simpler and more straightforward for frequent data transmission scenarios. + + + +Exactly, you've got it right! In scenarios where you need to read and buffer all available data for later processing, level-triggered mode is the better choice. It ensures that you'll be continuously notified as long as there's data available to read, allowing you to consume and buffer the data without worrying about missing any part of it. + +Level-triggered mode is particularly well-suited for scenarios where you want to handle data consumption and processing at your own pace, as the socket remains in the ready state as long as data is available, ensuring that you have the opportunity to read all available data before continuing with other tasks. + +So, for your specific use case of reading all the data available and buffering it for later use, level-triggered mode with epoll() is a solid choice. + +Yes, your approach of using one thread for epoll-based socket monitoring and another thread for data analysis using thread-safe queues is a valid and common way to handle this kind of scenario. Here's a high-level overview of how your setup would work: + +Epoll Thread: This thread will use epoll() with level-triggered mode to monitor multiple sockets for incoming data. Whenever data is available to read on a socket, the epoll thread can read the data and enqueue it into the thread-safe queue. + +Data Analysis Thread: This thread will be responsible for dequeuing the buffered data from the thread-safe queue and performing the necessary analysis on it. Since the queue is thread-safe, you won't have to worry about synchronization issues between the two threads. + +This separation of concerns allows you to isolate the low-level socket I/O and buffering logic from the data analysis logic, making your application more modular and maintainable. + +Keep in mind a few considerations: + +Concurrency: While using multiple threads can improve parallelism, it also introduces complexity. Ensure that you handle thread synchronization and communication properly to avoid race conditions or deadlocks. + +Resource Management: Manage your data buffers carefully to avoid excessive memory consumption, especially if data arrives rapidly. Consider setting limits on the size of your buffers and implementing buffer recycling mechanisms if needed. + +Thread Safety: Make sure the data analysis thread doesn't access or modify the same data buffers that the epoll thread is using. This is where your thread-safe queue comes in handy, as it provides a clean boundary between the two threads. + +Error Handling: Implement robust error handling mechanisms to gracefully handle unexpected situations, such as socket errors or issues with the thread-safe queue. + +Overall, your proposed approach seems reasonable and can be an effective way to achieve your goal of efficiently buffering data for later analysis while utilizing multi-threading for improved performance. + + diff --git a/testing/connection_method/prov.out b/testing/connection_method/prov.out new file mode 100755 index 0000000..026f9b2 Binary files /dev/null and b/testing/connection_method/prov.out differ diff --git a/testing/connection_method/provider.cxx b/testing/connection_method/provider.cxx new file mode 100644 index 0000000..fd08e57 --- /dev/null +++ b/testing/connection_method/provider.cxx @@ -0,0 +1,80 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +int makeSocket() { + int sockfd; + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + perror("socket failed"); + exit(EXIT_FAILURE); + } + return sockfd; +} + +void connectTo(int sock, const char* host, int port) { + struct sockaddr_in serv_addr; + serv_addr.sin_family = AF_INET; + serv_addr.sin_addr.s_addr = inet_addr(host); + serv_addr.sin_port = htons(port); + + if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { + perror("Connection failed"); + exit(EXIT_FAILURE); + } + + printf("Connected to %s: %d\n", host, port); +} + +int main(int argc, char* argv[]) { + + if (argc != 2) { + printf("Usage: ./prov.out timeout (ms)"); + exit(EXIT_FAILURE); + } + + int timeout = atoi(argv[1]); + //printf("Selected timeout: %f", static_cast(timeout) / 1000); + + int socket = makeSocket(); + connectTo(socket, "127.0.0.1", 7777); + + //allocating 100 megabytes of memory + uint64_t* chunky_boy = new uint64_t[67108]; + size_t chunky_boy_size = 67108 * sizeof(uint64_t); + printf("chonky size %d", static_cast(chunky_boy_size)); + + //setting memory to verify non-emptyness + memset(chunky_boy, 45678, chunky_boy_size); + + int buffer_size = 1024 * 32; + + + for ( ;;) { + + for ( int j = 0; j < chunky_boy_size; ) { + + ssize_t bytes = send(socket, reinterpret_cast(chunky_boy) + j, std::min(static_cast(chunky_boy_size) - j, buffer_size), 0); + if (timeout != 0) { + sleep(static_cast(timeout) / 1000); + } + j += buffer_size; + } + + } + + + return 0; +} \ No newline at end of file diff --git a/testing/connection_method/readme.txt b/testing/connection_method/readme.txt new file mode 100644 index 0000000..be42d79 --- /dev/null +++ b/testing/connection_method/readme.txt @@ -0,0 +1,17 @@ +this test wants to see how much data is possible to gather in 60 seconds with select and epoll. +For that reason, I'm removing the random time between provider data generation and send it asap. +I'll spawn 50 clients and let them connect and send data as fast as they can while I measure total received data on server side. +I'm ignoring all bottlenecks for now. All tests of this section are brought out on my local machine. + +EDIT: by default all clients allocate a massive 100 megabytes of space to send big chunks of data. +To test with a bigger number of descriptors (I'm making 100, 500, 1000, 5000, 10000) i'm lowering the chunk size as well as changing +the generation method of the data to send. +So trashing first result with 50 and re executing with all the different clien numbers. + + +since no big performance difference (as expected, since with all clients active also epoll has to iterate through everything since it gets notified from all), +retesting with timeout on majority of clients. files with *_TIMEOUT.csv have only 50 clients without timeout, files with *TIMEOUT_HARD.csv have only 2 clients. +The timeout is pretty hard, we're talking 1 second, to hilight the difference in performance. +With epoll we see a big rise in throughput with the 2 clients, since we kill cpu time for iteration and optimize the 30 seconds time analysis, +in the 50 clients it's not so evident. With 50 we start to see already big improvements with epoll vs select. + diff --git a/testing/connection_method/select_data_stats_1000desc_NOBLOCK_TIMEOUT.csv b/testing/connection_method/select_data_stats_1000desc_NOBLOCK_TIMEOUT.csv new file mode 100644 index 0000000..687919d --- /dev/null +++ b/testing/connection_method/select_data_stats_1000desc_NOBLOCK_TIMEOUT.csv @@ -0,0 +1,19 @@ +buffer_size;time;total_received_data; +1;30001;31734; +500;30000.3;5573836; +1000;30000;8694627; +2000;30000.1;14935890; +3000;30000.1;21792013; +4000;30000.1;24816724; +5000;30000.1;28805466; +10000;30000;46161885; +20000;30000.6;61985281; +30000;30000.9;60864280; +40000;30000.6;70116721; +50000;30000.4;79858909; +100000;30001.1;77035845; +200000;30001.2;98608909; +300000;30001.6;111016135; +400000;30002.2;109526878; +500000;30005.3;129750689; +1000000;30005;101069846; diff --git a/testing/connection_method/select_data_stats_1000desc_NOBLOCK_TIMEOUT_HARD.csv b/testing/connection_method/select_data_stats_1000desc_NOBLOCK_TIMEOUT_HARD.csv new file mode 100644 index 0000000..5ec6e0c --- /dev/null +++ b/testing/connection_method/select_data_stats_1000desc_NOBLOCK_TIMEOUT_HARD.csv @@ -0,0 +1,19 @@ +buffer_size;time;total_received_data; +1;30000.1;30805; +500;30000;1887572; +1000;30000;1390681; +2000;30000;1886540; +3000;30000;2337091; +4000;30000;2781395; +5000;30000;3236316; +10000;30000.1;5596495; +20000;30000;9857822; +30000;30000;13786084; +40000;30000.2;15183408; +50000;30000.5;16604221; +100000;30000.1;25196651; +200000;30000.2;44064204; +300000;30000;47852732; +400000;30000.4;51052155; +500000;30000.6;50078987; +1000000;30000.3;70992968; diff --git a/testing/connection_method/spawn_clients.sh b/testing/connection_method/spawn_clients.sh new file mode 100755 index 0000000..764566d --- /dev/null +++ b/testing/connection_method/spawn_clients.sh @@ -0,0 +1,15 @@ +#!/bin/bash +echo "Usage: $0 host port runNumber numberOfProviders" +if [ $# -eq 1 ] +then + for i in $(seq 1 $1); + do + echo "Spawning provider number $i" + if [ $i -le 2 ] + then + ./prov.out 0& + else + ./prov.out 1000& + fi + done +fi diff --git a/testing/results/select_data_stats.csv b/testing/results/select_data_stats.csv new file mode 100644 index 0000000..87929f3 --- /dev/null +++ b/testing/results/select_data_stats.csv @@ -0,0 +1,19 @@ +buffer_size;time;total_received_data; +500;30000;923066; +500;30000;1246851; +500;30000;1224399; +500;30000;1236942; +500;30000;1237006; +500;30000;1240083; +500;30000;1243543; +500;30000;1247446; +500;30000;1249498; +500;30000;1242588; +500;30000;1246731; +500;30000;1249731; +500;30000;1245551; +500;30000;1251264; +500;30000;1257202; +500;30000;1253106; +500;30000;1250601; +500;30000;1249947; diff --git a/testing/results/select_data_stats_1000desc_NOBLOCK.csv b/testing/results/select_data_stats_1000desc_NOBLOCK.csv new file mode 100644 index 0000000..95a44e7 --- /dev/null +++ b/testing/results/select_data_stats_1000desc_NOBLOCK.csv @@ -0,0 +1,19 @@ +buffer_size;time;total_received_data; +1;30000.5;30019; +500;30000.3;12629492; +1000;30003.2;20228484; +2000;30000.9;31157526; +3000;30000.5;38823216; +4000;30000.6;44107121; +5000;30000;45085442; +10000;30000.1;60564704; +20000;30001.2;72663492; +30000;30005.5;72002012; +40000;30000.2;77138855; +50000;30001.6;88049703; +100000;30005.6;101391654; +200000;30001.9;99283463; +300000;30014.1;91602483; +400000;30004.2;113396854; +500000;30008.1;112980666; +1000000;30015.8;105931378; diff --git a/testing/results/select_data_stats_100desc.csv b/testing/results/select_data_stats_100desc.csv new file mode 100644 index 0000000..ca62d71 --- /dev/null +++ b/testing/results/select_data_stats_100desc.csv @@ -0,0 +1,19 @@ +buffer_size;time;total_received_data; +1;30000;42850; +500;30000.1;15883661; +1000;30000;27186324; +2000;30000.2;41545982; +3000;30000.4;47881778; +4000;30004.2;54284932; +5000;30006.1;55478462; +10000;30000.1;95230218; +20000;30000.2;105701171; +30000;30000;103435546; +40000;30000.9;114492187; +50000;30000.7;112895507; +100000;30001;113681640; +200000;30000.6;113457031; +300000;30002.4;128701171; +400000;30002.3;129140625; +500000;30014.2;133642578; +1000000;30022;124511718; diff --git a/testing/results/select_data_stats_100desc_NOBLOCK.csv b/testing/results/select_data_stats_100desc_NOBLOCK.csv new file mode 100644 index 0000000..2338196 --- /dev/null +++ b/testing/results/select_data_stats_100desc_NOBLOCK.csv @@ -0,0 +1,19 @@ +buffer_size;time;total_received_data; +1;30000;39454; +500;30000.1;16157269; +1000;30000;27153432; +2000;30000.1;40100085; +3000;30000;48828124; +4000;30000.1;55680401; +5000;30000;61979270; +10000;30000.3;98380003; +20000;30000.1;106611328; +30000;30000.7;107302734; +40000;30000.2;101027343; +50000;30000;111542968; +100000;30001;102851562; +200000;30004.2;118359375; +300000;30003;122314453; +400000;30008.9;118750000; +500000;30009.5;118750000; +1000000;30020.8;117871093; diff --git a/testing/results/select_data_stats_500desc_NOBLOCK.csv b/testing/results/select_data_stats_500desc_NOBLOCK.csv new file mode 100644 index 0000000..c1af4f9 --- /dev/null +++ b/testing/results/select_data_stats_500desc_NOBLOCK.csv @@ -0,0 +1,19 @@ +buffer_size;time;total_received_data; +1;30000.2;31884; +500;30000.2;14397128; +1000;30000.4;23282151; +2000;30001;34224109; +3000;30000.5;42075605; +4000;30000;47592080; +5000;30000.5;50634489; +10000;30002.2;62469144; +20000;30013.4;65980444; +30000;30003.8;66720000; +40000;30005.9;74623936; +50000;30001.5;103636705; +100000;30002.9;111512675; +200000;30002.2;107186640; +300000;30013.8;111613113; +400000;30005.9;105724495; +500000;30008.1;106815424; +1000000;30037.6;108984396; diff --git a/testing/results/send_data_buffer.csv b/testing/results/send_data_buffer.csv new file mode 100644 index 0000000..02e6f9d --- /dev/null +++ b/testing/results/send_data_buffer.csv @@ -0,0 +1,1002 @@ +buffer_size;time; +1;87.9309; +1001;0.0893674; +2001;0.0592124; +3001;0.0485199; +4001;0.0492849; +5001;0.0398494; +6001;0.0364237; +7001;0.0358461; +8001;0.0383608; +9001;0.0338195; +10001;0.0324978; +11001;0.029857; +12001;0.0303058; +13001;0.0287335; +14001;0.0286668; +15001;0.0286333; +16001;0.0289975; +17001;0.0291874; +18001;0.0269786; +19001;0.0272858; +20001;0.0272955; +21001;0.0275356; +22001;0.0271853; +23001;0.0270467; +24001;0.0262923; +25001;0.0263059; +26001;0.0263216; +27001;0.0269245; +28001;0.026347; +29001;0.0262578; +30001;0.0256281; +31001;0.025248; +32001;0.0255907; +33001;0.0261745; +34001;0.0262026; +35001;0.0256409; +36001;0.0256219; +37001;0.0254912; +38001;0.026476; +39001;0.0262793; +40001;0.0251087; +41001;0.0246027; +42001;0.0257793; +43001;0.0248307; +44001;0.0309805; +45001;0.0303154; +46001;0.0254046; +47001;0.0248051; +48001;0.024884; +49001;0.0246509; +50001;0.0244738; +51001;0.0243873; +52001;0.0244064; +53001;0.024351; +54001;0.0241724; +55001;0.0240383; +56001;0.0240368; +57001;0.0241954; +58001;0.0246477; +59001;0.024407; +60001;0.0242947; +61001;0.024056; +62001;0.0250822; +63001;0.0240311; +64001;0.023674; +65001;0.0238547; +66001;0.0271549; +67001;0.0270472; +68001;0.027; +69001;0.0265107; +70001;0.0259204; +71001;0.0261101; +72001;0.0256541; +73001;0.0257699; +74001;0.0256938; +75001;0.0258904; +76001;0.0252955; +77001;0.025538; +78001;0.0249363; +79001;0.0261412; +80001;0.0250837; +81001;0.0247154; +82001;0.0245536; +83001;0.0243707; +84001;0.0318549; +85001;0.0264316; +86001;0.0250751; +87001;0.0242768; +88001;0.0243975; +89001;0.0240656; +90001;0.0239768; +91001;0.0240867; +92001;0.0242316; +93001;0.0240912; +94001;0.0242191; +95001;0.0241983; +96001;0.0244142; +97001;0.0241494; +98001;0.0239877; +99001;0.0249698; +100001;0.0250142; +101001;0.0243209; +102001;0.0241806; +103001;0.0237266; +104001;0.0249876; +105001;0.0240472; +106001;0.0243643; +107001;0.0238247; +108001;0.0239828; +109001;0.0240386; +110001;0.0242905; +111001;0.0241815; +112001;0.0237832; +113001;0.02404; +114001;0.0237891; +115001;0.0237028; +116001;0.0236344; +117001;0.0235514; +118001;0.0238168; +119001;0.0238106; +120001;0.0240809; +121001;0.0235752; +122001;0.0246327; +123001;0.024358; +124001;0.0239013; +125001;0.0282321; +126001;0.0240895; +127001;0.0256373; +128001;0.0243128; +129001;0.0234303; +130001;0.0235624; +131001;0.0241904; +132001;0.0245538; +133001;0.0242756; +134001;0.0242547; +135001;0.0248935; +136001;0.0247011; +137001;0.0241096; +138001;0.0240715; +139001;0.02397; +140001;0.0241387; +141001;0.0241085; +142001;0.0239715; +143001;0.025522; +144001;0.0245956; +145001;0.0241071; +146001;0.0238712; +147001;0.0245934; +148001;0.024231; +149001;0.0240329; +150001;0.0236885; +151001;0.0236899; +152001;0.0243104; +153001;0.0236414; +154001;0.0235434; +155001;0.0233067; +156001;0.0233362; +157001;0.0232659; +158001;0.0241406; +159001;0.0243417; +160001;0.0237077; +161001;0.0237777; +162001;0.0231811; +163001;0.023275; +164001;0.0233076; +165001;0.0270223; +166001;0.0317444; +167001;0.0300444; +168001;0.0298339; +169001;0.023872; +170001;0.0230265; +171001;0.0230668; +172001;0.0230516; +173001;0.0231017; +174001;0.0229901; +175001;0.0230306; +176001;0.02326; +177001;0.0236495; +178001;0.0226623; +179001;0.0229562; +180001;0.022766; +181001;0.0231187; +182001;0.0230433; +183001;0.0229115; +184001;0.0231073; +185001;0.0238701; +186001;0.0232845; +187001;0.0228816; +188001;0.0225595; +189001;0.0226804; +190001;0.0229255; +191001;0.0229101; +192001;0.0223701; +193001;0.0228701; +194001;0.0226946; +195001;0.0224592; +196001;0.0222653; +197001;0.0231463; +198001;0.0231337; +199001;0.0229255; +200001;0.0230521; +201001;0.0238793; +202001;0.0234556; +203001;0.0234274; +204001;0.0230482; +205001;0.0230609; +206001;0.0228007; +207001;0.0227871; +208001;0.0269512; +209001;0.0240393; +210001;0.0232556; +211001;0.0266479; +212001;0.0223081; +213001;0.0230049; +214001;0.0231418; +215001;0.0228633; +216001;0.0225202; +217001;0.022462; +218001;0.0227582; +219001;0.0236866; +220001;0.0231628; +221001;0.022768; +222001;0.0231355; +223001;0.0226859; +224001;0.0228791; +225001;0.0234715; +226001;0.0234475; +227001;0.0232228; +228001;0.0242492; +229001;0.0233657; +230001;0.0227931; +231001;0.0237369; +232001;0.0230075; +233001;0.0231535; +234001;0.0228516; +235001;0.0231846; +236001;0.0235808; +237001;0.0239794; +238001;0.0236266; +239001;0.0232983; +240001;0.0233774; +241001;0.0231651; +242001;0.0234513; +243001;0.0233445; +244001;0.0233017; +245001;0.0228586; +246001;0.0226534; +247001;0.0226128; +248001;0.0233934; +249001;0.023235; +250001;0.0240644; +251001;0.0310484; +252001;0.0230793; +253001;0.0231978; +254001;0.0225346; +255001;0.023456; +256001;0.0226809; +257001;0.0224949; +258001;0.0227302; +259001;0.0224099; +260001;0.0225742; +261001;0.0229879; +262001;0.0232294; +263001;0.0233269; +264001;0.0239077; +265001;0.0235496; +266001;0.0242001; +267001;0.0252571; +268001;0.0266083; +269001;0.0230584; +270001;0.0259026; +271001;0.0257846; +272001;0.0245431; +273001;0.0227111; +274001;0.0246467; +275001;0.0227772; +276001;0.022862; +277001;0.0224269; +278001;0.0224901; +279001;0.0225755; +280001;0.0225846; +281001;0.0227186; +282001;0.0224944; +283001;0.0225041; +284001;0.0227023; +285001;0.0225314; +286001;0.0228119; +287001;0.022768; +288001;0.0225812; +289001;0.022822; +290001;0.0223749; +291001;0.0226552; +292001;0.0228328; +293001;0.0225794; +294001;0.0336717; +295001;0.0240288; +296001;0.0228341; +297001;0.0237947; +298001;0.0225131; +299001;0.0230957; +300001;0.0225206; +301001;0.0224365; +302001;0.0225773; +303001;0.0226307; +304001;0.0227357; +305001;0.0223265; +306001;0.0228554; +307001;0.0225295; +308001;0.0225225; +309001;0.0228681; +310001;0.022989; +311001;0.0224278; +312001;0.0221478; +313001;0.0229368; +314001;0.023322; +315001;0.0227348; +316001;0.0232047; +317001;0.0227944; +318001;0.0227249; +319001;0.0225221; +320001;0.0231017; +321001;0.0220686; +322001;0.0222504; +323001;0.0226075; +324001;0.0222205; +325001;0.0226022; +326001;0.0224075; +327001;0.022525; +328001;0.0229188; +329001;0.0230906; +330001;0.0228088; +331001;0.0227268; +332001;0.0223918; +333001;0.0222266; +334001;0.0225657; +335001;0.0221627; +336001;0.0225003; +337001;0.0274659; +338001;0.026358; +339001;0.0231524; +340001;0.0229482; +341001;0.0224009; +342001;0.0230508; +343001;0.0227174; +344001;0.0227713; +345001;0.0226705; +346001;0.0228278; +347001;0.0227144; +348001;0.0225916; +349001;0.022924; +350001;0.0224489; +351001;0.022639; +352001;0.0229176; +353001;0.0226594; +354001;0.0224836; +355001;0.023016; +356001;0.0229625; +357001;0.0226725; +358001;0.0226642; +359001;0.0280504; +360001;0.0225366; +361001;0.0228499; +362001;0.0226178; +363001;0.0225407; +364001;0.0227772; +365001;0.022831; +366001;0.022725; +367001;0.0231848; +368001;0.0227016; +369001;0.0227749; +370001;0.0229231; +371001;0.022822; +372001;0.0227222; +373001;0.0231706; +374001;0.0227175; +375001;0.0227662; +376001;0.0221507; +377001;0.0224125; +378001;0.0225799; +379001;0.0228059; +380001;0.0235026; +381001;0.0255627; +382001;0.0227134; +383001;0.0232084; +384001;0.0226941; +385001;0.0221407; +386001;0.0223515; +387001;0.0219755; +388001;0.0220367; +389001;0.0220471; +390001;0.02206; +391001;0.0221862; +392001;0.0226857; +393001;0.0233221; +394001;0.0227577; +395001;0.0227514; +396001;0.0224452; +397001;0.0227495; +398001;0.0226097; +399001;0.0225138; +400001;0.0226469; +401001;0.0230569; +402001;0.0230445; +403001;0.0227406; +404001;0.0225299; +405001;0.0225647; +406001;0.0226751; +407001;0.0224497; +408001;0.0226778; +409001;0.0231452; +410001;0.0232906; +411001;0.0226691; +412001;0.0224087; +413001;0.0222702; +414001;0.0223742; +415001;0.0223759; +416001;0.0223235; +417001;0.0238031; +418001;0.0227239; +419001;0.0230108; +420001;0.0223778; +421001;0.0224506; +422001;0.0229636; +423001;0.022453; +424001;0.0247029; +425001;0.0266976; +426001;0.022425; +427001;0.0229008; +428001;0.0235711; +429001;0.0226269; +430001;0.0229804; +431001;0.0224728; +432001;0.0231492; +433001;0.0226238; +434001;0.0229454; +435001;0.0241565; +436001;0.0224319; +437001;0.0223036; +438001;0.022129; +439001;0.0220859; +440001;0.0224576; +441001;0.0227831; +442001;0.0226095; +443001;0.0227178; +444001;0.0231957; +445001;0.0231646; +446001;0.0227077; +447001;0.0225751; +448001;0.0223295; +449001;0.0229455; +450001;0.0228923; +451001;0.0221001; +452001;0.0226955; +453001;0.022723; +454001;0.0230543; +455001;0.0223779; +456001;0.0223631; +457001;0.0224204; +458001;0.0221805; +459001;0.022366; +460001;0.0227756; +461001;0.0235864; +462001;0.0228129; +463001;0.0234018; +464001;0.0231589; +465001;0.0233169; +466001;0.0300256; +467001;0.0297606; +468001;0.0324181; +469001;0.0268155; +470001;0.0222947; +471001;0.0231378; +472001;0.0224023; +473001;0.0231357; +474001;0.0231769; +475001;0.0223527; +476001;0.0224051; +477001;0.0241708; +478001;0.0227043; +479001;0.0225136; +480001;0.0223518; +481001;0.0230181; +482001;0.0223465; +483001;0.0223663; +484001;0.022445; +485001;0.0225387; +486001;0.0224345; +487001;0.0222781; +488001;0.0225332; +489001;0.0224554; +490001;0.02259; +491001;0.0223899; +492001;0.0228556; +493001;0.0220565; +494001;0.0226053; +495001;0.022933; +496001;0.0228009; +497001;0.0229762; +498001;0.023217; +499001;0.0223987; +500001;0.0226558; +501001;0.0228521; +502001;0.0225329; +503001;0.0229601; +504001;0.0226378; +505001;0.0225173; +506001;0.0223298; +507001;0.0221176; +508001;0.0228906; +509001;0.0221277; +510001;0.0223585; +511001;0.0285635; +512001;0.0232667; +513001;0.0227028; +514001;0.0225205; +515001;0.022351; +516001;0.0227781; +517001;0.0228956; +518001;0.0221618; +519001;0.0227025; +520001;0.0225109; +521001;0.0226041; +522001;0.0224779; +523001;0.0229535; +524001;0.0231055; +525001;0.0231023; +526001;0.0230971; +527001;0.0227653; +528001;0.0225899; +529001;0.0228139; +530001;0.0225741; +531001;0.0225675; +532001;0.0224928; +533001;0.0228587; +534001;0.0235146; +535001;0.022638; +536001;0.0225505; +537001;0.02272; +538001;0.0230663; +539001;0.0221058; +540001;0.0226197; +541001;0.0222531; +542001;0.0224409; +543001;0.0221372; +544001;0.0220763; +545001;0.0219029; +546001;0.0218145; +547001;0.0230213; +548001;0.0223103; +549001;0.022924; +550001;0.0227968; +551001;0.0225934; +552001;0.0232563; +553001;0.0225338; +554001;0.0224367; +555001;0.0353894; +556001;0.0283072; +557001;0.0226526; +558001;0.0223418; +559001;0.0223055; +560001;0.0222988; +561001;0.0224108; +562001;0.0222341; +563001;0.0224038; +564001;0.022094; +565001;0.0224535; +566001;0.0229574; +567001;0.0224166; +568001;0.0222865; +569001;0.0226506; +570001;0.0228621; +571001;0.0226119; +572001;0.0225331; +573001;0.0228573; +574001;0.0226151; +575001;0.022173; +576001;0.0220541; +577001;0.0221678; +578001;0.0225851; +579001;0.0234255; +580001;0.0222539; +581001;0.0225564; +582001;0.0230003; +583001;0.0226046; +584001;0.0222902; +585001;0.0219483; +586001;0.0223866; +587001;0.0223483; +588001;0.0221648; +589001;0.0224664; +590001;0.022354; +591001;0.0224962; +592001;0.0229969; +593001;0.0227603; +594001;0.0226076; +595001;0.022746; +596001;0.022914; +597001;0.0227682; +598001;0.0263089; +599001;0.0384467; +600001;0.0452436; +601001;0.03369; +602001;0.0265427; +603001;0.0224858; +604001;0.0224858; +605001;0.0222874; +606001;0.022456; +607001;0.0227506; +608001;0.0226439; +609001;0.0229784; +610001;0.0225925; +611001;0.0225326; +612001;0.0226349; +613001;0.0222811; +614001;0.0233497; +615001;0.0224987; +616001;0.0222687; +617001;0.022276; +618001;0.0224251; +619001;0.0223269; +620001;0.022315; +621001;0.0221377; +622001;0.0225193; +623001;0.0230752; +624001;0.0222825; +625001;0.0228613; +626001;0.0232574; +627001;0.022166; +628001;0.0222827; +629001;0.0222186; +630001;0.022567; +631001;0.0223198; +632001;0.0225445; +633001;0.0225993; +634001;0.0222097; +635001;0.0226038; +636001;0.0223565; +637001;0.022456; +638001;0.0221313; +639001;0.0225177; +640001;0.0270195; +641001;0.0304029; +642001;0.0257649; +643001;0.0241; +644001;0.0228717; +645001;0.0236946; +646001;0.0231014; +647001;0.0222795; +648001;0.0221882; +649001;0.0222607; +650001;0.0230042; +651001;0.0225098; +652001;0.0223156; +653001;0.0222486; +654001;0.0222203; +655001;0.0224661; +656001;0.0224029; +657001;0.0224112; +658001;0.0224432; +659001;0.0222946; +660001;0.0220242; +661001;0.0220141; +662001;0.0220229; +663001;0.0236717; +664001;0.022496; +665001;0.0224295; +666001;0.0223816; +667001;0.0222687; +668001;0.0224665; +669001;0.0221735; +670001;0.0225723; +671001;0.0222699; +672001;0.0223011; +673001;0.0222041; +674001;0.0223319; +675001;0.0222887; +676001;0.0224369; +677001;0.0224938; +678001;0.0228104; +679001;0.0229449; +680001;0.0227725; +681001;0.022588; +682001;0.0218226; +683001;0.0223417; +684001;0.0278192; +685001;0.0223689; +686001;0.0231111; +687001;0.0221952; +688001;0.0219974; +689001;0.0224429; +690001;0.022043; +691001;0.0223436; +692001;0.0226612; +693001;0.0332736; +694001;0.0344241; +695001;0.0281001; +696001;0.0475276; +697001;0.0308036; +698001;0.0290694; +699001;0.0303032; +700001;0.0251934; +701001;0.0227253; +702001;0.0225041; +703001;0.0227503; +704001;0.022342; +705001;0.0222145; +706001;0.0227158; +707001;0.0221233; +708001;0.0221964; +709001;0.0227296; +710001;0.0225054; +711001;0.0226487; +712001;0.0222905; +713001;0.0220439; +714001;0.0221234; +715001;0.022467; +716001;0.0222865; +717001;0.0224083; +718001;0.0218199; +719001;0.0222023; +720001;0.0221602; +721001;0.0221426; +722001;0.0222971; +723001;0.0220251; +724001;0.0221756; +725001;0.0285089; +726001;0.0225117; +727001;0.022425; +728001;0.0222723; +729001;0.0224023; +730001;0.0220781; +731001;0.0231521; +732001;0.0224913; +733001;0.0225258; +734001;0.022069; +735001;0.0230937; +736001;0.0281795; +737001;0.0227507; +738001;0.022381; +739001;0.0225612; +740001;0.0225574; +741001;0.0223113; +742001;0.0221363; +743001;0.0221314; +744001;0.022263; +745001;0.0225503; +746001;0.0226254; +747001;0.0222772; +748001;0.0225618; +749001;0.0227657; +750001;0.0224613; +751001;0.0222523; +752001;0.0218394; +753001;0.0222981; +754001;0.0217209; +755001;0.0229854; +756001;0.0222012; +757001;0.0224878; +758001;0.0224772; +759001;0.0222272; +760001;0.0218207; +761001;0.0232462; +762001;0.0227002; +763001;0.0219143; +764001;0.0225294; +765001;0.0226706; +766001;0.0225198; +767001;0.02266; +768001;0.0229902; +769001;0.0282163; +770001;0.0228647; +771001;0.0235029; +772001;0.022955; +773001;0.0223613; +774001;0.0227221; +775001;0.0224679; +776001;0.0225225; +777001;0.0226193; +778001;0.0224712; +779001;0.0228175; +780001;0.0227752; +781001;0.0229278; +782001;0.0223948; +783001;0.0227701; +784001;0.0221642; +785001;0.0225209; +786001;0.0227461; +787001;0.0226259; +788001;0.0226667; +789001;0.023102; +790001;0.0229719; +791001;0.0228435; +792001;0.0233381; +793001;0.0231936; +794001;0.0227471; +795001;0.0233563; +796001;0.0231775; +797001;0.0232941; +798001;0.0228844; +799001;0.02271; +800001;0.0228228; +801001;0.0226824; +802001;0.0221153; +803001;0.0224021; +804001;0.022659; +805001;0.0229164; +806001;0.022683; +807001;0.0224686; +808001;0.0223118; +809001;0.0225093; +810001;0.0223637; +811001;0.0226952; +812001;0.0251404; +813001;0.0274033; +814001;0.0224656; +815001;0.0229684; +816001;0.0227023; +817001;0.0243674; +818001;0.0230157; +819001;0.0223948; +820001;0.0223791; +821001;0.0223386; +822001;0.0229251; +823001;0.0231487; +824001;0.0226125; +825001;0.0227636; +826001;0.0226505; +827001;0.0221704; +828001;0.0219071; +829001;0.0224045; +830001;0.0224254; +831001;0.0221653; +832001;0.0226684; +833001;0.0225827; +834001;0.0225674; +835001;0.0221277; +836001;0.0222189; +837001;0.0218636; +838001;0.0220255; +839001;0.0216752; +840001;0.0220424; +841001;0.0223153; +842001;0.0220502; +843001;0.0222888; +844001;0.0223842; +845001;0.0223718; +846001;0.0223306; +847001;0.0223855; +848001;0.0223165; +849001;0.0238207; +850001;0.0226931; +851001;0.0222099; +852001;0.0224241; +853001;0.0224394; +854001;0.0222189; +855001;0.0219746; +856001;0.0350116; +857001;0.028005; +858001;0.0234783; +859001;0.0228089; +860001;0.0236031; +861001;0.0237798; +862001;0.0237001; +863001;0.0230194; +864001;0.022966; +865001;0.0233031; +866001;0.0233671; +867001;0.0229765; +868001;0.0222069; +869001;0.0225774; +870001;0.0222305; +871001;0.0220432; +872001;0.0227716; +873001;0.0225356; +874001;0.0224928; +875001;0.0220348; +876001;0.0225574; +877001;0.0226006; +878001;0.0261645; +879001;0.0221714; +880001;0.0222906; +881001;0.0221378; +882001;0.0223634; +883001;0.0293881; +884001;0.0225705; +885001;0.0222922; +886001;0.0223651; +887001;0.022484; +888001;0.0224685; +889001;0.0231379; +890001;0.0226749; +891001;0.0226601; +892001;0.0228082; +893001;0.0223149; +894001;0.0224184; +895001;0.0223675; +896001;0.022099; +897001;0.0223337; +898001;0.0227934; +899001;0.0256687; +900001;0.024356; +901001;0.0230691; +902001;0.0225954; +903001;0.0226281; +904001;0.022547; +905001;0.0222503; +906001;0.0227845; +907001;0.0232737; +908001;0.0225957; +909001;0.0224548; +910001;0.0284866; +911001;0.0224852; +912001;0.0219689; +913001;0.02247; +914001;0.0223789; +915001;0.0223245; +916001;0.0224082; +917001;0.0222221; +918001;0.0223718; +919001;0.0230577; +920001;0.0227464; +921001;0.0226724; +922001;0.0223465; +923001;0.0218772; +924001;0.0221017; +925001;0.0220882; +926001;0.0224033; +927001;0.0231403; +928001;0.021777; +929001;0.0218871; +930001;0.022978; +931001;0.0298374; +932001;0.0218594; +933001;0.0217164; +934001;0.0216996; +935001;0.0221743; +936001;0.021958; +937001;0.0216807; +938001;0.0221103; +939001;0.0217634; +940001;0.0216869; +941001;0.0220972; +942001;0.0215014; +943001;0.0263714; +944001;0.0289717; +945001;0.0218618; +946001;0.0216347; +947001;0.0245289; +948001;0.0287891; +949001;0.0292987; +950001;0.0299392; +951001;0.0297075; +952001;0.0300344; +953001;0.0293254; +954001;0.029154; +955001;0.0295389; +956001;0.0291967; +957001;0.0295022; +958001;0.0247234; +959001;0.0224954; +960001;0.0218175; +961001;0.0219593; +962001;0.022105; +963001;0.0225716; +964001;0.0220293; +965001;0.0218136; +966001;0.0218288; +967001;0.0223044; +968001;0.0221713; +969001;0.0220735; +970001;0.0218105; +971001;0.021904; +972001;0.0271583; +973001;0.0228952; +974001;0.0231112; +975001;0.0224962; +976001;0.0223215; +977001;0.0228982; +978001;0.0223205; +979001;0.0222691; +980001;0.0223038; +981001;0.0226408; +982001;0.0222032; +983001;0.0224058; +984001;0.028874; +985001;0.0302751; +986001;0.0242848; +987001;0.0226021; +988001;0.0228134; +989001;0.0226849; +990001;0.0224208; +991001;0.0226547; +992001;0.0219944; +993001;0.0225453; +994001;0.0221217; +995001;0.023027; +996001;0.0224441; +997001;0.0230408; +998001;0.0228266; +999001;0.0227225; +1000001;0.0226352;