ProcFS mm statistics hack...

David S. Miller (davem@caip.rutgers.edu)
Wed, 28 Jun 1995 14:06:03 -0400


I just whipped this up real quick, perhaps some others will find it
useful. Note that I have only modified the i386 specific files, doing
the Alpha or some other architecture should be pretty straight
forward. (see I was even too lazy to do the files for my own port)
;-) Note also that the ppp.c one-liner fix is in this patch too, this
is against stock 1.3.4

Later,
David S. Miller
davem@caip.rutgers.edu

--------------------------------------------
diff -u -b --recursive --new-file linux-1.3.4/arch/i386/config.in linux/arch/i386/config.in
--- linux-1.3.4/arch/i386/config.in Wed Jun 28 13:51:00 1995
+++ linux/arch/i386/config.in Wed Jun 28 11:29:17 1995
@@ -235,6 +235,9 @@
bool 'umsdos: Unix like fs on top of std MSDOS FAT fs' CONFIG_UMSDOS_FS n
fi
bool '/proc filesystem support' CONFIG_PROC_FS y
+if [ "$CONFIG_PROC_FS" = "y" ]; then
+bool 'Verbose memory management statistics?' CONFIG_PROCFS_MMSTAT n
+fi
if [ "$CONFIG_INET" = "y" ]; then
bool 'NFS filesystem support' CONFIG_NFS_FS y
fi
diff -u -b --recursive --new-file linux-1.3.4/arch/i386/mm/fault.c linux/arch/i386/mm/fault.c
--- linux-1.3.4/arch/i386/mm/fault.c Mon Jan 30 06:08:04 1995
+++ linux/arch/i386/mm/fault.c Wed Jun 28 13:32:59 1995
@@ -16,6 +16,10 @@
#include <linux/mman.h>
#include <linux/mm.h>

+#ifdef CONFIG_PROCFS_MMSTAT
+#include <linux/mmstat.h>
+#endif
+
#include <asm/system.h>
#include <asm/segment.h>
#include <asm/pgtable.h>
diff -u -b --recursive --new-file linux-1.3.4/arch/i386/mm/init.c linux/arch/i386/mm/init.c
--- linux-1.3.4/arch/i386/mm/init.c Mon Jun 12 06:56:46 1995
+++ linux/arch/i386/mm/init.c Wed Jun 28 13:31:04 1995
@@ -16,6 +16,10 @@
#include <linux/mman.h>
#include <linux/mm.h>

+#ifdef CONFIG_PROCFS_MMSTAT
+#include <linux/mmstat.h>
+#endif
+
#include <asm/system.h>
#include <asm/segment.h>
#include <asm/pgtable.h>
diff -u -b --recursive --new-file linux-1.3.4/drivers/net/ppp.c linux/drivers/net/ppp.c
--- linux-1.3.4/drivers/net/ppp.c Wed Jun 28 13:51:17 1995
+++ linux/drivers/net/ppp.c Tue Jun 27 08:08:59 1995
@@ -1517,7 +1517,7 @@
case PPPIOCSDEBUG:
error = verify_area (VERIFY_READ, (void *) l, sizeof (temp_i));
if (error == 0) {
- ppp_debug = get_int ((int *) l);
+ ppp_debug = get_user ((int *) l);
ppp_debug_netpackets = (ppp_debug & 0xff00) >> 8;
ppp_debug &= 0xff;
PRINTKN (1, (KERN_INFO "ppp_ioctl: set debug level %d, netpacket %d\n",
diff -u -b --recursive --new-file linux-1.3.4/fs/proc/Makefile linux/fs/proc/Makefile
--- linux-1.3.4/fs/proc/Makefile Wed Dec 1 07:44:15 1993
+++ linux/fs/proc/Makefile Wed Jun 28 12:06:38 1995
@@ -16,6 +16,10 @@

OBJS= inode.o root.o base.o mem.o link.o fd.o array.o kmsg.o net.o

+ifdef CONFIG_PROCFS_MMSTAT
+OBJS := $(OBJS) mmstat.o
+endif
+
proc.o: $(OBJS)
$(LD) -r -o proc.o $(OBJS)

diff -u -b --recursive --new-file linux-1.3.4/fs/proc/array.c linux/fs/proc/array.c
--- linux-1.3.4/fs/proc/array.c Wed Jun 28 13:51:28 1995
+++ linux/fs/proc/array.c Wed Jun 28 11:41:42 1995
@@ -701,6 +701,7 @@
extern int get_dma_list(char *);
extern int get_cpuinfo(char *);
extern int get_pci_list(char*);
+extern int get_mmstat(char *);

static int get_root_array(char * page, int type)
{
@@ -728,6 +729,11 @@
#ifdef CONFIG_DEBUG_MALLOC
case PROC_MALLOC:
return get_malloc(page);
+#endif
+
+#ifdef CONFIG_PROCFS_MMSTAT
+ case PROC_MMSTAT:
+ return get_mmstat(page);
#endif

case PROC_MODULES:
diff -u -b --recursive --new-file linux-1.3.4/fs/proc/mmstat.c linux/fs/proc/mmstat.c
--- linux-1.3.4/fs/proc/mmstat.c Wed Dec 31 19:00:00 1969
+++ linux/fs/proc/mmstat.c Wed Jun 28 13:43:10 1995
@@ -0,0 +1,44 @@
+/* mmstat.c: Memory management statistics for the Linux
+ * proc filesystem.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <linux/kernel.h>
+#include <linux/mmstat.h>
+#include <asm/page.h>
+
+struct linux_mmstat mm_stats = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+int
+get_mmstat(char *page)
+{
+ return sprintf(page,
+ "Invalidates\t:%d\n"
+ "Copypages\t:%d\n"
+ "Oom\t\t:%d\n"
+ "Free ptables\t:%d\n"
+ "Clear ptables\t:%d\n"
+ "Clone ptables\t:%d\n"
+ "Copy ptables\t:%d\n"
+ "Unmap prange\t:%d\n"
+ "Zeromap prange\t:%d\n"
+ "Remap prange\t:%d\n"
+ "do_wp_page\t:%d\n"
+ "do_no_page\t:%d\n"
+ "do_swap_page\t:%d\n"
+ "verify_area\t:%d\n"
+ "share_page\t:%d\n"
+ "handle_pte_fault:%d\n"
+ "handle_mm_fault\t:%d\n",
+ mm_stats.mm_invalidates, mm_stats.mm_copy_page_ops, mm_stats.mm_oom,
+ mm_stats.mm_free_ptables, mm_stats.mm_clear_ptables, mm_stats.mm_clone_ptables,
+ mm_stats.mm_copy_ptables, mm_stats.mm_unmap_prange, mm_stats.mm_zeromap_prange,
+ mm_stats.mm_remap_prange, mm_stats.mm_dowp_page, mm_stats.mm_dono_page,
+ mm_stats.mm_doswap_page, mm_stats.mm_verify_area, mm_stats.mm_share_page,
+ mm_stats.mm_hndl_pte_flt, mm_stats.mm_hndl_mm_flt
+ );
+}
diff -u -b --recursive --new-file linux-1.3.4/fs/proc/root.c linux/fs/proc/root.c
--- linux-1.3.4/fs/proc/root.c Sat Jun 10 12:31:19 1995
+++ linux/fs/proc/root.c Wed Jun 28 11:38:20 1995
@@ -68,6 +68,9 @@
#ifdef CONFIG_DEBUG_MALLOC
{ PROC_MALLOC, 6, "malloc" },
#endif
+#ifdef CONFIG_PROCFS_MMSTAT
+ { PROC_MMSTAT, 6, "mmstat" },
+#endif
{ PROC_KCORE, 5, "kcore" },
{ PROC_MODULES, 7, "modules" },
{ PROC_STAT, 4, "stat" },
diff -u -b --recursive --new-file linux-1.3.4/include/asm-i386/page.h linux/include/asm-i386/page.h
--- linux-1.3.4/include/asm-i386/page.h Mon Jan 30 06:08:04 1995
+++ linux/include/asm-i386/page.h Wed Jun 28 12:08:49 1995
@@ -50,8 +50,16 @@

#endif

+extern unsigned long kstat_invalidates;
+
+#ifdef CONFIG_PROCFS_MMSTAT
+#define invalidate() do { \
+__asm__ __volatile__("movl %%cr3,%%eax\n\tmovl %%eax,%%cr3": : :"ax"); \
+mm_stats.mm_invalidates++; } while(0)
+#else
#define invalidate() \
-__asm__ __volatile__("movl %%cr3,%%eax\n\tmovl %%eax,%%cr3": : :"ax")
+__asm__ __volatile__("movl %%cr3,%%eax\n\tmovl %%eax,%%cr3": : :"ax");
+#endif

/* to align the pointer to the (next) page boundary */
#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK)
diff -u -b --recursive --new-file linux-1.3.4/include/linux/mmstat.h linux/include/linux/mmstat.h
--- linux-1.3.4/include/linux/mmstat.h Wed Dec 31 19:00:00 1969
+++ linux/include/linux/mmstat.h Wed Jun 28 12:41:14 1995
@@ -0,0 +1,30 @@
+/* linux/mmstat.h: Memory management statistics for Linux.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+#ifndef _LINUX_MMSTAT_H
+#define _LINUX_MMSTAT_H
+
+struct linux_mmstat {
+ int mm_invalidates;
+ int mm_copy_page_ops;
+ int mm_oom;
+ int mm_free_ptables;
+ int mm_clear_ptables;
+ int mm_clone_ptables;
+ int mm_copy_ptables;
+ int mm_unmap_prange;
+ int mm_zeromap_prange;
+ int mm_remap_prange;
+ int mm_dowp_page;
+ int mm_dono_page;
+ int mm_verify_area;
+ int mm_share_page;
+ int mm_doswap_page;
+ int mm_hndl_pte_flt;
+ int mm_hndl_mm_flt;
+};
+
+extern struct linux_mmstat mm_stats;
+
+#endif /* !(_LINUX_MMSTAT_H) */
diff -u -b --recursive --new-file linux-1.3.4/include/linux/proc_fs.h linux/include/linux/proc_fs.h
--- linux-1.3.4/include/linux/proc_fs.h Mon Jun 12 09:49:42 1995
+++ linux/include/linux/proc_fs.h Wed Jun 28 11:37:41 1995
@@ -21,6 +21,9 @@
#ifdef CONFIG_DEBUG_MALLOC
PROC_MALLOC,
#endif
+#ifdef CONFIG_PROCFS_MMSTAT
+ PROC_MMSTAT,
+#endif
PROC_KCORE,
PROC_MODULES,
PROC_STAT,
diff -u -b --recursive --new-file linux-1.3.4/mm/memory.c linux/mm/memory.c
--- linux-1.3.4/mm/memory.c Wed Jun 28 13:50:50 1995
+++ linux/mm/memory.c Wed Jun 28 12:15:42 1995
@@ -45,6 +45,10 @@
#include <linux/mman.h>
#include <linux/mm.h>

+#ifdef CONFIG_PROCFS_MMSTAT
+#include <linux/mmstat.h>
+#endif
+
#include <asm/system.h>
#include <asm/segment.h>
#include <asm/pgtable.h>
@@ -60,7 +64,13 @@
struct mem_list free_area_list[NR_MEM_LISTS];
unsigned char * free_area_map[NR_MEM_LISTS];

+#ifdef CONFIG_PROCFS_MMSTAT
+#define copy_page(from,to) do { \
+memcpy((void *) to, (void *) from, PAGE_SIZE); \
+mm_stats.mm_copy_page_ops++; } while(0)
+#else
#define copy_page(from,to) memcpy((void *) to, (void *) from, PAGE_SIZE)
+#endif

#define USER_PTRS_PER_PGD (TASK_SIZE / PGDIR_SIZE)

@@ -72,6 +82,9 @@
*/
void oom(struct task_struct * task)
{
+#ifdef CONFIG_PROCFS_MMSTAT
+ mm_stats.mm_oom++;
+#endif
printk("\nOut of memory for %s.\n", current->comm);
task->sigaction[SIGKILL-1].sa_handler = NULL;
task->blocked &= ~(1<<(SIGKILL-1));
@@ -152,6 +165,9 @@
int i;
pgd_t * page_dir;

+#ifdef CONFIG_PROCFS_MMSTAT
+ mm_stats.mm_clear_ptables++;
+#endif
if (!tsk)
return;
if (tsk == task[0])
@@ -188,6 +204,9 @@
int i;
pgd_t * page_dir;

+#ifdef CONFIG_PROCFS_MMSTAT
+ mm_stats.mm_free_ptables++;
+#endif
if (!tsk)
return;
if (tsk == task[0]) {
@@ -220,6 +239,9 @@
{
pgd_t * pg_dir;

+#ifdef CONFIG_PROCFS_MMSTAT
+ mm_stats.mm_clone_ptables++;
+#endif
pg_dir = pgd_offset(current, 0);
pgd_reuse(pg_dir);
SET_PAGE_DIR(tsk, pg_dir);
@@ -321,6 +343,9 @@
pgd_t *old_pgd;
pgd_t *new_pgd;

+#ifdef CONFIG_PROCFS_MMSTAT
+ mm_stats.mm_copy_ptables++;
+#endif
new_pgd = pgd_alloc();
if (!new_pgd)
return -ENOMEM;
@@ -415,6 +440,9 @@
pgd_t * dir;
unsigned long end = address + size;

+#ifdef CONFIG_PROCFS_MMSTAT
+ mm_stats.mm_unmap_prange++;
+#endif
dir = pgd_offset(current, address);
while (address < end) {
unmap_pmd_range(dir, address, end - address);
@@ -468,6 +496,9 @@
unsigned long end = address + size;
pte_t zero_pte;

+#ifdef CONFIG_PROCFS_MMSTAT
+ mm_stats.mm_zeromap_prange++;
+#endif
zero_pte = pte_wrprotect(mk_pte(ZERO_PAGE, prot));
dir = pgd_offset(current, address);
while (address < end) {
@@ -538,6 +569,9 @@
pgd_t * dir;
unsigned long end = from + size;

+#ifdef CONFIG_PROCFS_MMSTAT
+ mm_stats.mm_remap_prange++;
+#endif
offset -= from;
dir = pgd_offset(current, from);
while (from < end) {
@@ -631,6 +665,9 @@
pte_t *page_table, pte;
unsigned long old_page, new_page;

+#ifdef CONFIG_PROCFS_MMSTAT
+ mm_stats.mm_dowp_page++;
+#endif
new_page = __get_free_page(GFP_KERNEL);
page_dir = pgd_offset(vma->vm_task,address);
if (pgd_none(*page_dir))
@@ -701,6 +738,10 @@
struct vm_area_struct * vma;
unsigned long start = (unsigned long) addr;

+#ifdef CONFIG_PROCFS_MMSTAT
+ mm_stats.mm_verify_area++;
+#endif
+
/* If the current user space is mapped to kernel space (for the
* case where we use a fake user buffer with get_fs/set_fs()) we
* don't expect to find the address in the user vm map.
@@ -914,6 +955,9 @@
unsigned long give_page;
struct vm_area_struct * mpnt;

+#ifdef CONFIG_PROCFS_MMSTAT
+ mm_stats.mm_share_page++;
+#endif
if (!area || !(inode = area->vm_inode) || inode->i_count < 2)
return 0;
/* do we need to copy or can we just share? */
@@ -979,6 +1023,9 @@
{
pte_t page;

+#ifdef CONFIG_PROCFS_MMSTAT
+ mm_stats.mm_doswap_page++;
+#endif
if (!vma->vm_ops || !vma->vm_ops->swapin) {
swap_in(vma, page_table, pte_val(entry), write_access);
return;
@@ -1009,6 +1056,9 @@
pte_t entry;
unsigned long page;

+#ifdef CONFIG_PROCFS_MMSTAT
+ mm_stats.mm_dono_page++;
+#endif
page_table = get_empty_pgtable(vma->vm_task,address);
if (!page_table)
return;
@@ -1084,6 +1134,9 @@
static inline void handle_pte_fault(struct vm_area_struct * vma, unsigned long address,
int write_access, pte_t * pte)
{
+#ifdef CONFIG_PROCFS_MMSTAT
+ mm_stats.mm_hndl_pte_flt++;
+#endif
if (!pte_present(*pte)) {
do_no_page(vma, address, write_access);
return;
@@ -1105,6 +1158,9 @@
pmd_t *pmd;
pte_t *pte;

+#ifdef CONFIG_PROCFS_MMSTAT
+ mm_stats.mm_hndl_mm_flt++;
+#endif
pgd = pgd_offset(vma->vm_task, address);
pmd = pmd_alloc(pgd, address);
if (!pmd)
diff -u -b --recursive --new-file linux-1.3.4/mm/vmalloc.c linux/mm/vmalloc.c
--- linux-1.3.4/mm/vmalloc.c Wed Jun 28 13:51:40 1995
+++ linux/mm/vmalloc.c Wed Jun 28 12:44:58 1995
@@ -15,6 +15,10 @@
#include <linux/malloc.h>
#include <linux/mm.h>

+#ifdef CONFIG_PROCFS_MMSTAT
+#include <linux/mmstat.h>
+#endif
+
#include <asm/segment.h>
#include <asm/pgtable.h>