[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