Bloehdian has asked for the wisdom of the Perl Monks concerning the following question:

Hello

According to the documentation the module writes it output to the cmd window. Is somehow possible to redirect the output so that I can catch it in a variable?

  • Comment on Win32::Process::CpuUsage: Redirect output?

Replies are listed 'Best First'.
Re: Win32::Process::CpuUsage: Redirect output?
by bliako (Abbot) on May 22, 2020 at 14:56 UTC

    The results are printed to STDOUT via XS using printf(). You can try capturing STDOUT thusly:

    use Capture::Tiny 'capture'; use Win32::Process::CpuUsage; my ($out, $err) = capture { my ($pid, $interval, $counts) = (4800, 1000, 3); my $rs = Win32::Process::CpuUsage::GetProcessCpuUsage($pid, $interval +, $counts, $prcCPU, $sysCPU); }; print "result: $out\n";

    If the above does work (with windows you never know) it will not be realtime unfortunately. But I am sure TIMTOWDY TIMTOWTDI.

      UPDATE: This does not work. :-< I was mislead by the output. The output of the function is NOT captured into $out, but just printed to the screen as normally. Any ideas?

      THX a lot. I have found Capture::Tiny (really nifty this stuff ;-)) in parallel to Your efforts and was about to present my working (on Win 10 at least) solution here. Now I can save this time.

        Does it work if you make a standalone script which just calls Win32::... and then from a second script you shell out to it while you capture its stdout? For capture you will have another choice IPC::Run3 which runs a system command and captures its stdout. It's a shot in the dark as I don't have these windows and can not understand why it is not captured in the first place. Plus it is ugly, it is not realtime and it shells out to another Perl script.

        If you feel hackish then you could patch the XS file of Win32::... https://metacpan.org/source/KXJ/Win32-Process-CpuUsage-0.02/CpuUsage.xs to accept one additional parameter: an output filehandle/filename. And replace all printf() with PerlIO_printf(FH, "..."); (seriously untested). But before you climb down that hole of daemons see if replacing with PerlIO_printf(PerlIO_stdout(), "..."); captures the stdout. Because if it can't capture stdout, they are probably talking about 2 different stdouts. Perhaps someone more knowledgable can shed some light to it.

        Capture::Tiny does not seem to capture XS's stdout, which is what printf() uses. In order to test this one needs a C compiler (I don't know what the procedure is in windows).

        First create a test XS module using h2xs -A -n Mytest

        cd Mytest and edit the file Mytest.xs and append this at the end:

        void hello(fh) INPUT: PerlIO* fh; CODE: printf("Hello, world via printf!\n"); PerlIO_printf(PerlIO_stdout(), "Hello, world via PerlIO_printf +\n"); PerlIO_printf(fh, "Hello, world to provided file-handle\n");

        Also create a new file test.pl with this content:

        #!/usr/bin/env perl use ExtUtils::testlib; use Mytest; use Capture::Tiny 'capture'; my $fh; open $fh, '>', 'out.txt' or die "open, $!"; my ($out, $err) = capture { Mytest::hello($fh); }; print "out=\n$out\nend out\n"; close $fh;

        Compile and run with these 3 commands: perl Makefile.PL followed by make all followed by ./test.pl

        The output is:

        out= Hello, world via PerlIO_printf end out Hello, world via printf!

        And the contents of 'out.txt' are: Hello, world to provided file-handle

        The most important thing is that the output produced by plain printf() is not captured. What is captured is the output produced by PerlIO_printf(PerlIO_stdout(), ...) as I suspected - meaning that there are 2 different stdouts...

        The example code above demonstrates how to provide a filehandle to an XS sub to print to it. This is IMO the cleanest solution. Whereas your perl script forks and in one strand you call CpuUsage($fh) to write to provided filehandle. And on another strand you tail that filehandle. A fork can be replaced by an alarm. Upon forking, an open filehandle will be duplicated which means that the file cursor will be distinct in the 2 strands and that makes it easy to tail and write at the "same" time. Opening a file for rw can be done using +>.

        So, is this a solution? I think yes but you need to be able to compile or post a patch to the author.

        The blahblah: I can't understand why write code which does not try to open up lots of possibilities for the user at reasonable/minimal cost for the author. Why printf() when you can fprintf(fh)? And also why write a Perl XS module which does not PerlIO_printf(PerlIO_stdout(),...)?

        bw, bliako

Re: Win32::Process::CpuUsage: Redirect output?
by Corion (Patriarch) on May 22, 2020 at 07:21 UTC