Beefy Boxes and Bandwidth Generously Provided by pair Networks Joe
We don't bite newbies here... much
 
PerlMonks  

Memory Monitoring

by steelrose (Scribe)
on Apr 25, 2005 at 12:59 UTC ( #451169=perlquestion: print w/ replies, xml ) Need Help??
steelrose has asked for the wisdom of the Perl Monks concerning the following question:

I'm trying to write a script to monitor memory. I was able to get inside the proc directory, and decode some of the process information. I know I could use ps, vmstat, etc, but I've had problems where /usr/ucb/ps -auxww locks up on some of our servers. I'm trying to have a one script fits all. Anyway, the biggest problem is, I'd like to verify processes by there COMPLETE process name. ps, vmstat, etc cuts off most of the process name / command line arguments. I believe I found in Solaris where this type of information is stored. But I'm not sure if I can get to it from perl.
foreach $pid (sort {$a<=>$b} <*>) { $uid = getpwuid((lstat "/proc/$pid")[4]); next if $pid == $$; next if $uid ne "netpoint"; open(PSINFO, "/proc/$pid/psinfo") || next; read(PSINFO, $psinfo,256); close PSINFO; my ( $pr_flag, $pr_nlwp, $pr_pid, $pr_ppid, $pr_pgid, $pr_sid, $pr_uid, $pr_euid, $pr_gid, $pr_egid, $pr_addr, $pr_size, $pr_rssize, $pr_pad1, $pr_ttydev, $pr_pctcpu, $pr_pctmem, $pr_start, $pr_time, $pr_ctime, $pr_fname, $pr_psargs, $pr_wstat, $pr_argc, $pr_argv, $pr_envp, $pr_dmodel, $pr_taskid, $pr_projid, $pr_nzomb, $pr_poolid, $pr_zoneid, $filler ) = unpack("iiiiiiiiiiIiiiiSSa8a8a8Z16Z80iiIIaa3iiiiii", $psinfo); print "\n\n---------------\n\nUser: " . $uid; print "\nPID: " . $pid; print "\nMemory: " . ($pr_pctmem / 0x8000 ) * 100; print "\nCPU: " . ($pr_pctcpu / 0x8000 ) * 100; print "\nArguments: " . $pr_envp[1]; }
$pr_envp and $pr_argv hold memory addresses of the command line. Is it possible memory addresses into an array of strings. I know I could write a C program to do this, but I'd like to stay in Perl.

If you give a man a fish he will eat for a day.
If you teach a man to fish he will buy an ugly hat.
If you talk about fish to a starving man, you're a consultant.

Comment on Memory Monitoring
Download Code
Re: Memory Monitoring
by salva (Monsignor) on Apr 25, 2005 at 13:20 UTC
    I think you can get all the information from the top utility, i.e.:
    $ top -n1 -c -b

    You can parse its output from perl and forget about all the portability issues associated to /proc

      I think there might be some portability issues, as those flags don't work on the versions of top that I have. (Solaris and MacOS):

        oops, it seems that there are several top implementations, with incompatible command line options...
Re: Memory Monitoring
by Roy Johnson (Monsignor) on Apr 25, 2005 at 13:22 UTC
    pack/unpack has a p format for pointer to null-terminated string. I would try that.

    Caution: Contents may have been coded under pressure.
Re: Memory Monitoring
by jmcnamara (Monsignor) on Apr 25, 2005 at 13:32 UTC
      You can pull proc info via snmp (net-snmp). Would be easier and more portable.
Re: Memory Monitoring
by naChoZ (Curate) on Apr 26, 2005 at 02:14 UTC

    I'm curious, what is the end result you're try to accomplish? Instead of reinventing the wheel, you could (amongst other possibilities) install the set of nagios plugins. They work on a large number of different platforms. I believe check_vsz (not perl) is their native plugin to monitor what you want, but there's other stuff for nagios people have written, including a fair number of perl scripts.

    --
    "This alcoholism thing, I think it's just clever propaganda produced by people who want you to buy more bottled water." -- pedestrianwolf

      Last week I tried the Proc::ProcessTable() module. Unfortunately in its build package, it installs an executable. This is bad, because were not supposed to install executables on our production system.

      In the /proc/<pid>/psinfo file, the pr_psargs is an 80 character string that contains the complete command line. The pr_psargv and pr_envp fields are memory addresses that are basically offsets inside the /proc/<pid>/as file (address space).

      The reason I need the complete command line are for java apps. Imagine having a classpath and env vars. You can see how quickly your command line grows above the 80 characters. In these cases, doing a grep to kill particular processes can be very dangerous.

      Anyway, the /proc/<pid>/as file is only readable by the person who owns the process. /usr/ucb/ps is owned by root and can read anyfile, so it doesn't have a problem.

      I really wasn't trying to "Reinvent the wheel" as your post was saying. Just trying to use what we have available and won't cause a problem with the Unix admins.

      So I went back to the simpliest way to do it. A pgrep with a /usr/ucb/ps -auxww <pid>. Then I parse out the memory and cpu statistics. Not happy about the solution, but it works...

      And now I know more about the internals of Solaris's proc directory :)

      Thanks to all the Monks who replied.

      If you give a man a fish he will eat for a day.
      If you teach a man to fish he will buy an ugly hat.
      If you talk about fish to a starving man, you're a consultant.

        Unfortunately my sparc is tucked behind a firewall at home and I can't reach it and try this out at the moment. I think the berkely ps in solaris can take a -p option. So you can do something like this to display the cli for a specific pid:

        /usr/ucb/ps -o command -p 12345

        --
        "This alcoholism thing, I think it's just clever propaganda produced by people who want you to buy more bottled water." -- pedestrianwolf

Re: Memory Monitoring
by zentara (Archbishop) on Apr 26, 2005 at 12:19 UTC
    #!/usr/bin/perl use Proc::ProcessTable; $FORMAT = "%-6s %-10s %-8s %-24s %s\n"; $t = new Proc::ProcessTable; printf($FORMAT, "PID", "TTY", "STAT", "START", "COMMAND"); foreach $p ( @{$t->table} ){ printf($FORMAT, $p->pid, $p->ttydev, $p->state, scalar(localtime($p->start)), $p->cmndline); } ############################################################# # Dump all the information in the current process table use Proc::ProcessTable; $t = new Proc::ProcessTable; foreach $p (@{$t->table}) { print "--------------------------------\n"; foreach $f ($t->fields){ print $f, ": ", $p->{$f}, "\n"; } }

    I'm not really a human, but I play one on earth. flash japh

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://451169]
Approved by JanneVee
Front-paged by ww
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others rifling through the Monastery: (7)
As of 2014-04-18 06:30 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    April first is:







    Results (462 votes), past polls