Skip to content

Commit 1972fc1

Browse files
authored
added ping/pong examples (posix only) (eclipse-zenoh#154)
* added ping/pong examples (posix only) * clean up includes * address comments, make cmake skip ping and pong on non-unixes
1 parent bd4ab71 commit 1972fc1

File tree

3 files changed

+155
-1
lines changed

3 files changed

+155
-1
lines changed

examples/CMakeLists.txt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,18 @@ endif()
1414
declare_cache_var(ZENOHC_BUILD_EXAMPLES_WITH_STATIC_LIB FALSE BOOL "Use static zenohc lib for examples")
1515

1616
file(GLOB files "${CMAKE_CURRENT_SOURCE_DIR}/*.c")
17+
1718
foreach(file ${files})
1819
get_filename_component(target ${file} NAME_WE)
20+
21+
if(NOT(UNIX) AND(${target} STREQUAL "z_ping" OR ${target} STREQUAL "z_pong"))
22+
continue()
23+
endif()
24+
1925
add_executable(${target} EXCLUDE_FROM_ALL ${file})
2026
add_dependencies(examples ${target})
2127
add_platform_libraries(${target})
28+
2229
if(ZENOHC_BUILD_EXAMPLES_WITH_STATIC_LIB)
2330
add_dependencies(${target} zenohc::static)
2431
target_link_libraries(${target} PRIVATE zenohc::static)
@@ -27,6 +34,6 @@ foreach(file ${files})
2734
target_link_libraries(${target} PRIVATE zenohc::lib)
2835
copy_dlls(${target})
2936
endif()
37+
3038
set_property(TARGET ${target} PROPERTY C_STANDARD 11)
3139
endforeach()
32-

examples/z_ping.c

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
#include <pthread.h>
2+
#include <stdint.h>
3+
#include <stdio.h>
4+
#include <string.h>
5+
#include <time.h>
6+
7+
#include "zenoh.h"
8+
9+
pthread_cond_t cond;
10+
pthread_mutex_t mutex;
11+
12+
void callback(const z_sample_t* sample, void* context) { pthread_cond_signal(&cond); }
13+
void drop(void* context) { pthread_cond_destroy(&cond); }
14+
15+
struct args_t {
16+
unsigned int size; // -s
17+
unsigned int number_of_pings; // -n
18+
unsigned int warmup_ms; // -w
19+
char* config_path; // -c
20+
uint8_t help_requested; // -h
21+
};
22+
struct args_t parse_args(int argc, char** argv);
23+
24+
int main(int argc, char** argv) {
25+
struct args_t args = parse_args(argc, argv);
26+
if (args.help_requested) {
27+
printf(
28+
"\
29+
-n (optional, int, default=4): the number of pings to be attempted\n\
30+
-s (optional, int, default=8): the size of the payload embedded in the ping and repeated by the pong\n\
31+
-w (optional, int, default=0): the warmup time in ms during which pings will be emitted but not measured\n\
32+
-c (optional, string): the path to a configuration file for the session. If this option isn't passed, the default configuration will be used.\n\
33+
");
34+
return 1;
35+
}
36+
pthread_mutex_init(&mutex, NULL);
37+
pthread_cond_init(&cond, NULL);
38+
z_owned_config_t config = args.config_path ? zc_config_from_file(args.config_path) : z_config_default();
39+
z_owned_session_t session = z_open(z_move(config));
40+
z_keyexpr_t ping = z_keyexpr_unchecked("test/ping");
41+
z_keyexpr_t pong = z_keyexpr_unchecked("test/pong");
42+
z_owned_publisher_t pub = z_declare_publisher(z_loan(session), ping, NULL);
43+
z_owned_closure_sample_t respond = z_closure(callback, drop, (void*)(&pub));
44+
z_owned_subscriber_t sub = z_declare_subscriber(z_loan(session), pong, z_move(respond), NULL);
45+
uint8_t* data = malloc(args.size);
46+
for (int i = 0; i < args.size; i++) {
47+
data[i] = i % 10;
48+
}
49+
pthread_mutex_lock(&mutex);
50+
if (args.warmup_ms) {
51+
printf("Warming up for %dms...\n", args.warmup_ms);
52+
clock_t warmup_end = clock() + CLOCKS_PER_SEC * args.warmup_ms / 1000;
53+
for (clock_t now = clock(); now < warmup_end; now = clock()) {
54+
z_publisher_put(z_loan(pub), data, args.size, NULL);
55+
pthread_cond_wait(&cond, &mutex);
56+
}
57+
}
58+
clock_t* results = malloc(sizeof(clock_t) * args.number_of_pings);
59+
for (int i = 0; i < args.number_of_pings; i++) {
60+
clock_t start = clock();
61+
z_publisher_put(z_loan(pub), data, args.size, NULL);
62+
pthread_cond_wait(&cond, &mutex);
63+
clock_t end = clock();
64+
results[i] = end - start;
65+
}
66+
for (int i = 0; i < args.number_of_pings; i++) {
67+
clock_t rtt = results[i] * 1000000 / CLOCKS_PER_SEC;
68+
printf("%d bytes: seq=%d rtt=%ldµs lat=%ldµs\n", args.size, i, rtt, rtt / 2);
69+
}
70+
pthread_mutex_unlock(&mutex);
71+
free(results);
72+
free(data);
73+
z_drop(z_move(sub));
74+
z_drop(z_move(pub));
75+
z_close(z_move(session));
76+
}
77+
78+
char* getopt(int argc, char** argv, char option) {
79+
for (int i = 0; i < argc; i++) {
80+
size_t len = strlen(argv[i]);
81+
if (len >= 2 && argv[i][0] == '-' && argv[i][1] == option) {
82+
if (len > 2 && argv[i][2] == '=') {
83+
return argv[i] + 3;
84+
} else if (i + 1 < argc) {
85+
return argv[i + 1];
86+
}
87+
}
88+
}
89+
return NULL;
90+
}
91+
92+
struct args_t parse_args(int argc, char** argv) {
93+
for (int i = 0; i < argc; i++) {
94+
if (strcmp(argv[i], "-h") == 0) {
95+
return (struct args_t){.help_requested = 1};
96+
}
97+
}
98+
char* arg = getopt(argc, argv, 's');
99+
unsigned int size = 8;
100+
if (arg) {
101+
size = atoi(arg);
102+
}
103+
arg = getopt(argc, argv, 'n');
104+
unsigned int number_of_pings = 4;
105+
if (arg) {
106+
number_of_pings = atoi(arg);
107+
}
108+
arg = getopt(argc, argv, 'w');
109+
unsigned int warmup_ms = 0;
110+
if (arg) {
111+
warmup_ms = atoi(arg);
112+
}
113+
return (struct args_t){.help_requested = 0,
114+
.size = size,
115+
.number_of_pings = number_of_pings,
116+
.warmup_ms = warmup_ms,
117+
.config_path = getopt(argc, argv, 'c')};
118+
}

examples/z_pong.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#include "stdio.h"
2+
#include "zenoh.h"
3+
4+
void callback(const z_sample_t* sample, void* context) {
5+
z_publisher_t pub = z_loan(*(z_owned_publisher_t*)context);
6+
z_publisher_put(pub, sample->payload.start, sample->payload.len, NULL);
7+
}
8+
void drop(void* context) {
9+
z_owned_publisher_t* pub = (z_owned_publisher_t*)context;
10+
z_drop(pub);
11+
// A note on lifetimes:
12+
// here, `sub` takes ownership of `pub` and will drop it before returning from its own `drop`,
13+
// which makes passing a pointer to the stack safe as long as `sub` is dropped in a scope where `pub` is still
14+
// valid.
15+
}
16+
17+
int main(int argc, char** argv) {
18+
z_owned_config_t config = z_config_default();
19+
z_owned_session_t session = z_open(z_move(config));
20+
z_keyexpr_t ping = z_keyexpr_unchecked("test/ping");
21+
z_keyexpr_t pong = z_keyexpr_unchecked("test/pong");
22+
z_owned_publisher_t pub = z_declare_publisher(z_loan(session), pong, NULL);
23+
z_owned_closure_sample_t respond = z_closure(callback, drop, (void*)z_move(pub));
24+
z_owned_subscriber_t sub = z_declare_subscriber(z_loan(session), ping, z_move(respond), NULL);
25+
while (getchar() != 'q') {
26+
}
27+
z_drop(z_move(sub));
28+
z_close(z_move(session));
29+
}

0 commit comments

Comments
 (0)