Forum: Ruby Finding CPU% of a linux task

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
38a8230ed3d5c685558b4f0aad3fc74b?d=identicon&s=25 Joe Van Dyk (Guest)
on 2006-01-10 22:32
(Received via mailing list)
Hi,

I'm writing a small Ruby module that can find how much cpu percentage
a given task is using.  I'm doing it by getting the process id of the
task that I care about, going into proc, checking the stat file for
the process (which contains how many jiffies the task has consumed)
and averaging the change of that over time to get a running
percentage.

However, that doesn't capture threads or forked processes.  If a
program starts a couple threads (or forks a child process), I then
have to figure out the cpu percentage of each of the child threads
(and their childs and their child's childs, and so on) and add them
together to get a total for the process.

I'm struggling to come up with an elegant way to solve this problem.
Any ideas?

Thanks,
Joe
4299e35bacef054df40583da2d51edea?d=identicon&s=25 James Gray (bbazzarrakk)
on 2006-01-10 22:35
(Received via mailing list)
On Jan 10, 2006, at 3:31 PM, Joe Van Dyk wrote:

> However, that doesn't capture threads or forked processes.  If a
> program starts a couple threads (or forks a child process), I then
> have to figure out the cpu percentage of each of the child threads
> (and their childs and their child's childs, and so on) and add them
> together to get a total for the process.

Ruby's threads are in process, so they should already be in your
percentage, shouldn't they?

James Edward Gray II
38a8230ed3d5c685558b4f0aad3fc74b?d=identicon&s=25 Joe Van Dyk (Guest)
on 2006-01-10 22:44
(Received via mailing list)
On 1/10/06, James Edward Gray II <james@grayproductions.net> wrote:
> On Jan 10, 2006, at 3:31 PM, Joe Van Dyk wrote:
>
> > However, that doesn't capture threads or forked processes.  If a
> > program starts a couple threads (or forks a child process), I then
> > have to figure out the cpu percentage of each of the child threads
> > (and their childs and their child's childs, and so on) and add them
> > together to get a total for the process.
>
> Ruby's threads are in process, so they should already be in your
> percentage, shouldn't they?

To clarify, these aren't Ruby processes I'm tracking.

Sample usage of my class:

pi = ProcessInfo.new <pid>
pi.cpu_percentage # returns the cpu % of the process
pi.running? # sees if the process is still running

etc

I added ProcessInfo#child_tasks, that searches /proc for all child
tasks of the process.  But then, when I calculate the cpu% of the
process, I need to recursively go in and get all the cpu% of all the
child threads/processes of the process.  And my code got ugly fast.
011737f94b61f527bd869eb54d735f57?d=identicon&s=25 Michal Suchanek (Guest)
on 2006-01-10 23:08
(Received via mailing list)
On 1/10/06, Joe Van Dyk <joevandyk@gmail.com> wrote:
> > percentage, shouldn't they?
>
> I added ProcessInfo#child_tasks, that searches /proc for all child
> tasks of the process.  But then, when I calculate the cpu% of the
> process, I need to recursively go in and get all the cpu% of all the
> child threads/processes of the process.  And my code got ugly fast.

What is wrong with

class ProcessInfo

def direct_children
 <grep for children>
 <return array of ProcessInfo or []>
end

def children
 direct_children.collect{|ch|ch.chilfren}.flatten!
end

def cpu_sum
 sum = cpu_percentage
 children.each{|ch| sum += ch.cpu_percentage}
 sum
end

end

Thanks

Michal



--
             Support the freedom of music!
Maybe it's a weird genre  ..  but weird is *not* illegal.
Maybe next time they will send a special forces commando
to your picnic .. because they think you are weird.
 www.music-versus-guns.org  http://en.policejnistat.cz
57db258c85d869acb110768cc675cfba?d=identicon&s=25 Barbier de Reuille Pierre (Guest)
on 2006-01-10 23:53
(Received via mailing list)
Well, on Linux 2.6, the list of the threads is in :

/proc/[pid]/task

But it is not true for Linux 2.4 :(
And on 2.4, I really don't know if you can tell a process from a thread
from the exterior. At least, I see no difference in the /proc virtual
system.

But then, this discussion should be in
comp.os.linux.development.system, isn't it ?

Pierre

On Wed, 11 Jan 2006 06:42:54 +0900
38a8230ed3d5c685558b4f0aad3fc74b?d=identicon&s=25 Joe Van Dyk (Guest)
on 2006-01-11 00:02
(Received via mailing list)
On 1/10/06, Barbier de Reuille Pierre <p.barbierdereuille@free.fr>
wrote:
> Well, on Linux 2.6, the list of the threads is in :
>
> /proc/[pid]/task
>
> But it is not true for Linux 2.4 :(
> And on 2.4, I really don't know if you can tell a process from a thread
> from the exterior. At least, I see no difference in the /proc virtual
> system.

For my purposes, I don't want to make a distinction between threads
and processes.  I just want an accurate cpu percentage of a running
program (which includes all of its threads and child processes).
82e62c756d89bc6fa0a0a2d7f2b1e617?d=identicon&s=25 Ross Bamford (Guest)
on 2006-01-11 00:29
(Received via mailing list)
On Tue, 10 Jan 2006 22:59:27 -0000, Joe Van Dyk <joevandyk@gmail.com>
wrote:

> For my purposes, I don't want to make a distinction between threads
> and processes.  I just want an accurate cpu percentage of a running
> program (which includes all of its threads and child processes).
>

Since you're looking in /proc anyway I guess this is for unixy systems,
so
_maybe_ the following is of use?

	module Process
	  class << self
	    def cpu_percent(pid)
	      pgid = getpgid(pid)
	      ps = `ps -Ao pcpu,pgrp`.to_a
	      (ps[1..-1]).inject(0.0) do |sum,s|
	        if s =~ /([\d.]+)\s*([\d]+)/
	          tcpu, tpgid = $~.captures
	          (tpgid.to_i == pgid) ? sum + tcpu.to_f: sum
	        end
	      end
	    end
	  end
	end

	pid = (ARGV[0] || Process.pid).to_i
	puts "#{pid}: #{Process.cpu_percent(pid)}"

Not a particularly clean one but maybe it gives a starting point? On my
system a quick test gives:

	$ ps -o cmd,pcpu,pid,pgrp,sid
	CMD                         %CPU   PID  PGRP   SID
	bash                         0.0  4540  4540  4540
	ruby -e fork { loop do 1000  2.2  4942  4942  4540
	ruby -e fork { loop do 1000  4.3  4943  4942  4540
	ps -o cmd,pcpu,pid,pgrp,sid  0.0  5393  5393  4540

	$ ruby pinfo.rb 4942
	4942: 6.5%

	$ ruby pinfo.rb 4294
	pinfo.rb:4:in `getpgid': No such process (Errno::ESRCH)
	        from pinfo.rb:4:in `cpu_percent'
	        from pinfo.rb:17

(that second one is a deliberate example :) )

Check out 'man ps' for the different args etc, and the proper output
format syntax if you're on non-GNU.
38a8230ed3d5c685558b4f0aad3fc74b?d=identicon&s=25 Joe Van Dyk (Guest)
on 2006-01-11 00:32
(Received via mailing list)
On 1/10/06, Joe Van Dyk <joevandyk@gmail.com> wrote:
> program starts a couple threads (or forks a child process), I then
> have to figure out the cpu percentage of each of the child threads
> (and their childs and their child's childs, and so on) and add them
> together to get a total for the process.
>
> I'm struggling to come up with an elegant way to solve this problem.  Any ideas?

I can't make heads or tails out of this behavior.  5463 is a thread,
btw.  Linux 2.4.21, Ruby 1.8.4.  When I do a directory glob of /proc/,
5463 isn't coming up.


irb(main):002:0> File.directory? "/proc/5463"
=> true

irb(main):003:0> Dir["/proc/5*"].sort
=> ["/proc/5", "/proc/5111", "/proc/5113", "/proc/5459", "/proc/5470",
"/proc/5477", "/proc/5486", "/proc/5487", "/proc/5653", "/proc/5654",
"/proc/5800", "/proc/5810", "/proc/5811"]

irb(main):004:0> Dir["/proc/5*"].include?("/proc/5463")
=> false

irb(main):005:0> # WTF
irb(main):006:0* exit

% ls -ld /proc/5463
dr-xr-xr-x    3 root     games           0 Jan 10 15:26 /proc/5463/

% ls -l /proc/5463
ls: cannot read symbolic link /proc/5463/cwd: Permission denied
ls: cannot read symbolic link /proc/5463/root: Permission denied
ls: cannot read symbolic link /proc/5463/exe: Permission denied
total 0
-r--r--r--    1 root     games           0 Jan 10 15:26 cmdline
-r--r--r--    1 root     games           0 Jan 10 15:26 cpu
lrwxrwxrwx    1 root     games           0 Jan 10 15:26 cwd
-r--------    1 root     games           0 Jan 10 15:26 environ
lrwxrwxrwx    1 root     games           0 Jan 10 15:26 exe
dr-x------    2 root     games           0 Jan 10 15:26 fd/
-r--------    1 root     games           0 Jan 10 15:26 maps
-rw-------    1 root     games           0 Jan 10 15:26 mem
-r--r--r--    1 root     games           0 Jan 10 15:26 mounts
lrwxrwxrwx    1 root     games           0 Jan 10 15:26 root
-r--r--r--    1 root     games           0 Jan 10 15:26 stat
-r--r--r--    1 root     games           0 Jan 10 15:26 statm
-r--r--r--    1 root     games           0 Jan 10 15:26 status

% cat /proc/5463/status
Name:   sccng.x
State:  S (sleeping)
Tgid:   5459
Pid:    5463
PPid:   5459
TracerPid:      0
Uid:    0       0       0       0
Gid:    20      20      20      20
FDSize: 256
Groups: 0 1 2 3 4 6 10 1 2 3 4
VmSize:   147612 kB
VmLck:    147612 kB
VmRSS:    146648 kB
VmData:    58268 kB
VmStk:       776 kB
VmExe:       468 kB
VmLib:     11512 kB
SigPnd: 0000000000000000
ShdPnd: 0000000000000000
SigBlk: 0000000000000000
SigIgn: 0000000000001000
SigCgt: 0000000080002e47
CapInh: 00000000ffffffff
CapPrm: 00000000ffffffff
CapEff: 00000000ffffffff
38a8230ed3d5c685558b4f0aad3fc74b?d=identicon&s=25 Joe Van Dyk (Guest)
on 2006-01-11 00:47
(Received via mailing list)
On 1/10/06, Joe Van Dyk <joevandyk@gmail.com> wrote:
> > However, that doesn't capture threads or forked processes.  If a
>
> => false
> ls: cannot read symbolic link /proc/5463/exe: Permission denied
> lrwxrwxrwx    1 root     games           0 Jan 10 15:26 root
> TracerPid:      0
> VmLib:     11512 kB
> SigPnd: 0000000000000000
> ShdPnd: 0000000000000000
> SigBlk: 0000000000000000
> SigIgn: 0000000000001000
> SigCgt: 0000000080002e47
> CapInh: 00000000ffffffff
> CapPrm: 00000000ffffffff
> CapEff: 00000000ffffffff


Solved!  I thought Ruby was being weird, shame on me.

Threads are represented in /proc with a '.' in front of the id.  i.e.
/proc/.5463. For some reason though, I can access /proc/5463, but
/proc/5463 doesn't show up in directory globs.

Joe
This topic is locked and can not be replied to.