linux-mm.kvack.org archive mirror
 help / color / mirror / Atom feed
* MM, TLB and speeding up suspend to disk for 2.4
@ 2005-02-07 16:30 Stefan Voelkel
  0 siblings, 0 replies; only message in thread
From: Stefan Voelkel @ 2005-02-07 16:30 UTC (permalink / raw)
  To: Linux-mm

[-- Attachment #1: Type: text/plain, Size: 1507 bytes --]

Hello,

since neither Understanding the Linux VMM nor the kernelnewbies ML could
help me, I am takin the problem here:

I have a IBM Thinkpad 600X and use the suspend to disk feature (called
hibernation) when carring the notebook around, but writing ~600MB to the
disk takes a while.

After finding out, that the bios does only write used pages to disk, I
wrote a small userspace programm called mhog (see attached mhog.c), that
allocates roughly as many pages as used by the page cache. mhog retrieves
the number of pages to allocate from /proc/meminfo.

This works find, but does take a while, so I wrote a kernel module
(see attached nocache.c) to do the same. During module initilization I
simply loop around a get_free_page(GFP_NIO) to get all pages that can be
discarded, and upon the first failure I free all reserved pages again and
return -ENOMEM.

The kernel module does not speed up hibernation (pages are freed just
fine), but something must be diffrent between userspace and kernelspace
page allocation. I suspect the TLB, but did not find a hint on which of the
many tlb flushing calls to use.

So what am I missing?

thanks in advance
        Stefan

-- 
Stefan Volkel                            stefan.voelkel@millenux.com
Millenux GmbH                              mobile: +49.170.79177.17
Lilienthalstrasse 2                          phone: +49.711.88770.300
70825 Stuttgart-Korntal                       fax: +49.711.88770.349
     -= linux without limits -=- http://linux.zSeries.org/ =-

[-- Attachment #2: nocache.c --]
[-- Type: application/octet-stream, Size: 1530 bytes --]

/*
	nocache.c (c) 2005 Stefan.Voelkel@millenux.com

	licensed under the GPL v2.
*/

#include <linux/module.h>
#include <linux/version.h>
#include <linux/mm.h>
#include <asm/pgalloc.h>

struct nc_pages;

#define NC_PAGES ((PAGE_SIZE - sizeof(struct nc_pages *) - sizeof(unsigned int))/ sizeof(unsigned long))

struct nc_pages {
	struct nc_pages *next;
	unsigned int order;
	unsigned long pages[NC_PAGES];
};

static struct nc_pages *pa = 0;

static inline void nc_alloc_pages(void) {
	struct nc_pages *list;
	unsigned long page;

	unsigned long index = 0;
	unsigned int order = MAX_ORDER - 1;

	while (order < MAX_ORDER) {
		page = __get_free_pages(GFP_NOIO, order);
		if (!page) {
			--order;
			continue;
		}
		
		if (!pa || index >= NC_PAGES || order != pa->order) {
			
			list = (struct nc_pages *) get_zeroed_page(GFP_NOIO);

			if (!list) {
				free_pages(page, order);
				break;
			}

			list->next = pa;
			pa = list;
			pa->order = order;
			index = 0;
		}

		pa->pages[index] = page;
		++index;
	}
}

static inline void nc_free_pages(void) {
	struct nc_pages *save;
	unsigned long index;

	while(pa) {
		for (index = 0; index < NC_PAGES && pa->pages[index]; ++index)
			free_pages(pa->pages[index], pa->order);
		
		save = pa;
		pa = pa->next;

		free_page((unsigned long) save);
	}
}

int init_module(void)
{
	nc_alloc_pages();
	nc_free_pages();

	flush_tlb();

	return -ENOMEM;
}

void cleanup_module(void)
{
}

MODULE_AUTHOR("Stefan Völkel <stefan.voelkel@millenux.com>");
MODULE_LICENSE("GPL");

EXPORT_NO_SYMBOLS;

[-- Attachment #3: mhog.c --]
[-- Type: application/octet-stream, Size: 1346 bytes --]

/*
 * mhog.c (c) Stefan Völkel <stefan.voelkel@millenux.com>
 *
 * LICENSED UNDER THE GPL v2
 *
 */

#include <string.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

#define PAGE_BIT 12
#define PAGE_SIZE (1 << PAGE_BIT)

int main(void)
{
	FILE *f;
	long buffers, cached, free, memory;
	int ret;

	/* get free memory, buffers and cached from /proc to calculate the
	 * number of pages we need to malloc() in order to invalidate the
	 * cache */
	f = fopen("/proc/meminfo", "r");
	if (!f) {
		printf("E: fopen() %d:'%s'\n", errno, strerror(errno));
		exit(errno);
	}

	ret = fscanf(f, "%*s %*s %*s %*s %*s %*s\n");
	if (ret) {
		printf("E: sscanf() (1) %d:'%s'\n", errno, strerror(errno));
		exit(errno);
	}

	ret = fscanf(f, "%*s %*ld %*ld %ld %*ld %ld %ld\n", &free, 
			&buffers, &cached);
	if (3 != ret) {
		printf("E: %d = sscanf() (2) %d:'%s'\n", ret, errno,
				strerror(errno));
		exit(errno);
	}

	fclose(f);

	memory = buffers + cached + free;
	memory >>= PAGE_BIT;

	printf("Need to flush %ld pages\n", memory);

	/* we need to write at least one byte to each page to take it away from
	 * the system */
	while (memory--) {
		char *c = malloc(PAGE_SIZE);
		*c = '0';

		printf("%d left \r", memory);
	}

	return 0;
}

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2005-02-07 16:30 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2005-02-07 16:30 MM, TLB and speeding up suspend to disk for 2.4 Stefan Voelkel

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox