aboutsummaryrefslogtreecommitdiff
path: root/slowbaud.c
diff options
context:
space:
mode:
Diffstat (limited to 'slowbaud.c')
-rw-r--r--slowbaud.c49
1 files changed, 38 insertions, 11 deletions
diff --git a/slowbaud.c b/slowbaud.c
index bbf31ac..63a8a3b 100644
--- a/slowbaud.c
+++ b/slowbaud.c
@@ -26,7 +26,7 @@
#include <pty.h>
#endif
-#define DEFAULT_BPS 1200
+#define DEFAULT_BPS 2400
#define MIN_BPS 1
#define MAX_BPS 500000
@@ -67,6 +67,8 @@ void setup_timer(void) {
sigprocmask(SIG_BLOCK, &sigmask, NULL);
}
+/* on both Linux and OSX, using setitimer() and sigwait() gives better
+ timing accuracy than usleep() or nanosleep(). */
void slow_write(int outfd, char c) {
int j;
unsigned long now, target, overslept;
@@ -84,13 +86,8 @@ void slow_write(int outfd, char c) {
if(now > target) {
overslept = now - target;
if(overslept < interval) {
- unsigned long old = itv.it_interval.tv_usec;
itv.it_interval.tv_usec -= overslept;
itv.it_value.tv_usec = itv.it_interval.tv_usec;
- if(debug) {
- fprintf(stderr, "tv_usec was %ldms, overslept %ld, new tv_usec %ldms\n",
- old, overslept, itv.it_interval.tv_usec);
- }
}
} else {
while(NOW_USEC() < target)
@@ -99,24 +96,25 @@ void slow_write(int outfd, char c) {
}
void debug_stats(void) {
- if(outbytes && debug) {
+ if(outbytes) {
unsigned long elapsed_us = NOW_USEC() - starttime;
double elapsed_sec = ((double)elapsed_us/1000000.0L);
double finterval = (1000000.0L / ((double)bps / 10.0L));
double actual = ((double)outbytes * 10.0L) / elapsed_sec;
double offby = 100.0L * (((double)bps / actual) - 1.0L);
fprintf(stderr,
- "outbytes %lu, elapsed_us %lu, requested bps %d (%.2fms), "
+ "outbytes %lu, elapsed_us %lu, tv_usec %lu, requested bps %d (%.2fms), "
"actual %.2f, accuracy %.2f%%\n",
- outbytes, elapsed_us, bps, finterval, actual, 100.0 - offby);
+ outbytes, elapsed_us, itv.it_value.tv_usec, bps, finterval, actual, 100.0 - offby);
}
- outbytes = 0;
}
void slowcat(int infd) {
int c;
+ outbytes = 0;
starttime = NOW_USEC();
+
while(read(infd, &c, 1) == 1) {
slow_write(1, c);
}
@@ -216,12 +214,32 @@ void echo_args(char **args) {
exit(0);
}
+void benchmark(char **args) {
+ int bytes = 0, devnull;
+
+ if(*args) bytes = atoi(*args);
+ if(bytes < 1) bytes = 4096;
+ fprintf(stderr, "benchmarking with %d bytes\n", bytes);
+
+ devnull = open("/dev/null", O_RDONLY);
+ if(devnull < 1) die("/dev/null");
+
+ starttime = NOW_USEC();
+ while(bytes--)
+ slow_write(devnull, 0);
+ close(devnull);
+
+ debug_stats();
+ exit(0);
+}
+
void usage(int exitstat) {
printf("Usage: %s [<bits-per-sec>] [<file> [<file> ...]]\n", self);
printf(" With no filenames, reads stdin.\n");
printf("or: %s [<bits-per-sec>] -c [<command> [<arg> ...]]\n", self);
printf(" With no command, spawns a shell.\n");
printf("or: %s [<bits-per-sec>] -e <string> [<string> ...]\n", self);
+ printf("or: %s [<bits-per-sec>] -b [<bytes>]\n", self);
printf("With no <bits-per-sec>, default rate is %d\n", DEFAULT_BPS);
exit(exitstat);
}
@@ -232,6 +250,7 @@ int main(int argc, char **argv) {
if(getenv("SLOWBAUD_DEBUG")) debug = 1;
+ /* for usage message, we want "slowbaud", not "/path/to/slowbaud" */
self = argv[0];
for(p = argv[0]; *p; p++) {
if(*p == '/') self = p + 1;
@@ -259,7 +278,12 @@ int main(int argc, char **argv) {
}
/* if we used only integer math here, we couldn't support bps not
- a multiple of 10 (e.g. 75 would be taken as 70). */
+ a multiple of 10 (e.g. 75 would be taken as 70).
+ We still have a rounding problem: 115200bps is 86.81ms/char, but
+ it gets rounded down to 86 here. Which would be around 116279bps,
+ or almost 1% too fast. We never reach 100% speed anyway, so the
+ loss from overhead actually offsets the extra bit of speed.
+ */
interval = (unsigned long)(1000000.0L / ((double)bps / 10.0L));
if(debug) fprintf(stderr, "interval %ld us\n", interval);
@@ -284,6 +308,9 @@ int main(int argc, char **argv) {
if(debug) fprintf(stderr, "-e given, echoing args\n");
echo_args(++argv);
break;
+ case 'b':
+ benchmark(++argv);
+ break;
case 'h':
case '?':
usage(0);