File: speedtest.c

package info (click to toggle)
lcrq 0.3.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 52,868 kB
  • sloc: ansic: 11,513; sh: 3,130; makefile: 338
file content (156 lines) | stat: -rw-r--r-- 4,272 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */
/* Copyright (c) 2022-2025 Brett Sheffield <bacs@librecast.net> */

#include <arpa/inet.h>
#include <assert.h>
#include <lcrq.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/param.h>
#include <time.h>
#include <unistd.h>

#define DECODER_RFC 1
#define DECODER_DEFAULT DECODER_RFC

#define NANO 1000000000ULL

#define DEFAULT_REPS 1000
#define DEFAULT_F 32768
#define DEFAULT_T 1024
#define DEFAULT_O 1

static uint32_t overhead = RQ_OVERHEAD;
static int encoder_type = DECODER_DEFAULT;
static int decoder_type = DECODER_DEFAULT;

uint8_t *generate_source_object(size_t F)
{
	uint8_t *obj = malloc(F);
	assert(obj);
	arc4random_buf(obj, F);
	return obj;
}

static uint8_t *encoder_generate_symbols(rq_t *rq, uint32_t ESI[], int nesi)
{
	uint8_t *enc, *sym;
	rq_pid_t pid = 0;

	assert(rq_Z(rq) == 1); /* FIXME - only one block supported by this test */
	enc = malloc(nesi * rq_T(rq));

	/* generate random repair symbols */
	sym = enc;
	for (int i = 0; i < nesi; i++) {
		rq_symbol(rq, &pid, sym, RQ_RAND);
		ESI[i] = rq_pid2esi(pid);
		sym += rq_T(rq);
	}
	return enc;
}

uint8_t *encoder(rq_t *rq, uint8_t *src, uint32_t *ESI, int nesi)
{
	int rc = rq_encode(rq, src, rq_F(rq));
	assert(rc == 0); (void)rc;
	return encoder_generate_symbols(rq, ESI, nesi);
}

static void dump_stats(const char *msg, size_t F, uint16_t T, size_t bytes, double s)
{
	fprintf(stderr, "%s %zu bytes in %0.4fs ", msg, bytes, s);
	double eBs = bytes / s;
	double ebps = eBs * 8;
	double eKbps = ebps / 1000;
	double eMbps = eKbps / 1000;
	double eGbps = eMbps / 1000;

	fprintf(stderr, "%0.1f Mbps, ", eMbps);
	fprintf(stderr, "%0.1f Gbps", eGbps);
	fprintf(stderr, " F=%zu, T=%u\n", F, T);
}

int main(int argc, char *argv[])
{
	rq_t *rq_enc = NULL, *rq_dec = NULL;
	double s_total_decoder = 0;
	double s_total_encoder = 0;
	struct timespec ts_enc_start = {0};
	struct timespec ts_enc_end = {0};
	struct timespec ts_dec_start = {0};
	struct timespec ts_dec_end = {0};
	uint8_t *srcobj, *enc;
	size_t bytes_total_decoder = 0;
	size_t bytes_total_encoder = 0;
	size_t F = DEFAULT_F;
	uint16_t T = DEFAULT_T;
	int reps = DEFAULT_REPS;
	uint32_t *ESI;
	int nesi;
	int fails = 0;

	if (argc > 1) F = atoll(argv[1]);
	if (argc > 2) T = atoll(argv[2]); /* TODO ensure multiple of Al */
	if (argc > 3) reps = atoll(argv[3]);
	if (argc > 4 && !strcmp(argv[4], "rfc")) {
		encoder_type = DECODER_RFC;
		decoder_type = DECODER_RFC;
	}

	for (int i = 0; i < reps; i++) {
		/* generate random source block for test */
		srcobj = generate_source_object(F);

		/* encoder test */
		clock_gettime(CLOCK_REALTIME, &ts_enc_start);
		rq_enc = rq_init(F, T);
		nesi = rq_KP(rq_enc) + overhead;
		ESI = calloc(nesi, sizeof(uint32_t));
		enc = encoder(rq_enc, srcobj, ESI, nesi);
		rq_free(rq_enc);
		clock_gettime(CLOCK_REALTIME, &ts_enc_end);

		/* encoder stats */
		uint64_t ensec = ((uint64_t)ts_enc_end.tv_sec * NANO + (uint64_t)ts_enc_end.tv_nsec);
		ensec -= ((uint64_t)ts_enc_start.tv_sec * NANO + (uint64_t)ts_enc_start.tv_nsec);
		double edsec = (double)ensec / NANO;
		bytes_total_encoder += F;
		s_total_encoder += edsec;

		/* decoder test */
		clock_gettime(CLOCK_REALTIME, &ts_dec_start);
		rq_dec = rq_init(F, T);
		uint8_t *dec = NULL;
		size_t decsz = rq_K(rq_dec) * rq_T(rq_dec);
		dec = malloc(decsz);
		memset(dec, 0, decsz);
		int ok = rq_decode(rq_dec, dec, enc, ESI, nesi);
		rq_free(rq_dec);
		clock_gettime(CLOCK_REALTIME, &ts_dec_end);

		if (ok == 0) ok = memcmp(dec, srcobj, F);
		free(dec);

		/* decoder stats */
		uint64_t dnsec = ((uint64_t)ts_dec_end.tv_sec * NANO + (uint64_t)ts_dec_end.tv_nsec);
		dnsec -= ((uint64_t)ts_dec_start.tv_sec * NANO + (uint64_t)ts_dec_start.tv_nsec);
		double ddsec = (double)dnsec / NANO;
		s_total_decoder += ddsec;
		if (ok == 0) bytes_total_decoder += F;
		else fails++;

		/* clean up */
		free(ESI);
		free(enc);
		free(srcobj);
	}
	fputc('\n', stderr);
	dump_stats("encoder avg", F, T, bytes_total_encoder, s_total_encoder);
	dump_stats("decoder avg", F, T, bytes_total_decoder, s_total_decoder);
	if (fails) fprintf(stderr, "decoder FAILs = %i/%i (%0.4f%%), overhead = %i\n", fails, reps,
		(double)fails/(double)reps * 100, RQ_OVERHEAD);

	return 0;
}