Commit 08bfdac7 authored by Joanne Hugé's avatar Joanne Hugé

Add test-board-synchro

Clean up client and add comments
add send_tx_data option
Clean up server and add emit signal option
Delete line breaks between static variables
Update ptp script
Add run-phc2sys script
Add gettime program
Add test-board-synchro script
parent 28675252
PROG = ptptime
SRCDIR = ../src
SRCS = main.c
OBJS = $(SRCS:%.c=%.o)
ifeq ($(DEBUG),)
CFLAGS = -O2
else
CFLAGS = -Og -g -Wall -Wextra
endif
CFLAGS += -MD -MP
CFLAGS += -I $(SRCDIR)
CFLAGS += -std=gnu99
LLIBS = -pthread
vpath %.c $(SRCDIR)
$(PROG): $(OBJS)
$(CC) $(LDFLAGS) $(LDIRS) $^ $(LLIBS) -o $@
-include $(subst .c,.d,$(SRCS))
clean:
$(RM) $(OBJS) $(PROG) $(subst .c,.d,$(SRCS))
.PHONY: clean
/*
* Get PTP time
*
* Large portions taken from cyclictest
*
*/
#define _GNU_SOURCE
#include <errno.h>
#include <error.h>
#include <inttypes.h>
#include <limits.h>
#include <pthread.h>
#include <sched.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <time.h>
#include <unistd.h>
#define NSEC_PER_SEC UINT64_C(1000000000)
// Structs
typedef struct thread_param {
int interval;
int priority;
} thread_param_t;
// Static functions
static void process_options(int argc, char *argv[]);
static void add_ns(struct timespec *t, uint64_t ns);
static uint64_t ts_to_uint(struct timespec t);
// Static variables
static thread_param_t thread_params;
static uint64_t ptptime;
static int quit;
static clockid_t clock_id;
static void help(char *argv[]) {
printf(
"Usage: %s [-h] [-i USEC]\n"
" -h Show help\n"
" -m Get time from CLOCK_MONOTONIC\n"
" -r Get time from CLOCK_REALTIME (default)\n"
" -t Get time from CLOCK_TAI\n"
" -q Get time then quit\n"
" -i USEC RT thread wake-up interval (default: 10ms)\n"
"\n",
argv[0]);
}
/*
* Real-time thread: Sends packets at a regular intervall
*/
static void *packet_sending_thread(void *p) {
(void)p;
struct timespec next, ptptime_ts;
cpu_set_t mask;
// Set thread CPU affinity
CPU_ZERO(&mask);
CPU_SET(1, &mask);
if (sched_setaffinity(0, sizeof(mask), &mask))
error(EXIT_FAILURE, errno, "Could not set CPU affinity to CPU #1\n");
clock_gettime(CLOCK_MONOTONIC, &next);
// Packet sending loop
for (;;) {
clock_gettime(clock_id, &ptptime_ts);
ptptime = ts_to_uint(ptptime_ts);
add_ns(&next, thread_params.interval);
clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &next, NULL);
}
return NULL;
}
/*
* Main thread, has non-real time priority
* Handles the IO and creates the real time thread
*/
int main(int argc, char *argv[]) {
pthread_t thread;
struct sched_param param;
pthread_attr_t attr;
// Default configuration values
thread_params.interval = 100000 * 1000;
thread_params.priority = 99;
clock_id = CLOCK_REALTIME;
/* Lock all current and future pages from preventing of being paged to
* swap */
if (mlockall(MCL_CURRENT | MCL_FUTURE)) {
perror("mlockall failed");
/* exit(-1) or do error handling */
}
// Process bash options
process_options(argc, argv);
if (quit) {
struct timespec ts;
clock_gettime(clock_id, &ts);
printf("%" PRIu64 "\n", ts_to_uint(ts));
exit(EXIT_SUCCESS);
}
/* Initialize pthread attributes (default values) */
if (pthread_attr_init(&attr)) {
fprintf(stderr, "init pthread attributes failed\n");
exit(EXIT_FAILURE);
}
/* Set a specific stack size */
if (pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN)) {
fprintf(stderr, "pthread setstacksize failed\n");
exit(EXIT_FAILURE);
}
/* Set scheduler policy and priority of pthread */
if (pthread_attr_setschedpolicy(&attr, SCHED_FIFO)) {
fprintf(stderr, "pthread setschedpolicy failed\n");
exit(EXIT_FAILURE);
}
param.sched_priority = thread_params.priority;
if (pthread_attr_setschedparam(&attr, &param)) {
fprintf(stderr, "pthread setschedparam failed\n");
exit(EXIT_FAILURE);
}
/* Use scheduling parameters of attr */
if (pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED)) {
fprintf(stderr, "pthread setinheritsched failed\n");
exit(EXIT_FAILURE);
}
// Create the real time thread
if (pthread_create(&thread, &attr, packet_sending_thread, NULL))
error(EXIT_FAILURE, errno, "Couldn't create packet sending thread");
// Verbose loop
for (;;) {
usleep(100000);
printf("%9" PRIu64 ": \n", ptptime);
printf("\033[%dA", 1);
}
exit(EXIT_SUCCESS);
}
// Process bash options
static void process_options(int argc, char *argv[]) {
for (;;) {
int c = getopt(argc, argv, "hi:qmrt");
if (c == -1) break;
switch (c) {
case 'm':
clock_id = CLOCK_MONOTONIC;
break;
case 'r':
clock_id = CLOCK_REALTIME;
break;
case 't':
clock_id = CLOCK_TAI;
break;
case 'h':
help(argv);
exit(EXIT_SUCCESS);
break;
case 'i':
thread_params.interval = atoi(optarg) * 1000;
break;
case 'q':
quit = 1;
break;
}
}
}
static void add_ns(struct timespec *t, uint64_t ns) {
t->tv_nsec += ns;
while ((unsigned int)t->tv_nsec >= NSEC_PER_SEC) {
t->tv_sec += 1;
t->tv_nsec -= NSEC_PER_SEC;
}
}
static uint64_t ts_to_uint(struct timespec t) {
return t.tv_sec * NSEC_PER_SEC + t.tv_nsec;
}
......@@ -7,6 +7,7 @@ SERVER_SRCS += recv_packet.c
SERVER_SRCS += send_packet.c
SERVER_SRCS += common.c
SERVER_SRCS += tracer.c
SERVER_SRCS += gpio.c
CLIENT_SRCS = client.c
CLIENT_SRCS += recv_packet.c
......
......@@ -30,25 +30,28 @@
enum TSNTask { SEND_PACKET_TASK, RTT_TASK };
typedef struct rtt_stat {
int min_rtt;
int avg_rtt;
int max_rtt;
int min_rtt;
int avg_rtt;
int max_rtt;
} rtt_stat_t;
typedef struct thread_param {
int interval;
unsigned int max_cycles;
int priority;
int etf_offset;
int interval;
unsigned int max_cycles;
int priority;
int etf_offset;
int send_tx_delay;
int affinity_cpu;
uint64_t start_ts;
} thread_param_t;
typedef struct main_param {
int refresh_rate;
int verbose;
int enable_tracing;
int enable_graph;
int refresh_rate;
int verbose;
int enable_tracing;
int enable_graph;
} main_param_t;
// Static functions
......@@ -62,433 +65,421 @@ static void sighand(int sig_num);
static uint64_t kernel_latency_hist[MAX_KERNEL_LATENCY];
static uint64_t rtt_hist[MAX_RTT];
static uint64_t nb_cycles;
static main_param_t main_params;
static thread_param_t thread_params;
static egress_param_t egress_params;
static ingress_param_t ingress_params;
static rtt_stat_t rtt_stats = {.min_rtt = INT_MAX};
static egress_stat_t egress_stats = {.min_kernel_latency = INT_MAX,
.min_interval = INT_MAX};
.min_interval = INT_MAX};
static ingress_stat_t ingress_stats = {.min_kernel_latency = INT_MAX,
.min_interval = INT_MAX};
.min_interval = INT_MAX};
static int enable_histograms;
static int enable_affinity;
static int enable_etf;
static int enable_timestamps;
static enum TSNTask tsn_task;
static struct timespec measures_start;
static struct timespec measures_end;
static char send_data[MAX_BUFFER_SIZE];
static void help(char *argv[]) {
printf(
"Usage: %s -f IF [-abthgv] [-e ETF_OFFSET] [-d BUF_LEN] [-i USEC] "
"[-l N]"
"[-p PRIO] [-q PACKET_PRIO] [-r USEC] [-T LATENCY_THRESHOLD -G]\n\n"
" -a Run the real time thread on CPU1\n"
" -b Measure RTT\n"
" -d BUF_LEN Set the length of tx buffer\n"
" -e ETF_OFFSET Set a txtime with an offset of "
"ETF_OFFSET "
"us (to be used in an ETF qdisc)\n"
" -f IF Set the network interface to be "
"used\n"
" -g Print histograms to sdtout on exit\n"
" -h Show help\n"
" -i USEC Wake up the real time thread every "
"USEC "
"microseconds (Default: 10ms)\n"
" -l N Wake up the real time thread N times "
"(Default: 0)\n"
" -p PRIO Run the real time thread at priority "
"PRIO\n"
" -q PACKET_PRIO Send packets with PACKET_PRIO "
"priority\n"
" -r USEC Refresh the non real time main "
"thread "
"every USEC microseconds (Default: 50ms)\n"
" -t Enable timestamps\n"
" -v Verbose\n"
" -T Enable tracing until deadline is "
"missed\n"
"\n",
argv[0]);
printf(
"Usage: %s [-a CPU -p PRIO -i USEC -r USEC -l N] [-d BUF_LEN | -c "
"DELAY -s NS] [-b -e OFFSET -q PK_PRIO -gtvT] IF IP\n\n"
" -h Show help\n"
" -f IF Set the network interface to be used\n"
" -a CPU Pin the real time thread to CPU\n"
" -p PRIO RT thread priority\n"
" -i USEC RT thread wake-up interval (default: 10ms)\n"
" -r USEC non-RT main thread refresh interval\n"
" -l N_CYCLES RT thread cycles amount (default: infinite)\n"
" -d BUF_LEN TX buffer len\n"
" -c USEC Send timestamp with the specified delay\n"
" -s NS Common start time reference\n"
" -b Measure RTT\n"
" -e USEC txtime userspace offset (for ETF qdisc)\n"
" -q PK_PRIO Packet priority \n"
" -g Print histograms to sdtout on exit\n"
" -t Enable TX timestamps\n"
" -v Verbose\n"
" -T Enable tracing until deadline is missed\n"
"\n",
argv[0]);
}
/*
* Real-time thread: Sends packets at a regular intervall
* Real-time thread:
* - Sends packets at a regular intervall
*/
static void *packet_sending_thread(void *p) {
(void)p;
struct timespec next, current, previous;
uint64_t next_txtime;
cpu_set_t mask;
// Set thread CPU affinity
if (enable_affinity) {
CPU_ZERO(&mask);
CPU_SET(1, &mask);
if (sched_setaffinity(0, sizeof(mask), &mask))
error(EXIT_FAILURE, errno,
"Could not set CPU affinity to CPU #1\n");
}
if (enable_etf) {
// Measure from CLOCK_TAI to generate timestamp
clock_gettime(CLOCK_TAI, &next);
next_txtime = next.tv_sec * NSEC_PER_SEC + next.tv_nsec;
next_txtime += thread_params.etf_offset;
} else {
next_txtime = 0;
}
clock_gettime(CLOCK_MONOTONIC, &next);
clock_gettime(CLOCK_MONOTONIC, &measures_start);
// Packet sending loop
for (nb_cycles = 0;; nb_cycles++) {
if (thread_params.max_cycles &&
nb_cycles >= ((unsigned int)thread_params.max_cycles))
break;
clock_gettime(CLOCK_MONOTONIC, &current);
sprintf(send_data, "%d", (int)(nb_cycles % 1000));
do_tsn_task(send_data, next_txtime);
add_ns(&next, thread_params.interval);
if (enable_etf) next_txtime += thread_params.interval;
if (nb_cycles) {
int interval_us = calcdiff_ns(current, previous) / 1000;
egress_stats.min_interval =
_min_(interval_us, egress_stats.min_interval);
egress_stats.max_interval =
_max_(interval_us, egress_stats.max_interval);
egress_stats.avg_interval =
(egress_stats.avg_interval * nb_cycles +
interval_us) /
(nb_cycles + 1);
}
previous = current;
clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &next, NULL);
}
return NULL;
(void)p;
struct timespec next, current, previous;
uint64_t next_txtime = 0, tx_data = 0;
cpu_set_t mask;
// Set thread CPU affinity
if (thread_params.affinity_cpu != -1) {
CPU_ZERO(&mask);
CPU_SET(thread_params.affinity_cpu, &mask);
if (sched_setaffinity(0, sizeof(mask), &mask))
error(EXIT_FAILURE, errno, "Could not set CPU affinity to CPU %d\n",
thread_params.affinity_cpu);
}
clock_gettime(CLOCK_MONOTONIC, &measures_start);
if(thread_params.start_ts)
next = uint_to_ts(thread_params.start_ts);
else
clock_gettime(CLOCK_REALTIME, &next);
// Set txtime and TX data timestamp if required
if (enable_etf || thread_params.send_tx_delay) {
if (enable_etf) {
next_txtime = next.tv_sec * NSEC_PER_SEC + next.tv_nsec;
next_txtime += thread_params.etf_offset;
}
if (thread_params.send_tx_delay) {
tx_data = next.tv_sec * NSEC_PER_SEC + next.tv_nsec;
tx_data += thread_params.send_tx_delay;
}
}
// Packet sending loop
for (nb_cycles = 0;; nb_cycles++) {
if (thread_params.max_cycles &&
nb_cycles >= ((unsigned int)thread_params.max_cycles))
break;
// TX data
*((uint64_t *)send_data) =
thread_params.send_tx_delay ? tx_data : 0xdeadbeef;
// Get timestamp before TSN task for stats
clock_gettime(CLOCK_REALTIME, &current);
do_tsn_task(send_data, next_txtime);
add_ns(&next, thread_params.interval);
// Update txtime and TX data timestamp if required
if (enable_etf) next_txtime += thread_params.interval;
if (thread_params.send_tx_delay) tx_data += thread_params.interval;
// Update statistics
if (nb_cycles) {
int interval_us = calcdiff_ns(current, previous) / 1000;
egress_stats.min_interval = _min_(interval_us, egress_stats.min_interval);
egress_stats.max_interval = _max_(interval_us, egress_stats.max_interval);
egress_stats.avg_interval =
(egress_stats.avg_interval * nb_cycles + interval_us) /
(nb_cycles + 1);
}
previous = current;
clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &next, NULL);
}
pthread_exit(NULL);
}
/*
* Main thread, has non-real time priority
* Handles the IO and creates the real time thread
* Main thread:
* - Has non-real time priority
* - Handles the IO and creates the real time thread
*/
int main(int argc, char *argv[]) {
pthread_t thread;
struct sched_param param;
pthread_attr_t attr;
// Default configuration values
thread_params.interval = 100000 * 1000;
thread_params.max_cycles = 0;
thread_params.priority = 99;
main_params.refresh_rate = 50000;
main_params.verbose = 0;
main_params.enable_tracing = 0;
main_params.enable_graph = 0;
enable_affinity = 0;
enable_etf = 0;
enable_timestamps = 0;
enable_histograms = 0;
tsn_task = SEND_PACKET_TASK;
egress_params.packet_priority = 3;
egress_params.tx_buffer_len = 1024;
/* Lock all current and future pages from preventing of being paged to
* swap */
if (mlockall(MCL_CURRENT | MCL_FUTURE)) {
perror("mlockall failed");
/* exit(-1) or do error handling */
}
// Process bash options
process_options(argc, argv);
egress_params.use_etf = enable_etf;
egress_params.use_timestamps = enable_timestamps;
if (enable_histograms) {
// Init histograms
memset(kernel_latency_hist, 0, sizeof(kernel_latency_hist));
memset(rtt_hist, 0, sizeof(rtt_hist));
}
if (main_params.enable_tracing) {
// Enable ftrace
open_fds();
}
// Catch breaks with sighand to print the histograms
init_signals(sighand);
// Initialize the UDP packet sending socket
init_udp_send(&egress_params, &egress_stats, enable_histograms,
main_params.enable_tracing, kernel_latency_hist);
// Initialize the UDP packet receiving socket if RTT is measured
if (tsn_task == RTT_TASK)
init_udp_recv(&ingress_params, &ingress_stats,
enable_histograms, kernel_latency_hist);
/* Initialize pthread attributes (default values) */
if (pthread_attr_init(&attr)) {
fprintf(stderr, "init pthread attributes failed\n");
exit(EXIT_FAILURE);
}
/* Set a specific stack size */
if (pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN)) {
fprintf(stderr, "pthread setstacksize failed\n");
exit(EXIT_FAILURE);
}
/* Set scheduler policy and priority of pthread */
if (pthread_attr_setschedpolicy(&attr, SCHED_FIFO)) {
fprintf(stderr, "pthread setschedpolicy failed\n");
exit(EXIT_FAILURE);
}
param.sched_priority = thread_params.priority;
if (pthread_attr_setschedparam(&attr, &param)) {
fprintf(stderr, "pthread setschedparam failed\n");
exit(EXIT_FAILURE);
}
/* Use scheduling parameters of attr */
if (pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED)) {
fprintf(stderr, "pthread setinheritsched failed\n");
exit(EXIT_FAILURE);
}
// Create the real time thread
if (pthread_create(&thread, &attr, packet_sending_thread, NULL))
error(EXIT_FAILURE, errno,
"Couldn't create packet sending thread");
// Verbose loop
for (;;) {
usleep(main_params.refresh_rate);
if (main_params.verbose) {
if (tsn_task == RTT_TASK) {
printf("%9" PRIu64 ": RTT: %4d %4d %4d\n",
nb_cycles, rtt_stats.min_rtt,
rtt_stats.avg_rtt, rtt_stats.max_rtt);
printf("\033[%dA", 1);
} else {
printf("%9" PRIu64
": [%4d, %4d], I (10us): %3d %3d %3d",
nb_cycles,
(int)egress_stats.invalid_parameter,
(int)egress_stats.missed_deadline,
egress_stats.min_interval / 10,
egress_stats.avg_interval / 10,
egress_stats.max_interval / 10);
if (enable_timestamps) {
printf(", K: %4d %4d %4d [%4d]\n",
egress_stats.min_kernel_latency,
egress_stats.avg_kernel_latency,
egress_stats.max_kernel_latency,
(int)egress_stats
.high_kernel_latency);
} else {
printf("\n");
}
printf("\033[%dA", 1);
}
}
if (thread_params.max_cycles)
if (thread_params.max_cycles == nb_cycles) break;
}
if (enable_histograms) print_histograms();
exit(EXIT_SUCCESS);
pthread_t thread;
struct sched_param param;
pthread_attr_t attr;
// Default configuration values
thread_params.interval = 100000 * 1000;
thread_params.max_cycles = 0;
thread_params.priority = 99;
thread_params.send_tx_delay = 0;
thread_params.affinity_cpu = -1;
thread_params.start_ts = 0;
main_params.refresh_rate = 50000;
main_params.verbose = 0;
main_params.enable_tracing = 0;
main_params.enable_graph = 0;
egress_params.packet_priority = 3;
egress_params.tx_buffer_len = 1024;
enable_etf = 0;
enable_timestamps = 0;
enable_histograms = 0;
tsn_task = SEND_PACKET_TASK;
// Lock all current and future pages from preventing of being paged to
// swap
if (mlockall(MCL_CURRENT | MCL_FUTURE)) {
fprintf(stderr, "mlockall failed");
exit(EXIT_FAILURE);
}
// Process bash options
process_options(argc, argv);
egress_params.use_etf = enable_etf;
egress_params.use_timestamps = enable_timestamps;
if (enable_histograms) {
// Init histograms
memset(kernel_latency_hist, 0, sizeof(kernel_latency_hist));
memset(rtt_hist, 0, sizeof(rtt_hist));
}
if (main_params.enable_tracing) {
// Enable ftrace
open_fds();
}
// Catch breaks with sighand to print the histograms
init_signals(sighand);
// Initialize the UDP packet sending socket
init_udp_send(&egress_params, &egress_stats, enable_histograms,
main_params.enable_tracing, kernel_latency_hist);
// Initialize the UDP packet receiving socket if RTT is measured
if (tsn_task == RTT_TASK)
init_udp_recv(&ingress_params, &ingress_stats, enable_histograms,
kernel_latency_hist);
// Initialize pthread attributes (default values)
if (pthread_attr_init(&attr)) {
fprintf(stderr, "init pthread attributes failed\n");
exit(EXIT_FAILURE);
}
// Set a specific stack size
if (pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN)) {
fprintf(stderr, "pthread setstacksize failed\n");
exit(EXIT_FAILURE);
}
// Set scheduler policy and priority of pthread
if (pthread_attr_setschedpolicy(&attr, SCHED_FIFO)) {
fprintf(stderr, "pthread setschedpolicy failed\n");
exit(EXIT_FAILURE);
}
param.sched_priority = thread_params.priority;
if (pthread_attr_setschedparam(&attr, &param)) {
fprintf(stderr, "pthread setschedparam failed\n");
exit(EXIT_FAILURE);
}
/* Use scheduling parameters of attr */
if (pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED)) {
fprintf(stderr, "pthread setinheritsched failed\n");
exit(EXIT_FAILURE);
}
// Create the real time thread
if (pthread_create(&thread, &attr, packet_sending_thread, NULL))
error(EXIT_FAILURE, errno, "Couldn't create packet sending thread");
// Verbose loop
for (;;) {
usleep(main_params.refresh_rate);
if (main_params.verbose) {
// RTT stats printing
if (tsn_task == RTT_TASK) {
// N_CYCLES, RTT min / avg / max
printf("%9" PRIu64 ": RTT: %4d %4d %4d\n", nb_cycles, rtt_stats.min_rtt,
rtt_stats.avg_rtt, rtt_stats.max_rtt);
printf("\033[%dA", 1);
// Packet send stats printing
} else {
// N_CYCLES, error queue, measured send interval min / avg / max
printf("%9" PRIu64 ": [%4d, %4d], I (10us): %3d %3d %3d", nb_cycles,
(int)egress_stats.invalid_parameter,
(int)egress_stats.missed_deadline,
egress_stats.min_interval / 10, egress_stats.avg_interval / 10,
egress_stats.max_interval / 10);
// SOF_TX timestamps
if (enable_timestamps)
printf(", K: %4d %4d %4d [%4d]\n", egress_stats.min_kernel_latency,
egress_stats.avg_kernel_latency,
egress_stats.max_kernel_latency,
(int)egress_stats.high_kernel_latency);
else
printf("\n");
printf("\033[%dA", 1);
}
}
if (thread_params.max_cycles)
if (thread_params.max_cycles == nb_cycles) break;
}
if (enable_histograms) print_histograms();
exit(EXIT_SUCCESS);
}
// Critical TSN task
/* Critical TSN task
*/
static void do_tsn_task(char *data, uint64_t next_txtime) {
struct timespec t1, t2;
int rtt_us;
// One way packet sending
if (tsn_task == SEND_PACKET_TASK) {
send_udp_packet(data, next_txtime);
// Round Trip Time measurement
} else if (tsn_task == RTT_TASK) {
clock_gettime(CLOCK_MONOTONIC, &t1);
send_udp_packet(data, next_txtime);
recv_udp_packet();
clock_gettime(CLOCK_MONOTONIC, &t2);
rtt_us = calcdiff_ns(t2, t1) / 1000;
rtt_stats.min_rtt = _min_(rtt_us, rtt_stats.min_rtt);
rtt_stats.max_rtt = _max_(rtt_us, rtt_stats.max_rtt);
rtt_stats.avg_rtt =
(((uint64_t)rtt_stats.avg_rtt) * (nb_cycles - 1) + rtt_us) /
nb_cycles;
if (rtt_us > MAX_RTT)
fprintf(stderr,
"RTT value higher than MAX_RTT : %d ( > %d)\n",
rtt_us, MAX_RTT);
else
rtt_hist[rtt_us]++;
}
struct timespec t1, t2;
int rtt_us;
// One way packet sending
if (tsn_task == SEND_PACKET_TASK) {
send_udp_packet(data, next_txtime);
// Round Trip Time measurement
} else if (tsn_task == RTT_TASK) {
clock_gettime(CLOCK_MONOTONIC, &t1);
send_udp_packet(data, next_txtime);
recv_udp_packet();
clock_gettime(CLOCK_MONOTONIC, &t2);
rtt_us = calcdiff_ns(t2, t1) / 1000;
rtt_stats.min_rtt = _min_(rtt_us, rtt_stats.min_rtt);
rtt_stats.max_rtt = _max_(rtt_us, rtt_stats.max_rtt);
rtt_stats.avg_rtt =
(((uint64_t)rtt_stats.avg_rtt) * (nb_cycles - 1) + rtt_us) / nb_cycles;
if (rtt_us > MAX_RTT)
fprintf(stderr, "RTT value higher than MAX_RTT : %d ( > %d)\n", rtt_us,
MAX_RTT);
else
rtt_hist[rtt_us]++;
}
}
// Print histograms in .json format
/* Print histograms in .json format
*/
static void print_histograms() {
uint64_t duration;
int duration_hour, duration_minutes, interval;
int max_hist_val;
uint64_t *histogram;
clock_gettime(CLOCK_MONOTONIC, &measures_end);
duration = calcdiff_ns(measures_end, measures_start);
duration_hour = duration / NSEC_PER_SEC / 3600;
duration_minutes = duration / NSEC_PER_SEC / 60 - duration_hour * 60;
interval = thread_params.interval / 1000;
printf(
"{\"measure_sets\": [{"
"\"measure_type\": \"%s\","
"\"props_names\": [\"%s\"],"
"\"units\": [\"us\"],"
"\"props_type\": \"histogram\","
"\"metadata\": {\"i\": \"%dus\", \"duration\": \"%dh%d\", "
"\"etf_offset\": \"%dus\"},"
"\"props\": [[",
(tsn_task == SEND_PACKET_TASK) ? "packet_send_timestamps"
: "packet_rtt",
(tsn_task == SEND_PACKET_TASK) ? "kernel_space" : "rtt", interval,
duration_hour, duration_minutes, thread_params.etf_offset);
if (tsn_task == SEND_PACKET_TASK) {
histogram = kernel_latency_hist;
max_hist_val = histogram_max(histogram, MAX_KERNEL_LATENCY - 1);
} else {
histogram = rtt_hist;
max_hist_val = histogram_max(histogram, MAX_RTT - 1);
}
for (int j = 0; j < max_hist_val; j++)
printf("%" PRIi64 "%s", histogram[j],
(j + 1 < max_hist_val ? ", " : ""));
printf("]]}]}\n");
uint64_t duration;
int duration_hour, duration_minutes, interval;
int max_hist_val;
uint64_t *histogram;
clock_gettime(CLOCK_MONOTONIC, &measures_end);
duration = calcdiff_ns(measures_end, measures_start);
duration_hour = duration / NSEC_PER_SEC / 3600;
duration_minutes = duration / NSEC_PER_SEC / 60 - duration_hour * 60;
interval = thread_params.interval / 1000;
printf(
"{\"measure_sets\": [{"
"\"measure_type\": \"%s\","
"\"props_names\": [\"%s\"],"
"\"units\": [\"us\"],"
"\"props_type\": \"histogram\","
"\"metadata\": {\"i\": \"%dus\", \"duration\": \"%dh%d\", "
"\"etf_offset\": \"%dus\"},"
"\"props\": [[",
(tsn_task == SEND_PACKET_TASK) ? "packet_send_timestamps" : "packet_rtt",
(tsn_task == SEND_PACKET_TASK) ? "kernel_space" : "rtt", interval,
duration_hour, duration_minutes, thread_params.etf_offset);
if (tsn_task == SEND_PACKET_TASK) {
histogram = kernel_latency_hist;
max_hist_val = histogram_max(histogram, MAX_KERNEL_LATENCY - 1);
} else {
histogram = rtt_hist;
max_hist_val = histogram_max(histogram, MAX_RTT - 1);
}
for (int j = 0; j < max_hist_val; j++)
printf("%" PRIi64 "%s", histogram[j], (j + 1 < max_hist_val ? ", " : ""));
printf("]]}]}\n");
}
static void sighand(int sig_num) {
(void)sig_num;
if (enable_histograms) print_histograms();
exit(EXIT_SUCCESS);
(void)sig_num;
if (enable_histograms) print_histograms();
exit(EXIT_SUCCESS);
}
// Process bash options
/* Process bash options
*/
static void process_options(int argc, char *argv[]) {
int network_if_specified = 0;
for (;;) {
int c = getopt(argc, argv, "abd:e:f:ghi:l:p:q:r:tvT");
if (c == -1) break;
switch (c) {
case 'a':
enable_affinity = 1;
break;
case 'b':
tsn_task = RTT_TASK;
break;
case 'd':
egress_params.tx_buffer_len = atoi(optarg);
if (egress_params.tx_buffer_len < 1) {
fprintf(stderr,
"BUF_LEN should be greater "
"than 1\n");
exit(EXIT_FAILURE);
}
break;
case 'e':
enable_etf = 1;
thread_params.etf_offset = atoi(optarg) * 1000;
break;
case 'f':
network_if_specified = 1;
strcpy(egress_params.network_if, optarg);
break;
case 'g':
enable_histograms = 1;
break;
case 'h':
help(argv);
exit(EXIT_SUCCESS);
break;
case 'i':
thread_params.interval = atoi(optarg) * 1000;
break;
case 'l':
thread_params.max_cycles = atoi(optarg);
break;
case 'p':
thread_params.priority = atoi(optarg);
break;
case 'q':
egress_params.packet_priority = atoi(optarg);
break;
case 'r':
main_params.refresh_rate = atoi(optarg);
break;
case 't':
enable_timestamps = 1;
break;
case 'v':
main_params.verbose = 1;
break;
case 'T':
main_params.enable_tracing = 1;
break;
}
}
if (!network_if_specified) {
fprintf(stderr, "You need to specifiy an network interface\n");
help(argv);
exit(EXIT_FAILURE);
}
if (argc != optind + 1) {
if (argc < optind + 1)
fprintf(stderr, "You need to specifiy an IP address\n");
else
fprintf(stderr, "Too many arguments\n");
help(argv);
exit(EXIT_FAILURE);
}
strcpy(egress_params.server_ip, argv[optind]);
for (;;) {
int c = getopt(argc, argv, "a:bc:d:e:ghi:l:p:q:r:s:tvT");
if (c == -1) break;
switch (c) {
case 'a':
thread_params.affinity_cpu = atoi(optarg);
break;
case 'b':
tsn_task = RTT_TASK;
break;
case 'c':
thread_params.send_tx_delay = atoi(optarg) * 1000;
break;
case 'd':
egress_params.tx_buffer_len = atoi(optarg);
if (egress_params.tx_buffer_len < 1) {
fprintf(stderr, "BUF_LEN should be greater than 1\n");
exit(EXIT_FAILURE);
}
break;
case 'e':
enable_etf = 1;
thread_params.etf_offset = atoi(optarg) * 1000;
break;
case 'g':
enable_histograms = 1;
break;
case 'h':
help(argv);
exit(EXIT_SUCCESS);
break;
case 'i':
thread_params.interval = atoi(optarg) * 1000;
break;
case 'l':
thread_params.max_cycles = atoi(optarg);
break;
case 'p':
thread_params.priority = atoi(optarg);
break;
case 'q':
egress_params.packet_priority = atoi(optarg);
break;
case 's':
thread_params.start_ts = strtoull(optarg, NULL, 10);
break;
case 'r':
main_params.refresh_rate = atoi(optarg);
break;
case 't':
enable_timestamps = 1;
break;
case 'v':
main_params.verbose = 1;
break;
case 'T':
main_params.enable_tracing = 1;
break;
}
}
if (argc != optind + 2) {
if (argc < optind + 2)
fprintf(stderr, "You need to specifiy an interface and IP address\n");
else
fprintf(stderr, "Too many arguments\n");
help(argv);
exit(EXIT_FAILURE);
}
strcpy(egress_params.network_if, argv[optind]);
strcpy(egress_params.server_ip, argv[optind + 1]);
}
......@@ -13,61 +13,66 @@ void (*previous_handlers[NSIG])(int);
static void (*sighand)(int);
uint64_t ts_to_uint(struct timespec t) {
return t.tv_sec * NSEC_PER_SEC + t.tv_nsec;
return t.tv_sec * NSEC_PER_SEC + t.tv_nsec;
}
struct timespec uint_to_ts(uint64_t t) {
struct timespec ts;
ts.tv_sec = t / NSEC_PER_SEC;
ts.tv_nsec = t - (ts.tv_sec * NSEC_PER_SEC);
return ts;
}
void add_ns(struct timespec *t, uint64_t ns) {
t->tv_nsec += ns;
t->tv_nsec += ns;
while ((unsigned int)t->tv_nsec >= NSEC_PER_SEC) {
t->tv_sec += 1;
t->tv_nsec -= NSEC_PER_SEC;
}
while ((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 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;
}
int _max_(int a, int b) { return a > b ? a : b; }
int _min_(int a, int b) { return a < b ? a : b; }
int histogram_min(uint64_t *histogram, int max_value) {
int ret = max_value;
for (int i = max_value; i >= 0; i--) ret = histogram[i] ? i : ret;
return ret;
int ret = max_value;
for (int i = max_value; i >= 0; i--) ret = histogram[i] ? i : ret;
return ret;
}
int histogram_max(uint64_t *histogram, int max_value) {
int ret = 0;
for (int i = 0; i <= max_value; i++) ret = histogram[i] ? i : ret;
return ret;
int ret = 0;
for (int i = 0; i <= max_value; i++) ret = histogram[i] ? i : ret;
return ret;
}
static void sighand_wrapper(int sig) {
// If we get un unexpected signal, report it, if not print the histogram
if (sig == SIGINT || sig == SIGTERM)
(*sighand)(sig); // Will print the histogram
else
printf("Uknown signal interrupt: %s (%d)\n", strsignal(sig),
sig);
// If we get un unexpected signal, report it, if not print the histogram
if (sig == SIGINT || sig == SIGTERM)
(*sighand)(sig); // Will print the histogram
else
printf("Uknown signal interrupt: %s (%d)\n", strsignal(sig), sig);
// Execute the default handler
if (previous_handlers[sig] == SIG_DFL) {
signal(sig, SIG_DFL);
raise(sig);
} else if (previous_handlers[sig] == SIG_IGN) {
return;
} else {
(*previous_handlers[sig])(sig);
}
// Execute the default handler
if (previous_handlers[sig] == SIG_DFL) {
signal(sig, SIG_DFL);
raise(sig);
} else if (previous_handlers[sig] == SIG_IGN) {
return;
} else {
(*previous_handlers[sig])(sig);
}
}
void init_signals(void (*_sighand)(int)) {
sighand = _sighand;
sighand = _sighand;
for (int i = 0; i < NSIG; i++) signal(i, sighand_wrapper);
for (int i = 0; i < NSIG; i++) signal(i, sighand_wrapper);
}
......@@ -39,6 +39,7 @@
#define err_errno(...) error(EXIT_FAILURE, errno, __VA_ARGS__);
uint64_t ts_to_uint(struct timespec t);
struct timespec uint_to_ts(uint64_t t);
void add_ns(struct timespec *t, uint64_t ns);
uint64_t calcdiff_ns(struct timespec t1, struct timespec t2);
......
#include "gpio.h"
#include <stdlib.h>
#include <stdio.h>
static int gpio_state;
static char cmd[128];
void enable_gpio(int gpio_index) {
sprintf(cmd, "echo %d > /sys/class/gpio/export", gpio_index);
system(cmd);
sprintf(cmd, "echo out > /sys/class/gpio/gpio%d/direction", gpio_index);
system(cmd);
}
void toggle_gpio(int gpio_index) {
sprintf(cmd, "echo %d > /sys/class/gpio/gpio%d/value", gpio_state, gpio_index);
system(cmd);
gpio_state = !gpio_state;
}
#ifndef GPIO_H
#define GPIO_H
void enable_gpio(int gpio_index);
void toggle_gpio(int gpio_index);
#endif
......@@ -26,7 +26,6 @@ typedef struct ingress_stat {
uint64_t packets_received;
uint64_t high_kernel_latency;
uint64_t high_jitter;
int lost_packets;
char data[MAX_BUFFER_SIZE];
} ingress_stat_t;
......
......@@ -22,32 +22,34 @@
#include <string.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include "common.h"
#include "recv_packet.h"
#include "send_packet.h"
#include "tracer.h"
#include "gpio.h"
// Structs
enum TSNTask { RECV_PACKET_TASK, RTT_TASK, XDP_TASK };
typedef struct thread_param {
int interval;
int priority;
uint64_t latency_threshold;
int interval;
int priority;
int affinity_cpu;
uint64_t latency_threshold;
int emit_signal;
} thread_param_t;
typedef struct main_params {
int refresh_rate;
int verbose;
int enable_tracing;
int enable_xdp_tracing;
int enable_graph;
int refresh_rate;
int verbose;
int enable_tracing;
int enable_xdp_tracing;
int enable_graph;
} main_param_t;
static void process_options(int argc, char *argv[]);
......@@ -58,459 +60,464 @@ static void sighand(int sig_num);
static uint64_t kernel_latency_hist[MAX_KERNEL_LATENCY];
static uint64_t jitter_hist[MAX_JITTER];
static main_param_t main_params;
static thread_param_t thread_params;
static ingress_param_t ingress_params;
static egress_param_t egress_params;
static egress_stat_t egress_stats = {.min_kernel_latency = INT_MAX};
static ingress_stat_t ingress_stats = {.min_kernel_latency = INT_MAX,
.min_interval = INT_MAX};
.min_interval = INT_MAX};
static int enable_histograms;
static int enable_affinity;
static int enable_timestamps;
static enum TSNTask tsn_task;
static struct timespec measures_start;
static struct timespec measures_end;
static struct timespec emit_signal_next;
static pthread_mutex_t emit_signal_mutex;
static pthread_cond_t emit_signal_ts_received;
static void help(char *argv[]) {
printf(
"Usage: %s [-aghtv] [-b CLIENT_IP] [-d BUF_LEN] [-f IF] [-i USEC] "
"[-p "
"PRIO] [-T LATENCY_THRESHOLD -G]"
" [-r USEC]\n\n"
" -a Run the real time thread on CPU1\n"
" -b CLIENT_IP Server side RTT\n"
" -d BUF_LEN Set the length of tx buffer\n"
" -f IF Set the network interface to be "
"used\n"
" -g Print histograms to sdtout on exit\n"
" -h Show help\n"
" -i USEC Wake up the real time thread every "
"USEC "
"microseconds (Default: 10ms)\n"
" -p PRIO Run the real time thread at priority "
"PRIO\n"
" -r USEC Refresh the non real time main "
"thread "
"every USEC microseconds\n"
" -t Enable timestamps\n"
" -v Verbose\n"
" -x POLL_MODE Use AF_XDP sockets\n"
" POLL_MODE: 0 for polling, 1 for combination of both\n"
" -X Trace during XDP packet reception\n"
" -T LATENCY_THRESHOLD Enable tracing until "
"LATENCY_THRESHOLD is "
"reached\n"
" -G Enable function_graph tracer, used "
"with "
"-T\n"
"\n",
argv[0]);
printf(
"Usage: %s [-f IF -a CPU -p PRIO -i USEC -r USEC] [-b CLIENT_IP] [-d "
"BUF_LEN -cgtv] [-T LATENCY_THRESHOLD -G] [-x POLL_MODE -X]\n\n"
" -h Show help\n"
" -f IF Set the network interface to be used\n"
" -a CPU Pin the real time thread to CPU\n"
" -p PRIO RT thread priority\n"
" -i USEC RT thread wake-up interval (default: 10ms)\n"
" -r USEC non-RT main thread refresh interval\n"
" -d BUF_LEN Set the length of tx buffer\n"
" -c Receive timestamp and emit signal\n"
" -b CLIENT_IP Server side RTT\n"
" -g Print histograms to sdtout on exit\n"
" -t Enable timestamps\n"
" -x POLL_MODE Use AF_XDP sockets\n"
" POLL_MODE: 0 for polling, 1 for combination of both\n"
" -X Trace during XDP packet reception\n"
" -T THRESHOLD Enable tracing until THRESHOLD is reached\n"
" -G Enable function_graph tracer, used with -T\n"
" -v Verbose\n"
"\n",
argv[0]);
}
// Real-time thread
// Measures intervals between packet receptions
static void *packet_receiving_thread(void *p) {
(void)p;
struct timespec current, previous;
cpu_set_t mask;
int prev_packet_id = 0;
char tracemark_message[128];
// Set thread CPU affinity
if (enable_affinity) {
CPU_ZERO(&mask);
CPU_SET(1, &mask);
if (sched_setaffinity(0, sizeof(mask), &mask))
error(EXIT_FAILURE, errno,
"Could not set CPU affinity to CPU #1\n");
}
clock_gettime(CLOCK_MONOTONIC, &measures_start);
if(tsn_task == XDP_TASK)
setup_poll_fd();
// Packet receiving loop
for (ingress_stats.packets_received = 0;;
ingress_stats.packets_received++) {
if (tsn_task == RTT_TASK) {
recv_udp_packet();
send_udp_packet("", 0);
} else if (tsn_task == RECV_PACKET_TASK ||
tsn_task == XDP_TASK) {
int current_packet_id;
if (tsn_task == RECV_PACKET_TASK)
recv_udp_packet();
else
recv_xdp_packet();
clock_gettime(CLOCK_MONOTONIC, &current);
recv_xdp_cleanup();
if (ingress_stats.packets_received) {
int interval_us =
calcdiff_ns(current, previous) / 1000;
ingress_stats.min_interval = _min_(
interval_us, ingress_stats.min_interval);
ingress_stats.max_interval = _max_(
interval_us, ingress_stats.max_interval);
ingress_stats.avg_interval =
(ingress_stats.avg_interval *
ingress_stats.packets_received +
interval_us) /
(ingress_stats.packets_received + 1);
if (tsn_task == RECV_PACKET_TASK) {
// Check if packets were lost
current_packet_id = atoi(ingress_stats.data);
ingress_stats.lost_packets +=
(current_packet_id -
prev_packet_id - 1) %
1000;
prev_packet_id = current_packet_id;
}
if (enable_histograms) {
int dist_to_interval =
interval_us -
(thread_params.interval / 1000);
dist_to_interval += MAX_JITTER / 2;
if (dist_to_interval >
((int)MAX_JITTER) ||
dist_to_interval < 0)
ingress_stats.high_jitter++;
else
jitter_hist[dist_to_interval]++;
}
}
// If the latency hits the tracing threshold, stop
// tracing
if (main_params.enable_tracing &&
(ingress_stats.max_interval >
((int)thread_params.latency_threshold))) {
sprintf(tracemark_message,
"Jitter threshold hit: %dus\n",
ingress_stats.max_interval);
tracemark(tracemark_message);
tracing(0);
break;
}
previous = current;
}
}
return NULL;
static void *emit_signal_thread(void *p) {
(void)p;
cpu_set_t mask;
// Set thread CPU affinity
if (thread_params.affinity_cpu) {
CPU_ZERO(&mask);
CPU_SET(thread_params.affinity_cpu, &mask);
if (sched_setaffinity(0, sizeof(mask), &mask))
error(EXIT_FAILURE, errno, "Could not set CPU affinity to CPU %d\n",
thread_params.affinity_cpu);
}
pthread_mutex_lock(&emit_signal_mutex);
for (;;) {
pthread_cond_wait(&emit_signal_ts_received, &emit_signal_mutex);
clock_nanosleep(CLOCK_TAI, TIMER_ABSTIME, &emit_signal_next, NULL);
toggle_gpio(49);
printf("Toggled GPIO\n");
}
pthread_mutex_unlock(&emit_signal_mutex);
pthread_exit(NULL);
}
/* Real-time thread:
* - Measures intervals between packet receptions
*/
static void *tsn_thread(void *p) {
(void)p;
struct timespec current, previous;
cpu_set_t mask;
char tracemark_message[128];
// Set thread CPU affinity
if (thread_params.affinity_cpu) {
CPU_ZERO(&mask);
CPU_SET(thread_params.affinity_cpu, &mask);
if (sched_setaffinity(0, sizeof(mask), &mask))
error(EXIT_FAILURE, errno, "Could not set CPU affinity to CPU %d\n", thread_params.affinity_cpu);
}
clock_gettime(CLOCK_MONOTONIC, &measures_start);
if (tsn_task == XDP_TASK) setup_poll_fd();
// Packet receiving loop
for (ingress_stats.packets_received = 0;; ingress_stats.packets_received++) {
// RTT
if (tsn_task == RTT_TASK) {
recv_udp_packet();
send_udp_packet("", 0);
// Receive packet
} else if (tsn_task == RECV_PACKET_TASK || tsn_task == XDP_TASK) {
// Receive UDP or XDP packet
if (tsn_task == RECV_PACKET_TASK)
recv_udp_packet();
else
recv_xdp_packet();
clock_gettime(CLOCK_MONOTONIC, &current);
recv_xdp_cleanup();
// Emit signal
if (thread_params.emit_signal) {
uint64_t emit_signal_t = *((uint64_t *) ingress_stats.data);
pthread_mutex_lock(&emit_signal_mutex);
emit_signal_next = uint_to_ts(emit_signal_t);
pthread_cond_signal(&emit_signal_ts_received);
pthread_mutex_unlock(&emit_signal_mutex);
}
// Update stats
if (ingress_stats.packets_received) {
int interval_us = calcdiff_ns(current, previous) / 1000;
ingress_stats.min_interval =
_min_(interval_us, ingress_stats.min_interval);
ingress_stats.max_interval =
_max_(interval_us, ingress_stats.max_interval);
ingress_stats.avg_interval =
(ingress_stats.avg_interval * ingress_stats.packets_received +
interval_us) /
(ingress_stats.packets_received + 1);
// Histogram
if (enable_histograms) {
int dist_to_interval = interval_us - (thread_params.interval / 1000);
dist_to_interval += MAX_JITTER / 2;
if (dist_to_interval > ((int)MAX_JITTER) || dist_to_interval < 0)
ingress_stats.high_jitter++;
else
jitter_hist[dist_to_interval]++;
}
}
// If the latency hits the tracing threshold, stop tracing
if (main_params.enable_tracing &&
(ingress_stats.max_interval >
((int)thread_params.latency_threshold))) {
sprintf(tracemark_message, "Jitter threshold hit: %dus\n",
ingress_stats.max_interval);
tracemark(tracemark_message);
tracing(0);
break;
}
previous = current;
}
}
return NULL;
}
// Main thread, has non-real time priority
// Handles the IO and creates real time threads
static void create_thread(void * (*thread_function)(void *)) {
pthread_t thread;
pthread_attr_t attr;
struct sched_param param;
// Initialize pthread attributes (default values)
if (pthread_attr_init(&attr)) {
fprintf(stderr, "init pthread attributes failed\n");
exit(EXIT_FAILURE);
}
// Set a specific stack size
if (pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN)) {
fprintf(stderr, "pthread setstacksize failed\n");
exit(EXIT_FAILURE);
}
// Set scheduler policy and priority of pthread
if (pthread_attr_setschedpolicy(&attr, SCHED_FIFO)) {
fprintf(stderr, "pthread setschedpolicy failed\n");
exit(EXIT_FAILURE);
}
param.sched_priority = thread_params.priority;
if (pthread_attr_setschedparam(&attr, &param)) {
fprintf(stderr, "pthread setschedparam failed\n");
exit(EXIT_FAILURE);
}
// Use scheduling parameters of attr
if (pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED)) {
fprintf(stderr, "pthread setinheritsched failed\n");
exit(EXIT_FAILURE);
}
// Create the real time thread
if (pthread_create(&thread, &attr, thread_function, NULL))
error(EXIT_FAILURE, errno, "Couldn't create packet receiving thread");
}
/* Main thread:
* - Has non-real time priority
* - Handles the IO and creates real time threads
*/
int main(int argc, char *argv[]) {
pthread_t thread;
struct sched_param param;
pthread_attr_t attr;
ingress_stats.min_interval = INT_MAX;
ingress_stats.avg_interval = 0;
ingress_stats.max_interval = 0;
ingress_stats.min_kernel_latency = INT_MAX;
ingress_stats.avg_kernel_latency = 0;
ingress_stats.max_kernel_latency = 0;
ingress_stats.packets_received = 0;
// Default configuration values
thread_params.interval = 100000 * 1000;
thread_params.priority = 99;
main_params.refresh_rate = 50000;
main_params.verbose = 0;
main_params.enable_tracing = 0;
main_params.enable_graph = 0;
enable_affinity = 0;
enable_timestamps = 0;
enable_histograms = 0;
tsn_task = RECV_PACKET_TASK;
ingress_params.tx_buffer_len = 1024;
// Process bash options
process_options(argc, argv);
ingress_params.use_timestamps = enable_timestamps;
ingress_params.interval = thread_params.interval;
if (enable_histograms) {
// Init histograms
memset(kernel_latency_hist, 0, sizeof(kernel_latency_hist));
memset(jitter_hist, 0, sizeof(jitter_hist));
}
if (main_params.enable_tracing || main_params.enable_xdp_tracing) {
// Enable ftrace
open_fds();
}
// Catch breaks with sighand to print the histograms or exit XDP
init_signals(sighand);
if (tsn_task == XDP_TASK) {
// Initialize the XDP packet receiving socket
init_xdp_recv(&ingress_params);
} else {
// Initialize the UDP packet receiving socket
init_udp_recv(&ingress_params, &ingress_stats,
enable_histograms, kernel_latency_hist);
}
// Initialize the UDP packet sending socket if RTT is measured
if (tsn_task == RTT_TASK)
init_udp_send(&egress_params, &egress_stats, 0, 0, NULL);
/* Initialize pthread attributes (default values) */
if (pthread_attr_init(&attr)) {
fprintf(stderr, "init pthread attributes failed\n");
exit(EXIT_FAILURE);
}
/* Set a specific stack size */
if (pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN)) {
fprintf(stderr, "pthread setstacksize failed\n");
exit(EXIT_FAILURE);
}
/* Set scheduler policy and priority of pthread */
if (pthread_attr_setschedpolicy(&attr, SCHED_FIFO)) {
fprintf(stderr, "pthread setschedpolicy failed\n");
exit(EXIT_FAILURE);
}
param.sched_priority = thread_params.priority;
if (pthread_attr_setschedparam(&attr, &param)) {
fprintf(stderr, "pthread setschedparam failed\n");
exit(EXIT_FAILURE);
}
/* Use scheduling parameters of attr */
if (pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED)) {
fprintf(stderr, "pthread setinheritsched failed\n");
exit(EXIT_FAILURE);
}
// Create the real time thread
if (pthread_create(&thread, &attr, packet_receiving_thread, NULL))
error(EXIT_FAILURE, errno,
"Couldn't create packet receiving thread");
// Verbose loop
for (;;) {
usleep(main_params.refresh_rate);
if (main_params.verbose && ingress_stats.packets_received > 1) {
if (tsn_task == RECV_PACKET_TASK ||
tsn_task == XDP_TASK) {
int jitter = ingress_stats.max_interval -
ingress_stats.min_interval;
printf(
"%9" PRIu64
": J: %5d, I (10us): %3d %3d %3d [%3d,%3d]",
ingress_stats.packets_received, jitter,
ingress_stats.min_interval / 10,
ingress_stats.avg_interval / 10,
ingress_stats.max_interval / 10,
(int)ingress_stats.high_jitter,
(int)ingress_stats.lost_packets);
if (enable_timestamps) {
printf(", K: %4d %4d %4d [%3d]\n",
ingress_stats.min_kernel_latency,
ingress_stats.avg_kernel_latency,
ingress_stats.max_kernel_latency,
(int)ingress_stats
.high_kernel_latency);
} else {
printf("\n");
}
printf("\033[%dA", 1);
}
}
if (main_params.enable_tracing &&
(ingress_stats.max_interval >=
((int)thread_params.latency_threshold)))
break;
}
close_xdp_socket();
// Initial values
ingress_stats.min_interval = INT_MAX;
ingress_stats.avg_interval = 0;
ingress_stats.max_interval = 0;
ingress_stats.min_kernel_latency = INT_MAX;
ingress_stats.avg_kernel_latency = 0;
ingress_stats.max_kernel_latency = 0;
ingress_stats.packets_received = 0;
// Default configuration values
thread_params.interval = 100000 * 1000;
thread_params.priority = 99;
thread_params.emit_signal = 0;
thread_params.affinity_cpu = 0;
main_params.refresh_rate = 50000;
main_params.verbose = 0;
main_params.enable_tracing = 0;
main_params.enable_graph = 0;
enable_timestamps = 0;
enable_histograms = 0;
tsn_task = RECV_PACKET_TASK;
ingress_params.tx_buffer_len = 1024;
// Process bash options
process_options(argc, argv);
ingress_params.use_timestamps = enable_timestamps;
ingress_params.interval = thread_params.interval;
// Init histograms
if (enable_histograms) {
memset(kernel_latency_hist, 0, sizeof(kernel_latency_hist));
memset(jitter_hist, 0, sizeof(jitter_hist));
}
// Enable ftrace
if (main_params.enable_tracing || main_params.enable_xdp_tracing) open_fds();
// Catch breaks with sighand to print the histograms or exit XDP
init_signals(sighand);
// Initialize the XDP or UDP packet receiving socket
if (tsn_task == XDP_TASK)
init_xdp_recv(&ingress_params);
else
init_udp_recv(&ingress_params, &ingress_stats, enable_histograms,
kernel_latency_hist);
// Initialize the UDP packet sending socket if RTT is measured
if (tsn_task == RTT_TASK)
init_udp_send(&egress_params, &egress_stats, 0, 0, NULL);
if(thread_params.emit_signal) {
pthread_mutex_init(&emit_signal_mutex, NULL);
pthread_cond_init(&emit_signal_ts_received, NULL);
enable_gpio(49);
}
create_thread(tsn_thread);
create_thread(emit_signal_thread);
// Verbose loop
for (;;) {
usleep(main_params.refresh_rate);
// Stats printing
if (main_params.verbose && ingress_stats.packets_received > 1 &&
(tsn_task == RECV_PACKET_TASK || tsn_task == XDP_TASK)) {
int jitter = ingress_stats.max_interval - ingress_stats.min_interval;
printf("%9" PRIu64 ": J: %5d, I (10us): %3d %3d %3d [%3d]",
ingress_stats.packets_received, jitter,
ingress_stats.min_interval / 10, ingress_stats.avg_interval / 10,
ingress_stats.max_interval / 10, (int)ingress_stats.high_jitter);
if (enable_timestamps)
printf(", K: %4d %4d %4d [%3d]\n", ingress_stats.min_kernel_latency,
ingress_stats.avg_kernel_latency,
ingress_stats.max_kernel_latency,
(int)ingress_stats.high_kernel_latency);
else
printf("\n");
printf("\033[%dA", 1);
}
if (main_params.enable_tracing &&
(ingress_stats.max_interval >= ((int)thread_params.latency_threshold)))
break;
}
pthread_mutex_destroy(&emit_signal_mutex);
pthread_cond_destroy(&emit_signal_ts_received);
close_xdp_socket();
}
// Print histograms in .json format
/* Print histograms in .json format
*/
static void print_histograms() {
uint64_t duration;
int duration_hour, duration_minutes, interval;
int max_latency, max_jitter, min_jitter;
clock_gettime(CLOCK_MONOTONIC, &measures_end);
duration = calcdiff_ns(measures_end, measures_start);
duration_hour = duration / NSEC_PER_SEC / 3600;
duration_minutes = duration / NSEC_PER_SEC / 60 - duration_hour * 60;
interval = thread_params.interval / 1000;
if (enable_timestamps) {
printf(
"{\"measure_sets\": [{"
"\"measure_type\": \"packet_recv_timestamps\","
"\"props_names\": [\"kernel_space\"],"
"\"units\": [\"us\"],"
"\"props_type\": \"histogram\","
"\"metadata\": {\"i\": \"%dus\", \"duration\": \"%dh%d\","
"\"lost_packets\": \"%d\"},"
"\"props\": [[",
interval, duration_hour, duration_minutes,
ingress_stats.lost_packets +
((int)ingress_stats.high_jitter));
max_latency =
histogram_max(kernel_latency_hist, MAX_KERNEL_LATENCY - 1);
for (int j = 0; j < max_latency; j++)
printf("%" PRIi64 "%s", kernel_latency_hist[j],
(j + 1 < max_latency ? ", " : ""));
printf("]]");
}
max_jitter = histogram_max(jitter_hist, MAX_JITTER - 1);
min_jitter = histogram_min(jitter_hist, MAX_JITTER - 1);
printf("%s", enable_timestamps ? "}, {" : "{\"measure_sets\": [{");
printf(
"\"measure_type\": \"packet_jitter\","
"\"props_names\": [\"jitter\"],"
"\"units\": [\"us\"],"
"\"props_type\": \"histogram\","
"\"middle\": \"%d\","
"\"metadata\": {\"i\": \"%dus\", \"duration\": \"%dh%d\","
"\"lost_packets\": \"%d\"},"
"\"props\": [[",
MAX_JITTER / 2 - min_jitter, interval, duration_hour,
duration_minutes,
ingress_stats.lost_packets + ((int)ingress_stats.high_jitter));
for (int j = min_jitter; j < max_jitter; j++)
printf("%" PRIi64 "%s", jitter_hist[j],
(j + 1 < max_jitter ? ", " : ""));
printf("]]}]}\n");
uint64_t duration;
int duration_hour, duration_minutes, interval;
int max_latency, max_jitter, min_jitter;
clock_gettime(CLOCK_MONOTONIC, &measures_end);
duration = calcdiff_ns(measures_end, measures_start);
duration_hour = duration / NSEC_PER_SEC / 3600;
duration_minutes = duration / NSEC_PER_SEC / 60 - duration_hour * 60;
interval = thread_params.interval / 1000;
if (enable_timestamps) {
printf(
"{\"measure_sets\": [{"
"\"measure_type\": \"packet_recv_timestamps\","
"\"props_names\": [\"kernel_space\"],"
"\"units\": [\"us\"],"
"\"props_type\": \"histogram\","
"\"metadata\": {\"i\": \"%dus\", \"duration\": \"%dh%d\","
"\"lost_packets\": \"%d\"},"
"\"props\": [[",
interval, duration_hour, duration_minutes,
((int)ingress_stats.high_jitter));
max_latency = histogram_max(kernel_latency_hist, MAX_KERNEL_LATENCY - 1);
for (int j = 0; j < max_latency; j++)
printf("%" PRIi64 "%s", kernel_latency_hist[j],
(j + 1 < max_latency ? ", " : ""));
printf("]]");
}
max_jitter = histogram_max(jitter_hist, MAX_JITTER - 1);
min_jitter = histogram_min(jitter_hist, MAX_JITTER - 1);
printf("%s", enable_timestamps ? "}, {" : "{\"measure_sets\": [{");
printf(
"\"measure_type\": \"packet_jitter\","
"\"props_names\": [\"jitter\"],"
"\"units\": [\"us\"],"
"\"props_type\": \"histogram\","
"\"middle\": \"%d\","
"\"metadata\": {\"i\": \"%dus\", \"duration\": \"%dh%d\","
"\"lost_packets\": \"%d\"},"
"\"props\": [[",
MAX_JITTER / 2 - min_jitter, interval, duration_hour, duration_minutes,
((int)ingress_stats.high_jitter));
for (int j = min_jitter; j < max_jitter; j++)
printf("%" PRIi64 "%s", jitter_hist[j], (j + 1 < max_jitter ? ", " : ""));
printf("]]}]}\n");
}
static void sighand(int sig_num) {
(void)sig_num;
(void)sig_num;
if (enable_histograms) {
print_histograms();
}
if (enable_histograms) {
print_histograms();
}
if (tsn_task == XDP_TASK) {
close_xdp_socket();
}
if (tsn_task == XDP_TASK) {
close_xdp_socket();
}
if (ingress_stats.lost_packets)
fprintf(stderr, "%d packets were lost\n",
ingress_stats.lost_packets);
if (ingress_stats.high_jitter)
fprintf(stderr, "%d packets were lost\n", ((int)ingress_stats.high_jitter));
exit(EXIT_SUCCESS);
exit(EXIT_SUCCESS);
}
// Process bash options
/* Process bash options
*/
static void process_options(int argc, char *argv[]) {
int network_if_specified = 0;
for (;;) {
int c = getopt(argc, argv, "ab:d:f:ghi:p:r:tvx:XT:G");
if (c == -1) break;
switch (c) {
case 'a':
enable_affinity = 1;
break;
case 'b':
tsn_task = RTT_TASK;
strcpy(egress_params.server_ip, optarg);
break;
case 'd':
ingress_params.tx_buffer_len = atoi(optarg);
if (ingress_params.tx_buffer_len < 1) {
fprintf(stderr,
"BUF_LEN should be greater "
"than 1\n");
exit(EXIT_FAILURE);
}
break;
case 'f':
network_if_specified = 1;
strcpy(ingress_params.network_if, optarg);
break;
case 'h':
help(argv);
exit(EXIT_SUCCESS);
break;
case 'i':
thread_params.interval = atoi(optarg) * 1000;
break;
case 'g':
enable_histograms = 1;
break;
case 'p':
thread_params.priority = atoi(optarg);
break;
case 'r':
main_params.refresh_rate = atoi(optarg);
break;
case 't':
enable_timestamps = 1;
break;
case 'v':
main_params.verbose = 1;
break;
case 'x':
tsn_task = XDP_TASK;
ingress_params.xdp_polling_mode = atoi(optarg);
break;
case 'X':
main_params.enable_xdp_tracing = 1;
break;
case 'T':
main_params.enable_tracing = 1;
thread_params.latency_threshold = atoi(optarg);
break;
case 'G':
main_params.enable_graph = 1;
break;
}
}
if (!network_if_specified) {
fprintf(stderr, "You need to specifiy an network interface\n");
help(argv);
exit(EXIT_FAILURE);
}
if (argc != optind) {
fprintf(stderr, "Too many arguments\n");
help(argv);
exit(EXIT_FAILURE);
}
int network_if_specified = 0;
for (;;) {
int c = getopt(argc, argv, "a:b:cd:f:ghi:p:r:tvx:XT:G");
if (c == -1) break;
switch (c) {
case 'a':
thread_params.affinity_cpu = atoi(optarg);
break;
case 'b':
tsn_task = RTT_TASK;
strcpy(egress_params.server_ip, optarg);
break;
case 'c':
thread_params.emit_signal = 1;
break;
case 'd':
ingress_params.tx_buffer_len = atoi(optarg);
if (ingress_params.tx_buffer_len < 1) {
fprintf(stderr, "BUF_LEN should be greater than 1\n");
exit(EXIT_FAILURE);
}
break;
case 'f':
network_if_specified = 1;
strcpy(ingress_params.network_if, optarg);
break;
case 'h':
help(argv);
exit(EXIT_SUCCESS);
break;
case 'i':
thread_params.interval = atoi(optarg) * 1000;
break;
case 'g':
enable_histograms = 1;
break;
case 'p':
thread_params.priority = atoi(optarg);
break;
case 'r':
main_params.refresh_rate = atoi(optarg);
break;
case 't':
enable_timestamps = 1;
break;
case 'v':
main_params.verbose = 1;
break;
case 'x':
tsn_task = XDP_TASK;
ingress_params.xdp_polling_mode = atoi(optarg);
break;
case 'X':
main_params.enable_xdp_tracing = 1;
break;
case 'T':
main_params.enable_tracing = 1;
thread_params.latency_threshold = atoi(optarg);
break;
case 'G':
main_params.enable_graph = 1;
break;
}
}
if (!network_if_specified) {
fprintf(stderr, "You need to specifiy an network interface\n");
help(argv);
exit(EXIT_FAILURE);
}
if (argc != optind) {
fprintf(stderr, "Too many arguments\n");
help(argv);
exit(EXIT_FAILURE);
}
}
......@@ -5,8 +5,8 @@ script_dir=$(dirname $(realpath $0))
usage() {
cat << ENDUSAGE
Usage: $0 QDISC_OPT [CLIENT_OPTS] BOARD
QDISC_OPTS: (-e delta [-o etf_offset] -H | -p)
CLIENT_OPTS: -bgt -i INTERVAL -I if -d TX_BUF_LEN [TRACE_OPTS]
QDISC_OPTS: (-e delta [-o etf_offset] -H | -p) [-q]
CLIENT_OPTS: -bgt -c DELAY -s NS -i INTERVAL -I if -a CPU -d TX_BUF_LEN [TRACE_OPTS]
TRACE_OPTS: [-T -P TRACER -E EVENTS -B SIZE]
default tracer opts: irq, sched, net_dev_start_xmit,
net_dev_xmit, net_dev_xmit_timeout
......@@ -21,17 +21,24 @@ interval=100000
# Default options
interface="eth0"
client_options="-a -p 99"
cpu="1"
client_options="-p 99"
qdisc_options=""
etf_offset=500
tracecmd_events="-e irq -e sched -e net_dev_start_xmit -e net_dev_xmit -e net_dev_xmit_timeout"
tracecmd_opts=""
while getopts "bd:e:o:ghi:ptB:E:I:HP:T" opt; do
while getopts "a:bc:d:e:o:ghi:pqs:tB:E:I:HP:T" opt; do
case "${opt}" in
a )
cpu=${OPTARG}
;;
b )
client_options+=" -b"
;;
c )
client_options+=" -c ${OPTARG}"
;;
d )
client_options+=" -d ${OPTARG}"
;;
......@@ -59,6 +66,12 @@ while getopts "bd:e:o:ghi:ptB:E:I:HP:T" opt; do
client_options+=" -q 1"
qdisc_options+="-p"
;;
q )
dont_create_qdisc=1
;;
s )
client_options+=" -s ${OPTARG}"
;;
t )
use_timestamps=1
client_options+=" -t"
......@@ -88,14 +101,15 @@ while getopts "bd:e:o:ghi:ptB:E:I:HP:T" opt; do
esac
done
shift $((OPTIND-1))
if [ -z "$1" ]; then
usage
fi
client_options+=" -f $interface"
qdisc_options+=" -I $interface"
client_options+=" -a $cpu"
board_name=$1
......@@ -131,8 +145,10 @@ fi
client_options+=" -i $interval"
echo "create-qdisc $qdisc_options";
$script_dir/create-qdisc $qdisc_options;
if [ -z "$dont_create_qdisc" ]; then
echo "create-qdisc $qdisc_options";
$script_dir/create-qdisc $qdisc_options;
fi
echo "make client";
cd $script_dir/../packet-exchange/build;
......@@ -140,13 +156,13 @@ make client;
cd $script_dir;
if [ -n "${use_histogram}" ]; then
echo "client $client_options $board_ip > $output;mv $output ~/";
$script_dir/../packet-exchange/build/client $client_options $board_ip > $output;
echo "client $client_options $interface $board_ip > $output;mv $output ~/";
$script_dir/../packet-exchange/build/client $client_options $interface $board_ip > $output;
mv $output ~/;
elif [ -n "${use_tracer}" ]; then
echo "trace-cmd record $tracecmd_opts $tracecmd_events ./client $client_options $board_ip";
trace-cmd record $tracecmd_opts $tracecmd_events $script_dir/../packet-exchange/build/client $client_options $board_ip;
echo "trace-cmd record $tracecmd_opts $tracecmd_events ./client $client_options $interface $board_ip";
trace-cmd record $tracecmd_opts $tracecmd_events $script_dir/../packet-exchange/build/client $client_options $interface $board_ip;
else
echo "client $client_options $board_ip";
$script_dir/../packet-exchange/build/client $client_options $board_ip;
echo "client $client_options $interface $board_ip";
$script_dir/../packet-exchange/build/client $client_options $interface $board_ip;
fi
#!/bin/bash
linuxptp_dir=/home/oli/linuxptp
opts=""
interface="eth0"
usage() {
echo "Usage: $0 [-r -i IF -o OPTS]" 1>&2;
exit 1;
}
while getopts "i:o:r" opt; do
case "${opt}" in
i )
interface=${OPTARG}
;;
o )
opts+=${OPTARG}
;;
r )
reset=1
;;
* )
usage
;;
esac
done
shift $((OPTIND-1))
opts+="-s $interface"
log=phc2sys_${interface}_log
if [ -n "$reset" ]; then
killall phc2sys;
fi
echo "phc2sys $opts -c CLOCK_REALTIME --step_threshold=1 --transportSpecific=1 -w -m &> ~/$log &";
phc2sys $opts -c CLOCK_REALTIME --step_threshold=1 --transportSpecific=1 -w -m &> ~/$log &
......@@ -6,20 +6,30 @@ telecom_profile="G.8265.1.cfg"
gPTP_profile="gPTP.cfg"
profile_name="none"
opts=""
interface="eth0"
usage() {
echo "Usage: $0 [-p telecom|gPTP|OTHER -s -o OPTS]" 1>&2;
echo "Usage: $0 [-r -p telecom|gPTP|OTHER -s -H -i IF -o OPTS]" 1>&2;
exit 1;
}
while getopts "o:p:s" opt; do
while getopts "i:o:p:rsH" opt; do
case "${opt}" in
i )
interface=${OPTARG}
;;
H )
opts+=" -H "
;;
o )
opts+=${OPTARG}
;;
p )
profile_name=${OPTARG}
;;
r )
reset=1
;;
s )
opts+=" -s "
;;
......@@ -31,6 +41,8 @@ done
shift $((OPTIND-1))
opts+="-i $interface"
if [ $profile_name == "none" ]; then
opts+=""
elif [ $profile_name == "telecom" ]; then
......@@ -41,6 +53,10 @@ else
opts=" -f $profile_name "
fi
killall ptp4l;
echo "ptp4l $opts -i eth0 --step_threshold=1 -m -S &> ~/ptp4l_log &";
ptp4l $opts -i eth0 --step_threshold=1 -m -S &> ~/ptp4l_log &
log=ptp4l_${interface}_log
if [ -n "$reset" ]; then
killall ptp4l;
fi
echo "ptp4l $opts --step_threshold=1 -m -S &> ~/$log &";
ptp4l $opts --step_threshold=1 -m -S &> ~/$log &
......@@ -9,7 +9,7 @@ usage() {
usage() {
cat << ENDUSAGE
Usage: $0 [-I if] SERVER | TCPDUMP [TRACE_OPTS]
SERVER: [-bt] [(-x | -X) POLL] [-g INTERVAL]
SERVER: [-bct] [(-x | -X) POLL] [-g INTERVAL] [-a CPU]
TCPDUMP: -d NB_PACKETS [-i INTERVAL]
TRACE_OPTS: (-T LATENCY_THRESHOLD -G) | -E LATENCY_THRESHOLD
ENDUSAGE
......@@ -20,18 +20,25 @@ ENDUSAGE
# Default options
interface="eth0"
server_options="-a -p 99"
server_options="-p 99"
make_opts=""
ip="10.100.21."
tcpdump_interval=1000000
tracecmd_events="-e irq -e sched -e xdp -e net -e page_pool -e preemptirq -e napi"
cpu=1
while getopts "b:htx:X:d:i:g:I:T:GE:" opt; do
while getopts "a:b:chtx:X:d:i:g:I:T:GE:" opt; do
case "${opt}" in
a )
cpu=${OPTARG}
;;
b )
use_rtt=1
board_name=${OPTARG}
;;
c )
server_options+=" -c"
;;
d )
use_tcpdump=1
nb_packets=${OPTARG}
......@@ -80,7 +87,7 @@ done
shift $((OPTIND-1))
server_options+=" -f $interface"
server_options+=" -f $interface -a $cpu"
if [ -n "${use_rtt}" ]; then
if [ $board_name != "emerald" ] && [ $board_name != "onyx" ] && [ $board_name != "slate" ]; then
......
#!/bin/bash
usage() {
echo "Usage: $0 [-r -i IF -o OPTS]" 1>&2;
exit 1;
}
while getopts "i:o:r" opt; do
case "${opt}" in
i )
interface=${OPTARG}
;;
o )
opts+=${OPTARG}
;;
r )
reset=1
;;
* )
usage
;;
esac
done
shift $((OPTIND-1))
# Setup irqs
ksoftirq1_pid=$(ps -eL -o pid,cmd | grep "ksoftirqd/1" | awk '{ print $1 }' | head -n1)
ksoftirq2_pid=$(ps -eL -o pid,cmd | grep "ksoftirqd/2" | awk '{ print $1 }' | head -n1)
# Set high priority for ksoftirq deamons
chrt -f -p 97 $ksoftirq1_pid;
chrt -f -p 97 $ksoftirq2_pid;
# Run linux-ptp
echo "Starting ptp4l on master";
killall ptp4l;
./run-ptp4l -i enp1s0 -H;
./run-ptp4l -i enp2s0 -H;
echo "Starting ptp4l on slaves";
./sudossh slate "killall ptp4l";
./sudossh onyx "killall ptp4l";
./sudossh slate "run-ptp4l -s";
./sudossh onyx "run-ptp4l -s";
echo "Waiting for ptp to take effect...";
sleep 10;
# Run phc2sys
./run-phc2sys -i enp1s0;
./run-phc2sys -i enp2s0;
echo "Waiting for phc2sys to take effect...";
sleep 2;
echo "Start servers on slave";
./sudossh slate "setup_irqs";
./sudossh onyx "setup_irqs";
./sudossh slate "killall server";
./sudossh onyx "killall server";
./exec-ssh-nohup slate "run-server -c";
./exec-ssh-nohup onyx "run-server -c";
cd ../gettime/build;
make;
time=$(./gettime -r -q)
echo "CLOCK_REALTIME time is $time";
time+=15000000000
echo "Start clients on master";
cd ../../scripts;
./run-client -a 1 -q -i 1000000 -p -I enp1s0 -c 500000 -s $time slate &> client_enp1s0_log&
./run-client -a 2 -q -i 1000000 -p -I enp2s0 -c 500000 -s $time onyx &> client_enp2s0_log&
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