1 ## -*- coding: utf-8 -*-
3 ## Process lister (control TBA)
5 ## Copyright 2007, Red Hat, Inc
6 ## Michael DeHaan <mdehaan@redhat.com>
8 ## This software may be freely redistributed under the terms of the GNU
9 ## general public license.
11 ## You should have received a copy of the GNU General Public License
12 ## along with this program; if not, write to the Free Software
13 ## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 # =================================
25 class ProcessModule(func_module
.FuncModule
):
29 description
= "Process related reporting and control."
31 def info(self
, flags
="-auxh"):
33 Returns a struct of hardware information. By default, this pulls down
34 all of the devices. If you don't care about them, set with_devices to
38 flags
.replace(";", "") # prevent stupidity
40 cmd
= sub_process
.Popen(["/bin/ps", flags
], executable
="/bin/ps",
41 stdout
=sub_process
.PIPE
,
42 stderr
=sub_process
.PIPE
,
45 data
, error
= cmd
.communicate()
47 # We can get warnings for odd formatting. warnings != errors.
48 if error
and error
[:7] != "Warning":
49 raise codes
.FuncException(error
.split('\n')[0])
52 for x
in data
.split("\n"):
54 results
.append(tokens
)
60 Returns a list of per-program memory usage.
62 Private + Shared = RAM used Program
64 [["39.4 MiB", "10.3 MiB", "49.8 MiB", "Xorg"],
65 ["42.2 MiB", "12.4 MiB", "54.6 MiB", "nautilus"],
66 ["52.3 MiB", "10.8 MiB", "63.0 MiB", "liferea-bin"]
67 ["171.6 MiB", "11.9 MiB", "183.5 MiB", "firefox-bin"]]
69 Taken from the ps_mem.py script written by Pádraig Brady.
70 http://www.pixelbeat.org/scripts/ps_mem.py
79 """ (major,minor,release) """
80 kv
=open("/proc/sys/kernel/osrelease").readline().split(".")[:3]
82 kv
[2]=kv
[2].split(char
)[0]
83 return (int(kv
[0]), int(kv
[1]), int(kv
[2]))
88 """ return Rss,Pss,Shared (note Private = Rss-Shared) """
91 pagesize
=os
.sysconf("SC_PAGE_SIZE")/1024 #KiB
92 Rss
=int(open("/proc/"+str(pid
)+"/statm").readline().split()[1])*pagesize
93 if os
.path
.exists("/proc/"+str(pid
)+"/smaps"): #stat
96 for line
in open("/proc/"+str(pid
)+"/smaps").readlines(): #open
97 #Note in smaps Shared+Private = Rss above
98 #The Rss in smaps includes video card mem etc.
99 if line
.startswith("Shared"):
100 Shared_lines
.append(line
)
101 elif line
.startswith("Pss"):
104 Pss_lines
.append(line
)
105 Shared
=sum([int(line
.split()[1]) for line
in Shared_lines
])
106 Pss
=sum([int(line
.split()[1]) for line
in Pss_lines
])
107 elif (2,6,1) <= kv
<= (2,6,9):
109 Shared
=0 #lots of overestimation, but what can we do?
112 Shared
=int(open("/proc/"+str(pid
)+"/statm").readline().split()[2])*pagesize
113 return (Rss
, Pss
, Shared
)
118 for pid
in os
.listdir("/proc/"):
120 pid
= int(pid
) #note Thread IDs not listed in /proc/
121 if pid
==our_pid
: continue
124 cmd
= file("/proc/%d/status" % pid
).readline()[6:-1]
126 exe
= os
.path
.basename(os
.path
.realpath("/proc/%d/exe" % pid
))
127 if exe
.startswith(cmd
):
128 cmd
=exe
#show non truncated version
129 #Note because we show the non truncated name
130 #one can have separated programs as follows:
131 #584.0 KiB + 1.0 MiB = 1.6 MiB mozilla-thunder (exe -> bash)
132 #56.0 MiB + 22.2 MiB = 78.2 MiB mozilla-thunderbird-bin
134 #permission denied or
135 #kernel threads don't have exe links or
139 rss
, pss
, shared
= getMemStats(pid
)
141 #Note shared is always a subset of rss (trs is not always)
143 continue #process gone
145 if pss
: #add shared portion of PSS together
146 shareds
[cmd
]+=pss
-private
147 elif shareds
[cmd
] < shared
: #just take largest shared val
151 shareds
[cmd
]=pss
-private
154 cmds
[cmd
]=cmds
.setdefault(cmd
,0)+private
155 if count
.has_key(cmd
):
160 #Add max shared mem for each program
162 for cmd
in cmds
.keys():
163 cmds
[cmd
]=cmds
[cmd
]+shareds
[cmd
]
164 total
+=cmds
[cmd
] #valid if PSS available
166 sort_list
= cmds
.items()
167 sort_list
.sort(lambda x
,y
:cmp(x
[1],y
[1]))
168 sort_list
=filter(lambda x
:x
[1],sort_list
) #get rid of zero sized processes
170 #The following matches "du -h" output
171 def human(num
, power
="Ki"):
172 powers
=["Ki","Mi","Gi","Ti"]
173 while num
>= 1000: #4 digits
175 power
=powers
[powers
.index(power
)+1]
176 return "%.1f %s" % (num
,power
)
178 def cmd_with_count(cmd
, count
):
180 return "%s (%u)" % (cmd
, count
)
184 for cmd
in sort_list
:
186 "%sB" % human(cmd
[1]-shareds
[cmd
[0]]),
187 "%sB" % human(shareds
[cmd
[0]]),
188 "%sB" % human(cmd
[1]),
189 "%s" % cmd_with_count(cmd
[0], count
[cmd
[0]])
192 results
.append(["", "", "", "%sB" % human(total
)])
198 def kill(self
,pid
,signal
="TERM"):
200 raise codes
.FuncException("Killing pid group 0 not permitted")
202 # this is default /bin/kill behaviour,
203 # it claims, but enfore it anyway
206 signal
= "-%s" % signal
207 rc
= sub_process
.call(["/bin/kill",signal
, pid
],
208 executable
="/bin/kill", shell
=False)
212 def pkill(self
,name
,level
=""):
213 # example killall("thunderbird","-9")
214 rc
= sub_process
.call(["/usr/bin/pkill", name
, level
],
215 executable
="/usr/bin/pkill", shell
=False)