Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
T
tsn-measures
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
nexedi
tsn-measures
Commits
31441586
Commit
31441586
authored
Jun 02, 2020
by
Joanne Hugé
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add option to print histograms to stdout on exit
parent
f696b55f
Changes
5
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
218 additions
and
118 deletions
+218
-118
packet-exchange/src/client.c
packet-exchange/src/client.c
+186
-112
packet-exchange/src/send_packet.c
packet-exchange/src/send_packet.c
+26
-4
packet-exchange/src/send_packet.h
packet-exchange/src/send_packet.h
+3
-1
packet-exchange/src/server.c
packet-exchange/src/server.c
+1
-1
packet-exchange/src/utilities.h
packet-exchange/src/utilities.h
+2
-0
No files found.
packet-exchange/src/client.c
View file @
31441586
/*
* Real time packet sending thread
*
* Bash options:
*
* -a Run the real time thread on CPU1
* -b Measure RTT
* -d BUF_LEN Set the length of tx buffer
* -e Set a txtime (to be used in an ETF qdisc)
* -f IF Set the network interface to be used
* -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)
* -p PRIO Run the real time thread at priority PRIO
* -r USEC Refresh the non real time main thread every USEC microseconds (Default: 50ms)
* -t Enable timestamps
*
* Large portions taken from cyclictest
*
*/
...
...
@@ -23,6 +10,7 @@
#include <error.h>
#include <pthread.h>
#include <sched.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
...
...
@@ -30,11 +18,14 @@
#include <time.h>
#include <unistd.h>
#include "send_packet.h"
#include "recv_packet.h"
#include "send_packet.h"
#include "utilities.h"
enum
TSNTask
{
SEND_PACKET_TASK
,
RTT_TASK
};
// Enum and structs
enum
TSNTask
{
SEND_PACKET_TASK
,
RTT_TASK
};
typedef
struct
thread_stat
{
int
nb_cycles
;
...
...
@@ -50,6 +41,7 @@ typedef struct thread_param {
int
enable_affinity
;
int
enable_etf
;
int
enable_timestamps
;
int
enable_histograms
;
enum
TSNTask
tsn_task
;
int
sockfd
;
...
...
@@ -62,12 +54,41 @@ typedef struct thread_param {
typedef
struct
main_param
{
int
refresh_rate
;
int
packet_priority
;
int
verbose
;
size_t
tx_buffer_len
;
}
main_param_t
;
// Static functions
static
void
process_options
(
int
argc
,
char
*
argv
[],
thread_param_t
*
param
,
main_param_t
*
main_param
);
static
void
do_tsn_task
(
struct
thread_param
*
param
,
uint64_t
next_txtime
);
static
void
do_tsn_task
(
struct
thread_param
*
param
,
uint64_t
next_txtime
);
static
void
print_histograms
();
static
void
sigint_handler
(
int
sig_num
);
// Static variables
static
int64_t
histograms
[
NB_HISTOGRAMS
][
MAX_HIST_VAL
];
static
main_param_t
main_param
;
static
thread_param_t
*
param
;
static
void
help
(
char
*
argv
[])
{
printf
(
"Usage: %s [-abethgv] [-d BUF_LEN] [-f IF] [-i USEC] [-l N] [-p PRIO] [-r USEC]
\n\n
"
,
argv
[
0
]);
printf
(
" -a Run the real time thread on CPU1
\n
"
);
printf
(
" -b Measure RTT
\n
"
);
printf
(
" -d BUF_LEN Set the length of tx buffer
\n
"
);
printf
(
" -e Set a txtime (to be used in an ETF qdisc)
\n
"
);
printf
(
" -f IF Set the network interface to be used
\n
"
);
printf
(
" -g Print histograms to sdtout on exit
\n
"
);
printf
(
" -h Show help
\n
"
);
printf
(
" -i USEC Wake up the real time thread every USEC microseconds (Default: 10ms)
\n
"
);
printf
(
" -l N Wake up the real time thread N times (Default: 0)
\n
"
);
printf
(
" -p PRIO Run the real time thread at priority PRIO
\n
"
);
printf
(
" -r USEC Refresh the non real time main thread every USEC microseconds (Default: 50ms)
\n
"
);
printf
(
" -t Enable timestamps
\n
"
);
printf
(
" -v Verbose
\n
"
);
printf
(
"
\n
"
);
}
// Real-time thread
// Sends packets at a regular intervall
...
...
@@ -101,7 +122,8 @@ static void *packet_sending_thread(void *p) {
// Packet sending loop
for
(
param
->
stats
.
nb_cycles
=
0
;;
param
->
stats
.
nb_cycles
++
)
{
if
(
param
->
max_cycles
)
if
(
param
->
stats
.
nb_cycles
>=
param
->
max_cycles
)
break
;
if
(
param
->
stats
.
nb_cycles
>=
param
->
max_cycles
)
break
;
do_tsn_task
(
param
,
next_txtime
);
...
...
@@ -118,65 +140,86 @@ static void *packet_sending_thread(void *p) {
// Handles the IO and creates real time threads
int
main
(
int
argc
,
char
*
argv
[])
{
pthread_t
thread
;
thread_param_t
param
;
main_param_t
main_param
;
signal
(
SIGINT
,
sigint_handler
);
param
=
malloc
(
sizeof
(
thread_param_t
));
// Default values
param
.
interval
=
100000
*
1000
;
param
.
max_cycles
=
0
;
param
.
priority
=
99
;
param
.
enable_affinity
=
0
;
param
.
enable_etf
=
0
;
param
.
enable_timestamps
=
0
;
param
.
tsn_task
=
SEND_PACKET_TASK
;
param
->
interval
=
100000
*
1000
;
param
->
max_cycles
=
0
;
param
->
priority
=
99
;
param
->
enable_affinity
=
0
;
param
->
enable_etf
=
0
;
param
->
enable_timestamps
=
0
;
param
->
enable_histograms
=
0
;
param
->
tsn_task
=
SEND_PACKET_TASK
;
main_param
.
refresh_rate
=
50000
;
main_param
.
packet_priority
=
3
;
main_param
.
tx_buffer_len
=
1024
;
main_param
.
verbose
=
0
;
// Process bash options
process_options
(
argc
,
argv
,
&
param
,
&
main_param
);
process_options
(
argc
,
argv
,
param
,
&
main_param
);
if
(
param
->
enable_histograms
)
{
// Init histograms
memset
((
int64_t
*
)
histograms
,
0
,
NB_HISTOGRAMS
*
MAX_HIST_VAL
);
}
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
();
if
(
param
->
tsn_task
==
RTT_TASK
)
param
->
sockfd
=
init_udp_recv
();
usleep
(
10000
);
if
(
pthread_create
(
&
thread
,
NULL
,
packet_sending_thread
,
(
void
*
)
&
param
))
if
(
pthread_create
(
&
thread
,
NULL
,
packet_sending_thread
,
(
void
*
)
param
))
error
(
EXIT_FAILURE
,
errno
,
"Couldn't create thread"
);
for
(;;)
{
usleep
(
main_param
.
refresh_rate
);
if
(
param
.
tsn_task
==
RTT_TASK
)
{
printf
(
"RTT: %"
PRIu64
" (%d)
\n
"
,
param
.
stats
.
rtt
,
param
.
stats
.
nb_cycles
);
if
(
main_param
.
verbose
)
{
if
(
param
->
tsn_task
==
RTT_TASK
)
{
printf
(
"RTT: %"
PRIu64
" (%d)
\n
"
,
param
->
stats
.
rtt
,
param
->
stats
.
nb_cycles
);
}
else
if
(
param
->
enable_timestamps
)
{
printf
(
"(%d)
\n
"
,
param
->
stats
.
nb_cycles
);
printf
(
" Enter send_udp_packet timestamp: %"
PRIu64
"
\n
"
,
param
->
stats
.
packet_ts
.
user_enter_send
);
printf
(
" Call sendmsg timestamp : %"
PRIu64
"
\n
"
,
param
->
stats
.
packet_ts
.
user_call_sendmsg
);
printf
(
" Leave kernel timestamp : %"
PRIu64
"
\n
"
,
param
->
stats
.
packet_ts
.
kernel_leave
);
}
else
if
(
param
.
enable_timestamps
)
{
printf
(
"(%d)
\n
"
,
param
.
stats
.
nb_cycles
);
printf
(
" Enter send_udp_packet timestamp: %"
PRIu64
"
\n
"
,
param
.
stats
.
packet_ts
.
user_enter_send
);
printf
(
" Call sendmsg timestamp : %"
PRIu64
"
\n
"
,
param
.
stats
.
packet_ts
.
user_call_sendmsg
);
printf
(
" Leave kernel timestamp : %"
PRIu64
"
\n
"
,
param
.
stats
.
packet_ts
.
kernel_leave
);
}
if
(
param
.
max_cycles
)
if
(
param
.
max_cycles
==
param
.
stats
.
nb_cycles
)
break
;
if
(
param
->
max_cycles
)
if
(
param
->
max_cycles
==
param
->
stats
.
nb_cycles
)
break
;
}
if
(
param
->
enable_histograms
)
print_histograms
();
exit
(
EXIT_SUCCESS
);
}
static
void
do_tsn_task
(
struct
thread_param
*
param
,
uint64_t
next_txtime
)
{
static
void
do_tsn_task
(
struct
thread_param
*
param
,
uint64_t
next_txtime
)
{
struct
timespec
t1
,
t2
;
if
(
param
->
tsn_task
==
SEND_PACKET_TASK
)
{
param
->
stats
.
packet_ts
=
send_udp_packet
(
param
->
enable_etf
,
param
->
enable_timestamps
,
next_txtime
,
param
->
ip_address
);
}
else
if
(
param
->
tsn_task
==
RTT_TASK
)
{
if
(
param
->
tsn_task
==
SEND_PACKET_TASK
)
{
param
->
stats
.
packet_ts
=
send_udp_packet
(
param
->
enable_etf
,
param
->
enable_timestamps
,
next_txtime
,
param
->
ip_address
,
histograms
);
}
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
);
send_udp_packet
(
param
->
enable_etf
,
param
->
enable_timestamps
,
next_txtime
,
param
->
ip_address
,
histograms
);
recv_udp_packet
(
param
->
sockfd
);
clock_gettime
(
CLOCK_MONOTONIC
,
&
t2
);
...
...
@@ -184,27 +227,52 @@ static void do_tsn_task(struct thread_param * param, uint64_t next_txtime) {
}
}
static
void
help
(
char
*
argv
[])
{
printf
(
"Usage: %s [-abet] [-d BUF_LEN] [-f IF] [-i USEC] [-l N] [-p PRIO] [-r USEC]
\n\n
"
,
argv
[
0
]);
printf
(
" -a Run the real time thread on CPU1
\n
"
);
printf
(
" -b Measure RTT
\n
"
);
printf
(
" -d BUF_LEN Set the length of tx buffer
\n
"
);
printf
(
" -e Set a txtime (to be used in an ETF qdisc)
\n
"
);
printf
(
" -f IF Set the network interface to be used
\n
"
);
printf
(
" -i USEC Wake up the real time thread every USEC microseconds (Default: 10ms)
\n
"
);
printf
(
" -l N Wake up the real time thread N times (Default: 0)
\n
"
);
printf
(
" -p PRIO Run the real time thread at priority PRIO
\n
"
);
printf
(
" -r USEC Refresh the non real time main thread every USEC microseconds (Default: 50ms)
\n
"
);
printf
(
" -t Enable timestamps
\n
"
);
printf
(
"
\n
"
);
static
void
print_histograms
()
{
printf
(
"{
\"
measure_type
\"
:
\"
packet_timestamps
\"
,\
\"
props_names
\"
: [
\"
user_space
\"
,
\"
kernel_space
\"
],\
\"
units
\"
: [
\"
us
\"
,
\"
us
\"
],\
\"
props
\"
: ["
);
for
(
int
i
=
0
;
i
<
NB_HISTOGRAMS
;
i
++
)
{
int
max_hist_val
=
MAX_HIST_VAL
;
for
(
int
j
=
0
;
j
<
MAX_HIST_VAL
;
j
++
)
max_hist_val
=
histograms
[
i
][
j
]
?
j
:
max_hist_val
;
printf
(
"["
);
for
(
int
j
=
0
;
j
<
max_hist_val
;
j
++
)
{
if
(
j
+
1
<
max_hist_val
)
printf
(
"%"
PRIi64
", "
,
histograms
[
i
][
j
]);
else
printf
(
"%"
PRIi64
,
histograms
[
i
][
j
]);
}
if
(
i
+
1
<
NB_HISTOGRAMS
)
printf
(
"], "
);
else
printf
(
"]"
);
}
int
interval
=
param
->
interval
/
1000
;
uint64_t
duration
=
interval
*
param
->
stats
.
nb_cycles
;
int
duration_hour
=
duration
/
(
1000000l
*
3600
);
int
duration_minutes
=
duration
/
(
1000000l
*
60
)
-
(
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
)
{
(
void
)
sig_num
;
if
(
param
->
enable_histograms
)
print_histograms
();
exit
(
EXIT_SUCCESS
);
}
static
void
process_options
(
int
argc
,
char
*
argv
[],
thread_param_t
*
param
,
main_param_t
*
main_param
)
{
for
(;;)
{
int
c
=
getopt
(
argc
,
argv
,
"abd:ef:
hi:l:p:q:r:t
"
);
int
c
=
getopt
(
argc
,
argv
,
"abd:ef:
ghi:l:p:q:r:tv
"
);
if
(
c
==
-
1
)
break
;
if
(
c
==
-
1
)
break
;
switch
(
c
)
{
case
'a'
:
...
...
@@ -215,7 +283,7 @@ static void process_options(int argc, char *argv[], thread_param_t *param,
break
;
case
'd'
:
main_param
->
tx_buffer_len
=
atoi
(
optarg
);
if
(
main_param
->
tx_buffer_len
<
1
)
{
if
(
main_param
->
tx_buffer_len
<
1
)
{
fprintf
(
stderr
,
"BUF_LEN should be greater than 1
\n
"
);
exit
(
EXIT_FAILURE
);
}
...
...
@@ -226,6 +294,9 @@ static void process_options(int argc, char *argv[], thread_param_t *param,
case
'f'
:
strcpy
(
param
->
network_if
,
optarg
);
break
;
case
'g'
:
param
->
enable_histograms
=
1
;
break
;
case
'h'
:
help
(
argv
);
exit
(
EXIT_SUCCESS
);
...
...
@@ -248,6 +319,9 @@ static void process_options(int argc, char *argv[], thread_param_t *param,
case
't'
:
param
->
enable_timestamps
=
1
;
break
;
case
'v'
:
main_param
->
verbose
=
1
;
break
;
default:
help
(
argv
);
exit
(
EXIT_FAILURE
);
...
...
packet-exchange/src/send_packet.c
View file @
31441586
...
...
@@ -41,7 +41,7 @@
#define MESSAGE ((uint32_t)0x00FACADE)
static
void
process_timestamps
(
struct
packet_timestamps
*
packet_ts
);
static
void
process_timestamps
(
struct
packet_timestamps
*
packet_ts
,
int64_t
histograms
[
NB_HISTOGRAMS
][
MAX_HIST_VAL
]
);
static
void
init_tx_buffer
(
size_t
_tx_buffer_len
);
static
int
so_priority
=
3
;
...
...
@@ -148,7 +148,8 @@ uint64_t get_txtime() {
*/
struct
packet_timestamps
send_udp_packet
(
int
use_etf
,
int
use_timestamps
,
uint64_t
txtime
,
const
char
*
server_ip
)
{
const
char
*
server_ip
,
int64_t
histograms
[
NB_HISTOGRAMS
][
MAX_HIST_VAL
])
{
char
control
[
CMSG_SPACE
(
sizeof
(
txtime
))]
=
{};
struct
sockaddr_in
sin
;
struct
cmsghdr
*
cmsg
;
...
...
@@ -205,7 +206,7 @@ struct packet_timestamps send_udp_packet(int use_etf, int use_timestamps,
if
(
use_timestamps
)
{
res
=
poll
(
&
poll_fd
,
1
,
0
);
if
(
res
>
0
)
process_timestamps
(
&
packet_ts
);
process_timestamps
(
&
packet_ts
,
histograms
);
else
fprintf
(
stderr
,
"select failed
\n
"
);
}
...
...
@@ -213,7 +214,27 @@ struct packet_timestamps send_udp_packet(int use_etf, int use_timestamps,
return
packet_ts
;
}
static
void
process_timestamps
(
struct
packet_timestamps
*
packet_ts
)
{
static
void
fill_histograms
(
struct
packet_timestamps
*
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
;
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
]
++
;
}
static
void
process_timestamps
(
struct
packet_timestamps
*
packet_ts
,
int64_t
histograms
[
NB_HISTOGRAMS
][
MAX_HIST_VAL
])
{
char
data
[
256
];
struct
msghdr
msg
;
struct
iovec
entry
;
...
...
@@ -243,6 +264,7 @@ static void process_timestamps(struct packet_timestamps *packet_ts) {
if
(
cmsg
->
cmsg_level
==
SOL_SOCKET
&&
cmsg
->
cmsg_type
==
SO_TIMESTAMPING
)
{
struct
timespec
*
stamp
=
(
struct
timespec
*
)
CMSG_DATA
(
cmsg
);
packet_ts
->
kernel_leave
=
ts_to_uint
(
*
stamp
);
fill_histograms
(
packet_ts
,
histograms
);
}
else
{
#ifdef DEBUG
fprintf
(
stderr
,
"process_timestamps: level %d type %d"
,
cmsg
->
cmsg_level
,
...
...
packet-exchange/src/send_packet.h
View file @
31441586
...
...
@@ -4,6 +4,8 @@
#include <stdint.h>
#include <stdio.h>
#include "utilities.h"
struct
packet_timestamps
{
uint64_t
user_enter_send
;
uint64_t
user_call_sendmsg
;
...
...
@@ -11,6 +13,6 @@ struct packet_timestamps {
};
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
);
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
packet-exchange/src/server.c
View file @
31441586
...
...
@@ -98,7 +98,7 @@ static void *packet_receiving_thread(void *p) {
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
);
send_udp_packet
(
0
,
0
,
0
,
param
->
ip_address
,
NULL
);
}
else
if
(
param
->
tsn_task
==
RECV_PACKET_TASK
)
{
recv_udp_packet
(
param
->
sockfd
);
...
...
packet-exchange/src/utilities.h
View file @
31441586
...
...
@@ -10,6 +10,8 @@
#define NSEC_PER_SEC UINT64_C(1000000000)
#define SERVER_PORT "50000"
#define SERVER_PORT_INT 50000
#define MAX_HIST_VAL 1000
#define NB_HISTOGRAMS 3
uint64_t
ts_to_uint
(
struct
timespec
t
);
void
add_ns
(
struct
timespec
*
t
,
uint64_t
ns
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment