Commit 33d0cb10 authored by Joanne Hugé's avatar Joanne Hugé

Merge branch 'packet-exchange' into measure-analysis

parents 7eeb79bf 612189aa
/* /*
* Real time packet sending thread * Real time packet sending client
* *
* Large portions taken from cyclictest * Large portions taken from cyclictest
* *
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
typedef struct thread_stat { typedef struct thread_stat {
int nb_cycles; int nb_cycles;
uint64_t rtt; uint64_t rtt;
struct packet_timestamps packet_ts; packet_timestamps_t packet_ts;
} thread_stat_t; } thread_stat_t;
typedef struct thread_param { typedef struct thread_param {
...@@ -74,6 +74,9 @@ enum TSNTask { SEND_PACKET_TASK, ...@@ -74,6 +74,9 @@ enum TSNTask { SEND_PACKET_TASK,
RTT_TASK }; RTT_TASK };
static enum TSNTask tsn_task; static enum TSNTask tsn_task;
struct timespec measures_start;
struct timespec measures_end;
static void help(char *argv[]) { static void help(char *argv[]) {
printf("Usage: %s -f IF [-abethgv] [-d BUF_LEN] [-i USEC] [-l N] [-p PRIO] [-r USEC]\n\n", argv[0]); printf("Usage: %s -f IF [-abethgv] [-d BUF_LEN] [-i USEC] [-l N] [-p PRIO] [-r USEC]\n\n", argv[0]);
printf(" -a Run the real time thread on CPU1\n"); printf(" -a Run the real time thread on CPU1\n");
...@@ -99,7 +102,7 @@ static void *packet_sending_thread(void *p) { ...@@ -99,7 +102,7 @@ static void *packet_sending_thread(void *p) {
uint64_t next_txtime; uint64_t next_txtime;
struct sched_param priority; struct sched_param priority;
thread_param_t *param = (thread_param_t *)p; thread_param_t *param = (thread_param_t *)p;
thread_stat_t * stats = &param->stats; thread_stat_t *stats = &param->stats;
cpu_set_t mask; cpu_set_t mask;
// Set thread CPU affinity // Set thread CPU affinity
...@@ -122,6 +125,7 @@ static void *packet_sending_thread(void *p) { ...@@ -122,6 +125,7 @@ static void *packet_sending_thread(void *p) {
// Send packet while thread is sleeping // Send packet while thread is sleeping
next_txtime += (param->interval) / 2; next_txtime += (param->interval) / 2;
clock_gettime(CLOCK_MONOTONIC, &measures_start);
// Packet sending loop // Packet sending loop
for (stats->nb_cycles = 0;; stats->nb_cycles++) { for (stats->nb_cycles = 0;; stats->nb_cycles++) {
if (param->max_cycles) if (param->max_cycles)
...@@ -184,7 +188,7 @@ int main(int argc, char *argv[]) { ...@@ -184,7 +188,7 @@ int main(int argc, char *argv[]) {
// Initialize the UDP packet receiving socket if RTT is measured // Initialize the UDP packet receiving socket if RTT is measured
if (tsn_task == RTT_TASK) if (tsn_task == RTT_TASK)
init_udp_recv(); init_udp_recv(0, network_config.network_if);
// Create the real time thread // Create the real time thread
if (pthread_create(&thread, NULL, packet_sending_thread, (void *)param)) if (pthread_create(&thread, NULL, packet_sending_thread, (void *)param))
...@@ -201,13 +205,15 @@ int main(int argc, char *argv[]) { ...@@ -201,13 +205,15 @@ int main(int argc, char *argv[]) {
} else if (enable_timestamps) { } else if (enable_timestamps) {
printf("(%d)\n", stats->nb_cycles); printf("(%d) Enter send_udp_packet timestamp: %" PRIu64 "\n",
printf(" Enter send_udp_packet timestamp: %" PRIu64 "\n", stats->nb_cycles,
stats->packet_ts.user_enter_send); stats->packet_ts.enter_user_space);
printf(" Call sendmsg timestamp : %" PRIu64 "\n", printf("(%d) Call sendmsg timestamp : %" PRIu64 "\n",
stats->packet_ts.user_call_sendmsg); stats->nb_cycles,
printf(" Leave kernel timestamp : %" PRIu64 "\n", stats->packet_ts.enter_kernel);
stats->packet_ts.kernel_leave); printf("(%d) Leave kernel timestamp : %" PRIu64 "\n",
stats->nb_cycles,
stats->packet_ts.leave_kernel);
} }
} }
...@@ -233,60 +239,57 @@ static void do_tsn_task(struct thread_param *param, uint64_t next_txtime) { ...@@ -233,60 +239,57 @@ static void do_tsn_task(struct thread_param *param, uint64_t next_txtime) {
enable_etf, enable_timestamps, next_txtime, enable_etf, enable_timestamps, next_txtime,
network_config.ip_address, histograms); network_config.ip_address, histograms);
// Round Trip Time measurement // Round Trip Time measurement
} else if (tsn_task == RTT_TASK) { } else if (tsn_task == RTT_TASK) {
clock_gettime(CLOCK_MONOTONIC, &t1); clock_gettime(CLOCK_MONOTONIC, &t1);
send_udp_packet(enable_etf, enable_timestamps, next_txtime, send_udp_packet(0, 0, next_txtime,
network_config.ip_address, histograms); network_config.ip_address, NULL);
recv_udp_packet(); recv_udp_packet(0, NULL);
clock_gettime(CLOCK_MONOTONIC, &t2); clock_gettime(CLOCK_MONOTONIC, &t2);
param->stats.rtt = calcdiff_ns(t2, t1); param->stats.rtt = calcdiff_ns(t2, t1);
} }
} }
// Print histograms in .json format // Print histograms in .json format
static void print_histograms() { static void print_histograms() {
printf("{\"measure_type\": \"packet_timestamps\",\ uint64_t duration;
\"props_names\": [\"user_space\", \"kernel_space\"],\ int duration_hour, duration_minutes, interval;
\"units\": [\"us\", \"us\"],\
\"props\": ["); 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 = param->interval / 1000;
printf("{\"measure_sets\": [{"
"\"measure_type\": \"packet_send_timestamps\","
"\"props_names\": [\"user_space\", \"kernel_space\"],"
"\"units\": [\"us\", \"us\"],"
"\"props_type\": \"histogram\","
"\"metadata\": {"
"\"i\": \"%dus\", \"duration\": \"%dh%d\""
"},"
"\"props\": [", interval, duration_hour, duration_minutes);
int max_hist_val = 0; int max_hist_val = 0;
for (int i = 0; i < NB_HISTOGRAMS; i++) { for (int i = 0; i < 2; i++)
for (int j = 0; j < MAX_HIST_VAL; j++) for (int j = 0; j < MAX_HIST_VAL; j++)
if (histograms[i][j]) if (histograms[i][j])
max_hist_val = j > max_hist_val ? j : max_hist_val; max_hist_val = j > max_hist_val ? j : max_hist_val;
}
for (int i = 0; i < NB_HISTOGRAMS; i++) {
for (int i = 0; i < 2; i++) {
printf("["); printf("[");
for (int j = 0; j < max_hist_val; j++) { for (int j = 0; j < max_hist_val; j++)
if (j + 1 < max_hist_val) printf("%" PRIi64 "%s", histograms[i][j], (j + 1 < max_hist_val ? ", " : ""));
printf("%" PRIi64 ", ", histograms[i][j]); printf("%s", (i + 1 < 2 ? "], " : "]"));
else
printf("%" PRIi64, histograms[i][j]);
}
if (i + 1 < NB_HISTOGRAMS)
printf("], ");
else
printf("]");
} }
int interval = param->interval / 1000; printf( "]]}]}\n");
uint64_t duration = interval * param->stats.nb_cycles;
int duration_hour = duration / 1000000;
duration_hour /= 3600;
int duration_minutes = duration / 1000000;
duration_minutes /= 60;
duration_minutes -= duration_hour * 60;
printf("], ");
printf("\"props_type\": \"histogram\", \"metadata\": {\"i\": \"%dus\", \"duration\": \"%dh%d\"}}\n", interval, duration_hour, duration_minutes);
} }
static void sigint_handler(int sig_num) { static void sigint_handler(int sig_num) {
...@@ -359,14 +362,14 @@ static void process_options(int argc, char *argv[]) { ...@@ -359,14 +362,14 @@ static void process_options(int argc, char *argv[]) {
} }
} }
if(!network_if_specified) { if (!network_if_specified) {
fprintf(stderr, "You need to specifiy an network interface\n"); fprintf(stderr, "You need to specifiy an network interface\n");
help(argv); help(argv);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if (argc != optind + 1) { if (argc != optind + 1) {
if( argc < optind + 1) if (argc < optind + 1)
fprintf(stderr, "You need to specifiy an IP address\n"); fprintf(stderr, "You need to specifiy an IP address\n");
else else
fprintf(stderr, "Too many arguments\n"); fprintf(stderr, "Too many arguments\n");
...@@ -375,4 +378,3 @@ static void process_options(int argc, char *argv[]) { ...@@ -375,4 +378,3 @@ static void process_options(int argc, char *argv[]) {
} }
strcpy(network_config.ip_address, argv[optind]); strcpy(network_config.ip_address, argv[optind]);
} }
...@@ -2,31 +2,60 @@ ...@@ -2,31 +2,60 @@
#include <arpa/inet.h> #include <arpa/inet.h>
#include <errno.h> #include <errno.h>
#include <error.h> #include <error.h>
#include <fcntl.h>
#include <ifaddrs.h>
#include <inttypes.h> #include <inttypes.h>
#include <linux/errqueue.h>
#include <linux/ethtool.h>
#include <linux/net_tstamp.h>
#include <linux/sockios.h>
#include <net/if.h>
#include <netdb.h> #include <netdb.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <poll.h>
#include <pthread.h> #include <pthread.h>
#include <sched.h> #include <sched.h>
#include <signal.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/ioctl.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
#include <time.h>
#include <unistd.h> #include <unistd.h>
#include "send_packet.h"
#include "utilities.h" #include "utilities.h"
#define SERVER_PORT "50000"
#define BUFFER_SIZE 1024 #define BUFFER_SIZE 1024
static void fill_histograms(packet_timestamps_t *packet_ts, int64_t histograms[NB_HISTOGRAMS][MAX_HIST_VAL]);
static char rx_buffer[BUFFER_SIZE]; static char rx_buffer[BUFFER_SIZE];
static int sock_fd; static int sock_fd;
int init_udp_recv() { static int so_timestamping_flags =
int status; SOF_TIMESTAMPING_RX_SOFTWARE | SOF_TIMESTAMPING_SOFTWARE;
int sock_fd = -1;
// Sets the interface
static int set_if(char *network_if) {
struct ifreq ifreq;
memset(&ifreq, 0, sizeof(ifreq));
strncpy(ifreq.ifr_name, network_if, sizeof(ifreq.ifr_name) - 1);
if (ioctl(sock_fd, SIOCGIFINDEX, &ifreq))
error(EXIT_FAILURE, errno, "ioctl SIOCGIFINDEX failed\n");
return ifreq.ifr_ifindex;
}
int init_udp_recv(int use_timestamps, char *network_if) {
int getaddrinfo_err;
int set_if_err;
struct addrinfo hints, *servinfo, *servinfo_it; struct addrinfo hints, *servinfo, *servinfo_it;
memset(&hints, 0, sizeof hints); memset(&hints, 0, sizeof hints);
...@@ -34,16 +63,16 @@ int init_udp_recv() { ...@@ -34,16 +63,16 @@ int init_udp_recv() {
hints.ai_socktype = SOCK_DGRAM; hints.ai_socktype = SOCK_DGRAM;
hints.ai_flags = AI_PASSIVE; hints.ai_flags = AI_PASSIVE;
status = getaddrinfo(NULL, SERVER_PORT, &hints, &servinfo); getaddrinfo_err = getaddrinfo(NULL, SERVER_PORT, &hints, &servinfo);
if (status != 0) { if (getaddrinfo_err != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(status)); fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(getaddrinfo_err));
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
for (servinfo_it = servinfo; servinfo_it; for (servinfo_it = servinfo; servinfo_it;
servinfo_it = servinfo_it->ai_next) { servinfo_it = servinfo_it->ai_next) {
sock_fd = socket(servinfo->ai_family, servinfo->ai_socktype, sock_fd = socket(servinfo->ai_family, servinfo->ai_socktype,
servinfo->ai_protocol); servinfo->ai_protocol);
if (bind(sock_fd, servinfo_it->ai_addr, servinfo_it->ai_addrlen) == -1) { if (bind(sock_fd, servinfo_it->ai_addr, servinfo_it->ai_addrlen) == -1) {
close(sock_fd); close(sock_fd);
...@@ -54,23 +83,148 @@ int init_udp_recv() { ...@@ -54,23 +83,148 @@ int init_udp_recv() {
freeaddrinfo(servinfo); freeaddrinfo(servinfo);
if(sock_fd == -1) if (sock_fd == -1)
error(EXIT_FAILURE, errno, "Couldn't create receive socket"); error(EXIT_FAILURE, errno, "Couldn't create receive socket");
printf("waiting to receive...\n"); set_if_err = set_if(network_if);
if (set_if_err < 0)
error(EXIT_FAILURE, errno, "Couldn't set interface\n");
if (setsockopt(sock_fd, SOL_SOCKET, SO_BINDTODEVICE, network_if,
strlen(network_if)))
error(EXIT_FAILURE, errno, "setsockopt SO_BINDTODEVICE failed\n");
if (use_timestamps) {
if (setsockopt(sock_fd, SOL_SOCKET, SO_TIMESTAMPING, &so_timestamping_flags,
sizeof(so_timestamping_flags)))
error(EXIT_FAILURE, errno, "setsockopt SO_TIMESTAMPING failed\n");
}
return sock_fd; return sock_fd;
} }
void recv_udp_packet() { /*
* Receives udp packets
*/
packet_timestamps_t recv_udp_packet(int use_timestamps, int64_t histograms[NB_HISTOGRAMS][MAX_HIST_VAL]) {
struct cmsghdr *cmsg;
struct msghdr msg; // Message hardware, sent to the socket
struct iovec iov; // The iovec structures stores the RX buffer
struct sockaddr_in sin;
int recvmsgerr;
packet_timestamps_t packet_ts;
struct timespec ts;
if (use_timestamps) {
clock_gettime(CLOCK_REALTIME, &ts);
packet_ts.enter_user_space = ts_to_uint(ts);
}
iov.iov_base = &rx_buffer;
iov.iov_len = BUFFER_SIZE - 1;
memset(&msg, 0, sizeof(msg));
msg.msg_name = &sin;
msg.msg_namelen = sizeof(sin);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
if (use_timestamps) {
clock_gettime(CLOCK_REALTIME, &ts);
packet_ts.enter_kernel = ts_to_uint(ts);
}
recvmsgerr = recvmsg(sock_fd, &msg, 0);
if (recvmsgerr < 0)
error(EXIT_FAILURE, errno, "recvmsg failed, ret value: %d\n", recvmsgerr);
if(use_timestamps) {
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SO_TIMESTAMPING) {
struct timespec *stamp = (struct timespec *)CMSG_DATA(cmsg);
packet_ts.leave_kernel = ts_to_uint(*stamp);
fill_histograms(&packet_ts, histograms);
}
}
}
return packet_ts;
}
static void fill_histograms(packet_timestamps_t *packet_ts, int64_t histograms[NB_HISTOGRAMS][MAX_HIST_VAL]) {
uint64_t user_space_time = packet_ts->enter_kernel - packet_ts->enter_user_space;
uint64_t kernel_space_time = packet_ts->leave_kernel - packet_ts->enter_kernel;
user_space_time /= 1000u;
kernel_space_time /= 1000u;
if (user_space_time > MAX_HIST_VAL) {
fprintf(stderr, "user_space_time value too high: %" PRIu64 "us\n", user_space_time);
exit(EXIT_FAILURE);
}
if (kernel_space_time > MAX_HIST_VAL) {
fprintf(stderr, "kernel_space_time value too high: %" PRIu64 "us\n", kernel_space_time);
exit(EXIT_FAILURE);
}
histograms[0][user_space_time]++;
histograms[1][kernel_space_time]++;
}
#ifdef DEBUG #ifdef DEBUG
int bytes_received = 0;
bytes_received = recvfrom(sock_fd, rx_buffer, BUFFER_SIZE - 1, 0, NULL, NULL); /*
* Code from scheduled_tx_tools
*/
static int process_socket_error_queue() {
uint8_t msg_control[CMSG_SPACE(sizeof(struct sock_extended_err))];
unsigned char err_buffer[256];
struct sock_extended_err *serr;
struct cmsghdr *cmsg;
__u64 tstamp = 0;
if (bytes_received == -1) struct iovec iov = {.iov_base = err_buffer, .iov_len = sizeof(err_buffer)};
error(EXIT_FAILURE, errno, "Error while attempting to receive packets"); struct msghdr msg = {.msg_iov = &iov,
#else .msg_iovlen = 1,
recvfrom(sock_fd, rx_buffer, BUFFER_SIZE - 1, 0, NULL, NULL); .msg_control = msg_control,
#endif .msg_controllen = sizeof(msg_control)};
if (recvmsg(sock_fd, &msg, MSG_ERRQUEUE) == -1) {
fprintf(stderr, "recvmsg failed");
return -1;
}
cmsg = CMSG_FIRSTHDR(&msg);
while (cmsg != NULL) {
serr = (void *)CMSG_DATA(cmsg);
if (serr->ee_origin == SO_EE_ORIGIN_TXTIME) {
tstamp = ((__u64)serr->ee_data << 32) + serr->ee_info;
switch (serr->ee_code) {
case SO_EE_CODE_TXTIME_INVALID_PARAM:
fprintf(stderr,
"packet with tstamp %llu dropped due to invalid params\n",
tstamp);
return 0;
case SO_EE_CODE_TXTIME_MISSED:
fprintf(stderr,
"packet with tstamp %llu dropped due to missed deadline\n",
tstamp);
return 0;
default:
return -1;
}
}
cmsg = CMSG_NXTHDR(&msg, cmsg);
}
return 0;
} }
#endif
#ifndef RECV_PACKET #ifndef RECV_PACKET
#define RECV_PACKET #define RECV_PACKET
int init_udp_recv(); #include "utilities.h"
void recv_udp_packet();
int init_udp_recv(int use_timestamps, char *network_if);
packet_timestamps_t recv_udp_packet(int use_timestamps, int64_t histograms[NB_HISTOGRAMS][MAX_HIST_VAL]);
#endif #endif
...@@ -7,7 +7,6 @@ ...@@ -7,7 +7,6 @@
* *
*/ */
#define _GNU_SOURCE #define _GNU_SOURCE
#include <arpa/inet.h> #include <arpa/inet.h>
#include <errno.h> #include <errno.h>
...@@ -36,12 +35,12 @@ ...@@ -36,12 +35,12 @@
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h> #include <unistd.h>
#include "utilities.h"
#include "send_packet.h" #include "send_packet.h"
#include "utilities.h"
#define MESSAGE ((uint32_t)0x00FACADE) #define MESSAGE ((uint32_t)0x00FACADE)
static void process_timestamps(struct packet_timestamps *packet_ts, int64_t histograms[NB_HISTOGRAMS][MAX_HIST_VAL]); static void process_timestamps(packet_timestamps_t *packet_ts, int64_t histograms[NB_HISTOGRAMS][MAX_HIST_VAL]);
static void init_tx_buffer(size_t _tx_buffer_len); static void init_tx_buffer(size_t _tx_buffer_len);
static int so_priority = 3; static int so_priority = 3;
...@@ -89,7 +88,7 @@ static void init_tx_buffer(size_t _tx_buffer_len) { ...@@ -89,7 +88,7 @@ static void init_tx_buffer(size_t _tx_buffer_len) {
*/ */
void init_udp_send(int use_etf, int use_timestamps, int packet_priority, void init_udp_send(int use_etf, int use_timestamps, int packet_priority,
char *network_if, size_t _tx_buffer_len) { char *network_if, size_t _tx_buffer_len) {
int index; int set_if_err;
struct timespec ts_mon; struct timespec ts_mon;
struct timespec ts_tai; struct timespec ts_tai;
...@@ -104,10 +103,12 @@ void init_udp_send(int use_etf, int use_timestamps, int packet_priority, ...@@ -104,10 +103,12 @@ void init_udp_send(int use_etf, int use_timestamps, int packet_priority,
so_priority = packet_priority; so_priority = packet_priority;
sock_fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); sock_fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sock_fd < 0) error(EXIT_FAILURE, errno, "Socket creation failed\n"); if (sock_fd < 0)
error(EXIT_FAILURE, errno, "Socket creation failed\n");
index = set_if(network_if); set_if_err = set_if(network_if);
if (index < 0) error(EXIT_FAILURE, errno, "Couldn't set interface\n"); if (set_if_err < 0)
error(EXIT_FAILURE, errno, "Couldn't set interface\n");
if (setsockopt(sock_fd, SOL_SOCKET, SO_PRIORITY, &so_priority, if (setsockopt(sock_fd, SOL_SOCKET, SO_PRIORITY, &so_priority,
sizeof(so_priority))) sizeof(so_priority)))
...@@ -146,25 +147,26 @@ uint64_t get_txtime() { ...@@ -146,25 +147,26 @@ uint64_t get_txtime() {
/* /*
* Sends udp packets * Sends udp packets
*/ */
struct packet_timestamps send_udp_packet(int use_etf, int use_timestamps, packet_timestamps_t send_udp_packet(int use_etf, int use_timestamps,
uint64_t txtime, uint64_t txtime,
const char *server_ip, const char *server_ip,
int64_t histograms[NB_HISTOGRAMS][MAX_HIST_VAL]) { int64_t histograms[NB_HISTOGRAMS][MAX_HIST_VAL]) {
char control[CMSG_SPACE(sizeof(txtime))] = {}; struct msghdr msg; // Message hardware, sent to the socket
struct sockaddr_in sin; struct cmsghdr *cmsg; // Control message hardware, for txtime
struct cmsghdr *cmsg; char control[CMSG_SPACE(sizeof(txtime))] = {}; // Stores txtime
struct msghdr msg; struct iovec iov; // The iovec structures stores the TX buffer
struct iovec iov; // Poll file descriptor, used to poll for timestamp messages
int sendmsgerr;
int res;
struct pollfd poll_fd = {sock_fd, POLLPRI, 0}; struct pollfd poll_fd = {sock_fd, POLLPRI, 0};
int sendmsgerr, pollerr;
// Server address
struct sockaddr_in sin;
struct packet_timestamps packet_ts; packet_timestamps_t packet_ts;
struct timespec ts; struct timespec ts;
if (use_timestamps) { if (use_timestamps) {
clock_gettime(CLOCK_REALTIME, &ts); clock_gettime(CLOCK_REALTIME, &ts);
packet_ts.user_enter_send = ts_to_uint(ts); packet_ts.enter_user_space = ts_to_uint(ts);
} }
memset(&sin, 0, sizeof(sin)); memset(&sin, 0, sizeof(sin));
...@@ -196,7 +198,7 @@ struct packet_timestamps send_udp_packet(int use_etf, int use_timestamps, ...@@ -196,7 +198,7 @@ struct packet_timestamps send_udp_packet(int use_etf, int use_timestamps,
if (use_timestamps) { if (use_timestamps) {
clock_gettime(CLOCK_REALTIME, &ts); clock_gettime(CLOCK_REALTIME, &ts);
packet_ts.user_call_sendmsg = ts_to_uint(ts); packet_ts.enter_kernel = ts_to_uint(ts);
} }
sendmsgerr = sendmsg(sock_fd, &msg, 0); sendmsgerr = sendmsg(sock_fd, &msg, 0);
...@@ -204,8 +206,8 @@ struct packet_timestamps send_udp_packet(int use_etf, int use_timestamps, ...@@ -204,8 +206,8 @@ struct packet_timestamps send_udp_packet(int use_etf, int use_timestamps,
error(EXIT_FAILURE, errno, "sendmsg failed, ret value: %d\n", sendmsgerr); error(EXIT_FAILURE, errno, "sendmsg failed, ret value: %d\n", sendmsgerr);
if (use_timestamps) { if (use_timestamps) {
res = poll(&poll_fd, 1, 0); pollerr = poll(&poll_fd, 1, 0);
if (res > 0) if (pollerr > 0)
process_timestamps(&packet_ts, histograms); process_timestamps(&packet_ts, histograms);
else else
fprintf(stderr, "select failed\n"); fprintf(stderr, "select failed\n");
...@@ -214,18 +216,19 @@ struct packet_timestamps send_udp_packet(int use_etf, int use_timestamps, ...@@ -214,18 +216,19 @@ struct packet_timestamps send_udp_packet(int use_etf, int use_timestamps,
return packet_ts; return packet_ts;
} }
static void fill_histograms(struct packet_timestamps *packet_ts, int64_t histograms[NB_HISTOGRAMS][MAX_HIST_VAL]) { static void fill_histograms(packet_timestamps_t *packet_ts, int64_t histograms[NB_HISTOGRAMS][MAX_HIST_VAL]) {
uint64_t user_space_time = packet_ts->user_call_sendmsg - packet_ts->user_enter_send;
uint64_t kernel_space_time = packet_ts->kernel_leave - packet_ts->user_call_sendmsg; uint64_t user_space_time = packet_ts->enter_kernel - packet_ts->enter_user_space;
uint64_t kernel_space_time = packet_ts->leave_kernel - packet_ts->enter_kernel;
user_space_time /= 1000u; user_space_time /= 1000u;
kernel_space_time /= 1000u; kernel_space_time /= 1000u;
if(user_space_time > MAX_HIST_VAL) { if (user_space_time > MAX_HIST_VAL) {
fprintf(stderr, "user_space_time value too high: %" PRIu64 "us\n", user_space_time); fprintf(stderr, "user_space_time value too high: %" PRIu64 "us\n", user_space_time);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if(kernel_space_time > MAX_HIST_VAL) { if (kernel_space_time > MAX_HIST_VAL) {
fprintf(stderr, "kernel_space_time value too high: %" PRIu64 "us\n", kernel_space_time); fprintf(stderr, "kernel_space_time value too high: %" PRIu64 "us\n", kernel_space_time);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
...@@ -234,7 +237,7 @@ static void fill_histograms(struct packet_timestamps *packet_ts, int64_t histogr ...@@ -234,7 +237,7 @@ static void fill_histograms(struct packet_timestamps *packet_ts, int64_t histogr
histograms[1][kernel_space_time]++; histograms[1][kernel_space_time]++;
} }
static void process_timestamps(struct packet_timestamps *packet_ts, int64_t histograms[NB_HISTOGRAMS][MAX_HIST_VAL]) { static void process_timestamps(packet_timestamps_t *packet_ts, int64_t histograms[NB_HISTOGRAMS][MAX_HIST_VAL]) {
char data[256]; char data[256];
struct msghdr msg; struct msghdr msg;
struct iovec entry; struct iovec entry;
...@@ -262,14 +265,18 @@ static void process_timestamps(struct packet_timestamps *packet_ts, int64_t hist ...@@ -262,14 +265,18 @@ static void process_timestamps(struct packet_timestamps *packet_ts, int64_t hist
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SO_TIMESTAMPING) { if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SO_TIMESTAMPING) {
struct timespec *stamp = (struct timespec *)CMSG_DATA(cmsg); struct timespec *stamp = (struct timespec *)CMSG_DATA(cmsg);
packet_ts->kernel_leave = ts_to_uint(*stamp); packet_ts->leave_kernel = ts_to_uint(*stamp);
fill_histograms(packet_ts, histograms); fill_histograms(packet_ts, histograms);
} else { } else {
#ifdef DEBUG #ifdef DEBUG
fprintf(stderr, "process_timestamps: level %d type %d", cmsg->cmsg_level, fprintf(stderr, "process_timestamps: level %d type %d", cmsg->cmsg_level,
cmsg->cmsg_type); cmsg->cmsg_type);
#endif #endif
} }
} }
} }
...@@ -304,18 +311,18 @@ static int process_socket_error_queue() { ...@@ -304,18 +311,18 @@ static int process_socket_error_queue() {
tstamp = ((__u64)serr->ee_data << 32) + serr->ee_info; tstamp = ((__u64)serr->ee_data << 32) + serr->ee_info;
switch (serr->ee_code) { switch (serr->ee_code) {
case SO_EE_CODE_TXTIME_INVALID_PARAM: case SO_EE_CODE_TXTIME_INVALID_PARAM:
fprintf(stderr, fprintf(stderr,
"packet with tstamp %llu dropped due to invalid params\n", "packet with tstamp %llu dropped due to invalid params\n",
tstamp); tstamp);
return 0; return 0;
case SO_EE_CODE_TXTIME_MISSED: case SO_EE_CODE_TXTIME_MISSED:
fprintf(stderr, fprintf(stderr,
"packet with tstamp %llu dropped due to missed deadline\n", "packet with tstamp %llu dropped due to missed deadline\n",
tstamp); tstamp);
return 0; return 0;
default: default:
return -1; return -1;
} }
} }
......
#ifndef SEND_PACKET_H #ifndef SEND_PACKET_H
#define SEND_PACKET_H #define SEND_PACKET_H
#include <stdint.h>
#include <stdio.h>
#include "utilities.h" #include "utilities.h"
struct packet_timestamps { void init_udp_send(int use_etf, int use_timestamps, int so_priority, char *network_if, size_t tx_buffer_len);
uint64_t user_enter_send; packet_timestamps_t send_udp_packet(int use_etf, int use_timestamps, uint64_t txtime, const char *server_ip, int64_t histograms[NB_HISTOGRAMS][MAX_HIST_VAL]);
uint64_t user_call_sendmsg;
uint64_t kernel_leave;
};
void init_udp_send(int use_etf, int use_timestamps, int so_priority, char * network_if, size_t tx_buffer_len);
struct packet_timestamps send_udp_packet(int use_etf, int use_timestamps, uint64_t txtime, const char *server_ip, int64_t histograms[NB_HISTOGRAMS][MAX_HIST_VAL]);
#endif #endif
This diff is collapsed.
...@@ -28,4 +28,3 @@ uint64_t calcdiff_ns(struct timespec t1, struct timespec t2) { ...@@ -28,4 +28,3 @@ uint64_t calcdiff_ns(struct timespec t1, struct timespec t2) {
uint64_t max(uint64_t a, uint64_t b) { return a > b ? a : b; } 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; } uint64_t min(uint64_t a, uint64_t b) { return a < b ? a : b; }
...@@ -10,8 +10,14 @@ ...@@ -10,8 +10,14 @@
#define NSEC_PER_SEC UINT64_C(1000000000) #define NSEC_PER_SEC UINT64_C(1000000000)
#define SERVER_PORT "50000" #define SERVER_PORT "50000"
#define SERVER_PORT_INT 50000 #define SERVER_PORT_INT 50000
#define MAX_HIST_VAL 1000 #define MAX_HIST_VAL 2000
#define NB_HISTOGRAMS 2 #define NB_HISTOGRAMS 3
typedef struct packet_timestamps {
uint64_t enter_user_space;
uint64_t enter_kernel;
uint64_t leave_kernel;
} packet_timestamps_t;
uint64_t ts_to_uint(struct timespec t); uint64_t ts_to_uint(struct timespec t);
void add_ns(struct timespec *t, uint64_t ns); void add_ns(struct timespec *t, uint64_t ns);
......
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