I'd like to use nanomsg as bus-system. So I tried to code a performance test and testing it by using two PCs.
At first I wrote an server, which connects to the other server:
#include <nanomsg/nn.h>
#include <nanomsg/bus.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
int main(int argc, char *argv[]) {
if (argc == 2) {
int socket = nn_socket (AF_SP_RAW, NN_BUS);
assert(nn_bind (socket, "tcp://*:27384") != -1);
assert(nn_connect (socket, argv[1]) != -1);
assert(nn_device(socket, -1) != -1);
nn_close(socket);
}
}
In my case I run these commands as:
On the first PC:./server tcp://192.168.1.11:27384
On the second PC:./server tcp://192.168.1.241:27384
They are connected, to prove it, I used nanocat and connected it locally to the server:
On the first PC:
nanocat --bus --connect tcp://127.0.0.1:27384 --data foo --interval 1 --ascii
On the second PC:
nanocat --bus --connect tcp://127.0.0.1:27384 --data bar --interval 1 --ascii
On the first PC, I received a 'bar' every second, on the second PC a 'foo', also every second.
So I wrote now the receiver.
#include <nanomsg/nn.h>
#include <nanomsg/bus.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
int main(int argc, char *argv[]) {
int socket = nn_socket (AF_SP, NN_BUS);
assert(nn_connect (socket, "tcp://127.0.0.1:27384") != -1);
sleep(1);
unsigned char buffer[4096];
while(1) {
int n = nn_recv(socket, buffer, 4096, 0);
if (n > 0) {
nn_send(socket, buffer, strlen(buffer), 0);
}
}
nn_close(socket);
}
It receives a message and sends it back.
Then I wrote the sender:
#include <nanomsg/nn.h>
#include <nanomsg/bus.h>
#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include <string.h>
#define NANO_PER_SEC 1000000000.0
int main(int argc, char *argv[]) {
int socket = nn_socket (AF_SP, NN_BUS);
nn_connect (socket, "tcp://127.0.0.1:27384");
sleep(1);
unsigned char buffer[4096];
int i = 0;
for (i = 0; i < 1024; i++) {
buffer[i] = 'a';
}
buffer[i] = '\0';
struct timespec start, end;
double start_sec, end_sec, elapsed_sec;
double average;
double m[4096];
for (i = 0; i < 4096; i++) {
clock_gettime(CLOCK_REALTIME, &start);
int ns = nn_send(socket, buffer, strlen(buffer), 0);
int nr = nn_recv(socket, buffer, 4096, 0);
clock_gettime(CLOCK_REALTIME, &end);
start_sec = start.tv_sec + start.tv_nsec/NANO_PER_SEC;
end_sec = end.tv_sec + end.tv_nsec/NANO_PER_SEC;
m[i] = end_sec - start_sec;
}
elapsed_sec = 0.0;
for (i = 0; i < 4096; i++) {
elapsed_sec = elapsed_sec + m[i];
}
average = (elapsed_sec / 4096.0) * 1000000.0;
printf("Average: %.3f micros\nWhole: %.12f seconds\n", average, elapsed_sec);
nn_close(socket);
}
The sender transmits 4096 times 1kbyte to the receiver and measures the time,
so I get the whole time and the average time.
At first I test it at only one PC locally, in three opened bash-terminals.
First terminal:./server tcp://192.168.1.11:27384
Second terminal:./receiver
Third terminal:./sender
So, I got from the "sender" programme this output:
Average: 60.386 micros
Whole: 0.247341632843 seconds
Then I tried to run this:
On first PC:
./server tcp://192.168.1.11:27384
./receiver
On second PC:
./server tcp://192.168.1.241:27384
./sender
But it stucks, the first PC running the "receiver" doesn't receive any message from the second PC, which runs the "sender". I don't get it whats wrong, because with nanocat it works fine.
Can somebody please help me?
Related
This is a short version of my code: I have a 64 bit fedora 21 on which the code works fine. However on my other 32bit machine on which I have installed ubuntu Kylin 16.04 32 bit version, poll does not return when text is entered on stdin, it just stays blocked. When I hit Ctrl-C in gdb after the text is entered, and then try executing next command it works... Is this a bug of ubuntu 32 bit version or I have to use poll differently on 32 bit version?
#include <sys/ioctl.h>
#include <sys/poll.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int
main(int argc, char **argv)
{
int sockfd;
int const myOPEN_MAX=100,MAXLINE=4096;
struct pollfd client[myOPEN_MAX];
int maxi,nready,n;
char buf[4096];
client[0].fd = fileno(stdin);
client[0].events = POLLRDNORM;
for (int i = 1; i < myOPEN_MAX; i++){
client[i].fd = -1; /* -1 indicates available entry */
}
maxi = 1; /* max index into client[] array */
printf("enter something\n");
for ( ; ; ) {
nready = poll(client, maxi+1, -1);
for (int i = 0; i <= maxi; i++) { /* check all clients for data */
if ( (sockfd = client[i].fd) < 0)
continue;
if (client[i].revents & (POLLRDNORM | POLLERR)) {
if ( (n = read(sockfd, buf, MAXLINE)) > 0) {
if (i == 0) { //stdin
printf("works\n");
return 0;
}
if (--nready <= 0)
break; /* no more readable descriptors */
}
}
}
}
return 0;
}
I have the following code for my education socket server in C.
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
double get_wall_time()
{
struct timeval time;
if (gettimeofday(&time, NULL)){
return 0;
}
return (double)time.tv_sec + (double)time.tv_usec * 0.000001;
}
double get_cpu_time()
{
return (double)clock() / CLOCKS_PER_SEC;
}
int main()
{
double wall = get_wall_time();
double cpu = get_cpu_time();
int sfd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in own_addr = {0};
own_addr.sin_family = AF_INET;
own_addr.sin_port = htons(5678);
bind(sfd, (struct sockaddr *)&own_addr, sizeof(own_addr));
listen(sfd, 5);
static char message[] = "hello from server\n";
double wall_accept = 0;
double cpu_accept = 0;
int count = 0;
while (1) {
if (count++ == 1000) {
break;
}
double wall_start = get_wall_time();
double cpu_start = get_cpu_time();
int client_sfd = accept(sfd, NULL, NULL);
wall_accept += get_wall_time() - wall_start;
cpu_accept += get_cpu_time() - cpu_start;
send(client_sfd, message, sizeof(message), 0);
close(client_sfd);
}
wall = get_wall_time() - wall;
cpu = get_cpu_time() - cpu;
printf("wall accept: %lf\n", wall_accept);
printf("cpu accept: %lf\n", cpu_accept);
printf("wall: %lf\n", wall);
printf("cpu: %lf\n", cpu);
}
To test I use seq 1000 | time parallel -j 1 -n0 'nc 127.0.0.1 5678' | wc -l with results
wall accept: 6.436480
cpu accept: 0.010000
wall: 6.456266
cpu: 0.020000
For 10000 requests result is
wall accept: 55.434541
cpu accept: 0.080000
wall: 55.633679
cpu: 0.260000
Is accept() slow or I do something wrong? Or maybe this is normal result for single-thread implementation?
UPD. I also wrote a server with pthreads to send a message in different thread.
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>
#include <sys/time.h>
double get_wall_time()
{
struct timeval time;
if (gettimeofday(&time, NULL)){
return 0;
}
return (double)time.tv_sec + (double)time.tv_usec * 0.000001;
}
double get_cpu_time()
{
return (double)clock() / CLOCKS_PER_SEC;
}
void *send_message(void *pclient_sfd)
{
int client_sfd = *(int *)pclient_sfd;
free(pclient_sfd);
static char message[] = "hello from server\n";
send(client_sfd, message, sizeof(message), 0);
close(client_sfd);
return NULL;
}
int main()
{
double wall = get_wall_time();
double cpu = get_cpu_time();
int sfd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in own_addr = {0};
own_addr.sin_family = AF_INET;
own_addr.sin_port = htons(5678);
bind(sfd, (struct sockaddr *)&own_addr, sizeof(own_addr));
listen(sfd, 5);
double wall_accept = 0;
double cpu_accept = 0;
int count = 0;
while (1) {
if (count++ == 10000) {
break;
}
int *pclient_sfd = malloc(sizeof(*pclient_sfd));
double wall_start = get_wall_time();
double cpu_start = get_cpu_time();
*pclient_sfd = accept(sfd, NULL, NULL);
wall_accept += get_wall_time() - wall_start;
cpu_accept += get_cpu_time() - cpu_start;
pthread_t tid;
pthread_create(&tid, NULL, send_message, (void *)pclient_sfd);
}
wall = get_wall_time() - wall;
cpu = get_cpu_time() - cpu;
printf("wall accept: %lf\n", wall_accept);
printf("cpu accept: %lf\n", cpu_accept);
printf("wall: %lf\n", wall);
printf("cpu: %lf\n", cpu);
return 0;
}
Then I use seq 10000 | time parallel -j 4 -n0 'nc 127.0.0.1 5678' | wc -l and it takes 58 seconds.
It's the way you're testing it. When you use this
seq 10000 | time parallel -j 4 -n0 'nc 127.0.0.1 5678' | wc -l
That's actually going to impact the test because you're spawning lots of processes etc ie you're not actually testing the C application your testing the ability to spawn processes.
If we change this to a simple python script ie
#!/usr/bin/env python
import socket
TCP_IP = '127.0.0.1'
TCP_PORT = 5678
BUFFER_SIZE = 1024
msg = "1"
for i in range(0, 1000):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((TCP_IP, TCP_PORT))
s.send(msg.encode('utf-8'))
data = s.recv(BUFFER_SIZE)
s.close()
print("received data: %s" % data)
and run the test the results are vastly different.
real 0m0.269s
user 0m0.074s
sys 0m0.114s
If you really want to test this and see how fast it is you need to use separate machines etc and typically you might need to use C or your limiting factor might be the client. The best tool I've seen for this (HTTP Specific) where you might find some good code is wrk
https://github.com/wg/wrk
Take a look at your listen() second argument. Try to increase it.
here is text from man 2 listen
The backlog argument defines the maximum length to which the queue of
pending connections for sockfd may grow. If a connection request
arrives when the queue is full, the client may receive an error with
an indication of ECONNREFUSED or, if the underlying protocol supports
retransmission, the request may be ignored so that a later reattempt
at connection succeeds.
I write a test program as follows:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/msg.h>
#include <time.h>
#define PACKET_SIZE 500
#define LOOP_COUNT 30000
int g_sndsucc = 0;
int g_sndfail = 0;
const int C_IPC_KEY = 0x00231a95;
const int COUNT_SIZE = 10000;
unsigned long g_count = 0;
unsigned long g_t1 = 0;
struct timeval s1, s2, s3, s4;
int main(int argc, char* argv[])
{
int ipckey = C_IPC_KEY;
if(argc > 1)
{
ipckey = atoi(argv[1]);
printf("ipckey is %d\n", ipckey);
}
int qid = msgget(ipckey, IPC_CREAT | 0666);
if(qid <= 0)
{
printf("msgget err: %d \n", errno);
return 0;
}
char data[PACKET_SIZE];
memset(data, 'a', PACKET_SIZE-1);
data[PACKET_SIZE-1] = '\0';
*((long *)data) = 0;
int ret = 0;
struct timeval start;
gettimeofday (&start, NULL);
while(1)
{
*((long *)data) +=1;
gettimeofday (&s1, NULL);
ret = msgsnd(qid, data, PACKET_SIZE,0);
gettimeofday (&s2, NULL);
if(ret != 0)
{
g_sndfail ++;
}
else
{
g_sndsucc ++;
}
g_count++;
g_t1 += (s2.tv_sec-s1.tv_sec)*1000000 + (s2.tv_usec-s1.tv_usec);
if ( g_count >= 10000)
{
printf("STAT1: t1 : %f\n",
10000000000.0 / g_t1);
g_count = 0;
g_t1 = 0;
}
usleep(1000);
}
return 0;
}
I create 100 same processes to msgsnd , and on suse, each process's msgsnd tps only reaches 50/s.
But on AIX5 the msgsnd tps can reaches 10000/s.
Does anyone know why the performance of IPC on linux when multi-processes is so poor?
And how to increase the performance on linux??
BTW, the kenel version of suse is linux 3.0.13
I checked the source code of the msgget in linux3.8.
When the thread did not get the msg lock, it is not release cpu and sleep some time.
Instead it will call ipc_lock_by_ptr(&msq->q_perm); frequently.
So the cpu usage will be very high, and the collision rate will grow rapidly when the threads increas.
How can I calculate or estimate the RTT (Round Trip Time) between client and server?
A tutorial or sample addressing this can also help.
Here what I do:
#include <rpc/rpc.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/times.h>
#include <fcntl.h>
#include <time.h>
int main(int argc, char *argv[]) {
enum clnt_stat status;
CLIENT *handle;
struct timeval t;
clock_t rtime;
struct tms dumm;
int count = 100000;
int i;
time_t now;
char stamp[27];
int programm;
int version;
if (argc != 4) {
printf("Usage: rpcping <host> <program> <version>\n");
exit(1);
}
/*
* Create Client Handle
*/
programm = atoi(argv[2]);
version = atoi(argv[3]);
handle = clnt_create(argv[1], programm, version, "tcp");
if (handle == NULL) {
printf("clnt failed\n");
exit(1);
}
/*
* use 30 seconds timeout
*/
t.tv_sec = 30;
t.tv_usec = 0;
while (1) {
rtime = times(&dumm);
for (i = 0; i < count; i++) {
status = clnt_call(handle, 0, (xdrproc_t) xdr_void,
NULL, (xdrproc_t) xdr_void, NULL, t);
if (status == RPC_SUCCESS) { /* NOP */ }
}
now = time(NULL);
ctime_r(&now, stamp);
stamp[strlen(stamp) - 1] = '\0';
fprintf(stdout, "[%s]: Speed: %2.4fs.\n", stamp,
count / ((double) (times(&dumm) - rtime) / (double) sysconf(_SC_CLK_TCK)));
fflush(stdout);
}
clnt_destroy(handle);
}
I have a multithread version as well
https://gist.github.com/2401404
tigran.
need some advice on this one as im struggling abit and cannot figure it out.
i have a file that gets updated on a PC to indicate a system ran and what time it ran. i am writing a very simple linux console app (will eventually be a nagios plugin). that reads this file and responds depending on what it found within the file.
i am a total newbie to programming on Linux and using C so please be patient and if you would explain any answers it would really be appreciated.
basically i want to convert a char array containing 5 characters into an integer, however the 5th char in the array is always a letter. so technically all i want to-do is convert the first 4 chars in the array to a integer... how?? ive tried multiple ways with no success, my problem is that presently i do not have a good grasp of the language so have no real ideas on what it can and cannot do.
here is the source to my program.
basically the buf array will be holding a string taken from the file that will look something like this
3455Y (the number will be random but always 4 chars long).
Sorry for the poor formatting of the code, but i cannot get this stupid window for love nor money to format it correctly....
include <fcntl.h>
include <unistd.h>
include <stdio.h>
include <stdlib.h>
include <time.h>
include <string.h>
define COPYMODE 0644
int main(int argc, char *argv[])
{
int i, nRead, fd;
int source;
int STATE_OK = 0;
int STATE_WARNING = 1;
int STATE_CRITICAL = 2;
int STATE_UNKNOWN = 3;
int system_paused = 0;
char buf[5];
int testnumber;
if((fd = open(argv[1], O_RDONLY)) == -1)
{
printf("failed open : %s", argv[1]);
return STATE_UNKNOWN;
}
else
{
nRead = read(fd, buf, 5);
}
close(source);
if (buf[4] == 'P')
{
printf("Software Paused");
return STATE_WARNING;
}
else
{
return STATE_OK;
}
time_t ltime; /* calendar time */
struct tm *Tm;
ltime=time(NULL); /* get current cal time */
Tm=localtime(<ime);
int test;
test = Tm->tm_hour + Tm->tm_min;
printf("%d", test);
printf("%d", strtoi(buf));
}
You can use sscanf to do the job:
int num = 0;
sscanf(buf, "%4d", &num);
Then num should hold the number from the line in the file.
You can use atoi
atoi requires one char * argument and returns an int.
If the string is empty, or first character isn't a number or a minus sign, then atoi returns 0.If atoi encounters a non-number character, it returns the number formed up until that point
int num = atoi(buf);
if you want to convert the first four characters of a string to an integer do this:
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <stdint.h>
uint8_t convertFirstFourChars(char * str, uint32_t *value){
char tmp[5] = {0};
strncpy((char *) tmp, str, 4);
*value = strtoul(tmp);
return errno;
}
then call / test this function like this
#include <stdint.h>
#include <stdio.h>
int main(int argc, char **argv){
char test1[5] = "1234A";
char test2[5] = "ABCDE";
uint32_t val = 0;
if(convertFirstFourChars((char *) test1, &val) == 0){
printf("conversion of %s succeeded, value = %ld\n", test1, val);
}
else{
printf("conversion of %s failed!\n", test1);
}
if(convertFirstFourChars((char *) test2, &val) == 0){
printf("conversion succeeded of %s, value = %ld\n", test2, val);
}
else{
printf("conversion of %s failed!\n", test2);
}
return 0;
}
FWIW, don't use atoi(...) because it converts any string to an integer regardless of its validity as a number. atoi("foo") === 0.
this is as much of your code as I was able to recover from the formatting:
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <time.h>
#define COPYMODE 0644
int main(int argc, char *argv[])
{
int i, nRead, fd;
int source;
int STATE_OK = 0;
int STATE_WARNING = 1;
int STATE_CRITICAL = 2;
int STATE_UNKNOWN = 3;
int system_paused = 0;
char buf[5];
int testnumber;
if((fd = open(argv[1], O_RDONLY)) == -1)
{
printf("failed open : %s", argv[1]);
return STATE_UNKNOWN;
}
else
{
nRead = read(fd, buf, 5);
}
close(source);
if (buf[4] == 'P')
{
printf("Software Paused");
return STATE_WARNING;
} else {
return STATE_OK;
}
time_t ltime; /* calendar time /
struct tm Tm;
ltime=time(NULL); / get current cal time */
Tm=localtime(<ime);
int test;
test = Tm->tm_hour + Tm->tm_min;
printf("%d", test);
printf("%d", strtoi(buf));
}
this is the version that does what you specified:
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <time.h>
#define COPYMODE 0644
int main(int argc, char *argv[])
{
int i, nRead, fd;
int source;
int STATE_OK = 0;
int STATE_WARNING = 1;
int STATE_CRITICAL = 2;
int STATE_UNKNOWN = 3;
int system_paused = 0;
char buf[5];
int testnumber;
if((fd = open(argv[1], O_RDONLY)) == -1)
{
printf("failed open : %s", argv[1]);
return STATE_UNKNOWN;
}
else
{
nRead = read(fd, buf, 5);
}
close(source);
if (buf[4] == 'P')
{
printf("Software Paused");
return STATE_WARNING;
}/* else {
return STATE_OK;
buf[4] = 0;
} */
time_t ltime; /* calendar time */
struct tm *Tm;
ltime=time(NULL); /* get current cal time */
Tm=localtime(<ime);
int test;
test = Tm->tm_hour + Tm->tm_min;
printf("%d\n", test);
printf("%d\n", atoi(buf));
}
The biggest problem with your code was the if statement with the returns in each branch, insuring that nothing after the if statement was ever executed.