[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

Re: Memory usage - default X install can't use yum with 1GB RAM machine



On Fri, 2007-10-12 at 11:09 -0700, Curtis Doty wrote:

> Yes way cool, James. That script hightlights a bunch of info I've been 
> curious about and too lazy to RTF proc(5). Here's a little patch to make 
> it disclose which processes are sitting on the deleted libs.

 Well it was something I threw together a few months ago to give myself
some rough numbers, but here's an update which is a bit more
userfriendly (also does the detailed info by pids, if that is the first
argument).

-- 
James Antill <james antill redhat com>
Red Hat
#! /usr/bin/python -t


import os
import sys


# Decent (UK/US English only) number formatting.
import locale
locale.setlocale(locale.LC_ALL, '') 

def loc_num(x):
    """ Return a string of a number in the readable "locale" format. """
    return locale.format("%d", int(x), True)
def kmgtp_num(x):
    """ Return a string of a number in the MEM size format, Ie. "30 MB". """
    ends = [" ", "K", "M", "G", "T", "P"]
    while len(ends) and x > 1024:
        ends.pop(0)
        x /= 1024
    return "%u %s" % (x, ends[0])

def cmdline_from_pid(pid):
    """ Fetch command line from a process id. """
    try:
        cmdline= open("/proc/%i/cmdline" %pid).readlines()[0]
        return " ".join(cmdline.split("\x00")).rstrip()
    except:
        return ""

pids = {}
for d in os.listdir("/proc/"):
    try:
        pid = int(d)
        pids[pid] = lambda x: x
        pids[pid].files = set()
        pids[pid].vsz   = 0
        pids[pid].s_size          = 0
        pids[pid].s_rss           = 0
        pids[pid].s_shared_clean  = 0
        pids[pid].s_shared_dirty  = 0
        pids[pid].s_private_clean = 0
        pids[pid].s_private_dirty = 0
        pids[pid].referenced      = 0
        pids[pid].name            = cmdline_from_pid(pid)
    except:
        pass

def map_sz(x):
    """ Work out vsz from mapping range. """
    (beg, end) = x.split('-')
    return (int(end, 16) - int(beg, 16))

files = {}
for pid in pids.keys():
    try:
        try:
            lines = open("/proc/%d/smaps" % pid).readlines()
            smaps = True
        except:
            lines = open("/proc/%d/maps" % pid).readlines()
            smaps = False

        off = 0
        while off < len(lines):
            line = lines[off]
            off += 1
            try:
                int(line[0])
            except:
                continue

            data = line.split(None, 5)
            try:
                ino = int(data[4])
                dev = int(data[3].split(":", 2)[0], 16)
            except:
                print "DBG: Bad line:", lines[off - 1]
                print "DBG:     data=", data
                continue
                
            if dev == 0:
                continue
            if ino == 0:
                continue
            if '(deleted)' not in data[5]:
                continue

            key = "%s:%d" % (data[3], ino)
            if key not in files:
                files[key] = lambda x: x # Hack
                
                files[key].s_size          = 0
                files[key].s_rss           = 0
                files[key].s_shared_clean  = 0
                files[key].s_shared_dirty  = 0
                files[key].s_private_clean = 0
                files[key].s_private_dirty = 0
                files[key].referenced      = 0
                
                files[key].vsz  = 0
                files[key].pids = set()
                files[key].name = data[5]
                
            num = map_sz(data[0])
            pids[pid].vsz  += num
            pids[pid].files.update([key])
            files[key].vsz += num
            files[key].pids.update([pid])
            try:
                if smaps:
                    off += 1
                    num = int(lines[off].split(None, 3)[1])
                    pids[pid].s_size += num
                    files[key].s_size          += num
                    off += 1
                    num = int(lines[off].split(None, 3)[1])
                    pids[pid].s_rss            += num
                    files[key].s_rss           += num
                    off += 1
                    num = int(lines[off].split(None, 3)[1])
                    pids[pid].s_shared_clean   += num
                    files[key].s_shared_clean  += num
                    off += 1
                    num = int(lines[off].split(None, 3)[1])
                    pids[pid].s_shared_dirty   += num
                    files[key].s_shared_dirty  += num
                    off += 1
                    num = int(lines[off].split(None, 3)[1])
                    pids[pid].s_private_clean  += num
                    files[key].s_private_clean += num
                    off += 1
                    num = int(lines[off].split(None, 3)[1])
                    pids[pid].s_private_dirty  += num
                    files[key].s_private_dirty += num
                    off += 1
                    try:
                        num = int(lines[off].split(None, 3)[1])
                        pids[pid].referenced   += num
                        files[key].referenced  += num
                        off += 1
                    except:
                        pass
            except:
                print "DBG: Bad data:";, lines[off - 1]
                
    except:
        pass

vsz             = 0
s_size          = 0
s_rss           = 0
s_shared_clean  = 0
s_shared_dirty  = 0
s_private_clean = 0
s_private_dirty = 0
referenced      = 0

out_type = "files"
if len(sys.argv) > 1 and sys.argv[1] == "pids":
    out_type = "pids"
if len(sys.argv) > 1 and sys.argv[1] == "summary":
    out_type = "summary"

for x in files.values():
    vsz             += x.vsz
    s_size          += x.s_size
    s_rss           += x.s_rss
    s_shared_clean  += x.s_shared_clean
    s_shared_dirty  += x.s_shared_dirty
    s_private_clean += x.s_private_clean
    s_private_dirty += x.s_private_dirty
    referenced      += x.referenced

    if out_type == "files":
        print "%5sB:" % kmgtp_num(x.vsz), x.name,
        print "\ts_size          = %5sB" % kmgtp_num(x.s_size * 1024)
        print "\ts_rss           = %5sB" % kmgtp_num(x.s_rss * 1024)
        print "\ts_shared_clean  = %5sB" % kmgtp_num(x.s_shared_clean * 1024)
        print "\ts_shared_dirty  = %5sB" % kmgtp_num(x.s_shared_dirty * 1024)
        print "\ts_private_clean = %5sB" % kmgtp_num(x.s_private_clean * 1024)
        print "\ts_private_dirty = %5sB" % kmgtp_num(x.s_private_dirty * 1024)
        print "\treferenced      = %5sB" % kmgtp_num(x.referenced * 1024)
        for pid in frozenset(x.pids):
            print "\t\t", pid, pids[pid].name


for pid in pids.keys():
    if not pids[pid].vsz:
         del pids[pid]

if out_type == "pids":
    for pid in pids.keys():
        print "%5sB:" % kmgtp_num(pids[pid].vsz), pid, pids[pid].name
        print "\ts_size          = %5sB" % kmgtp_num(pids[pid].s_size * 1024)
        print "\ts_rss           = %5sB" % kmgtp_num(pids[pid].s_rss * 1024)
        print "\ts_shared_clean  = %5sB" % kmgtp_num(pids[pid].s_shared_clean * 1024)
        print "\ts_shared_dirty  = %5sB" % kmgtp_num(pids[pid].s_shared_dirty * 1024)
        print "\ts_private_clean = %5sB" % kmgtp_num(pids[pid].s_private_clean * 1024)
        print "\ts_private_dirty = %5sB" % kmgtp_num(pids[pid].s_private_dirty * 1024)
        print "\treferenced      = %5sB" % kmgtp_num(pids[pid].referenced * 1024)
        for key in pids[pid].files:
            print "\t\t", files[key].name,

print "\
=============================================================================="
print "files           = %8s" % loc_num(len(files))
print "pids            = %8s" % loc_num(len(pids.keys()))
print "vsz             = %5sB" % kmgtp_num(vsz)
print "\
------------------------------------------------------------------------------"
print "s_size          = %5sB" % kmgtp_num(s_size * 1024)
print "s_rss           = %5sB" % kmgtp_num(s_rss * 1024)
print "s_shared_clean  = %5sB" % kmgtp_num(s_shared_clean * 1024)
print "s_shared_dirty  = %5sB" % kmgtp_num(s_shared_dirty * 1024)
print "s_private_clean = %5sB" % kmgtp_num(s_private_clean * 1024)
print "s_private_dirty = %5sB" % kmgtp_num(s_private_dirty * 1024)
print "referenced      = %5sB" % kmgtp_num(referenced * 1024)
print "\
=============================================================================="

Attachment: signature.asc
Description: This is a digitally signed message part


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]