#!/usr/local/bin/perl -w use IO::Select; use Data::Dumper; use sigtrap; use IO::Select; use POSIX ":sys_wait_h"; my (%pidHandles, %fhPids); # keep both, avoid key-stringification my $s = IO::Select->new(); # gets workload handles added to it. my ($rd, $wr, $exc); my $pid; local %SIG = ( CHLD => sub { # catches cmd = 'sleep 30; echo yay $$' my ($kid,$fh); do { $kid = waitpid(-1, WNOHANG); print "$$ gbye chld @_ pid $kid $!\n"; } until $kid > 0; if ($pidHandles{$kid}) { print "restarting workload task, retiring $kid\n"; $fh = delete $pidHandles{$kid}; delete $fhPids{"$fh"}; $s->remove($fh); mkload(); } }, PIPE => sub { print "$$ gbye pipe @_$!\n"; die "$$ gbye pipe @_ $!\n"; }, INT => sub { print "$$ gbye int @_\n"; die "$$ gbye int @_\n"; }, TERM => sub { print "$$ gbye term @_\n"; die "$$ gbye term @_\n"; }); my $cmd = (shift) || "dd if=/dev/zero of=/dev/null"; sub mkload { $! = 0; my $pid = open(my $fh, "$cmd |") or die "$! cant pipe-open '$cmd'\n"; print "opened pid $pid, status $? $!\n"; $pidHandles{$pid} = $fh; # help sig-handler $fhPids{$fh} = $pid; # select() lookup $s->add($fh); } for (1..3) { mkload() } while (1) { ($rd, $wr, $exc) = $s->select(); # print "readys: ", Dumper [$rd, $wr, $exc]; print "exc on $_ $fhPids{$_}\n" foreach @$exc; print "wr on $_ $fhPids{$_}\n" foreach @$wr; # check readables foreach my $h (@$rd) { print "$$ fh ", fileno($h); my $buf = <$h>; if ($buf) { print "$fhPids{$h} says: $buf"; # has own \n next; } # else rd is null, should be end ?? $pid = delete $fhPids{$h}; delete $pidHandles{$pid}; print "$pid is closed\n"; $s->remove($h); } } END { # final check: gave input foreach my $pid (keys %pidHandles) { my $fh = $pidHandles{$pid}; warn "$$ prob w $pid $fh\n" and next unless $fh; my $out = <$fh> || ''; print "command $pid produced output <$out>\n"; } } __END__ =head1 pl-sub2 Develop sub-process management needed for workload generation to support xenomai testing. Its maeant to help (me) understand the shortcomings of xeno-test.pl. =head1 Workload Process Management Workload tasks should present a uniform demand for the kernel's attention, and be repeatable over many tests. There are 2 basic scenarios for workloads =head2 timed-test In this test scenario, latency tests are run with "-T " option, and terminate after N seconds. While it runs, terminating workloads should be restarted to maintain test-conditions uniformly. The default workload doesnt actally trigger restarts, cuz it uses /dev/zero, which is a never-ending data source. Unfortunately, that source doesnt generate interrupts, thus isnt a hard test to pass. But if you use "-d /dev/hda1", the workload task will end once /dev/hda1 has been copied, and must be restarted to keep the uniformity. =head2 single workload, untimed test This mode supports running a 'meaningful' workload (a real benchmark test), and terminating the current latency test when it finishes. The duration of the benchmark is the simplest measure of performance, and 3 test-scenarios can be meaningfully compared to each other: 1. benchmark running under latency 'load' 2. benchmark running on ipipe kernel w/o latency 'load' 3. benchmark on vanilla kernel 2-vs-3 shows the 'cost' of determinism vs thruput 1-vs-2 indirectly shows the latency test demands upon the CPU. =head2 Implementation We start the workload tasks with pipe open("$cmd|")s, and use a select-loop to handle workload STDOUT, STDERR, and exceptions. We catch CHLD signals when workloads terminate, so we can restart them as needed. I hope the belt & suspenders approach proves adequate Its unclear whether this is entirely workable for all unforseen workloads, but these following invocations have tested good in tests so far: perl pl-sub1 'sleep 10 ; echo yay $$' perl pl-sub1 'while true; do echo hay; done' perl pl-sub1 'while true; do sleep 5; echo hay; done' perl pl-sub1 'while true; do sleep 5; echo hey > out$$; done' =head1 Limitations (not Bugs) Only non-interactive workload/benchmarks will work properly ( the pipes are one-way).