Skip to content

Instantly share code, notes, and snippets.

@Xliff
Last active June 19, 2019 11:09
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save Xliff/c6db1e84e9ff76749897b38d60921233 to your computer and use it in GitHub Desktop.
A quick and dirty memory sentinel in Perl6

Every had that worry that a program will break its bonds and chew up all of your RAM? That worry came face-to-face with me recently, so I decided to do something about it: write a quick utility in Perl6 to solve the problem:

However, first things first: what -is- a memory sentinel?

Simply put, it's something that looks at a process and makes sure it doesn't get too large. If it does, it dies.

These thnigs usually take at least one call to a kernel routine, but for Linux-based systems, it's as simple as looking into the /proc filesystem, so that made things easy. I thought it would be a bit more difficult to write. It wasn't:

perl6 -e 'repeat { (my $p = "/proc/12031/status".IO.slurp) ~~ /"VmRSS:" \s* (\d+)/; say $/[0]; if $/[0].Int > 10500944 { qqx[kill -9 12031]; say "Memory flagged"; exit } ; sleep 30 } while True'

To break it down into something more reusable:

sub MAIN (:$pid, :$gigs) {
  # Repeat, infinitely.
  loop {
    # Query /proc for status of process, and extract memory usage
    (my $p = "/proc/{$pid}/status".IO.slurp) ~~ /"VmRSS:" \s* (\d+)/; 
    # Show current memory usage
    say $/[0]; 
    # Check memory usage against our limit, specified by --gigs
    if $/[0].Int > ($gigs * 1024 ** 3) { 
      # It's grown too large, kill it!
      qqx[kill -9 $pid]; 
      say "Target memory usage exceeded. Killing process and exiting..."; 
      exit 
    }  
    # Wait an appropriate amount of time and try again.
    sleep 30 
  } 
}

This is just a basic sketch, but if someone finds this useful, then I am more than happy to share.

@lizmat
Copy link

lizmat commented Jun 19, 2019

This feels way to complicated :-) You should just be able to start a thread watching the memory usage of itself and exiting whenever it is over the limit.

Have a look at https://docs.perl6.org/type/ThreadPoolScheduler#(Scheduler)_method_cue and at https://github.com/rakudo/rakudo/blob/master/lib/Telemetry.pm6#L70

@Xliff
Copy link
Author

Xliff commented Jun 19, 2019

Just out of curiosity... how is this complex? It's 12 lines that allow one to monitor the memory usage of an arbitrary process and to kill it if it gets too big for its britches! :)

Thanks for the suggestions, though!

@Xliff
Copy link
Author

Xliff commented Jun 19, 2019

@lizmat : Also, wouldn't the use of $*SCHEDULER.cue imply the need for a do-nothing endless loop to keep the process alive for .cue to execute?

Since the loop is the main driver of the code, $*SCHEDULER.cue would appear to be overkill, would it not?

@lizmat
Copy link

lizmat commented Jun 19, 2019

$*SCHEDULER.cue uses the libuv event loop to schedule code to run repeatedly. Since that nearly always runs already, there isn't much overhead there. Especially if you only run it once every 30 seconds.

If you don't want to depend on the libuv event loop, you can just start a Thread. See the Telemetry::snapper for an example of that.

@lizmat
Copy link

lizmat commented Jun 19, 2019

Also: repeat { ... } while True is better written as loop { ... } :-)

@Xliff
Copy link
Author

Xliff commented Jun 19, 2019

Also: repeat { ... } while True is better written as loop { ... } :-)

Ah! So it is. Gist updated. ;)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment