Commit ac8f6f5e authored by Joanne Hugé's avatar Joanne Hugé

Add RTT option

parent 04802a76
...@@ -7,9 +7,13 @@ SRCDIR = ../src ...@@ -7,9 +7,13 @@ SRCDIR = ../src
SERVER_SRCS = server.c SERVER_SRCS = server.c
SERVER_SRCS += recv_packet.c SERVER_SRCS += recv_packet.c
SERVER_SRCS += send_packet.c
SERVER_SRCS += utilities.c
CLIENT_SRCS = client.c CLIENT_SRCS = client.c
CLIENT_SRCS += recv_packet.c
CLIENT_SRCS += send_packet.c CLIENT_SRCS += send_packet.c
CLIENT_SRCS += utilities.c
SERVER_OBJS = $(SERVER_SRCS:%.c=%.o) SERVER_OBJS = $(SERVER_SRCS:%.c=%.o)
CLIENT_OBJS = $(CLIENT_SRCS:%.c=%.o) CLIENT_OBJS = $(CLIENT_SRCS:%.c=%.o)
......
...@@ -4,9 +4,10 @@ ...@@ -4,9 +4,10 @@
* Bash options: * Bash options:
* *
* -a Run the real time thread on CPU1 * -a Run the real time thread on CPU1
* -b Measure RTT
* -d TX_BUFFER_LEN Set the length of tx buffer * -d TX_BUFFER_LEN Set the length of tx buffer
* -e Set a txtime (to be used in an ETF qdisc) * -e Set a txtime (to be used in an ETF qdisc)
* -f Set the network interface to be used * -f IF Set the network interface to be used
* -i USEC Wake up the real time thread every USEC microseconds (Default: 10ms) * -i USEC Wake up the real time thread every USEC microseconds (Default: 10ms)
* -l N Wake up the real time thread N times (Default: 0) * -l N Wake up the real time thread N times (Default: 0)
* -p PRIO Run the real time thread at priority PRIO * -p PRIO Run the real time thread at priority PRIO
...@@ -30,12 +31,14 @@ ...@@ -30,12 +31,14 @@
#include <unistd.h> #include <unistd.h>
#include "send_packet.h" #include "send_packet.h"
#include "recv_packet.h"
#include "utilities.h"
#define CLOCK_ID CLOCK_MONOTONIC enum TSNTask {SEND_PACKET_TASK, RTT_TASK};
#define NSEC_PER_SEC UINT64_C(1000000000)
typedef struct thread_stat { typedef struct thread_stat {
int nb_cycles; int nb_cycles;
uint64_t rtt;
} thread_stat_t; } thread_stat_t;
typedef struct thread_param { typedef struct thread_param {
...@@ -46,9 +49,12 @@ typedef struct thread_param { ...@@ -46,9 +49,12 @@ typedef struct thread_param {
int enable_affinity; int enable_affinity;
int enable_etf; int enable_etf;
int enable_timestamps; int enable_timestamps;
enum TSNTask tsn_task;
int sockfd;
const char *ip_address; const char *ip_address;
char network_if[256]; char network_if[256];
thread_stat_t stats; thread_stat_t stats;
} thread_param_t; } thread_param_t;
...@@ -58,9 +64,9 @@ typedef struct main_param { ...@@ -58,9 +64,9 @@ typedef struct main_param {
size_t tx_buffer_len; size_t tx_buffer_len;
} main_param_t; } main_param_t;
static inline void add_ns(struct timespec *t, uint64_t ns);
static void process_options(int argc, char *argv[], thread_param_t *param, static void process_options(int argc, char *argv[], thread_param_t *param,
main_param_t *main_param); main_param_t *main_param);
static void do_tsn_task(struct thread_param * param, uint64_t next_txtime);
// Real-time thread // Real-time thread
// Sends packets at a regular intervall // Sends packets at a regular intervall
...@@ -84,7 +90,7 @@ static void *packet_sending_thread(void *p) { ...@@ -84,7 +90,7 @@ static void *packet_sending_thread(void *p) {
if (sched_setscheduler(0, SCHED_FIFO, &priority)) if (sched_setscheduler(0, SCHED_FIFO, &priority))
error(EXIT_FAILURE, errno, "Couldn't set priority"); error(EXIT_FAILURE, errno, "Couldn't set priority");
clock_gettime(CLOCK_ID, &next); clock_gettime(CLOCK_MONOTONIC, &next);
next_txtime = next.tv_sec * NSEC_PER_SEC + next.tv_nsec; next_txtime = next.tv_sec * NSEC_PER_SEC + next.tv_nsec;
// Wait around 1 second // Wait around 1 second
next_txtime += (10 * NSEC_PER_SEC / param->interval) * param->interval; next_txtime += (10 * NSEC_PER_SEC / param->interval) * param->interval;
...@@ -96,12 +102,12 @@ static void *packet_sending_thread(void *p) { ...@@ -96,12 +102,12 @@ static void *packet_sending_thread(void *p) {
if (param->max_cycles) if (param->max_cycles)
if (param->stats.nb_cycles >= param->max_cycles) break; if (param->stats.nb_cycles >= param->max_cycles) break;
send_udp_packet(param->enable_etf, param->enable_timestamps, next_txtime, param->ip_address); do_tsn_task(param, next_txtime);
add_ns(&next, param->interval); add_ns(&next, param->interval);
next_txtime += (param->interval) / 2; next_txtime += (param->interval) / 2;
clock_nanosleep(CLOCK_ID, TIMER_ABSTIME, &next, NULL); clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &next, NULL);
} }
return NULL; return NULL;
...@@ -121,6 +127,7 @@ int main(int argc, char *argv[]) { ...@@ -121,6 +127,7 @@ int main(int argc, char *argv[]) {
param.enable_affinity = 0; param.enable_affinity = 0;
param.enable_etf = 0; param.enable_etf = 0;
param.enable_timestamps = 0; param.enable_timestamps = 0;
param.tsn_task = SEND_PACKET_TASK;
main_param.refresh_rate = 50000; main_param.refresh_rate = 50000;
main_param.packet_priority = 3; main_param.packet_priority = 3;
...@@ -131,6 +138,9 @@ int main(int argc, char *argv[]) { ...@@ -131,6 +138,9 @@ int main(int argc, char *argv[]) {
init_udp_send(param.enable_etf, param.enable_timestamps, main_param.packet_priority, param.network_if, main_param.tx_buffer_len); init_udp_send(param.enable_etf, param.enable_timestamps, main_param.packet_priority, param.network_if, main_param.tx_buffer_len);
if(param.tsn_task == RTT_TASK)
param.sockfd = init_udp_recv();
usleep(10000); usleep(10000);
if (pthread_create(&thread, NULL, packet_sending_thread, (void *)&param)) if (pthread_create(&thread, NULL, packet_sending_thread, (void *)&param))
...@@ -139,9 +149,9 @@ int main(int argc, char *argv[]) { ...@@ -139,9 +149,9 @@ int main(int argc, char *argv[]) {
for (;;) { for (;;) {
usleep(main_param.refresh_rate); usleep(main_param.refresh_rate);
#ifdef DEBUG_ENABLE if(param.tsn_task == RTT_TASK) {
printf("Nb cycles: %d\n", param.stats.nb_cycles); printf("RTT: %" PRIu64 " (%d)\n", param.stats.rtt, param.stats.nb_cycles);
#endif }
if (param.max_cycles) if (param.max_cycles)
if (param.max_cycles == param.stats.nb_cycles) break; if (param.max_cycles == param.stats.nb_cycles) break;
...@@ -150,10 +160,27 @@ int main(int argc, char *argv[]) { ...@@ -150,10 +160,27 @@ int main(int argc, char *argv[]) {
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} }
static void do_tsn_task(struct thread_param * param, uint64_t next_txtime) {
struct timespec t1, t2;
if(param->tsn_task == SEND_PACKET_TASK) {
send_udp_packet(param->enable_etf, param->enable_timestamps, next_txtime, param->ip_address);
}
else if(param->tsn_task == RTT_TASK) {
clock_gettime(CLOCK_MONOTONIC, &t1);
send_udp_packet(param->enable_etf, param->enable_timestamps, next_txtime, param->ip_address);
recv_udp_packet(param->sockfd);
clock_gettime(CLOCK_MONOTONIC, &t2);
param->stats.rtt = calcdiff_ns(t2, t1);
}
}
static void process_options(int argc, char *argv[], thread_param_t *param, static void process_options(int argc, char *argv[], thread_param_t *param,
main_param_t *main_param) { main_param_t *main_param) {
for (;;) { for (;;) {
int c = getopt(argc, argv, "ad:ef:i:l:p:q:r:t"); int c = getopt(argc, argv, "abd:ef:i:l:p:q:r:t");
if (c == -1) break; if (c == -1) break;
...@@ -161,6 +188,9 @@ static void process_options(int argc, char *argv[], thread_param_t *param, ...@@ -161,6 +188,9 @@ static void process_options(int argc, char *argv[], thread_param_t *param,
case 'a': case 'a':
param->enable_affinity = 1; param->enable_affinity = 1;
break; break;
case 'b':
param->tsn_task = RTT_TASK;
break;
case 'd': case 'd':
main_param->tx_buffer_len = atoi(optarg); main_param->tx_buffer_len = atoi(optarg);
if( main_param->tx_buffer_len < 1 ) { if( main_param->tx_buffer_len < 1 ) {
...@@ -205,11 +235,3 @@ static void process_options(int argc, char *argv[], thread_param_t *param, ...@@ -205,11 +235,3 @@ static void process_options(int argc, char *argv[], thread_param_t *param,
param->ip_address = argv[optind]; param->ip_address = argv[optind];
} }
static inline void add_ns(struct timespec *t, uint64_t ns) {
t->tv_nsec += ns;
if ((unsigned int)t->tv_nsec >= NSEC_PER_SEC) {
t->tv_sec += 1;
t->tv_nsec -= NSEC_PER_SEC;
}
}
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
#include <time.h> #include <time.h>
#include <unistd.h> #include <unistd.h>
#include "utilities.h"
#define SERVER_PORT "50000" #define SERVER_PORT "50000"
#define BUFFER_SIZE 1024 #define BUFFER_SIZE 1024
......
...@@ -36,11 +36,9 @@ ...@@ -36,11 +36,9 @@
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h> #include <unistd.h>
#define SERVER_PORT "50000" #include "utilities.h"
#define SERVER_PORT_INT 50000
#define CLOCK_ID CLOCK_TAI
#define MESSAGE ((uint32_t)0x00FACADE) #define MESSAGE ((uint32_t)0x00FACADE)
#define NSEC_PER_SEC ((uint64_t)1000000000)
static void print_timestamps(struct msghdr *msg, uint64_t txtime); static void print_timestamps(struct msghdr *msg, uint64_t txtime);
static void process_timestamps(uint64_t txtime); static void process_timestamps(uint64_t txtime);
...@@ -120,7 +118,7 @@ void init_udp_send(int use_etf, int use_timestamps, int packet_priority, ...@@ -120,7 +118,7 @@ void init_udp_send(int use_etf, int use_timestamps, int packet_priority,
error(EXIT_FAILURE, errno, "setsockopt SO_BINDTODEVICE failed\n"); error(EXIT_FAILURE, errno, "setsockopt SO_BINDTODEVICE failed\n");
if (use_etf) { if (use_etf) {
sk_txtime.clockid = CLOCK_ID; sk_txtime.clockid = CLOCK_TAI;
sk_txtime.flags = 0; sk_txtime.flags = 0;
if (setsockopt(fd, SOL_SOCKET, SO_TXTIME, &sk_txtime, sizeof(sk_txtime))) if (setsockopt(fd, SOL_SOCKET, SO_TXTIME, &sk_txtime, sizeof(sk_txtime)))
......
...@@ -4,8 +4,12 @@ ...@@ -4,8 +4,12 @@
* Bash options: * Bash options:
* *
* -a Run the real time thread on CPU1 * -a Run the real time thread on CPU1
* -b Server side RTT
* -d TX_BUFFER_LEN Set the length of tx buffer
* -f IF Set the network interface to be used
* -p PRIO Run the real time thread at priority PRIO * -p PRIO Run the real time thread at priority PRIO
* -r USEC Refresh the non real time main thread every USEC microseconds * -r USEC Refresh the non real time main thread every USEC
* microseconds
* *
* Large portions taken from cyclictest * Large portions taken from cyclictest
* *
...@@ -30,12 +34,13 @@ ...@@ -30,12 +34,13 @@
#include <unistd.h> #include <unistd.h>
#include "recv_packet.h" #include "recv_packet.h"
#include "send_packet.h"
#include "utilities.h"
#define NSEC_PER_SEC UINT64_C(1000000000)
#define SERVER_PORT "50000"
#define BUFFER_SIZE 1024 #define BUFFER_SIZE 1024
enum TSNTask { RECV_PACKET_TASK, RTT_TASK };
typedef struct thread_stat { typedef struct thread_stat {
uint64_t min_interval; uint64_t min_interval;
uint64_t max_interval; uint64_t max_interval;
...@@ -44,24 +49,24 @@ typedef struct thread_stat { ...@@ -44,24 +49,24 @@ typedef struct thread_stat {
typedef struct thread_param { typedef struct thread_param {
int priority; int priority;
thread_stat_t stats;
int enable_affinity; int enable_affinity;
enum TSNTask tsn_task;
int sockfd; int sockfd;
const char *ip_address;
char network_if[256];
thread_stat_t stats;
} thread_param_t; } thread_param_t;
typedef struct main_param { typedef struct main_param {
int refresh_rate; int refresh_rate;
size_t tx_buffer_len;
} main_param_t; } main_param_t;
static inline uint64_t calcdiff_ns(struct timespec t1, struct timespec t2);
static inline uint64_t max(uint64_t a, uint64_t b);
static inline uint64_t min(uint64_t a, uint64_t b);
static void process_options(int argc, char *argv[], thread_param_t *param, static void process_options(int argc, char *argv[], thread_param_t *param,
main_param_t *main_param); main_param_t *main_param);
void init_server(thread_param_t *param);
// Real-time thread // Real-time thread
// Measures intervals between packet receptions // Measures intervals between packet receptions
...@@ -91,7 +96,10 @@ static void *packet_receiving_thread(void *p) { ...@@ -91,7 +96,10 @@ static void *packet_receiving_thread(void *p) {
// Packet receiving loop // Packet receiving loop
for (stats->packets_received = 0;; stats->packets_received++) { for (stats->packets_received = 0;; stats->packets_received++) {
if (param->tsn_task == RTT_TASK) {
recv_udp_packet(param->sockfd);
send_udp_packet(0, 0, 0, param->ip_address);
} else if (param->tsn_task == RECV_PACKET_TASK) {
recv_udp_packet(param->sockfd); recv_udp_packet(param->sockfd);
clock_gettime(CLOCK_MONOTONIC, &current); clock_gettime(CLOCK_MONOTONIC, &current);
...@@ -104,6 +112,7 @@ static void *packet_receiving_thread(void *p) { ...@@ -104,6 +112,7 @@ static void *packet_receiving_thread(void *p) {
previous = current; previous = current;
} }
}
return NULL; return NULL;
} }
...@@ -115,8 +124,12 @@ int main(int argc, char *argv[]) { ...@@ -115,8 +124,12 @@ int main(int argc, char *argv[]) {
thread_param_t param; thread_param_t param;
main_param_t main_param; main_param_t main_param;
int64_t diff;
// Default values // Default values
param.priority = 99; param.priority = 99;
param.tsn_task = RECV_PACKET_TASK;
main_param.refresh_rate = 50000; main_param.refresh_rate = 50000;
// Process bash options // Process bash options
...@@ -124,6 +137,9 @@ int main(int argc, char *argv[]) { ...@@ -124,6 +137,9 @@ int main(int argc, char *argv[]) {
param.sockfd = init_udp_recv(); param.sockfd = init_udp_recv();
if (param.tsn_task == RTT_TASK)
init_udp_send(0, 0, 1, param.network_if, main_param.tx_buffer_len);
usleep(10000); usleep(10000);
if (pthread_create(&thread, NULL, packet_receiving_thread, (void *)&param)) if (pthread_create(&thread, NULL, packet_receiving_thread, (void *)&param))
...@@ -132,11 +148,13 @@ int main(int argc, char *argv[]) { ...@@ -132,11 +148,13 @@ int main(int argc, char *argv[]) {
for (;;) { for (;;) {
usleep(main_param.refresh_rate); usleep(main_param.refresh_rate);
printf("%" PRIu64 " - %" PRIu64 ", %" PRIu64 " (%d)\n", if (param.tsn_task == RECV_PACKET_TASK) {
param.stats.max_interval - param.stats.min_interval, diff = ((int64_t)param.stats.max_interval) - param.stats.min_interval;
printf("%" PRIi64 " - %" PRIu64 ", %" PRIu64 " (%d)\n", diff,
param.stats.min_interval, param.stats.max_interval, param.stats.min_interval, param.stats.max_interval,
param.stats.packets_received); param.stats.packets_received);
} }
}
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} }
...@@ -144,7 +162,7 @@ int main(int argc, char *argv[]) { ...@@ -144,7 +162,7 @@ int main(int argc, char *argv[]) {
static void process_options(int argc, char *argv[], thread_param_t *param, static void process_options(int argc, char *argv[], thread_param_t *param,
main_param_t *main_param) { main_param_t *main_param) {
for (;;) { for (;;) {
int c = getopt(argc, argv, "ap:r:"); int c = getopt(argc, argv, "abd:p:r:");
if (c == -1) break; if (c == -1) break;
...@@ -152,6 +170,19 @@ static void process_options(int argc, char *argv[], thread_param_t *param, ...@@ -152,6 +170,19 @@ static void process_options(int argc, char *argv[], thread_param_t *param,
case 'a': case 'a':
param->enable_affinity = 1; param->enable_affinity = 1;
break; break;
case 'b':
param->tsn_task = RTT_TASK;
break;
case 'd':
main_param->tx_buffer_len = atoi(optarg);
if (main_param->tx_buffer_len < 1) {
fprintf(stderr, "TX_BUFFER_LEN should be greater than 1\n");
exit(EXIT_FAILURE);
}
break;
case 'f':
strcpy(param->network_if, optarg);
break;
case 'p': case 'p':
param->priority = atoi(optarg); param->priority = atoi(optarg);
break; break;
...@@ -165,13 +196,3 @@ static void process_options(int argc, char *argv[], thread_param_t *param, ...@@ -165,13 +196,3 @@ static void process_options(int argc, char *argv[], thread_param_t *param,
} }
} }
static inline uint64_t calcdiff_ns(struct timespec t1, struct timespec t2) {
uint64_t diff;
diff = NSEC_PER_SEC * (uint64_t)((int)t1.tv_sec - (int)t2.tv_sec);
diff += ((int)t1.tv_nsec - (int)t2.tv_nsec);
return diff;
}
static inline uint64_t max(uint64_t a, uint64_t b) { return a > b ? a : b; }
static inline uint64_t min(uint64_t a, uint64_t b) { return a < b ? a : b; }
#define _GNU_SOURCE
#include <inttypes.h>
#include <stdint.h>
#include <time.h>
#include <unistd.h>
#include "utilities.h"
void add_ns(struct timespec *t, uint64_t ns) {
t->tv_nsec += ns;
if ((unsigned int)t->tv_nsec >= NSEC_PER_SEC) {
t->tv_sec += 1;
t->tv_nsec -= NSEC_PER_SEC;
}
}
uint64_t calcdiff_ns(struct timespec t1, struct timespec t2) {
uint64_t diff;
diff = NSEC_PER_SEC * (uint64_t)((int)t1.tv_sec - (int)t2.tv_sec);
diff += ((int)t1.tv_nsec - (int)t2.tv_nsec);
return diff;
}
uint64_t max(uint64_t a, uint64_t b) { return a > b ? a : b; }
uint64_t min(uint64_t a, uint64_t b) { return a < b ? a : b; }
#ifndef UTILITIES_H
#define UTILITIES_H
#define _GNU_SOURCE
#include <inttypes.h>
#include <stdint.h>
#include <time.h>
#include <unistd.h>
#define NSEC_PER_SEC UINT64_C(1000000000)
#define SERVER_PORT "50000"
#define SERVER_PORT_INT 50000
void add_ns(struct timespec *t, uint64_t ns);
uint64_t calcdiff_ns(struct timespec t1, struct timespec t2);
uint64_t max(uint64_t a, uint64_t b);
uint64_t min(uint64_t a, uint64_t b);
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment