[Codefragments-commits] manish commits r2 - in trunk: . pagecache-info

svn-commits at oss.oracle.com svn-commits at oss.oracle.com
Thu Apr 1 20:08:54 CST 2004


Author: manish
Date: 2004-04-01 20:08:52 -0600 (Thu, 01 Apr 2004)
New Revision: 2

Added:
   trunk/pagecache-info/
   trunk/pagecache-info/Makefile.pre.in
   trunk/pagecache-info/README
   trunk/pagecache-info/Setup.in
   trunk/pagecache-info/pagecache-info
   trunk/pagecache-info/seekfixupmodule.c
Log:
Add pagecache-info utility


Added: trunk/pagecache-info/Makefile.pre.in
===================================================================
--- trunk/pagecache-info/Makefile.pre.in	2003-05-23 23:21:27 UTC (rev 1)
+++ trunk/pagecache-info/Makefile.pre.in	2004-04-02 02:08:52 UTC (rev 2)
@@ -0,0 +1,305 @@
+# Universal Unix Makefile for Python extensions
+# =============================================
+
+# Short Instructions
+# ------------------
+
+# 1. Build and install Python (1.5 or newer).
+# 2. "make -f Makefile.pre.in boot"
+# 3. "make"
+# You should now have a shared library.
+
+# Long Instructions
+# -----------------
+
+# Build *and install* the basic Python 1.5 distribution.  See the
+# Python README for instructions.  (This version of Makefile.pre.in
+# only withs with Python 1.5, alpha 3 or newer.)
+
+# Create a file Setup.in for your extension.  This file follows the
+# format of the Modules/Setup.in file; see the instructions there.
+# For a simple module called "spam" on file "spammodule.c", it can
+# contain a single line:
+#   spam spammodule.c
+# You can build as many modules as you want in the same directory --
+# just have a separate line for each of them in the Setup.in file.
+
+# If you want to build your extension as a shared library, insert a
+# line containing just the string
+#   *shared*
+# at the top of your Setup.in file.
+
+# Note that the build process copies Setup.in to Setup, and then works
+# with Setup.  It doesn't overwrite Setup when Setup.in is changed, so
+# while you're in the process of debugging your Setup.in file, you may
+# want to edit Setup instead, and copy it back to Setup.in later.
+# (All this is done so you can distribute your extension easily and
+# someone else can select the modules they actually want to build by
+# commenting out lines in the Setup file, without editing the
+# original.  Editing Setup is also used to specify nonstandard
+# locations for include or library files.)
+
+# Copy this file (Misc/Makefile.pre.in) to the directory containing
+# your extension.
+
+# Run "make -f Makefile.pre.in boot".  This creates Makefile
+# (producing Makefile.pre and sedscript as intermediate files) and
+# config.c, incorporating the values for sys.prefix, sys.exec_prefix
+# and sys.version from the installed Python binary.  For this to work,
+# the python binary must be on your path.  If this fails, try
+#   make -f Makefile.pre.in Makefile VERSION=1.5 installdir=<prefix>
+# where <prefix> is the prefix used to install Python for installdir
+# (and possibly similar for exec_installdir=<exec_prefix>).
+
+# Note: "make boot" implies "make clobber" -- it assumes that when you
+# bootstrap you may have changed platforms so it removes all previous
+# output files.
+
+# If you are building your extension as a shared library (your
+# Setup.in file starts with *shared*), run "make" or "make sharedmods"
+# to build the shared library files.  If you are building a statically
+# linked Python binary (the only solution of your platform doesn't
+# support shared libraries, and sometimes handy if you want to
+# distribute or install the resulting Python binary), run "make
+# python".
+
+# Note: Each time you edit Makefile.pre.in or Setup, you must run
+# "make Makefile" before running "make".
+
+# Hint: if you want to use VPATH, you can start in an empty
+# subdirectory and say (e.g.):
+#   make -f ../Makefile.pre.in boot srcdir=.. VPATH=..
+
+
+# === Bootstrap variables (edited through "make boot") ===
+
+# The prefix used by "make inclinstall libainstall" of core python
+installdir=	/usr/local
+
+# The exec_prefix used by the same
+exec_installdir=$(installdir)
+
+# Source directory and VPATH in case you want to use VPATH.
+# (You will have to edit these two lines yourself -- there is no
+# automatic support as the Makefile is not generated by
+# config.status.)
+srcdir=		.
+VPATH=		.
+
+# === Variables that you may want to customize (rarely) ===
+
+# (Static) build target
+TARGET=		python
+
+# Installed python binary (used only by boot target)
+PYTHON=		python
+
+# Add more -I and -D options here
+CFLAGS=		$(OPT) -I$(INCLUDEPY) -I$(EXECINCLUDEPY) $(DEFS)
+
+# These two variables can be set in Setup to merge extensions.
+# See example[23].
+BASELIB=	
+BASESETUP=	
+
+# === Variables set by makesetup ===
+
+MODOBJS=	_MODOBJS_
+MODLIBS=	_MODLIBS_
+
+# === Definitions added by makesetup ===
+
+# === Variables from configure (through sedscript) ===
+
+VERSION=	@VERSION@
+CC=		@CC@
+LINKCC=		@LINKCC@
+SGI_ABI=	@SGI_ABI@
+OPT=		@OPT@
+LDFLAGS=	@LDFLAGS@
+LDLAST=		@LDLAST@
+DEFS=		@DEFS@
+LIBS=		@LIBS@
+LIBM=		@LIBM@
+LIBC=		@LIBC@
+RANLIB=		@RANLIB@
+MACHDEP=	@MACHDEP@
+SO=		@SO@
+LDSHARED=	@LDSHARED@
+CCSHARED=	@CCSHARED@
+LINKFORSHARED=	@LINKFORSHARED@
+#@SET_CCC@
+
+# Install prefix for architecture-independent files
+prefix=		/usr/local
+
+# Install prefix for architecture-dependent files
+exec_prefix=	$(prefix)
+
+# Uncomment the following two lines for AIX
+#LINKCC= 	$(LIBPL)/makexp_aix $(LIBPL)/python.exp "" $(LIBRARY); $(PURIFY) $(CC)
+#LDSHARED=	$(LIBPL)/ld_so_aix $(CC) -bI:$(LIBPL)/python.exp
+
+# === Fixed definitions ===
+
+# Shell used by make (some versions default to the login shell, which is bad)
+SHELL=		/bin/sh
+
+# Expanded directories
+BINDIR=		$(exec_installdir)/bin
+LIBDIR=		$(exec_prefix)/lib
+MANDIR=		$(installdir)/man
+INCLUDEDIR=	$(installdir)/include
+SCRIPTDIR=	$(prefix)/lib
+
+# Detailed destination directories
+BINLIBDEST=	$(LIBDIR)/python$(VERSION)
+LIBDEST=	$(SCRIPTDIR)/python$(VERSION)
+INCLUDEPY=	$(INCLUDEDIR)/python$(VERSION)
+EXECINCLUDEPY=	$(exec_installdir)/include/python$(VERSION)
+LIBP=		$(exec_installdir)/lib/python$(VERSION)
+DESTSHARED=	$(BINLIBDEST)/site-packages
+
+LIBPL=		$(LIBP)/config
+
+PYTHONLIBS=	$(LIBPL)/libpython$(VERSION).a
+
+MAKESETUP=	$(LIBPL)/makesetup
+MAKEFILE=	$(LIBPL)/Makefile
+CONFIGC=	$(LIBPL)/config.c
+CONFIGCIN=	$(LIBPL)/config.c.in
+SETUP=		$(LIBPL)/Setup.thread $(LIBPL)/Setup.local $(LIBPL)/Setup
+
+SYSLIBS=	$(LIBM) $(LIBC)
+
+ADDOBJS=	$(LIBPL)/python.o config.o
+
+# Portable install script (configure doesn't always guess right)
+INSTALL=	$(LIBPL)/install-sh -c
+# Shared libraries must be installed with executable mode on some systems;
+# rather than figuring out exactly which, we always give them executable mode.
+# Also, making them read-only seems to be a good idea...
+INSTALL_SHARED=	${INSTALL} -m 555
+
+# === Fixed rules ===
+
+# Default target.  This builds shared libraries only
+default:	sharedmods
+
+# Build everything
+all:		static sharedmods
+
+# Build shared libraries from our extension modules
+sharedmods:	$(SHAREDMODS)
+
+# Build a static Python binary containing our extension modules
+static:		$(TARGET)
+$(TARGET):	$(ADDOBJS) lib.a $(PYTHONLIBS) Makefile $(BASELIB)
+		$(LINKCC) $(LDFLAGS) $(LINKFORSHARED) \
+		 $(ADDOBJS) lib.a $(PYTHONLIBS) \
+		 $(LINKPATH) $(BASELIB) $(MODLIBS) $(LIBS) $(SYSLIBS) \
+		 -o $(TARGET) $(LDLAST)
+
+install:	sharedmods
+		if test ! -d $(DESTSHARED) ; then \
+			mkdir $(DESTSHARED) ; else true ; fi
+		-for i in X $(SHAREDMODS); do \
+			if test $$i != X; \
+			then $(INSTALL_SHARED) $$i $(DESTSHARED)/$$i; \
+			fi; \
+		done
+
+# Build the library containing our extension modules
+lib.a:		$(MODOBJS)
+		-rm -f lib.a
+		ar cr lib.a $(MODOBJS)
+		-$(RANLIB) lib.a 
+
+# This runs makesetup *twice* to use the BASESETUP definition from Setup
+config.c Makefile:	Makefile.pre Setup $(BASESETUP) $(MAKESETUP)
+		$(MAKESETUP) \
+		 -m Makefile.pre -c $(CONFIGCIN) Setup -n $(BASESETUP) $(SETUP)
+		$(MAKE) -f Makefile do-it-again
+
+# Internal target to run makesetup for the second time
+do-it-again:
+		$(MAKESETUP) \
+		 -m Makefile.pre -c $(CONFIGCIN) Setup -n $(BASESETUP) $(SETUP)
+
+# Make config.o from the config.c created by makesetup
+config.o:	config.c
+		$(CC) $(CFLAGS) -c config.c
+
+# Setup is copied from Setup.in *only* if it doesn't yet exist
+Setup:
+		cp $(srcdir)/Setup.in Setup
+
+# Make the intermediate Makefile.pre from Makefile.pre.in
+Makefile.pre: Makefile.pre.in sedscript
+		sed -f sedscript $(srcdir)/Makefile.pre.in >Makefile.pre
+
+# Shortcuts to make the sed arguments on one line
+P=prefix
+E=exec_prefix
+H=Generated automatically from Makefile.pre.in by sedscript.
+L=LINKFORSHARED
+
+# Make the sed script used to create Makefile.pre from Makefile.pre.in
+sedscript:	$(MAKEFILE)
+	sed -n \
+	 -e '1s/.*/1i\\/p' \
+	 -e '2s%.*%# $H%p' \
+	 -e '/^VERSION=/s/^VERSION=[ 	]*\(.*\)/s%@VERSION[@]%\1%/p' \
+	 -e '/^CC=/s/^CC=[ 	]*\(.*\)/s%@CC[@]%\1%/p' \
+	 -e '/^CCC=/s/^CCC=[ 	]*\(.*\)/s%#@SET_CCC[@]%CCC=\1%/p' \
+	 -e '/^LINKCC=/s/^LINKCC=[ 	]*\(.*\)/s%@LINKCC[@]%\1%/p' \
+	 -e '/^OPT=/s/^OPT=[ 	]*\(.*\)/s%@OPT[@]%\1%/p' \
+	 -e '/^LDFLAGS=/s/^LDFLAGS=[ 	]*\(.*\)/s%@LDFLAGS[@]%\1%/p' \
+	 -e '/^LDLAST=/s/^LDLAST=[      ]*\(.*\)/s%@LDLAST[@]%\1%/p' \
+	 -e '/^DEFS=/s/^DEFS=[ 	]*\(.*\)/s%@DEFS[@]%\1%/p' \
+	 -e '/^LIBS=/s/^LIBS=[ 	]*\(.*\)/s%@LIBS[@]%\1%/p' \
+	 -e '/^LIBM=/s/^LIBM=[ 	]*\(.*\)/s%@LIBM[@]%\1%/p' \
+	 -e '/^LIBC=/s/^LIBC=[ 	]*\(.*\)/s%@LIBC[@]%\1%/p' \
+	 -e '/^RANLIB=/s/^RANLIB=[ 	]*\(.*\)/s%@RANLIB[@]%\1%/p' \
+	 -e '/^MACHDEP=/s/^MACHDEP=[ 	]*\(.*\)/s%@MACHDEP[@]%\1%/p' \
+	 -e '/^SO=/s/^SO=[ 	]*\(.*\)/s%@SO[@]%\1%/p' \
+	 -e '/^LDSHARED=/s/^LDSHARED=[ 	]*\(.*\)/s%@LDSHARED[@]%\1%/p' \
+	 -e '/^CCSHARED=/s/^CCSHARED=[ 	]*\(.*\)/s%@CCSHARED[@]%\1%/p' \
+	 -e '/^SGI_ABI=/s/^SGI_ABI=[ 	]*\(.*\)/s%@SGI_ABI[@]%\1%/p' \
+	 -e '/^$L=/s/^$L=[ 	]*\(.*\)/s%@$L[@]%\1%/p' \
+	 -e '/^$P=/s/^$P=\(.*\)/s%^$P=.*%$P=\1%/p' \
+	 -e '/^$E=/s/^$E=\(.*\)/s%^$E=.*%$E=\1%/p' \
+	 $(MAKEFILE) >sedscript
+	echo "/^#@SET_CCC@/d" >>sedscript
+	echo "/^installdir=/s%=.*%=	$(installdir)%" >>sedscript
+	echo "/^exec_installdir=/s%=.*%=$(exec_installdir)%" >>sedscript
+	echo "/^srcdir=/s%=.*%=		$(srcdir)%" >>sedscript
+	echo "/^VPATH=/s%=.*%=		$(VPATH)%" >>sedscript
+	echo "/^LINKPATH=/s%=.*%=	$(LINKPATH)%" >>sedscript
+	echo "/^BASELIB=/s%=.*%=	$(BASELIB)%" >>sedscript
+	echo "/^BASESETUP=/s%=.*%=	$(BASESETUP)%" >>sedscript
+
+# Bootstrap target
+boot:	clobber
+	VERSION=`$(PYTHON) -c "import sys; print sys.version[:3]"`; \
+	installdir=`$(PYTHON) -c "import sys; print sys.prefix"`; \
+	exec_installdir=`$(PYTHON) -c "import sys; print sys.exec_prefix"`; \
+	$(MAKE) -f $(srcdir)/Makefile.pre.in VPATH=$(VPATH) srcdir=$(srcdir) \
+		VERSION=$$VERSION \
+		installdir=$$installdir \
+		exec_installdir=$$exec_installdir \
+		Makefile
+
+# Handy target to remove intermediate files and backups
+clean:
+		-rm -f *.o *~
+
+# Handy target to remove everything that is easily regenerated
+clobber:	clean
+		-rm -f *.a tags TAGS config.c Makefile.pre $(TARGET) sedscript
+		-rm -f *.so *.sl so_locations
+
+
+# Handy target to remove everything you don't want to distribute
+distclean:	clobber
+		-rm -f Makefile Setup

Added: trunk/pagecache-info/README
===================================================================
--- trunk/pagecache-info/README	2003-05-23 23:21:27 UTC (rev 1)
+++ trunk/pagecache-info/README	2004-04-02 02:08:52 UTC (rev 2)
@@ -0,0 +1,29 @@
+pagecache-info
+--------------
+
+Usage: pagecache-info [OPTIONS] [file pattern...]
+ 
+Display the statistics on the kernel page cache.
+ 
+  -s             show page cache summary (default action)
+  -f             show files with >= 1000 pages in the page cache
+  -m <n>         change the minimum number of pages threshold for above to <n>
+  -n             sort files by name instead of size
+  -V, --version  print version information and exit
+      --help     display this help and exit
+ 
+file pattern is a wildcard pattern (like *.db) to filter on when showing files.
+You can specify multiple patterns.
+
+This script currently works with Red Hat AS 2.1 and EL3 kernels only.
+
+* Note for AS 2.1 users
+
+You need to get the seekfixupmodule.so file and put it in the same directory
+as the script for it to work, since the Python runtime that comes with
+AS 2.1 is not built with large file support.
+
+The interface and output of this tool was inspired by a similar tool written
+by Amazon.com, Inc.
+
+Manish Singh <manish.singh at oracle.com>

Added: trunk/pagecache-info/Setup.in
===================================================================
--- trunk/pagecache-info/Setup.in	2003-05-23 23:21:27 UTC (rev 1)
+++ trunk/pagecache-info/Setup.in	2004-04-02 02:08:52 UTC (rev 2)
@@ -0,0 +1,2 @@
+*shared*
+seekfixup seekfixupmodule.c

Added: trunk/pagecache-info/pagecache-info
===================================================================
--- trunk/pagecache-info/pagecache-info	2003-05-23 23:21:27 UTC (rev 1)
+++ trunk/pagecache-info/pagecache-info	2004-04-02 02:08:52 UTC (rev 2)
@@ -0,0 +1,527 @@
+#!/usr/bin/python
+
+# pagecache-info - Display statistics about the Linux kernel page cache
+# 
+# Copyright (C) 2004 Oracle.  All rights reserved.
+#
+# Author: Manish Singh <manish.singh at oracle.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+import sys
+import string
+import getopt
+import fnmatch
+import re
+import os
+import struct
+
+version = '0.1.0'
+
+default_file_min = 1000
+
+syms = ('page_hash_table', 'page_hash_bits', 'page_cache_size', 'swapper_space')
+
+def check_kernel_version():
+    if sys.platform[:5] != 'linux':
+        print "This script only works on a Linux system"
+        sys.exit(1)
+
+    try:
+        f = open('/proc/sys/kernel/osrelease')
+        osver = f.readline()
+        f.close()
+    except IOError:
+        print "Couldn't determine kernel version"
+        sys.exit(1)
+
+    osver = string.rstrip(osver)
+
+    if osver[:5] == '2.4.9':
+        return osver, MemReader249
+    elif osver[:6] == '2.4.21':
+        return osver, MemReader2421
+    else:
+        print "This script requires a 2.4.9 or 2.4.21 kernel"
+        sys.exit(1)
+
+def init_sym_re():
+    pattern = ' (?:%s)$' % string.join(syms, '|')
+
+    global sym_re
+    sym_re = re.compile(pattern)
+
+def check_symbols(symbols):
+    for s in syms:
+        if not symbols.has_key(s):
+            return None
+
+    return symbols
+    
+def load_symbols(symfile):
+    symbols = {}
+
+    while 1:
+        line = symfile.readline()
+
+        if not line:
+            break
+
+        line = line[:-1]
+
+        if sym_re.search(line):
+            addr, type, name = string.split(line)
+
+            try:
+                address = string.atol(addr, 16)
+            except ValueError:
+                print "Invalid address for %s" % name
+            else:
+                symbols[name] = address
+
+    return check_symbols(symbols)
+
+def cache_filename(osver):
+     return '/tmp/ksymcache-%s' % osver
+
+def get_cached_symbols(osver):
+    fname = cache_filename(osver)
+
+    try:
+        cachefile = open(fname)
+        symbols = load_symbols(cachefile)
+        cachefile.close()
+    except IOError:
+        return None
+
+    return symbols
+
+def get_boot_symbols(osver):
+    fname = '/boot/System.map'
+
+    try:
+        mapfile = open(fname)
+        symbols = load_symbols(mapfile)
+        mapfile.close()
+    except IOError:
+        print "Couldn't read %s" % fname
+        sys.exit(1)
+
+    return symbols
+
+def write_symbol_cache(osver, symbols):
+    fname = cache_filename(osver)
+
+    try:
+        cachefile = open(fname, 'w')
+
+        for name, address in symbols.items():
+            addrstr = string.lower(hex(address)[2:-1])
+            cachefile.write("%s . %s\n" % (addrstr, name))
+
+        cachefile.close()
+    except IOError:
+        pass
+
+def get_symbols(osver):
+    init_sym_re()
+
+    symbols = get_cached_symbols(osver)
+
+    if not symbols:
+        symbols = get_boot_symbols(osver)
+
+        if symbols:
+            write_symbol_cache(osver, symbols) 
+        else:
+            print "Couldn't find all the kernel symbols needed"
+            sys.exit(1)
+
+    return symbols
+
+def read_pointer(kmem, address):
+    seekaddr(kmem, address)
+    buf = kmem.read(4)
+    return struct.unpack('I', buf)[0]
+
+read_uint = read_pointer
+
+class MemReader:
+    page_fmt = '4x4xI4xI'
+    mapping_fmt = '4x4x4x4x4x4x4x4xI'
+    inode_fmt = '4x4x4x4xI'
+    alias_fmt = 'IIIIIIIIIIII'
+    dentry_fmt = '4x4x4xI4x4x4x4x4x4x4x4x4x4x4xII'
+
+    table_start = 0
+    table_step = 4
+
+    def __init__(self, kmem):
+        self.kmem = kmem
+
+    def read_page_hash(self, page_hash_table, page_hash_size):
+        size = page_hash_size * self.table_step
+
+        seekaddr(self.kmem, page_hash_table)
+        buf = self.kmem.read(size)
+
+        buckets = []
+
+        for i in xrange(self.table_start, size, self.table_step):
+            addr = struct.unpack('I', buf[i:i + 4])[0]
+
+            if addr:
+                buckets.append(addr)
+
+        return buckets
+
+    def read_fmt(self, addr, fmt):
+        seekaddr(self.kmem, addr)
+        buf = self.kmem.read(struct.calcsize(fmt))
+        return struct.unpack(fmt, buf)
+
+    def read_page(self, addr):
+        mapping, next_page = self.read_fmt(addr, self.page_fmt)
+        return mapping, next_page
+
+    def read_mapping(self, addr):
+        inode = self.read_fmt(addr, self.mapping_fmt)[0]
+        return inode
+
+    def read_inode(self, addr):
+        dentry = self.read_fmt(addr, self.inode_fmt)[0]
+
+        if dentry != addr + struct.calcsize(self.inode_fmt[:-1]):
+            dentry = dentry - struct.calcsize(self.alias_fmt)
+            return dentry
+        else:
+            return None
+
+    def read_dentry(self, addr):
+        parent, qname, qlen = self.read_fmt(addr, self.dentry_fmt)
+        return qname, qlen, parent
+
+    def read_qname(self, addr, len):
+        seekaddr(self.kmem, addr)
+        return self.kmem.read(len)
+
+class MemReader249(MemReader):
+    mapping_fmt = '4x4x4x4x4x4x4x4x4xI'
+
+    table_start = 4
+    table_step = 8
+
+class MemReader2421(MemReader):
+    pass
+
+class Info:
+    def __init__(self):
+        self.start_size = 0
+        self.end_size = 0
+
+        self.pages = {}
+        self.files = {}
+        self.inodes = {}
+
+        self.swap_pages = []
+        self.swapper_space = 0
+
+        self.noinode_pages = []
+
+def walk_pages(memreader, info, addr):
+    name = None
+
+    mapping, next_addr = memreader.read_page(addr)
+
+    if mapping == info.swapper_space:
+        inode = None
+        info.swap_pages.append(addr)
+    else:
+        inode = memreader.read_mapping(mapping)
+
+    if inode and not info.inodes.has_key(inode):
+        dentry = memreader.read_inode(inode)
+
+        if dentry:
+            parts = []
+
+            while 1:
+                qname, qlen, parent = memreader.read_dentry(dentry)
+
+                part = memreader.read_qname(qname, qlen)
+
+                parts.insert(0, part)
+
+                if parent != dentry:
+                    dentry = parent
+                else:
+                    break 
+
+            name = apply(os.path.join, parts)
+
+        info.inodes[inode] = name
+
+    if inode:
+        name = info.inodes[inode]
+
+        if name:
+            if info.files.has_key(name):
+                info.files[name].append(addr)
+            else:
+                info.files[name] = [addr]
+
+    elif inode == 0:
+        info.noinode_pages.append(addr)
+
+    info.pages[addr] = name
+
+    if next_addr:
+        walk_pages(memreader, info, next_addr)
+
+def walk_kmem(symbols, reader_class):
+    info = Info()
+
+    try:
+        kmem = open('/dev/kmem')
+
+        memreader = reader_class(kmem)
+
+        page_hash_table = read_pointer(kmem, symbols['page_hash_table'])
+        page_hash_bits = read_uint(kmem, symbols['page_hash_bits'])
+        page_hash_size = (1L << page_hash_bits)
+
+        info.swapper_space = read_pointer(kmem, symbols['swapper_space'])
+
+        buckets = memreader.read_page_hash(page_hash_table, page_hash_size)
+
+        info.start_size = read_uint(kmem, symbols['page_cache_size'])
+
+        for addr in buckets:
+            walk_pages(memreader, info, addr)
+
+        info.end_size = read_uint(kmem, symbols['page_cache_size'])
+        
+        kmem.close()
+
+    except IOError, e:
+        print "Error reading /dev/kmem: %s" % e
+        sys.exit(1)
+
+    return info
+
+def print_results(info):
+    size_tmpl = "%%(%s_total)8d pages (%%(%s_total_kb)8d KB)"
+
+    tmpl = """Page cache summary
+number of files  =  %(files_total)8d
+page_cache_size  =  %(page_cache_size)s
+pages with path  =  %(page_paths)8d pages (%(page_paths_kb)8d KB)
+pages w/o path   =  %(page_nopaths)8d pages (%(page_nopaths_kb)8d KB)
+swapfile pages   =  %(page_swap)8d pages (%(page_swap_kb)8d KB)
+pages w/o inode  =  %(page_noinodes)8d pages (%(page_noinodes_kb)8d KB)
+Total            =  %(start_cache_size)s%(end_cache_size)s"""
+
+    with = without = 0
+    for n in info.pages.values():
+        if n:
+            with = with + 1
+        else:
+            without = without + 1
+
+    data = {'files_total'  : len(info.files),
+            'page_total'   : len(info.pages),
+            'page_paths'   : with,
+            'page_nopaths' : without,
+            'page_swap'    : len(info.swap_pages),
+            'page_noinodes': len(info.noinode_pages),
+            'start_total'  : info.start_size,
+            'end_total'    : info.end_size}
+
+    for key, val in data.items():
+        data[key + '_kb'] = val * 4
+
+    for n in 'page', 'start', 'end':
+        data[n + '_cache_size'] = (size_tmpl % (n, n)) % data
+
+    if info.start_size != info.end_size:
+        d = (data['end_cache_size'], abs(info.end_size - info.start_size))
+        data['end_cache_size'] = '\npage cache size  =  %s changed during kmem by %d pages' % d
+    else:
+        data['end_cache_size'] = ''
+
+    print tmpl % data
+
+def print_files(info, remain, min, by_name):
+    files = []
+
+    for f, p in info.files.items():
+        if remain:
+            matched = 0
+
+            for pattern in remain:
+                if fnmatch.fnmatch(f, pattern):
+                    matched = 1
+                    break
+
+            if not matched:
+                continue
+
+        count = len(p)
+
+        if count >= min:
+            size = count * 4 / 1024.0
+
+            element = {'output': "%6d %7.2f %s" % (count, size, f)}
+        
+            if by_name:
+                element['key'] = f
+            else:
+                element['key'] = count
+
+            files.append(element)
+
+    def sorter(a, b):
+        return cmp(a['key'], b['key'])
+
+    files.sort(sorter)
+
+    if not by_name:
+       files.reverse()
+
+    print "Files with >= %d pages in the page cache" % min
+    print " pages      MB path"
+
+    for f in files:
+        print f['output']
+
+def usage(progname):
+    tmpl = """Usage: %(progname)s [OPTIONS] [file pattern...]
+
+Display the statistics on the kernel page cache.
+
+  -s             show page cache summary (default action)
+  -f             show files with >= %(file_min)d pages in the page cache
+  -m <n>         change the minimum number of pages threshold for above to <n>
+  -n             sort files by name instead of size
+  -V, --version  print version information and exit
+      --help     display this help and exit
+
+file pattern is a wildcard pattern (like *.db) to filter on when showing files.
+You can specify multiple patterns.
+
+This script currently works with Red Hat AS 2.1 and EL3 kernels only."""
+
+    data = {'progname': progname,
+            'file_min': default_file_min}
+
+    print tmpl % data
+
+def print_ver():
+    print "pagecache-info version %s" % version
+    print "Written by Manish Singh.\n\nCopyright (C) 2004 Oracle."
+
+def main(argv):
+    try:
+        opts, remain = getopt.getopt(argv[1:], 'Vhsfnm:', ['version', 'help'])
+    except getopt.error, e:
+        print "%s: %s\n" % (argv[0], str(e))
+        usage(argv[0])
+        sys.exit(1)
+
+    default = 1
+
+    show_help = 0
+    show_ver = 0
+
+    summary = 0
+    files = 0
+    file_min = default_file_min
+    by_name = 0
+
+    for o, v in opts:
+        default = 0
+
+        if o in ('-h', '--help'):
+            show_help = 1
+        elif o in ('-V', '--version'):
+            show_ver = 1
+        elif o == '-s':
+            summary = 1
+        elif o == '-f':
+            files = 1 
+        elif o == '-n':
+            by_name = 1
+        elif o == '-m':
+            try:
+                file_min = string.atoi(v)
+            except ValueError, e:
+                print "%s is not a valid number" % v
+                sys.exit(1)
+
+            if file_min <= 0:
+                print "%s is too small" % v
+                sys.exit(1)
+
+    if show_help:
+       usage(argv[0])
+       sys.exit(0)
+
+    if show_ver:
+       print_ver()
+       sys.exit(0)
+
+    if default:
+        summary = 1
+
+    osver, reader_class = check_kernel_version()
+
+    print "Kernel version %s" % osver
+
+    symbols = get_symbols(osver)
+
+    info = walk_kmem(symbols, reader_class)
+
+    if summary:
+       print_results(info)
+
+    if files:
+       print_files(info, remain, file_min, by_name)
+
+# Argh!
+can_seek_properly = 1
+
+try:
+    test = open('/dev/null')
+    test.seek(2147483648L)
+    test.close()
+except OverflowError:
+    can_seek_properly = 0
+
+if can_seek_properly:
+    def seekaddr(fp, addr):
+        fp.seek(addr)
+else:
+    try:
+        import seekfixup
+    except ImportError:
+        print "Python not built with large file support and seekfixup module not found."
+        print "Did you forget to download seekfixupmodule.so and put it in the same directory"
+        print "as this script?"
+        sys.exit(1)
+
+    seekaddr = seekfixup.seekaddr 
+
+if __name__ == "__main__":
+    main(sys.argv)


Property changes on: trunk/pagecache-info/pagecache-info
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/pagecache-info/seekfixupmodule.c
===================================================================
--- trunk/pagecache-info/seekfixupmodule.c	2003-05-23 23:21:27 UTC (rev 1)
+++ trunk/pagecache-info/seekfixupmodule.c	2004-04-02 02:08:52 UTC (rev 2)
@@ -0,0 +1,79 @@
+/*
+ * seekfixupmodule.c
+ *
+ * Work around braindead distribution people who build python without large
+ * file support.
+ *
+ * Copyright (C) 2004 Oracle.  All rights reserved.
+ *
+ * Author: Manish Singh <manish.singh at oracle.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have recieved a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ */
+
+#define _LARGEFILE64_SOURCE
+
+#include "Python.h"
+
+static PyObject *
+seekaddr (PyObject *self,
+          PyObject *args)
+{
+  PyObject *fileobj, *numobj;
+  FILE     *fp;
+  off64_t   addr;
+  int       ret;
+
+  if (!PyArg_ParseTuple (args, "OO:seekaddr", &fileobj, &numobj))
+    return NULL;
+
+  fp = PyFile_AsFile (fileobj);
+
+  if (fp == NULL)
+    {
+      PyErr_SetString (PyExc_TypeError,
+		       "seekaddr requires a file object");
+      return NULL;
+    }
+
+  addr = PyLong_Check (numobj) ? PyLong_AsLongLong (numobj)
+			       : PyInt_AsLong (numobj);
+
+  if (PyErr_Occurred ())
+    return NULL;
+
+  errno = 0;
+  if (fseeko64 (fp, addr, SEEK_SET) != 0)
+    {
+      PyErr_SetFromErrno (PyExc_IOError);
+      clearerr (fp);
+      return NULL;
+    }
+
+  Py_INCREF(Py_None);
+  return Py_None;
+}
+
+static PyMethodDef seekfixup_methods[] = {
+  {"seekaddr", seekaddr, METH_VARARGS},
+  {NULL,       NULL}    /* sentinel */
+};
+
+void
+initseekfixup (void)
+{
+  Py_InitModule ("seekfixup", seekfixup_methods);
+}



More information about the Codefragments-commits mailing list