do stdout output with specific speed
Asked Answered
O

4

6

For a load test of my application (under Linux), I'm looking for a tool that outputs data on stdout at a specific rate (like 100 bytes/s), so that I can pipe the output to netcat which sends it to my application. Some option for dd would be ideal, but I didn't find anything so far. It doesn't really matter what kind of data is printed (NUL bytes are OK). Any hints?

Ozone answered 28/10, 2008 at 9:51 Comment(1)
A correspondent has commented to me that using a pipe to netcat could mean that the pipe could be a limiting factor. It's thus more reliable to write directly to the socket at the rate you seek.Jacobinism
W
3

I think that this is what you really want: Pipe Viewer

Using <fast input> | pv -qL <rate>[k|m|g|t] | <rate-limited output> will limit the pipe to the requested rate.

Warty answered 29/6, 2012 at 14:4 Comment(0)
J
5

I wrote a quick program that takes one argument, how many A characters to print to standard output per second (negative argument means no rate limiting). Hope this helps! :-) (On GNU libc, you will need to link your program with -lrt.)

Edit: revised to print dot by default, unless a second argument is specified, in which case the first character of that is used. (And that means, if you want to print the NUL character, just specify an empty string as the second argument. :-))

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>

int
sleeptill(const struct timespec *when)
{
    struct timespec now, diff;

    clock_gettime(CLOCK_REALTIME, &now);
    diff.tv_sec = when->tv_sec - now.tv_sec;
    diff.tv_nsec = when->tv_nsec - now.tv_nsec;
    while (diff.tv_nsec < 0) {
        diff.tv_nsec += 1000000000;
        --diff.tv_sec;
    }
    if (diff.tv_sec < 0)
        return 0;
    return nanosleep(&diff, 0);
}

int
main(int argc, char **argv)
{
    double rate = 0.0;
    char *endp;
    struct timespec start;
    double offset;

    if (argc >= 2) {
        rate = strtod(argv[1], &endp);
        if (endp == argv[1] || *endp)
            rate = 0.0;
        else
            rate = 1 / rate;

        if (!argv[2])
            argv[2] = ".";
    }

    if (!rate) {
        fprintf(stderr, "usage: %s rate [char]\n", argv[0]);
        return 1;
    }

    clock_gettime(CLOCK_REALTIME, &start);
    offset = start.tv_nsec / 1000000000.0;

    while (1) {
        struct timespec till = start;
        double frac;
        double whole;

        frac = modf(offset += rate, &whole);
        till.tv_sec += whole;
        till.tv_nsec = frac * 1000000000.0;
        sleeptill(&till);
        write(STDOUT_FILENO, argv[2], 1);
    }
}
Jacobinism answered 28/10, 2008 at 10:30 Comment(5)
With the latest revision, you can now specify 0 as the rate. Technically, it doesn't wait "forever" (as it should, mathematically); rather, it waits until the end of time_t (January 2038, on platforms with a 32-bit time_t). That's still quite a while to wait, though. :-DJacobinism
Nice stuff - thanks! How about putting it up on some revision control site (github, launchpad, sourceforge...) so people can add changes? Also, I think for performance it would be useful to write() a whole block of data at once.Ozone
I deliberately used write() with no buffering so the data is guaranteed to come at a constant rate. To use buffering, change the write() call to putchar(*argv[2]). :-) I'll see what I can do about public revision control....Jacobinism
Also, if you're using something small for the rate like 100 (as in your original question), most of the time will be taken by the sleep, not by the write. I wrote the sleeptill() function expressly to avoid "time slippage" due to the time taken, such as by the write.Jacobinism
Okay, this isn't github or anything like it, however it'll hopefully do the trick: refactormycode.com/codes/…Jacobinism
W
3

I think that this is what you really want: Pipe Viewer

Using <fast input> | pv -qL <rate>[k|m|g|t] | <rate-limited output> will limit the pipe to the requested rate.

Warty answered 29/6, 2012 at 14:4 Comment(0)
A
2

If you're fine with getting all hundred bytes at a time, you could do a loop with sleep and plain old echo in the shell as a first attempt at least.

Aldric answered 28/10, 2008 at 9:55 Comment(1)
good idea - something like "while [ true ]; do echo -n "1234567890"; usleep 10000; done" already works.Ozone
O
0

Well, I'm now using nuttcp to do "real" load tests instead. It seems to have quite low overhead, so the test system is not too much disturbed.

Ozone answered 28/10, 2008 at 10:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.