summaryrefslogtreecommitdiff
path: root/serve_image.c
diff options
context:
space:
mode:
authorDavid Woodhouse <dwmw2@infradead.org>2007-08-14 22:54:49 +0800
committerDavid Woodhouse <dwmw2@infradead.org>2007-08-14 22:54:49 +0800
commit5f262bc2fc1a427b20fd4f54df0dbe650da47807 (patch)
tree48ebd3fa20534eeb70e0163eba1b029e09492c00 /serve_image.c
parent596450e1d50cce8701dccd65eaa3d646f525b375 (diff)
Switch multicast distribution system to round-robin mode
Send one packet from each eraseblock in turn, rather than all packets for one eraseblock together. This means that bursts of loss are evenly spread between blocks. It also makes the client side a bit more complex if you can't assume that there's anywhere except the flash to store its intermediate data. Signed-off-by: David Woodhouse <dwmw2@infradead.org>
Diffstat (limited to 'serve_image.c')
-rw-r--r--serve_image.c114
1 files changed, 63 insertions, 51 deletions
diff --git a/serve_image.c b/serve_image.c
index 57d2bd9..30ceaeb 100644
--- a/serve_image.c
+++ b/serve_image.c
@@ -36,36 +36,26 @@ int main(int argc, char **argv)
struct stat st;
int writeerrors = 0;
uint32_t erasesize;
- unsigned char *image, *blockptr;
+ unsigned char *image, *blockptr = NULL;
uint32_t block_nr, pkt_nr;
int nr_blocks;
struct timeval then, now, nextpkt;
long time_msecs;
- int pkts_extra = 6;
int pkts_per_block;
struct fec_parms *fec;
unsigned char *last_block;
uint32_t *block_crcs;
- int crcs_checked = 0;
long tosleep;
+ uint32_t sequence = 0;
- if (argc == 7) {
- tx_rate = atol(argv[6]) * 1024;
+ if (argc == 6) {
+ tx_rate = atol(argv[5]) * 1024;
if (tx_rate < PKT_SIZE || tx_rate > 20000000) {
fprintf(stderr, "Bogus TX rate %d KiB/s\n", tx_rate);
exit(1);
}
- argc = 6;
- }
- if (argc == 6) {
- pkts_extra = atol(argv[5]);
- if (pkts_extra < 0 || pkts_extra > 200) {
- fprintf(stderr, "Bogus redundancy %d packets\n", pkts_extra);
- exit(1);
- }
argc = 5;
}
-
if (argc != 5) {
fprintf(stderr, "usage: %s <host> <port> <image> <erasesize> [<redundancy>] [<tx_rate>]\n",
(strrchr(argv[0], '/')?:argv[0]-1)+1);
@@ -90,7 +80,7 @@ int main(int argc, char **argv)
exit(1);
}
- fec = fec_new(pkts_per_block, pkts_per_block + pkts_extra);
+ fec = fec_new(pkts_per_block, pkts_per_block * 2);
if (!fec) {
fprintf(stderr, "Error initialising FEC\n");
exit(1);
@@ -162,16 +152,23 @@ int main(int argc, char **argv)
pktbuf.hdr.nr_blocks = htonl(nr_blocks);
pktbuf.hdr.blocksize = htonl(erasesize);
pktbuf.hdr.thislen = htonl(PKT_SIZE);
- pktbuf.hdr.nr_pkts = htons(pkts_per_block + pkts_extra);
+ pktbuf.hdr.nr_pkts = htons(pkts_per_block * 2);
printf("%08x\n", ntohl(pktbuf.hdr.totcrc));
-
- again:
- printf("Image size %ld KiB (%08lx). %d redundant packets per block (%d total)\n"
- "Data to send %d KiB. Estimated transmit time: %ds\n",
- (long)st.st_size / 1024, (long) st.st_size, pkts_extra, pkts_extra+pkts_per_block,
- nr_blocks * PKT_SIZE * (pkts_per_block+pkts_extra) / 1024,
- nr_blocks * (pkts_per_block+pkts_extra) * pkt_delay / 1000000);
+ printf("Checking block CRCs....");
+ fflush(stdout);
+ for (block_nr=0; block_nr < nr_blocks; block_nr++) {
+ printf("\rChecking block CRCS.... %d/%d",
+ block_nr + 1, nr_blocks);
+ fflush(stdout);
+ block_crcs[block_nr] = crc32(-1, image + (block_nr * erasesize), erasesize);
+ }
+
+ printf("\nImage size %ld KiB (0x%08lx). %d blocks at %d pkts/block\n"
+ "Estimated transmit time per cycle: %ds\n",
+ (long)st.st_size / 1024, (long) st.st_size,
+ nr_blocks, pkts_per_block,
+ nr_blocks * pkts_per_block * pkt_delay / 1000000);
gettimeofday(&then, NULL);
nextpkt = then;
@@ -179,47 +176,69 @@ int main(int argc, char **argv)
srand((unsigned)then.tv_usec);
printf("Random seed %u\n", (unsigned)then.tv_usec);
#endif
- blockptr = image;
+ while (1) for (pkt_nr=0; pkt_nr < pkts_per_block * 2; pkt_nr++) {
+
+ if (blockptr && pkt_nr == 0) {
+ unsigned long amt_sent = pkts_per_block * nr_blocks * sizeof(pktbuf) * 2;
+ gettimeofday(&now, NULL);
- for (block_nr = 0; block_nr < nr_blocks; block_nr++) {
+ time_msecs = (now.tv_sec - then.tv_sec) * 1000;
+ time_msecs += ((int)(now.tv_usec - then.tv_usec)) / 1000;
+ printf("\n%ld KiB sent in %ldms (%ld KiB/s)\n",
+ amt_sent / 1024, time_msecs,
+ amt_sent / 1024 * 1000 / time_msecs);
+ then = now;
+ }
+
+ for (block_nr = 0; block_nr < nr_blocks; block_nr++) {
+
+ int actualpkt;
- for (pkt_nr=0; pkt_nr < pkts_per_block + pkts_extra; pkt_nr++) {
+ /* Calculating the redundant FEC blocks is expensive;
+ the first $pkts_per_block are cheap enough though
+ because they're just copies. So alternate between
+ simple and complex stuff, so that we don't start
+ to choke and fail to keep up with the expected
+ bitrate in the second half of the sequence */
+ if (block_nr & 1)
+ actualpkt = pkt_nr;
+ else if (pkt_nr >= pkts_per_block)
+ actualpkt = pkt_nr - pkts_per_block;
+ else
+ actualpkt = pkt_nr + pkts_per_block;
blockptr = image + (erasesize * block_nr);
if (block_nr == nr_blocks - 1)
blockptr = last_block;
- /* Calculate the block CRCs first time around */
- if (block_nr >= crcs_checked) {
- block_crcs[block_nr] = crc32(-1, blockptr, erasesize);
- crcs_checked = block_nr + 1;
- }
+ fec_encode_linear(fec, blockptr, pktbuf.data, actualpkt, PKT_SIZE);
+ pktbuf.hdr.thiscrc = htonl(crc32(-1, pktbuf.data, PKT_SIZE));
pktbuf.hdr.block_crc = htonl(block_crcs[block_nr]);
pktbuf.hdr.block_nr = htonl(block_nr);
+ pktbuf.hdr.pkt_nr = htons(actualpkt);
+ pktbuf.hdr.pkt_sequence = htonl(sequence++);
- fec_encode_linear(fec, blockptr, pktbuf.data, pkt_nr, PKT_SIZE);
-
printf("\rSending data block %08x packet %3d/%d",
- block_nr * erasesize, pkt_nr, pkts_per_block + pkts_extra);
+ block_nr * erasesize,
+ pkt_nr, pkts_per_block * 2);
+
+ if (pkt_nr && !block_nr) {
+ unsigned long amt_sent = pkt_nr * nr_blocks * sizeof(pktbuf);
- if (block_nr && !pkt_nr) {
gettimeofday(&now, NULL);
time_msecs = (now.tv_sec - then.tv_sec) * 1000;
time_msecs += ((int)(now.tv_usec - then.tv_usec)) / 1000;
printf(" (%ld KiB/s) ",
- (block_nr * sizeof(pktbuf) * (pkts_per_block+pkts_extra))
- / 1024 * 1000 / time_msecs);
+ amt_sent / 1024 * 1000 / time_msecs);
}
fflush(stdout);
- pktbuf.hdr.pkt_nr = htons(pkt_nr);
- pktbuf.hdr.thiscrc = htonl(crc32(-1, pktbuf.data, PKT_SIZE));
#ifdef RANDOMDROP
if ((rand() % 1000) < 20) {
- printf("\nDropping packet %d\n", pkt_nr+1);
+ printf("\nDropping packet %d of block %08x\n", pkt_nr+1, block_nr * erasesize);
continue;
}
#endif
@@ -251,9 +270,10 @@ int main(int argc, char **argv)
}
/* If the time for the next packet has already
- passed, then we've lost time. Adjust our expected
- timings accordingly. */
- if (now.tv_usec > (now.tv_usec +
+ passed (by some margin), then we've lost time
+ Adjust our expected timings accordingly. If
+ we're only a little way behind, don't slip yet */
+ if (now.tv_usec > (now.tv_usec + (5 * pkt_delay) +
1000000 * (nextpkt.tv_sec - now.tv_sec))) {
nextpkt = now;
}
@@ -272,14 +292,6 @@ int main(int argc, char **argv)
}
}
- gettimeofday(&now, NULL);
-
- time_msecs = (now.tv_sec - then.tv_sec) * 1000;
- time_msecs += ((int)(now.tv_usec - then.tv_usec)) / 1000;
- printf("\n%d KiB sent in %ldms (%ld KiB/s)\n",
- nr_blocks * sizeof(pktbuf) * (pkts_per_block+pkts_extra) / 1024, time_msecs,
- nr_blocks * sizeof(pktbuf) * (pkts_per_block+pkts_extra) / 1024 * 1000 / time_msecs);
-
munmap(image, st.st_size);
close(rfd);
close(sock);