From: Adrian Hunter <adrian.hunter@nokia.com>
To: Andrew Morton <akpm@linux-foundation.org>
Cc: "linux-mmc@vger.kernel.org" <linux-mmc@vger.kernel.org>
Subject: [PATCH] mmc_test: Fix large memory allocation
Date: Mon, 02 Aug 2010 11:17:11 +0300 [thread overview]
Message-ID: <4C567F07.2070809@nokia.com> (raw)
In-Reply-To: <20100726155234.3aca5a83.akpm@linux-foundation.org>
>From 665c12a94bd66a96adfad0b83deb6c6a72fb60e9 Mon Sep 17 00:00:00 2001
From: Adrian Hunter <adrian.hunter@nokia.com>
Date: Mon, 2 Aug 2010 11:15:17 +0300
Subject: [PATCH] mmc_test: Fix large memory allocation
- Fix mmc_test_alloc_mem.
- Use nr_free_buffer_pages() instead of sysinfo.totalram to
determine total lowmem pages.
- Change variables containing memory sizes to unsigned long.
- Limit maximum test area size to 128MiB because that is the
maximum MMC high capacity erase size (the maxmium SD allocation
unit size is just 4MiB)
Signed-off-by: Adrian Hunter <adrian.hunter@nokia.com>
---
drivers/mmc/card/mmc_test.c | 76 ++++++++++++++++++++++++++----------------
1 files changed, 47 insertions(+), 29 deletions(-)
diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c
index 197f387..5dd8576 100644
--- a/drivers/mmc/card/mmc_test.c
+++ b/drivers/mmc/card/mmc_test.c
@@ -16,6 +16,7 @@
#include <linux/slab.h>
#include <linux/scatterlist.h>
+#include <linux/swap.h> /* For nr_free_buffer_pages() */
#define RESULT_OK 0
#define RESULT_FAIL 1
@@ -25,6 +26,12 @@
#define BUFFER_ORDER 2
#define BUFFER_SIZE (PAGE_SIZE << BUFFER_ORDER)
+/*
+ * Limit the test area size to the maximum MMC HC erase group size. Note that
+ * the maximum SD allocation unit size is just 4MiB.
+ */
+#define TEST_AREA_MAX_SIZE (128 * 1024 * 1024)
+
/**
* struct mmc_test_pages - pages allocated by 'alloc_pages()'.
* @page: first page in the allocation
@@ -47,8 +54,8 @@ struct mmc_test_mem {
/**
* struct mmc_test_area - information for performance tests.
- * @dev_addr: address on card at which to do performance tests
* @max_sz: test area size (in bytes)
+ * @dev_addr: address on card at which to do performance tests
* @max_segs: maximum segments in scatterlist @sg
* @blocks: number of (512 byte) blocks currently mapped by @sg
* @sg_len: length of currently mapped scatterlist @sg
@@ -56,8 +63,8 @@ struct mmc_test_mem {
* @sg: scatterlist
*/
struct mmc_test_area {
+ unsigned long max_sz;
unsigned int dev_addr;
- unsigned int max_sz;
unsigned int max_segs;
unsigned int blocks;
unsigned int sg_len;
@@ -238,20 +245,19 @@ static void mmc_test_free_mem(struct mmc_test_mem *mem)
/*
* Allocate a lot of memory, preferrably max_sz but at least min_sz. In case
- * there isn't much memory do not exceed 1/16th total RAM.
+ * there isn't much memory do not exceed 1/16th total lowmem pages.
*/
-static struct mmc_test_mem *mmc_test_alloc_mem(unsigned int min_sz,
- unsigned int max_sz)
+static struct mmc_test_mem *mmc_test_alloc_mem(unsigned long min_sz,
+ unsigned long max_sz)
{
- unsigned int max_page_cnt = DIV_ROUND_UP(max_sz, PAGE_SIZE);
- unsigned int min_page_cnt = DIV_ROUND_UP(min_sz, PAGE_SIZE);
- unsigned int page_cnt = 0;
+ unsigned long max_page_cnt = DIV_ROUND_UP(max_sz, PAGE_SIZE);
+ unsigned long min_page_cnt = DIV_ROUND_UP(min_sz, PAGE_SIZE);
+ unsigned long page_cnt = 0;
+ unsigned long limit = nr_free_buffer_pages() >> 4;
struct mmc_test_mem *mem;
- struct sysinfo si;
- si_meminfo(&si);
- if (max_page_cnt > si.totalram >> 4)
- max_page_cnt = si.totalram >> 4;
+ if (max_page_cnt > limit)
+ max_page_cnt = limit;
if (max_page_cnt < min_page_cnt)
max_page_cnt = min_page_cnt;
@@ -270,7 +276,7 @@ static struct mmc_test_mem *mmc_test_alloc_mem(unsigned int min_sz,
gfp_t flags = GFP_KERNEL | GFP_DMA | __GFP_NOWARN |
__GFP_NORETRY;
- order = get_order(page_cnt << PAGE_SHIFT);
+ order = get_order(max_page_cnt << PAGE_SHIFT);
while (1) {
page = alloc_pages(flags, order);
if (page || !order)
@@ -285,8 +291,10 @@ static struct mmc_test_mem *mmc_test_alloc_mem(unsigned int min_sz,
mem->arr[mem->cnt].page = page;
mem->arr[mem->cnt].order = order;
mem->cnt += 1;
- max_page_cnt -= 1 << order;
- page_cnt += 1 << order;
+ if (max_page_cnt <= (1UL << order))
+ break;
+ max_page_cnt -= 1UL << order;
+ page_cnt += 1UL << order;
}
return mem;
@@ -300,7 +308,7 @@ out_free:
* Map memory into a scatterlist. Optionally allow the same memory to be
* mapped more than once.
*/
-static int mmc_test_map_sg(struct mmc_test_mem *mem, unsigned int sz,
+static int mmc_test_map_sg(struct mmc_test_mem *mem, unsigned long sz,
struct scatterlist *sglist, int repeat,
unsigned int max_segs, unsigned int *sg_len)
{
@@ -312,7 +320,7 @@ static int mmc_test_map_sg(struct mmc_test_mem *mem, unsigned int sz,
*sg_len = 0;
do {
for (i = 0; i < mem->cnt; i++) {
- unsigned int len = PAGE_SIZE << mem->arr[i].order;
+ unsigned long len = PAGE_SIZE << mem->arr[i].order;
if (sz < len)
len = sz;
@@ -344,13 +352,14 @@ static int mmc_test_map_sg(struct mmc_test_mem *mem, unsigned int sz,
* same memory to be mapped more than once.
*/
static int mmc_test_map_sg_max_scatter(struct mmc_test_mem *mem,
- unsigned int sz,
+ unsigned long sz,
struct scatterlist *sglist,
unsigned int max_segs,
unsigned int *sg_len)
{
struct scatterlist *sg = NULL;
- unsigned int i = mem->cnt, cnt, len;
+ unsigned int i = mem->cnt, cnt;
+ unsigned long len;
void *base, *addr, *last_addr = NULL;
sg_init_table(sglist, max_segs);
@@ -1202,7 +1211,7 @@ static int mmc_test_no_highmem(struct mmc_test_card *test)
/*
* Map sz bytes so that it can be transferred.
*/
-static int mmc_test_area_map(struct mmc_test_card *test, unsigned int sz,
+static int mmc_test_area_map(struct mmc_test_card *test, unsigned long sz,
int max_scatter)
{
struct mmc_test_area *t = &test->area;
@@ -1233,7 +1242,7 @@ static int mmc_test_area_transfer(struct mmc_test_card *test,
/*
* Map and transfer bytes.
*/
-static int mmc_test_area_io(struct mmc_test_card *test, unsigned int sz,
+static int mmc_test_area_io(struct mmc_test_card *test, unsigned long sz,
unsigned int dev_addr, int write, int max_scatter,
int timed)
{
@@ -1308,19 +1317,22 @@ static int mmc_test_area_cleanup(struct mmc_test_card *test)
static int mmc_test_area_init(struct mmc_test_card *test, int erase, int fill)
{
struct mmc_test_area *t = &test->area;
- unsigned int min_sz = 64 * 1024;
+ unsigned long min_sz = 64 * 1024;
int ret;
ret = mmc_test_set_blksize(test, 512);
if (ret)
return ret;
+ if (test->card->pref_erase > TEST_AREA_MAX_SIZE >> 9)
+ t->max_sz = TEST_AREA_MAX_SIZE;
+ else
+ t->max_sz = (unsigned long)test->card->pref_erase << 9;
/*
* Try to allocate enough memory for the whole area. Less is OK
* because the same memory can be mapped into the scatterlist more than
* once.
*/
- t->max_sz = test->card->pref_erase << 9;
t->mem = mmc_test_alloc_mem(min_sz, t->max_sz);
if (!t->mem)
return -ENOMEM;
@@ -1430,7 +1442,8 @@ static int mmc_test_best_write_perf_max_scatter(struct mmc_test_card *test)
*/
static int mmc_test_profile_read_perf(struct mmc_test_card *test)
{
- unsigned int sz, dev_addr;
+ unsigned long sz;
+ unsigned int dev_addr;
int ret;
for (sz = 512; sz < test->area.max_sz; sz <<= 1) {
@@ -1448,7 +1461,8 @@ static int mmc_test_profile_read_perf(struct mmc_test_card *test)
*/
static int mmc_test_profile_write_perf(struct mmc_test_card *test)
{
- unsigned int sz, dev_addr;
+ unsigned long sz;
+ unsigned int dev_addr;
int ret;
ret = mmc_test_area_erase(test);
@@ -1472,7 +1486,8 @@ static int mmc_test_profile_write_perf(struct mmc_test_card *test)
*/
static int mmc_test_profile_trim_perf(struct mmc_test_card *test)
{
- unsigned int sz, dev_addr;
+ unsigned long sz;
+ unsigned int dev_addr;
struct timespec ts1, ts2;
int ret;
@@ -1506,7 +1521,8 @@ static int mmc_test_profile_trim_perf(struct mmc_test_card *test)
*/
static int mmc_test_profile_seq_read_perf(struct mmc_test_card *test)
{
- unsigned int sz, dev_addr, i, cnt;
+ unsigned long sz;
+ unsigned int dev_addr, i, cnt;
struct timespec ts1, ts2;
int ret;
@@ -1531,7 +1547,8 @@ static int mmc_test_profile_seq_read_perf(struct mmc_test_card *test)
*/
static int mmc_test_profile_seq_write_perf(struct mmc_test_card *test)
{
- unsigned int sz, dev_addr, i, cnt;
+ unsigned long sz;
+ unsigned int dev_addr, i, cnt;
struct timespec ts1, ts2;
int ret;
@@ -1559,7 +1576,8 @@ static int mmc_test_profile_seq_write_perf(struct mmc_test_card *test)
*/
static int mmc_test_profile_seq_trim_perf(struct mmc_test_card *test)
{
- unsigned int sz, dev_addr, i, cnt;
+ unsigned long sz;
+ unsigned int dev_addr, i, cnt;
struct timespec ts1, ts2;
int ret;
--
1.6.3.3
prev parent reply other threads:[~2010-08-02 8:17 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-07-23 9:25 [PATCH] mmc_test: Add performance tests Adrian Hunter
2010-07-26 22:52 ` Andrew Morton
2010-08-02 8:17 ` Adrian Hunter [this message]
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=4C567F07.2070809@nokia.com \
--to=adrian.hunter@nokia.com \
--cc=akpm@linux-foundation.org \
--cc=linux-mmc@vger.kernel.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.