From: Hideo AOKI <haoki@redhat.com>
To: akpm@osdl.org
Cc: linux-kernel@vger.kernel.org, linux-mm@kvack.org
Subject: A test kernel module of OVERCOMMIT_GUESS
Date: Wed, 05 Apr 2006 19:51:58 -0400 [thread overview]
Message-ID: <4434581E.4080505@redhat.com> (raw)
In-Reply-To: <4434570F.9030507@redhat.com>
[-- Attachment #1: Type: text/plain, Size: 978 bytes --]
Hello Andrew,
This is a kernel module patch which I developed to test my patches.
The module makes a kind of memory pressure situation. After that, the
module tests if the OVERCOMMIT_GUESS detects overcommit.
The module has "mode" option. If you specify "mode=1", the module
tries to allocate pages in the test phase.
Here is the test result when I did "mode=1" test on my machine.
* 2.6.17-rc1-mm1
kernel: Test MAY be <failed>.
kernel: allocation failed: out of vmalloc space - use vmalloc=<size> to increase size.
kernel: allocation failed: out of vmalloc space - use vmalloc=<size> to increase size.
kernel: Test SURELY was <FAILED>.
* 2.6.17-rc1-mm1 + my patches
kernel: Test was <PASSED>.
Unfortunately, this kernel module needs another kernel patch.
I will send it in later e-mail.
Please note that I don't intend to propose to apply the module to
kernel tree.
Best regards,
Hideo Aoki
---
Hideo Aoki, Hitachi Computer Products (America) Inc.
[-- Attachment #2: mm-test_overcommit.patch --]
[-- Type: text/x-patch, Size: 14341 bytes --]
A kernel module to test OVERCOMMIT_GUESS.
lib/Kconfig.debug | 11 +
mm/Makefile | 1
mm/test_overcommit.c | 515 +++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 527 insertions(+)
diff -purN linux-2.6.17-rc1-mm1/lib/Kconfig.debug linux-2.6.17-rc1-mm1-test1/lib/Kconfig.debug
--- linux-2.6.17-rc1-mm1/lib/Kconfig.debug 2006-04-04 10:43:57.000000000 -0400
+++ linux-2.6.17-rc1-mm1-test1/lib/Kconfig.debug 2006-04-04 16:30:31.000000000 -0400
@@ -282,6 +282,17 @@ config RCU_TORTURE_TEST
Say M if you want the RCU torture tests to build as a module.
Say N if you are unsure.
+config OVERCOMMIT_GUESS_TEST
+ tristate "An overcommit guess testing module"
+ depends on DEBUG_KERNEL && X86
+ default n
+ help
+ This option provides a kernel module that can test OVERCOMMIT_GUESS
+ in __vm_enough_memory().
+
+ You should say N or M here. Say M if you want to build the module.
+ Say N if you are unsure.
+
config WANT_EXTRA_DEBUG_INFORMATION
bool
select DEBUG_INFO
diff -purN linux-2.6.17-rc1-mm1/mm/Makefile linux-2.6.17-rc1-mm1-test1/mm/Makefile
--- linux-2.6.17-rc1-mm1/mm/Makefile 2006-04-04 10:43:57.000000000 -0400
+++ linux-2.6.17-rc1-mm1-test1/mm/Makefile 2006-04-04 16:23:09.000000000 -0400
@@ -24,4 +24,5 @@ obj-$(CONFIG_SLAB) += slab.o
obj-$(CONFIG_MEMORY_HOTPLUG) += memory_hotplug.o
obj-$(CONFIG_FS_XIP) += filemap_xip.o
obj-$(CONFIG_MIGRATION) += migrate.o
+obj-$(CONFIG_OVERCOMMIT_GUESS_TEST) += test_overcommit.o
diff -purN linux-2.6.17-rc1-mm1/mm/test_overcommit.c linux-2.6.17-rc1-mm1-test1/mm/test_overcommit.c
--- linux-2.6.17-rc1-mm1/mm/test_overcommit.c 1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.17-rc1-mm1-test1/mm/test_overcommit.c 2006-04-04 16:23:09.000000000 -0400
@@ -0,0 +1,515 @@
+/*
+ * A kernel module for testing OVERCOMMIT_GUESS. ver 0.0.1
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+/*
+ * This kernel module tests the later part of OVERCOMMIT_GUESS algorithm.
+ * To test the algorithm, the module makes a kind of memory pressure situation.
+ * After that, the module tests if the algorithm detects overcommit.
+ *
+ * You can specify by "mode" module option if the module actually tries to
+ * allocate pages in the situation.
+ *
+ * You have to apply a kernel patch to use the module currently, since the
+ * module needs to refer some internal symbols for testing.
+ *
+ * The module was tested on only i386 SMP machines.
+ */
+#include <linux/module.h> /* Needed by all modules */
+#include <linux/moduleparam.h>
+#include <linux/kernel.h> /* Needed for KERN_INFO */
+
+#include <linux/gfp.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/pagemap.h>
+#include <linux/slab.h>
+#include <linux/swap.h>
+#include <linux/vmalloc.h>
+
+#include <asm/kmap_types.h>
+#include <asm/system.h>
+#include <linux/blkdev.h>
+#include <linux/string.h>
+
+/*
+ * Get rid of taint message by declaring code as GPL v2.
+ */
+MODULE_LICENSE("GPL v2");
+
+/*
+ * Module documentation
+ */
+MODULE_AUTHOR("Hideo Aoki");
+MODULE_DESCRIPTION("test module of overcommit guess");
+
+/*
+ * Module parameter(s)
+ */
+enum { MODE_DEFALUT = 0, MODE_DOLASTALLOC = 1 };
+static int mode = MODE_DEFALUT;
+
+module_param(mode, int, S_IRUSR);
+MODULE_PARM_DESC(mode, "test mode. If mode is 1, the module executes actual page allocation in concrete test.");
+
+/*
+ * declarations
+ */
+#define MOD_MM 1 /* modify kernel */
+#define DEF_PRT_LV KERN_DEBUG /* default print level in this mod. */
+
+/*
+ * Page managemnt: We manage allocated pages. When module is unloaded,
+ * the module releases them.
+ */
+struct page_mng_t {
+ struct page *listp; /* list of allocated pages */
+ int zone; /* which zone manage */
+};
+
+/* We use head of allocated pages for managing page list */
+struct mypage_t {
+ struct page *next_page;
+ int order; /* page order */
+};
+
+
+enum {
+ NORMAL, HIGH
+};
+
+static struct page_mng_t low_pg; /* LOWMEM pages management */
+static struct page_mng_t high_pg;/* HIGHMEM pages management */
+static unsigned long committed_pages;/* number of pages committed in the mod.*/
+
+void prepare_test_env(void);
+void final_test(int mode);
+int commit_pages(unsigned long target, struct page_mng_t *mng, int gfp,
+ char *msg);
+int try_to_commit_pages(int order, int gfp, struct page_mng_t *mng,
+ unsigned long *n_alloced);
+int alloc_last_pages(unsigned long npage);
+
+/* allocated page management */
+int page_mng_init(struct page_mng_t *mng, int gfp);
+void page_mng_add(struct page_mng_t *mng, struct page *newp, int order);
+void page_mng_freeall(struct page_mng_t *mng);
+
+/* zone */
+struct zone *get_zone(char *name);
+void print_zone_info(struct zone *zone, char *msg);
+
+
+/*
+ * initialize module and invoke test functions
+ */
+int init_module(void)
+{
+ int ret;
+
+ printk(DEF_PRT_LV "Test module was loaded. <mode %d>\n", mode);
+
+ if (mode != MODE_DEFALUT && mode != MODE_DOLASTALLOC) {
+ printk(KERN_ERR "invalid mode. <mode %d>\n", mode);
+ return 1;
+ }
+
+ /*
+ * making a memory pressure situation
+ */
+ printk(DEF_PRT_LV "init ...");
+ committed_pages = 0;
+ ret = page_mng_init(&low_pg, GFP_KERNEL);
+ if (ret == 1) {
+ printk(KERN_ERR "failed to init lowmem mng\n");
+ return 1;
+ }
+ ret = page_mng_init(&high_pg, GFP_HIGHUSER);
+ if (ret == 1) {
+ printk(KERN_ERR "failed to init highmem mng\n");
+ return 1;
+ }
+ printk(DEF_PRT_LV "done\n");
+
+ prepare_test_env();
+
+ /*
+ * concrete test
+ */
+ printk(DEF_PRT_LV "concrete test ...\n");
+ final_test(mode);
+ printk(DEF_PRT_LV "concrete test ...done.\n");
+
+ /*
+ * A non 0 return means init_module failed; module can't be loaded.
+ */
+ return 0;
+}
+
+
+/*
+ * destructor of module
+ */
+void cleanup_module(void)
+{
+ printk(DEF_PRT_LV "Unloading module ...\n");
+ page_mng_freeall(&low_pg);
+ page_mng_freeall(&high_pg);
+ vm_unacct_memory(committed_pages);
+}
+
+
+/*
+ * To prepare test environment, this function repeat to allocate pages
+ * in ZONE_HIGHMEM and ZONE_NORMAL until the number of free pages is
+ * pages_high in the zone.
+ */
+void prepare_test_env(void)
+{
+ struct zone *high_zone; /* high mem zone */
+ struct zone *normal_zone; /* normal zone */
+ int i;
+ int ret;
+ unsigned long target;
+
+ high_zone = get_zone("HighMem");
+ if (high_zone == NULL) {
+ printk(KERN_ERR "fail to get higmem zone\n");
+ return ;
+ }
+ for (i = 0; i < 100; i++) {
+ if (high_zone->free_pages <= high_zone->pages_high) {
+ printk(DEF_PRT_LV "already satisfied\n");
+ break;
+ }
+
+ spin_lock_irq(&high_zone->lru_lock);
+ target = high_zone->free_pages - high_zone->pages_high;
+ spin_unlock_irq(&high_zone->lru_lock);
+ print_zone_info(high_zone, "HIGH");
+ ret = commit_pages(target, &high_pg, GFP_HIGHUSER, "HighMem");
+ if (ret < 0) {
+ printk(KERN_ERR "error high %i\n", i);
+ goto error;
+ }
+
+ print_zone_info(high_zone, "HIGH");
+ /* printk(DEF_PRT_LV "%i\n", i); */
+ blk_congestion_wait(WRITE, HZ/2);
+ }
+
+ normal_zone = get_zone("Normal");
+ if (high_zone == NULL) {
+ printk(KERN_ERR "fail to get normal zone\n");
+ return ;
+ }
+ for (i = 0; i < 100; i++) {
+ if (normal_zone->free_pages <= normal_zone->pages_high) {
+ printk(DEF_PRT_LV "already satisfied\n");
+ break;
+ }
+
+ spin_lock_irq(&normal_zone->lru_lock);
+ target = normal_zone->free_pages - normal_zone->pages_high;
+ spin_unlock_irq(&normal_zone->lru_lock);
+ print_zone_info(normal_zone, "NORMAL");
+ ret = commit_pages(target, &low_pg, GFP_KERNEL, "Normal");
+ if (ret < 0) {
+ printk(KERN_ERR "error %i\n", i);
+ goto error;
+ }
+
+ print_zone_info(normal_zone, "NORMAL");
+ /* printk(DEF_PRT_LV "%i\n", i); */
+ blk_congestion_wait(WRITE, HZ/2);
+ }
+
+error:
+ return;
+}
+
+/*
+ * main test function
+ */
+void final_test(int mode)
+{
+ int ret;
+ unsigned long n;
+ unsigned long nbuffer;
+ unsigned long ncache;
+ unsigned long nmargin;
+#if MOD_MM
+ unsigned long nslabrec;
+ unsigned long nswap;
+#endif
+ struct sysinfo info;
+
+
+ for (nmargin = 1; nmargin < 100000; nmargin *= 10) {
+ si_meminfo(&info);
+ nbuffer = info.bufferram;
+ ncache = get_page_cache_size();
+#if MOD_MM
+ nslabrec = atomic_read(&slab_reclaim_pages);
+ nswap = nr_swap_pages;
+ n = ncache + nslabrec + nmargin + nswap;
+ printk(DEF_PRT_LV "<buf %lu><cache %lu><slab reclaim %lu><swap %lu> <+ %lu> <target %lu>\n",
+ nbuffer, ncache, nslabrec, nswap, nmargin, n);
+#else
+ n = ncache + nmargin;
+ printk(DEF_PRT_LV "<buf %lu> <cache %lu> <+ %lu> <target %lu>\n",
+ nbuffer, ncache, nmargin, n);
+#endif
+
+ ret = __vm_enough_memory(n, 0);
+ if (ret != 0) {
+ printk(KERN_ERR "Test was <PASSED>.\n");
+ break ;
+ }
+
+ /* unexpected result */
+ committed_pages += n;
+ if (mode == MODE_DOLASTALLOC) {
+ printk(KERN_ERR "Test MAY be <failed>.\n");
+ ret = alloc_last_pages(n);
+ if (ret == 0) {
+ printk(KERN_ERR "Test modeule has problem\n");
+ } else {
+ printk(KERN_ERR "Test SURELY was <FAILED>.\n");
+ break ;
+ }
+ } else {
+ printk(KERN_ERR "Test was <FAILED>\n");
+ }
+ }
+}
+
+int commit_pages(unsigned long target, struct page_mng_t *mng, int gfp,
+ char *msg)
+{
+ int ret;
+ unsigned long total;
+ unsigned long npage;
+
+ if (target == 0 || mng == NULL)
+ goto error;
+
+ /*
+ * try to commit anonymous pages
+ */
+ total = 0;
+ while (total < target) {
+ ret = try_to_commit_pages(0, gfp, mng, &npage);
+ if (ret == 1) {
+ printk(DEF_PRT_LV "%s test stoped. <target %lu>\n",
+ msg, target);
+ return 1;
+ } else if (ret == 0) {
+ total += npage;
+ /* printk(KERN_ERR "p"); */
+ } else if (ret == -1) {
+ printk(KERN_ERR "error %s overcommit.\n", msg);
+ goto error;
+ } else {
+ printk(KERN_ERR "error %s test environment.\n", msg);
+ goto error;
+ }
+ }
+ printk(DEF_PRT_LV "%s <target %lu>, ", msg, target);
+
+ return 0;
+
+ error:
+ return -1;
+}
+
+/*
+ * ret: 1; success (detected overcommit)
+ * 0: success
+ * -1: error (overcommiet was not detected)
+ */
+int try_to_commit_pages(int order, int gfp, struct page_mng_t *mng,
+ unsigned long *n_alloced)
+{
+ int ret;
+ long n_pages;
+ struct page *p;
+
+ n_pages = 1L << order;
+ /* printk(KERN_ERR "<order %d>, <pages %ld>\n,", order, n_pages); */
+
+ *n_alloced = 0;
+
+ ret = __vm_enough_memory(n_pages, 0);
+ if (ret != 0) {
+ printk(KERN_ERR "<order %d>, <pages %ld> ", order, n_pages);
+ printk(KERN_ERR "overcommit was detected.\n");
+ return 1;
+ }
+ committed_pages += n_pages;
+
+ p = alloc_pages(gfp, order);
+ if (p == NULL) {
+ /* error */
+ printk(KERN_ERR "<order %d>, <pages %ld> ", order, n_pages);
+ printk(KERN_ERR "allocation failed\n");
+ return -1;
+ } else {
+ page_mng_add(mng, p, order);
+ *n_alloced += n_pages;
+ /*
+ * printk(KERN_ERR "<order %d>, <pages %ld> <alloced %lu> ",
+ * order, n_pages, *n_alloced);
+ * printk(KERN_ERR " succeed\n");
+ */
+ return 0;
+ }
+}
+
+/*
+ * 0: success, 1: failure
+ */
+int alloc_last_pages(unsigned long npage)
+{
+ int i;
+ int ret;
+ void *mem;
+ struct mypage2_t {
+ struct mypage2_t *next;
+ } *endp, *listp, *p, *nextp;
+
+ /*
+ * allocation scenario 1
+ */
+ mem = vmalloc(npage * PAGE_SIZE);
+ if (mem != NULL) {
+ printk(KERN_ERR "TEST MODULE HAS PROBLEMS.\n");
+ vfree(mem);
+ return 0;
+ }
+
+ /*
+ * allocation scenario 2
+ */
+ for (listp = endp = NULL, i = 0; i < npage; i++) {
+ p = (struct mypage2_t *)vmalloc(PAGE_SIZE);
+ if (p == NULL) {
+ ret = 1;
+ goto release;
+ }
+
+ p->next = NULL;
+ if (listp == NULL)
+ listp = p;
+ else
+ endp->next = p;
+
+ endp = p;
+ }
+
+ printk(KERN_ERR "TEST MODULE HAS PROBLEMS.\n");
+ ret = 0;
+
+release:
+ for ( ; listp != NULL; listp = nextp) {
+ nextp = listp->next;
+ vfree(listp);
+ }
+
+ return ret;
+}
+
+/*
+ * ret: 1: error, 0: success
+ */
+int page_mng_init(struct page_mng_t *mng, int gfp)
+{
+ mng->listp = NULL;
+ if (gfp == GFP_HIGHUSER)
+ mng->zone = HIGH;
+ else if (gfp == GFP_KERNEL || gfp == GFP_USER)
+ mng->zone = NORMAL;
+ else
+ return 1;
+
+ return 0;
+}
+
+void page_mng_add(struct page_mng_t *mng, struct page *newp, int order)
+{
+ struct mypage_t *p;
+
+ if (mng->zone != NORMAL && mng->zone != HIGH) {
+ printk(KERN_ERR "PAGE_MNG: ERROR \n");
+ return ;
+ }
+
+ p = (struct mypage_t *)kmap_atomic(newp, KM_TYPE_NR);
+ p->order = order;
+ p->next_page = mng->listp;
+ mng->listp = newp;
+
+ kunmap_atomic((void *)p, KM_TYPE_NR);
+}
+
+void page_mng_freeall(struct page_mng_t *mng)
+{
+ int order;
+ struct page *next;
+ struct mypage_t *p;
+
+ for ( ; mng->listp != NULL; mng->listp = next) {
+ p = (struct mypage_t *)kmap_atomic(mng->listp, KM_TYPE_NR);
+ next = p->next_page;
+ order = p->order;
+ kunmap_atomic((void *)p, KM_TYPE_NR);
+ __free_pages(mng->listp, order);
+ }
+}
+
+struct zone *get_zone(char *name)
+{
+ struct zone *zone;
+ for_each_zone(zone) {
+ if (strcmp(zone->name, name) == 0)
+ return zone;
+ }
+
+ return NULL;
+}
+
+void print_zone_info(struct zone *zone, char *msg)
+{
+ unsigned long free_pages;
+ unsigned long nr_active;
+ unsigned long nr_inactive;
+ unsigned long present_pages;
+
+ spin_lock_irq(&zone->lru_lock);
+ free_pages = zone->free_pages;
+ nr_active = zone->nr_active;
+ nr_inactive = zone->nr_inactive;
+ present_pages = zone->present_pages;
+ spin_unlock_irq(&zone->lru_lock);
+
+ printk(DEF_PRT_LV "\n%s: <active %lu><inactive %lu><free %lu><sum %lu><present %lu>\n",
+ msg,
+ nr_active,
+ nr_inactive,
+ free_pages,
+ nr_active + nr_inactive + free_pages,
+ present_pages);
+}
next prev parent reply other threads:[~2006-04-05 23:52 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2006-04-05 23:47 [patch 1/3] mm: An enhancement of OVERCOMMIT_GUESS Hideo AOKI
2006-04-05 23:51 ` Hideo AOKI [this message]
2006-04-05 23:52 ` A patch for test_overcommit module Hideo AOKI
2006-04-06 0:45 ` [patch 1/3] mm: An enhancement of OVERCOMMIT_GUESS KAMEZAWA Hiroyuki
2006-04-06 0:45 ` KAMEZAWA Hiroyuki
2006-04-06 7:20 ` Hideo AOKI
2006-04-06 7:20 ` Hideo AOKI
2006-04-06 8:08 ` KAMEZAWA Hiroyuki
2006-04-06 8:08 ` KAMEZAWA Hiroyuki
2006-04-07 11:49 ` Hideo AOKI
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4434581E.4080505@redhat.com \
--to=haoki@redhat.com \
--cc=akpm@osdl.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.