samples: net: zperf: Convert to use usec directly

Currently the code uses hw cycles and tries to convert them
to usec. I noticed some failures with this, for example the test
duration was sometimes missed meaning that instead of testing 5
seconds, we bailed out after 2 sec etc. After the kernel k_timeout_t
changes, which added APIs to support usec accuracy, we can use usec
and ticks here. This simplifies the code a bit.

Signed-off-by: Jukka Rissanen <jukka.rissanen@linux.intel.com>
This commit is contained in:
Jukka Rissanen 2020-11-25 18:14:16 +02:00 committed by Jukka Rissanen
commit 77a74414d1
6 changed files with 84 additions and 95 deletions

View file

@ -37,32 +37,6 @@
#define PACKET_SIZE_MAX 1024
#define HW_CYCLES_TO_USEC(__hw_cycle__) \
( \
((uint64_t)(__hw_cycle__) * (uint64_t)USEC_PER_SEC) / \
((uint64_t)sys_clock_hw_cycles_per_sec()) \
)
#define HW_CYCLES_TO_SEC(__hw_cycle__) \
( \
((uint64_t)(HW_CYCLES_TO_USEC(__hw_cycle__))) / \
((uint64_t)USEC_PER_SEC) \
)
#define USEC_TO_HW_CYCLES(__usec__) \
( \
((uint64_t)(__usec__) * (uint64_t)sys_clock_hw_cycles_per_sec()) / \
((uint64_t)USEC_PER_SEC) \
)
#define SEC_TO_HW_CYCLES(__sec__) \
USEC_TO_HW_CYCLES((uint64_t)(__sec__) * \
(uint64_t)USEC_PER_SEC)
#define MSEC_TO_HW_CYCLES(__msec__) \
USEC_TO_HW_CYCLES((uint64_t)(__msec__) * \
(uint64_t)MSEC_PER_SEC)
struct zperf_udp_datagram {
int32_t id;
uint32_t tv_sec;

View file

@ -49,7 +49,7 @@ struct session {
uint32_t outorder;
uint32_t error;
uint64_t length;
uint32_t start_time;
int64_t start_time;
uint32_t last_time;
int32_t jitter;
int32_t last_transit_time;

View file

@ -41,14 +41,14 @@ static void tcp_received(struct net_context *context,
{
const struct shell *shell = tcp_shell;
struct session *session;
uint32_t time;
int64_t time;
if (!shell) {
printk("Shell is not set!\n");
return;
}
time = k_cycle_get_32();
time = k_uptime_ticks();
session = get_tcp_session(context);
if (!session) {
@ -63,7 +63,7 @@ static void tcp_received(struct net_context *context,
shell_fprintf(shell, SHELL_NORMAL,
"New TCP session started\n");
zperf_reset_session_stats(session);
session->start_time = k_cycle_get_32();
session->start_time = k_uptime_ticks();
session->state = STATE_ONGOING;
__fallthrough;
case STATE_ONGOING:
@ -75,18 +75,19 @@ static void tcp_received(struct net_context *context,
if (pkt == NULL && status == 0) { /* EOF */
uint32_t rate_in_kbps;
uint32_t duration = HW_CYCLES_TO_USEC(
time_delta(session->start_time, time));
uint32_t duration;
duration = k_ticks_to_us_ceil32(time -
session->start_time);
session->state = STATE_COMPLETED;
/* Compute baud rate */
if (duration != 0U) {
rate_in_kbps = (uint32_t)
(((uint64_t)session->length *
(uint64_t)8 *
((session->length * 8ULL *
(uint64_t)USEC_PER_SEC) /
((uint64_t)duration * 1024U));
((uint64_t)duration * 1024ULL));
} else {
rate_in_kbps = 0U;
}

View file

@ -27,10 +27,9 @@ void zperf_tcp_upload(const struct shell *shell,
unsigned int packet_size,
struct zperf_results *results)
{
uint32_t duration = MSEC_TO_HW_CYCLES(duration_in_ms);
int64_t duration = z_timeout_end_calc(K_MSEC(duration_in_ms));
int64_t start_time, last_print_time, end_time, remaining;
uint32_t nb_packets = 0U, nb_errors = 0U;
uint32_t start_time, last_print_time, end_time;
uint8_t time_elapsed = 0U, finished = 0U;
uint32_t alloc_errors = 0U;
if (packet_size > PACKET_SIZE_MAX) {
@ -41,7 +40,7 @@ void zperf_tcp_upload(const struct shell *shell,
}
/* Start the loop */
start_time = k_cycle_get_32();
start_time = k_uptime_ticks();
last_print_time = start_time;
shell_fprintf(shell, SHELL_NORMAL,
@ -57,10 +56,6 @@ void zperf_tcp_upload(const struct shell *shell,
do {
int ret = 0;
uint32_t loop_time;
/* Timestamps */
loop_time = k_cycle_get_32();
/* Send the packet */
ret = net_context_send(ctx, sample_packet,
@ -87,15 +82,6 @@ void zperf_tcp_upload(const struct shell *shell,
}
} else {
nb_packets++;
if (time_elapsed) {
finished = 1U;
}
}
if (!time_elapsed && time_delta(start_time,
loop_time) > duration) {
time_elapsed = 1U;
}
#if defined(CONFIG_ARCH_POSIX)
@ -103,14 +89,16 @@ void zperf_tcp_upload(const struct shell *shell,
#else
k_yield();
#endif
} while (!finished);
end_time = k_cycle_get_32();
remaining = duration - k_uptime_ticks();
} while (remaining > 0);
end_time = k_uptime_ticks();
/* Add result coming from the client */
results->nb_packets_sent = nb_packets;
results->client_time_in_us =
HW_CYCLES_TO_USEC(time_delta(start_time, end_time));
k_ticks_to_us_ceil32(end_time - start_time);
results->packet_size = packet_size;
results->nb_packets_errors = nb_errors;

View file

@ -125,7 +125,7 @@ static void udp_received(struct net_context *context,
struct zperf_udp_datagram *hdr;
struct session *session;
int32_t transit_time;
uint32_t time;
int64_t time;
int32_t id;
if (!pkt) {
@ -139,7 +139,7 @@ static void udp_received(struct net_context *context,
goto out;
}
time = k_cycle_get_32();
time = k_uptime_ticks();
session = get_session(pkt, ip_hdr, proto_hdr, SESSION_UDP);
if (!session) {
@ -180,17 +180,18 @@ static void udp_received(struct net_context *context,
shell_fprintf(shell, SHELL_NORMAL, "End of session!\n");
duration = HW_CYCLES_TO_USEC(
time_delta(session->start_time, time));
duration = k_ticks_to_us_ceil32(time -
session->start_time);
/* Update state machine */
session->state = STATE_COMPLETED;
/* Compute baud rate */
if (duration != 0U) {
rate_in_kbps = (uint32_t)
(((uint64_t)session->length * (uint64_t)8 *
((session->length * 8ULL *
(uint64_t)USEC_PER_SEC) /
((uint64_t)duration * 1024U));
((uint64_t)duration * 1024ULL));
} else {
rate_in_kbps = 0U;
}
@ -246,10 +247,10 @@ static void udp_received(struct net_context *context,
session->length += net_pkt_remaining_data(pkt);
/* Compute jitter */
transit_time = time_delta(HW_CYCLES_TO_USEC(time),
ntohl(hdr->tv_sec) *
USEC_PER_SEC +
ntohl(hdr->tv_usec));
transit_time = time_delta(
k_ticks_to_us_ceil32(time),
ntohl(hdr->tv_sec) * USEC_PER_SEC +
ntohl(hdr->tv_usec));
if (session->last_transit_time != 0) {
int32_t delta_transit = transit_time -
session->last_transit_time;

View file

@ -75,13 +75,15 @@ static void stat_received(struct net_context *context,
static inline void zperf_upload_fin(const struct shell *shell,
struct net_context *context,
uint32_t nb_packets,
uint32_t end_time,
uint64_t end_time,
uint32_t packet_size,
struct zperf_results *results)
{
struct net_pkt *stat = NULL;
struct zperf_udp_datagram *datagram;
struct zperf_client_hdr_v1 *hdr;
uint32_t secs = k_ticks_to_ms_ceil32(end_time) / 1000U;
uint32_t usecs = k_ticks_to_us_ceil32(end_time) - secs * USEC_PER_SEC;
int loop = 2;
int ret;
@ -90,9 +92,8 @@ static inline void zperf_upload_fin(const struct shell *shell,
/* Fill the packet header */
datagram->id = htonl(-nb_packets);
datagram->tv_sec = htonl(HW_CYCLES_TO_SEC(end_time));
datagram->tv_usec = htonl(HW_CYCLES_TO_USEC(end_time) %
USEC_PER_SEC);
datagram->tv_sec = htonl(secs);
datagram->tv_usec = htonl(usecs);
hdr = (struct zperf_client_hdr_v1 *)(sample_packet +
sizeof(*datagram));
@ -164,14 +165,15 @@ void zperf_udp_upload(const struct shell *shell,
unsigned int rate_in_kbps,
struct zperf_results *results)
{
uint32_t packet_duration = (uint32_t)(((uint64_t) packet_size *
SEC_TO_HW_CYCLES(1) * 8U) /
(uint64_t)(rate_in_kbps * 1024U));
uint32_t duration = MSEC_TO_HW_CYCLES(duration_in_ms);
uint32_t print_interval = SEC_TO_HW_CYCLES(1);
uint32_t delay = packet_duration;
uint32_t packet_duration = ((uint32_t)packet_size * 8U * USEC_PER_SEC) /
(rate_in_kbps * 1024U);
uint64_t duration = z_timeout_end_calc(K_MSEC(duration_in_ms));
int64_t print_interval = z_timeout_end_calc(K_SECONDS(1));
uint64_t delay = packet_duration;
uint32_t nb_packets = 0U;
uint32_t start_time, last_print_time, last_loop_time, end_time;
int64_t start_time, end_time;
int64_t last_print_time, last_loop_time;
int64_t remaining, print_info;
if (packet_size > PACKET_SIZE_MAX) {
shell_fprintf(shell, SHELL_WARNING,
@ -185,8 +187,18 @@ void zperf_udp_upload(const struct shell *shell,
packet_size = sizeof(struct zperf_udp_datagram);
}
if (packet_duration > 1000U) {
shell_fprintf(shell, SHELL_NORMAL,
"Packet duration %u ms\n",
(unsigned int)(packet_duration / 1000U));
} else {
shell_fprintf(shell, SHELL_NORMAL,
"Packet duration %u us\n",
(unsigned int)packet_duration);
}
/* Start the loop */
start_time = k_cycle_get_32();
start_time = k_uptime_ticks();
last_print_time = start_time;
last_loop_time = start_time;
@ -195,38 +207,44 @@ void zperf_udp_upload(const struct shell *shell,
do {
struct zperf_udp_datagram *datagram;
struct zperf_client_hdr_v1 *hdr;
uint32_t loop_time;
uint32_t secs, usecs;
int64_t loop_time;
int32_t adjust;
int ret;
/* Timestamp */
loop_time = k_cycle_get_32();
loop_time = k_uptime_ticks();
/* Algorithm to maintain a given baud rate */
if (last_loop_time != loop_time) {
adjust = packet_duration - time_delta(last_loop_time,
loop_time);
adjust = (int32_t)(packet_duration -
k_ticks_to_us_ceil32(loop_time -
last_loop_time));
} else {
/* It's the first iteration so no need for adjustment
*/
adjust = 0;
}
if (adjust >= 0 || -adjust < delay) {
if (adjust >= 0) {
delay += adjust;
} else if ((uint64_t)-adjust < delay) {
delay -= (uint64_t)-adjust;
} else {
delay = 0U; /* delay should never be a negative value */
delay = 0U; /* delay should never be negative */
}
last_loop_time = loop_time;
secs = k_ticks_to_ms_ceil32(loop_time) / 1000U;
usecs = k_ticks_to_us_ceil32(loop_time) - secs * USEC_PER_SEC;
/* Fill the packet header */
datagram = (struct zperf_udp_datagram *)sample_packet;
datagram->id = htonl(nb_packets);
datagram->tv_sec = htonl(HW_CYCLES_TO_SEC(loop_time));
datagram->tv_usec =
htonl(HW_CYCLES_TO_USEC(loop_time) % USEC_PER_SEC);
datagram->tv_sec = htonl(secs);
datagram->tv_usec = htonl(usecs);
hdr = (struct zperf_client_hdr_v1 *)(sample_packet +
sizeof(*datagram));
@ -251,25 +269,32 @@ void zperf_udp_upload(const struct shell *shell,
}
/* Print log every seconds */
if (time_delta(last_print_time, loop_time) > print_interval) {
print_info = print_interval - k_uptime_ticks();
if (print_info <= 0) {
shell_fprintf(shell, SHELL_WARNING,
"nb_packets=%u\tdelay=%u\tadjust=%d\n",
nb_packets, delay, adjust);
last_print_time = loop_time;
nb_packets, (unsigned int)delay,
(int)adjust);
print_interval = z_timeout_end_calc(K_SECONDS(1));
}
remaining = duration - k_uptime_ticks();
/* Wait */
#if defined(CONFIG_ARCH_POSIX)
k_busy_wait(USEC_PER_MSEC);
#else
while (time_delta(loop_time, k_cycle_get_32()) < delay) {
k_yield();
if (delay != 0) {
if (k_us_to_ticks_floor64(delay) > remaining) {
delay = k_ticks_to_us_ceil64(remaining);
}
k_sleep(K_USEC(delay));
}
#endif
} while (remaining > 0);
} while (time_delta(start_time, last_loop_time) < duration);
end_time = k_cycle_get_32();
end_time = k_uptime_ticks();
zperf_upload_fin(shell, context, nb_packets, end_time, packet_size,
results);
@ -277,6 +302,6 @@ void zperf_udp_upload(const struct shell *shell,
/* Add result coming from the client */
results->nb_packets_sent = nb_packets;
results->client_time_in_us =
HW_CYCLES_TO_USEC(time_delta(start_time, end_time));
k_ticks_to_us_ceil32(end_time - start_time);
results->packet_size = packet_size;
}