http://qs321.pair.com?node_id=11116250


in reply to Re^2: System call doesn't work when there is a large amount of data in a hash
in thread System call doesn't work when there is a large amount of data in a hash

Using the memory gobbling technique by Corion here, let's do some testing. I divided by 2 to reflect the actual memory consumption desired.

My virtual CentOS 7 machine has 4 GB of RAM allocated to it. This creates a 3 GB scalar key-value pair to consume 75%. The system command called by the main process fails, no ls output on the 2nd time. Calling syscmd succeeds due to the background worker spun early.

syscmd

use strict; use warnings; use MCE::Child; use MCE::Channel; my $chnl = MCE::Channel->new( impl => 'Simple' ); # spin up worker early before creating big hash mce_child { local $SIG{__WARN__} = sub {}; while ( my ($cmd, @args) = $chnl->recv ) { local ($?, $!); system($cmd, @args); $chnl->send2($?, $!); } }; sub syscmd { my $cmd = shift; return unless $cmd; $chnl->send($cmd, @_); my ($status, $errmsg) = $chnl->recv2; if ($status == -1) { print "SYSTEM: failed to execute ($cmd): $errmsg\n"; } elsif ($status & 127) { printf "SYSTEM: $cmd died with signal %s, %s coredump\n", ($status & 127), ($status & 128) ? 'with' : 'without'; } else { printf "SYSTEM: $cmd exited with status %d\n", $status >> 8; } } # My CentOS VM has 4 GB of RAM # create big hash my $memory_eaten = 3 * 1024*1024*1024 / 2; # 3 GB, adjust to fit my %memory_eater = ( foo => scalar( ' ' x $memory_eaten ), ); # pass command and optionally args syscmd('ls'); # this one works; see status that it succeeded system('ls'); # this one fails; no ls output the 2nd time # attempt to run a command not found syscmd('something'); # sleep for 2 seconds syscmd('sleep', '2'); # busy loop, see top output in another terminal # notice the memory consumption (i.e. RES) # press Ctrl-C to exit or let it finish 1 for 1..3e8; # notify no more work, then reap worker $chnl->end; MCE::Child->waitall;

output:

ls output from syscmd SYSTEM: ls exited with status 0 SYSTEM: failed to execute (something): No such file or directory SYSTEM: sleep exited with status 0

Regards, Mario

Replies are listed 'Best First'.
Re^4: System call doesn't work when there is a large amount of data in a hash (testing)
by Nicolasd (Acolyte) on May 01, 2020 at 00:33 UTC
    Hi again,
    I tested your example and it seems to work great, so the problem is solved!
    Thank you so much!
Re^4: System call doesn't work when there is a large amount of data in a hash (testing)
by Nicolasd (Acolyte) on Apr 30, 2020 at 00:44 UTC
    I quickly tested your script on the Centos, and it works perfectly! I will implement it in my script tomorrow, hopefully it will work as good. You can send me your name, I would like to thank you when the tool will be published.
Re^4: System call doesn't work when there is a large amount of data in a hash (testing)
by Nicolasd (Acolyte) on Apr 30, 2020 at 00:19 UTC
    Wow thanks so much for your help! I will test it tomorrow for sure! I thought I had to give up the system call, would be amazing if it works!

      Hi Nicolasd,

      POSIX::RT::Spawn also works, a suggestion made here. Unfortunately, POSIX::RT::Spawn doesn't capture the error string (for example command not found). Well, two solutions this one using POSIX::RT::Spawn and the other using MCE::Child with MCE::Channel.

      spawn:

      The system command by the main process fails like before, but not syscmd calling spawn.

      use strict; use warnings; use POSIX::RT::Spawn; sub syscmd { my $cmd = shift; return unless $cmd; local ($?, $!); my $pid = spawn $cmd, @_; waitpid $pid, 0; my ($status, $errmsg) = ($?, $!); if ($status == -1) { print "SYSTEM: failed to execute ($cmd): $errmsg\n"; } elsif ($status & 127) { printf "SYSTEM: $cmd died with signal %s, %s coredump\n", ($status & 127), ($status & 128) ? 'with' : 'without'; } else { printf "SYSTEM: $cmd exited with status %d\n", $status >> 8; } } # My CentOS VM has 4 GB of RAM # create big hash my $memory_eaten = 3 * 1024*1024*1024 / 2; # 3 GB, adjust to fit my %memory_eater = ( foo => scalar( ' ' x $memory_eaten ), ); # pass command and optionally args syscmd('ls'); # this one works; see status that it succeeded system('ls'); # this one fails; no ls output the 2nd time # attempt to run a command not found syscmd('something'); # sleep for 2 seconds syscmd('sleep', '2'); # busy loop, see top output in another terminal # notice the memory consumption (i.e. RES) # press Ctrl-C to exit or let it finish 1 for 1..3e8;

      output:

      ls output from spawn SYSTEM: ls exited with status 0 SYSTEM: something exited with status 127 SYSTEM: sleep exited with status 0

      Regards, Mario