我试图在客户端(PC i7 3.4 GHz Kubuntu 15.04) - 带有套接字的服务器(RaspberryPi 700 Mhz Raspbian Jessie)架构中获得性能,测量发送和接收所花费的时间,精度至少为微秒。
具体来说,我有一个100次的客户端(PC):
和生成100次的服务器(RaspberryPi):
我在发送之前和客户端接收之后测量时间并减去服务器接收和发送所花费的时间,因此总时间将为: TT = T-T” 但有时我会得到消极的措施......:S
我正在用这个宏测量,在'X'我放置了我的代码(C:sendto() - recvfrom()或S:recvfrom() - sendto()):
float timef=0.0;
#define TIME_MEASURE(X) \
{ \
struct timespec ts1, ts2; \
clock_gettime( CLOCK_REALTIME, &ts1 ); \
X; \
clock_gettime( CLOCK_REALTIME, &ts2 ); \
timef=(float) ( 1.0*(1.0*ts2.tv_nsec - ts1.tv_nsec*1.0)*1e-9 \
+ 1.0*ts2.tv_sec - 1.0*ts1.tv_sec ) ); \
}
//Client pseudo-code example
main(){
TIME_MEASURE(
while(i<100)
{
sendto(...);
recvfrom(..);
}
);
}
我必须在任何情况下测量时间,因此获得性能的另一种解决方案对我无效。
有谁能建议我该怎么做才能解决这个问题?
比你多。
(V2。使用'int64_t'和'double'VALUES编辑)
这是我的完整代码。
可从以下网址下载:
V1 -
https://www.dropbox.com/sh/gb4mhn3amkyqhc1/AAC6FxKCfDxXQYgzRsjArvXQa?dl=0
V2 - https://www.dropbox.com/sh/byipa75qruc71gj/AAD2ExMlnQSaUk_Pbc5xR2lZa?dl=0
server.c:
/****************************************
* Servidor UDP. Recibe como argumento
* en linea de comandos el numero de puerto. El servidor
* se ejecuta en bucle
***************************************/
#include <sys/types.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <pthread.h>
#define TAMANO 256
#include <sys/time.h>
#include <math.h>
#include <time.h>
void * ack();
void error_fatal(char *); /* Imprime un mensaje de error y sale del programa */
int sock, length, fromlen, n, i, j, port ;
struct sockaddr_in server;
struct sockaddr_in from;
char buffer[TAMANO];
float timeArr;
float timeVector[101];
double timed;
#define TIME_MEASURE(X) \
{ \
struct timespec ts1, ts2, diff; \
clock_gettime( CLOCK_REALTIME, &ts1 ); \
X; \
clock_gettime( CLOCK_REALTIME, &ts2 ); \
timeArr= (float) ( 1.0*(1.0*ts2.tv_nsec - ts1.tv_nsec*1.0)*1e-9 \
+ 1.0*ts2.tv_sec - 1.0*ts1.tv_sec ); \
diff.tv_sec = ts2.tv_sec - ts1.tv_sec; \
diff.tv_nsec = ts2.tv_nsec - ts1.tv_nsec; \
if( diff.tv_nsec < 0 ) { \
diff.tv_sec--; \
diff.tv_nsec += 1000000000LL; \
} \
printf( "Elapsed: %u.%09lld secs\n", diff.tv_sec, diff.tv_nsec );\
const int64_t NANO = 1000000000LL; \
int64_t nsec = (int64_t)(ts2.tv_sec - ts1.tv_sec) * NANO; \
nsec += (int64_t)(ts2.tv_nsec - ts1.tv_nsec); \
printf( "Elapsed nsec: %lld.%09lld secs\n", nsec / NANO, nsec % NANO );\
timed = (double)nsec * 1e-9; \
printf("nsec=%ld\n"); \
}\
int main(int argc, char *argv[])
{
timeArr=0.1;
i=0;
pthread_t recv;
FILE *f;
if (argc < 2)
{
fprintf(stderr, "ERROR, no se ha indicado el puerto \n");
exit(1);
}
/* obtain port number */
if (sscanf(argv[1], "%d", &port) <= 0)
{
fprintf(stderr, "%s: error: wrong parameter: port\n", argv[0]);
return -2;
}
/* (1) creacion del socket del servidor*/
sock=socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0)
error_fatal("Creando el socket");
length = sizeof(server);
memset(&server,0,length); /*limpio la direccion del socket del servidor*/
/* (2) vinculo la direccion IP y puerto local al socket creado anteriormente */
server.sin_family=AF_INET;
server.sin_addr.s_addr=INADDR_ANY;
server.sin_port=htons(port);
if (bind(sock,(struct sockaddr *)&server,length)<0)
error_fatal("binding");
fromlen = sizeof(struct sockaddr_in);
/* (3) bucle principal. Pongo a recibir y responder mensajes a traves del socket*/
printf("Servidor listo y esperando tramas UDP en el puerto %d...\n", port);
while (1)
{
//el cliente manda una trama de prueba para no contar el tiempo de espera en el servidor
//client sends init frame and it is not counted
if(i==0)
{
//Recibo paquete de prueba para empezar a contar, desecho este tiempo
n = recvfrom(sock,buffer,TAMANO,0,(struct sockaddr *)&from,&fromlen);
pthread_create (&recv, NULL,ack, &fromlen);
i++;
}
else
{
TIME_MEASURE(
n = recvfrom(sock,buffer,TAMANO,0,(struct sockaddr *)&from,&fromlen);
if (n < 0)
error_fatal("recvfrom");
/*datagrama recibido*/
pthread_create (&recv, NULL,ack, &fromlen);
);
timeVector[i]=(float)timeArr;
printf("timevector[%d] = %f\n", i, timeArr);
if(i==100)
{
f=fopen("dataserver.txt", "w+");
printf("Se han recibido 100 tramas UDP\n\n\n");
for(j=0;j<=100;j++)
{
fprintf(f,"%f\n",timeVector[j]);
//printf("valores: %f\n",timeVector[j]);
}
i=0;
fclose(f);
memset(timeVector,0,100);
}
else
{
i++;
}
}
}
return 0;
}
void *ack(void *ptr){
int *fl;
fl= (int *)ptr;
buffer[n]='\0'; /* para poder imprimirlo con prinft*/
//printf("Recibido en el servidor: %s\n", buffer);
/*enviar respuesta*/
float t;
t=(float)timeArr;
//It is like an ACK, now I am not using this value
n = sendto(sock,&t,sizeof(float),0,(struct sockaddr *)&from,fromlen);
memset(buffer,0,TAMANO);
if (n < 0)
error_fatal("sendto");
pthread_exit(NULL);
}
void error_fatal(char *msg)
{
perror(msg);
exit(1);
}
client.c
/*******************************************************************
* Cliente de eco remoto sobre UDP:
*
* cliente dir_ip_maquina puerto
********************************************************************/
#include <sys/types.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#define TAMANO 256 /* tamano del buffer de recepcion */
#include <sys/time.h>
#include <math.h>
#include <time.h>
void error_fatal(char *); /* Imprime un mensaje de error y sale del programa */
float timeArr;
float timeVector[101];
int i;
double timed;
#define TIME_MEASURE(X) \
{ \
struct timespec ts1, ts2, diff; \
clock_gettime( CLOCK_REALTIME, &ts1 ); \
X; \
clock_gettime( CLOCK_REALTIME, &ts2 ); \
timeArr= (float) ( 1.0*(1.0*ts2.tv_nsec - ts1.tv_nsec*1.0)*1e-9 \
+ 1.0*ts2.tv_sec - 1.0*ts1.tv_sec ); \
diff.tv_sec = ts2.tv_sec - ts1.tv_sec; \
diff.tv_nsec = ts2.tv_nsec - ts1.tv_nsec; \
if( diff.tv_nsec < 0 ) { \
diff.tv_sec--; \
diff.tv_nsec += 1000000000LL; \
} \
printf( "Elapsed: %u.%09lld secs\n", diff.tv_sec, diff.tv_nsec );\
const int64_t NANO = 1000000000LL; \
int64_t nsec = (int64_t)(ts2.tv_sec - ts1.tv_sec) * NANO; \
nsec += (int64_t)(ts2.tv_nsec - ts1.tv_nsec); \
printf( "Elapsed nsec: %lld.%09lld secs\n", nsec / NANO, nsec % NANO );\
timed = (double)nsec * 1e-9; \
printf("nsec=%ld\n"); \
}\
/*
*
* const int64_t NANO = 1000000000LL; \
int64_t nsec = (int64_t)(ts2.tv_sec - ts1.tv_sec) * NANO; \
nsec += (int64_t)(ts2.tv_nsec - ts1.tv_nsec); \
printf( "Elapsed: %lld.%09lld secs\n", nsec / NANO, nsec % NANO );\
\
*/
int main(int argc, char *argv[])
{
int sock; /* descriptor del socket del cliente */
int length, n, j, port;
struct sockaddr_in server, from; /* direcciones del socket del servidor y cliente */
struct hostent *hp; /* estructura para el nombre del servidor (ver gethostbyname) */
char buffer[TAMANO]; /* buffer de recepcion y envio del mensaje */
char buffercpy[TAMANO];
float bufferf[7];
FILE *f = fopen("data.txt", "w+");
struct timespec spec;
clockid_t clk_id;
clk_id=CLOCK_REALTIME;
i=0;
if (argc != 3)
{
fprintf(stderr,"Uso: ./client server port\n");
exit(1);
}
/* obtain port number */
if (sscanf(argv[2], "%d", &port) <= 0)
{
fprintf(stderr, "%s: error: wrong parameter: port\n", argv[0]);
return -2;
}
printf("El cliente va a mandar por el puerto %d\n", port);
/* (1) creacion del socket UDP del cliente */
sock= socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0)
error_fatal("socket");
server.sin_family = AF_INET; /*dominio de Internet*/
/* (2) averigua la direccion IP a partir del nombre del servidor*/
hp = gethostbyname(argv[1]);
if (hp==0)
error_fatal("Host desconocido");
/* (3) copia la IP resuelta anteriormente en la direccion del socket del servidor */
memcpy((char *)&server.sin_addr,(char *)hp->h_addr,hp->h_length);
if ( clock_getres( clk_id, &spec) == -1 )
{
perror( "clock get resolution" );
return EXIT_FAILURE;
}
//printf ("CLOCK_REALTIME: %ld s, %ld ns\n", spec.tv_sec,spec.tv_nsec);
/* (4) copia el puerto destino en la direccion del socket del servidor */
server.sin_port = htons(port);
length=sizeof(struct sockaddr_in);
printf("Por favor, introduce el mensaje: ");
memset(buffer,0,TAMANO); /*limpio el buffer*/
fgets(buffer,TAMANO-1,stdin);
strcpy(buffercpy, buffer);//Copio el mensaje a un nuevo buffer para que se repita en el while
while(i<=100)
{
//client sends init frame and it is not counted
if(i==0)
{
/* (5) envia al socket del servidor el mensaje almacenado en el buffer*/
n=sendto(sock,buffer,strlen(buffer),0,(struct sockaddr *) &server,length);
if (n < 0)
error_fatal("Sendto");
/* (6) lee del socket el mensaje de respuesta del servidor*/
n = recvfrom(sock,bufferf,sizeof(float),0,(struct sockaddr *) &from, &length);
if (n < 0)
error_fatal("recvfrom");
i++;
}
else
{
TIME_MEASURE(
memset(buffer, '\0', sizeof(buffer));
strcpy(buffer, buffercpy);
/* (5) envia al socket del servidor el mensaje almacenado en el buffer*/
n=sendto(sock,buffer,strlen(buffer),0,(struct sockaddr *) &server,length);
if (n < 0)
error_fatal("Sendto");
/* (6) lee del socket el mensaje de respuesta del servidor*/
n = recvfrom(sock,bufferf,sizeof(float),0,(struct sockaddr *) &from, &length);
if (n < 0)
error_fatal("recvfrom");
);
timeVector[i]=(float)timeArr;
printf("Tiempo de procesamiento cliente - timeVector [%d]: %f\n", i,timeArr);
//timeVector[i]+=(float)(0.0 - *bufferf);
//printf("timeVector negativo[%d]= %f\n", i, timeVector[i]);
buffer[n]='\0'; /* para poder imprimirlo con printf*/
bufferf[n]='\0'; /* para poder imprimirlo con printf*/
//printf("Recibido en el cliente: %f ACK(%d)%c\n",*bufferf,i,'\0');
printf("timeVector TOTAL= %f\n\n", timeVector[i]);
//printf("buffer=%s%c\n",buffer,'\0');
if(i==100){
for(j=1;j<=100;j++){
fprintf(f,"%f\n",timeVector[j]);
//printf("valores: %f\n",timeVector[j]);
}
printf("Se han enviado 100 tramas UDP \n\n\n");
}
i++;
}
}
fclose(f);
/*cerramos el socket*/
if(close(sock) < 0)
error_fatal("close");
}
void error_fatal(char *msg)
{
perror(msg);
exit(1);
}
我收到数字格式的警告,所以我认为打印值可能不正确。
这些是我得到的警告:
server.c: In function ‘main’:
server.c:50:18: warning: format ‘%u’ expects argument of type ‘unsigned int’, but argument 2 has type ‘__time_t {aka long int}’ [-Wformat=]
printf( "Elapsed: %u.%09lld secs\n", diff.tv_sec, diff.tv_nsec );\
^
server.c:122:13: note: in expansion of macro ‘TIME_MEASURE’
TIME_MEASURE(
^
server.c:50:18: warning: format ‘%lld’ expects argument of type ‘long long int’, but argument 3 has type ‘__syscall_slong_t {aka long int}’ [-Wformat=]
printf( "Elapsed: %u.%09lld secs\n", diff.tv_sec, diff.tv_nsec );\
^
server.c:122:13: note: in expansion of macro ‘TIME_MEASURE’
TIME_MEASURE(
^
server.c:54:18: warning: format ‘%lld’ expects argument of type ‘long long int’, but argument 2 has type ‘long int’ [-Wformat=]
printf( "Elapsed nsec: %lld.%09lld secs\n", nsec / NANO, nsec % NANO )
^
server.c:122:13: note: in expansion of macro ‘TIME_MEASURE’
TIME_MEASURE(
^
server.c:54:18: warning: format ‘%lld’ expects argument of type ‘long long int’, but argument 3 has type ‘long int’ [-Wformat=]
printf( "Elapsed nsec: %lld.%09lld secs\n", nsec / NANO, nsec % NANO )
^
server.c:122:13: note: in expansion of macro ‘TIME_MEASURE’
TIME_MEASURE(
^
server.c:56:17: warning: format ‘%ld’ expects a matching ‘long int’ argument [-Wformat=]
printf("nsec=%ld\n"); \
^
server.c:122:13: note: in expansion of macro ‘TIME_MEASURE’
TIME_MEASURE(
^
答案 0 :(得分:0)
将这些数字转换为浮点数可能会遇到问题。尝试将差异计算为适当大的整数数据类型。至少从开始,然后从那里开始工作。
const int64_t NANO = 1000000000LL;
int64_t nsec = (int64_t)(ts2.tv_sec - ts1.tv_sec) * NANO;
nsec += (int64_t)(ts2.tv_nsec - ts1.tv_nsec);
printf( "Elapsed: %lld.%09lld secs\n", nsec / NANO, nsec % NANO );
如果你想要一个漂浮物,请注意单精度是非常有限的。您可以将其钳制到微秒,但是对于更长的间隔,您可能无法获得微秒级的分辨率。
timef = (float)(nsec / 1000LL) * 1e-6f;
最好使用double:
double timef;
timef = (double)nsec * 1e-9;
当然,你可以自己使用timespec:
struct timespec diff;
diff.tv_sec = ts2.tv_sec - ts1.tv_sec;
diff.tv_nsec = ts2.tv_nsec - ts1.tv_nsec;
if( diff.tv_nsec < 0 ) {
diff.tv_sec--;
diff.tv_nsec += 1000000000LL;
}
printf( "Elapsed: %u.%09lld secs\n", diff.tv_sec, diff.tv_nsec );