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
1595e1c1
Commit
1595e1c1
authored
Jun 09, 2020
by
Joanne Hugé
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Update makefiles, remove latency-measure program, and upadte README
parent
aea66d79
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
10 additions
and
306 deletions
+10
-306
README.md
README.md
+1
-4
clockres/build/Makefile
clockres/build/Makefile
+7
-17
clockres/src/clockres.c
clockres/src/clockres.c
+1
-0
clockres/src/tracer.c
clockres/src/tracer.c
+1
-0
latency-measure/build/Makefile
latency-measure/build/Makefile
+0
-38
latency-measure/src/main.c
latency-measure/src/main.c
+0
-247
No files found.
README.md
View file @
1595e1c1
...
...
@@ -5,7 +5,7 @@ of three OLinuXino LIME2 boards I have.
## cyclictest like programs
clockres,
latency-measure
and packet-exchange are C programs wrote using
clockres, and packet-exchange are C programs wrote using
the same structure as cyclictest, and borrows large portions of the cyclictest
code:
...
...
@@ -18,9 +18,6 @@ can have it's priority set as an option, default is to 99. It writes results in
*
clockres is used to determine the resolution of the clock (CLOCK_MONOTONIC), by doing successive
calls to clock_gettime
*
latency-measure is used to determine the maximum wakeup latency of a real-time thread. It is
a simplified version of cyclictest I wrote to have a better understanding and more control.
*
packet-exchange has a client and a server, which exchange UDP ethernet packets using real-time threads,
and can send them on a ETF qdisc by setting a txtime timestamp. software timestamps can be generated using
the SO_TIMESTAMPING option, and timestamps inside the userspace program, for measuring purposes. A RTT
...
...
clockres/build/Makefile
View file @
1595e1c1
ARM_CC
=
arm-linux-gnueabihf-gcc
ARM_PROG
=
clockres_arm
PROG
=
clockres
SRCDIR
=
../src
...
...
@@ -8,34 +6,26 @@ SRCS += tracer.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
CPPFLAGS
=
-D_GNU_SOURCE
LDFLAGS
=
-pthread
vpath
%.c
$(SRCDIR)
$(ARM_PROG)
:
FORCE
make clean
make
-e
CC:
=
arm-linux-gnueabihf-gcc
$(PROG)
mv
$(PROG)
$(ARM_PROG)
FORCE
:
$(PROG)
:
$(OBJS)
$(CC)
$(LDFLAGS)
$^
-o
$@
-include
$(subst .c,.d,$(SRCS))
run
:
$(PROG)
./
$^
clean
:
$(RM)
$(OBJS)
$(PROG)
$(
ARM_PROG)
$(
subst
.c,.d,
$(SRCS)
)
$(RM)
$(OBJS)
$(PROG)
$(
subst
.c,.d,
$(SRCS)
)
.PHONY
:
clean
FORCE
.PHONY
:
clean
clockres/src/clockres.c
View file @
1595e1c1
#define _GNU_SOURCE
#include <errno.h>
#include <error.h>
#include <inttypes.h>
...
...
clockres/src/tracer.c
View file @
1595e1c1
#include "tracer.h"
#define _GNU_SOURCE
#include <errno.h>
#include <error.h>
#include <fcntl.h>
...
...
latency-measure/build/Makefile
deleted
100644 → 0
View file @
aea66d79
ARM_CC
=
arm-linux-gnueabihf-gcc
ARM_PROG
=
main_arm
PROG
=
main
SRCDIR
=
../src
SRCS
=
main.c
OBJS
=
$(SRCS:%.c=%.o)
CFLAGS
=
-Og
-g
-Wall
-Wextra
CFLAGS
+=
-MD
-MP
CFLAGS
+=
-I
$(SRCDIR)
CFLAGS
+=
-std
=
gnu99
LDFLAGS
=
-pthread
vpath
%.c
$(SRCDIR)
$(ARM_PROG)
:
FORCE
make clean
make
-e
CC:
=
arm-linux-gnueabihf-gcc
$(PROG)
mv
$(PROG)
$(ARM_PROG)
FORCE
:
$(PROG)
:
$(OBJS)
$(CC)
$(LDFLAGS)
$^
-o
$@
-include
$(subst .c,.d,$(SRCS))
run
:
$(PROG)
./
$^
clean
:
$(RM)
$(OBJS)
$(PROG)
$(
subst
.c,.d,
$(SRCS)
)
.PHONY
:
clean FORCE
latency-measure/src/main.c
deleted
100644 → 0
View file @
aea66d79
#include <errno.h>
#include <error.h>
#include <pthread.h>
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <stdint.h>
#include <inttypes.h>
#define CLOCK_ID CLOCK_MONOTONIC
#define NSECS_PER_SECOND INT64_C(1000000000)
#ifdef DEBUG_TRACE
struct
timespec
*
debug_current_times
;
struct
timespec
*
debug_next_times
;
int64_t
*
debug_diffs
;
#endif
typedef
struct
thread_stat
{
int
nb_cycles
;
int64_t
max_diff
;
int64_t
min_diff
;
}
thread_stat_t
;
typedef
struct
thread_param
{
int64_t
interval
;
int
priority
;
int
max_cycles
;
thread_stat_t
stat
;
}
thread_param_t
;
typedef
struct
main_param
{
int
refresh_rate
;
}
main_param_t
;
static
inline
int64_t
diff_ns
(
struct
timespec
t1
,
struct
timespec
t2
);
static
inline
int64_t
max
(
int64_t
a
,
int64_t
b
);
static
inline
int64_t
min
(
int64_t
a
,
int64_t
b
);
static
inline
struct
timespec
add_ns
(
struct
timespec
t
,
int64_t
ns
);
static
inline
struct
timespec
sub_ns
(
struct
timespec
t
,
int64_t
ns
);
static
void
sleep_poll
(
struct
timespec
*
next
,
struct
timespec
*
current
)
{
struct
timespec
pre_next
;
pre_next
=
sub_ns
(
next
,
3000000
);
clock_nanosleep
(
CLOCK_ID
,
TIMER_ABSTIME
,
pre_next
);
for
(;;)
{
clock_gettime
(
CLOCK_ID
,
current
);
if
(
current
->
tv_sec
>
next
->
tv_sec
||
(
current
->
tv_sec
==
next
->
tv_sec
&&
current
->
tv_nsec
>=
next
->
tv_nsec
)
)
break
;
}
}
static
void
sleep_nanosleep
(
struct
timespec
*
next
,
struct
timespec
*
current
)
{
clock_nanosleep
(
CLOCK_ID
,
TIMER_ABSTIME
,
next
,
NULL
);
clock_gettime
(
CLOCK_ID
,
current
);
}
// Real-time thread
static
void
*
timerthread
(
void
*
p
)
{
struct
timespec
next
;
struct
timespec
current
;
struct
sched_param
priority
;
thread_param_t
*
param
=
(
thread_param_t
*
)
p
;
thread_stat_t
*
stat
=
&
param
->
stat
;
priority
.
sched_priority
=
param
->
priority
;
int
err
=
sched_setscheduler
(
0
,
SCHED_FIFO
,
&
priority
);
if
(
err
)
error
(
EXIT_FAILURE
,
errno
,
"Couldn't set priority"
);
stat
->
max_diff
=
0
;
stat
->
min_diff
=
1000000
;
clock_gettime
(
CLOCK_ID
,
&
next
);
next
=
add_ns
(
next
,
param
->
interval
);
for
(
stat
->
nb_cycles
=
0
;;
stat
->
nb_cycles
++
)
{
if
(
param
->
max_cycles
)
if
(
stat
->
nb_cycles
>=
param
->
max_cycles
)
break
;
#ifdef DEBUG_TRACE
debug_next_times
[
stat
->
nb_cycles
]
=
next
;
#endif
sleep_poll
(
&
next
,
&
current
);
#ifdef DEBUG_TRACE
debug_current_times
[
stat
->
nb_cycles
]
=
current
;
#endif
int64_t
diff
=
diff_ns
(
current
,
next
);
#ifdef DEBUG_TRACE
debug_diffs
[
stat
->
nb_cycles
]
=
diff
;
#endif
stat
->
max_diff
=
max
(
stat
->
max_diff
,
diff
);
stat
->
min_diff
=
min
(
stat
->
min_diff
,
diff
);
next
=
add_ns
(
current
,
param
->
interval
);
}
printf
(
"Done
\n
"
);
return
NULL
;
}
static
void
process_options
(
int
argc
,
char
*
argv
[],
thread_param_t
*
param
,
main_param_t
*
main_param
)
{
for
(;;)
{
int
c
=
getopt
(
argc
,
argv
,
"l:p:i:r:"
);
if
(
c
==
-
1
)
break
;
switch
(
c
)
{
case
'p'
:
param
->
priority
=
atoi
(
optarg
);
break
;
case
'l'
:
param
->
max_cycles
=
atoi
(
optarg
);
break
;
case
'i'
:
param
->
interval
=
(
atoi
(
optarg
)
*
1000
);
break
;
case
'r'
:
main_param
->
refresh_rate
=
atoi
(
optarg
);
break
;
default:
exit
(
EXIT_FAILURE
);
break
;
}
}
}
// Main thread, has non-real time priority
// 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
;
int
err
;
// Default values
param
.
interval
=
1000000
;
param
.
max_cycles
=
100
;
param
.
priority
=
80
;
main_param
.
refresh_rate
=
10000
;
process_options
(
argc
,
argv
,
&
param
,
&
main_param
);
usleep
(
10000
);
#ifdef DEBUG_TRACE
debug_current_times
=
malloc
(
sizeof
(
struct
timespec
)
*
param
.
max_cycles
);
debug_next_times
=
malloc
(
sizeof
(
struct
timespec
)
*
param
.
max_cycles
);
debug_diffs
=
malloc
(
sizeof
(
int64_t
)
*
param
.
max_cycles
);
FILE
*
debug_log
=
fopen
(
"latency-measure-log"
,
"w+"
);
#endif
err
=
pthread_create
(
&
thread
,
NULL
,
timerthread
,
(
void
*
)
&
param
);
if
(
err
)
error
(
EXIT_FAILURE
,
errno
,
"Couldn't create thread"
);
for
(;;)
{
usleep
(
main_param
.
refresh_rate
);
printf
(
"Maximum latency: %"
PRIi64
"ns (%d)"
,
(
param
.
stat
.
max_diff
),
param
.
stat
.
nb_cycles
);
printf
(
", minimum latency: %"
PRIi64
"ns (%d)
\n
"
,
(
param
.
stat
.
min_diff
),
param
.
stat
.
nb_cycles
);
if
(
param
.
max_cycles
==
param
.
stat
.
nb_cycles
)
break
;
}
#ifdef DEBUG_TRACE
for
(
int
i
=
0
;
i
<
param
.
max_cycles
;
i
++
)
{
fprintf
(
debug_log
,
"%ld %"
PRIi64
"
\n\n
"
,
debug_next_times
[
i
].
tv_sec
,
debug_next_times
[
i
].
tv_nsec
);
fprintf
(
debug_log
,
"%ld %"
PRIi64
"
\n
"
,
debug_current_times
[
i
].
tv_sec
,
debug_current_times
[
i
].
tv_nsec
);
fprintf
(
debug_log
,
" %"
PRIi64
"
\n
"
,
debug_diffs
[
i
]);
}
fclose
(
debug_log
);
#endif
exit
(
EXIT_SUCCESS
);
}
static
inline
int64_t
diff_ns
(
struct
timespec
t1
,
struct
timespec
t2
)
{
int64_t
diff
;
diff
=
NSECS_PER_SECOND
*
(
t1
.
tv_sec
-
t2
.
tv_sec
);
diff
+=
((
int64_t
)
t1
.
tv_nsec
)
-
((
int64_t
)
t2
.
tv_nsec
);
if
(
diff
<
0
)
diff
=
-
diff
;
return
diff
;
}
static
inline
int64_t
max
(
int64_t
a
,
int64_t
b
)
{
return
a
>
b
?
a
:
b
;
}
static
inline
int64_t
min
(
int64_t
a
,
int64_t
b
)
{
return
a
<
b
?
a
:
b
;
}
static
inline
struct
timespec
add_ns
(
struct
timespec
t
,
int64_t
ns
)
{
struct
timespec
ret
;
ret
.
tv_nsec
=
t
.
tv_nsec
+
ns
;
ret
.
tv_sec
=
t
.
tv_sec
;
if
(
ret
.
tv_nsec
>=
NSECS_PER_SECOND
)
{
ret
.
tv_sec
++
;
ret
.
tv_nsec
-=
NSECS_PER_SECOND
;
}
return
ret
;
}
static
inline
struct
timespec
sub_ns
(
struct
timespec
t
,
int64_t
ns
)
{
struct
timespec
ret
;
ret
.
tv_nsec
=
t
.
tv_nsec
-
ns
;
ret
.
tv_sec
=
t
.
tv_sec
;
if
(
ret
.
tv_nsec
<
0
)
{
ret
.
tv_sec
--
;
ret
.
tv_nsec
+=
NSECS_PER_SECOND
;
}
return
ret
;
}
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