improve cache footprint of MARS

This commit is contained in:
Thomas Schoebel-Theuer 2012-02-20 10:34:42 +01:00 committed by Thomas Schoebel-Theuer
parent 2e923f145e
commit d5cb69b391
5 changed files with 166 additions and 5 deletions

17
Kconfig
View File

@ -99,6 +99,23 @@ config MARS_LOADAVG_LIMIT
---help---
Normally ON.
config MARS_LINEAR_CACHE_SIZE
int "cache size for linear scans of logfiles (in MB)"
depends on MARS
default 64
---help---
Setting this to high numbers (or disabling by setting to 0)
may disturb the application performance, because MARS will
pollute the page cache with pages from the MARS logfiles.
Setting this to low numbers will prevent such a pollution,
at the cost of (sometimes) more IO operations.
EXCEPTION: when you run MARS on a standalone storage server
(e.g. exporting devices via iSCSI), you should use high numbers
here or even disable this feature. THEN (and ONLY THEN)
you want MARS to use all the memory for its own caching,
since there is no other application competing for main memory.
In unsure, take the default of 64.
#config MARS_HUNG
# bool "hangup on kernel stacktrace (EXPERIMENTAL!!!)"
# depends on MARS && MARS_BIGMODULE!=m

View File

@ -669,6 +669,50 @@ void fd_uninstall(unsigned int fd)
EXPORT_SYMBOL(fd_uninstall);
#endif
static
void _mapfree_pages(struct aio_output *output, bool force)
{
struct aio_brick *brick = output->brick;
struct address_space *mapping;
pgoff_t start;
pgoff_t end;
pgoff_t gap;
if (brick->linear_cache_size <= 0)
goto done;
if (!force && ++output->rounds < brick->linear_cache_rounds)
goto done;
if (unlikely(!output->filp || !(mapping = output->filp->f_mapping)))
goto done;
if (unlikely(brick->linear_cache_rounds <= 0))
brick->linear_cache_rounds = 1024;
if (force) {
start = 0;
end = -1;
} else {
gap = brick->linear_cache_size * (1024 * 1024 / PAGE_SIZE);
end = output->min_pos / PAGE_SIZE - gap;
if (end <= 0)
goto done;
start = end - gap * 4;
if (start < 0)
start = 0;
}
output->min_pos = 0;
output->rounds = 0;
atomic_inc(&output->total_mapfree_count);
invalidate_mapping_pages(mapping, start, end);
done:;
}
static int aio_submit_thread(void *data)
{
struct aio_threadinfo *tinfo = data;
@ -718,6 +762,8 @@ static int aio_submit_thread(void *data)
int sleeptime;
int err;
_mapfree_pages(output, false);
wait_event_interruptible_timeout(
tinfo->event,
kthread_should_stop() ||
@ -729,8 +775,14 @@ static int aio_submit_thread(void *data)
continue;
}
// check for reads exactly at EOF (special case)
mref = mref_a->object;
err = -EINVAL;
CHECK_PTR(mref, err);
if (!output->min_pos || mref->ref_pos < output->min_pos)
output->min_pos = mref->ref_pos;
// check for reads exactly at EOF (special case)
if (mref->ref_pos == mref->ref_total_size &&
!mref->ref_rw &&
mref->ref_timeout > 0) {
@ -786,6 +838,7 @@ static int aio_submit_thread(void *data)
sleeptime += 1000 / HZ;
}
}
err:
if (unlikely(err < 0)) {
_complete(output, mref, err);
}
@ -856,7 +909,8 @@ char *aio_statistics(struct aio_brick *brick, int verbose)
"delays = %d "
"msleeps = %d "
"fdsyncs = %d "
"fdsync_waits = %d | "
"fdsync_waits = %d "
"map_free = %d | "
"flying reads = %d "
"writes = %d "
"allocs = %d "
@ -871,6 +925,7 @@ char *aio_statistics(struct aio_brick *brick, int verbose)
atomic_read(&output->total_msleep_count),
atomic_read(&output->total_fdsync_count),
atomic_read(&output->total_fdsync_wait_count),
atomic_read(&output->total_mapfree_count),
atomic_read(&output->read_count),
atomic_read(&output->write_count),
atomic_read(&output->alloc_count),
@ -900,6 +955,7 @@ void aio_reset_statistics(struct aio_brick *brick)
atomic_set(&output->total_msleep_count, 0);
atomic_set(&output->total_fdsync_count, 0);
atomic_set(&output->total_fdsync_wait_count, 0);
atomic_set(&output->total_mapfree_count, 0);
for (i = 0; i < 3; i++) {
struct aio_threadinfo *tinfo = &output->tinfo[i];
atomic_set(&tinfo->total_enqueue_count, 0);
@ -1008,6 +1064,7 @@ cleanup:
if (brick->power.led_off) {
if (output->filp) {
_mapfree_pages(output, true);
filp_close(output->filp, NULL);
output->filp = NULL;
}

View File

@ -34,6 +34,8 @@ struct aio_brick {
MARS_BRICK(aio);
// parameters
int readahead;
int linear_cache_size; // in MB
int linear_cache_rounds;
bool o_direct;
bool o_fdsync;
bool wait_during_fdsync;
@ -59,6 +61,8 @@ struct aio_output {
// private
struct file *filp;
int fd; // FIXME: remove this!
int rounds;
loff_t min_pos;
struct aio_threadinfo tinfo[3];
aio_context_t ctxp;
wait_queue_head_t fdsync_event;
@ -71,6 +75,7 @@ struct aio_output {
atomic_t total_msleep_count;
atomic_t total_fdsync_count;
atomic_t total_fdsync_wait_count;
atomic_t total_mapfree_count;
atomic_t read_count;
atomic_t write_count;
atomic_t alloc_count;

View File

@ -13,6 +13,9 @@
#define _STRATEGY
#include "mars.h"
#include "mars_bio.h"
#include "mars_aio.h"
#include "mars_sio.h"
///////////////////////// own type definitions ////////////////////////
@ -202,6 +205,63 @@ void _clean_list(struct server_brick *brick, struct list_head *start)
}
}
static
int _set_server_sio_params(struct mars_brick *_brick, void *private)
{
struct sio_brick *sio_brick = (void*)_brick;
if (_brick->type != (void*)_sio_brick_type) {
MARS_ERR("bad brick type\n");
return -EINVAL;
}
sio_brick->o_direct = false;
sio_brick->o_fdsync = false;
MARS_INF("name = '%s' path = '%s'\n", _brick->brick_name, _brick->brick_path);
return 1;
}
static
int _set_server_aio_params(struct mars_brick *_brick, void *private)
{
struct aio_brick *aio_brick = (void*)_brick;
if (_brick->type == (void*)_sio_brick_type) {
return _set_server_sio_params(_brick, private);
}
if (_brick->type != (void*)_aio_brick_type) {
MARS_ERR("bad brick type\n");
return -EINVAL;
}
aio_brick->readahead = 1;
aio_brick->linear_cache_size = CONFIG_MARS_LINEAR_CACHE_SIZE;
aio_brick->o_direct = false;
aio_brick->o_fdsync = false;
aio_brick->wait_during_fdsync = false;
MARS_INF("name = '%s' path = '%s'\n", _brick->brick_name, _brick->brick_path);
return 1;
}
static
int _set_server_bio_params(struct mars_brick *_brick, void *private)
{
struct bio_brick *bio_brick;
if (_brick->type == (void*)_aio_brick_type) {
return _set_server_aio_params(_brick, private);
}
if (_brick->type == (void*)_sio_brick_type) {
return _set_server_sio_params(_brick, private);
}
if (_brick->type != (void*)_bio_brick_type) {
MARS_ERR("bad brick type\n");
return -EINVAL;
}
bio_brick = (void*)_brick;
bio_brick->ra_pages = 1;
bio_brick->do_noidle = true;
bio_brick->do_sync = true;
bio_brick->do_unplug = true;
MARS_INF("name = '%s' path = '%s'\n", _brick->brick_name, _brick->brick_path);
return 1;
}
static
struct task_struct *_grab_handler(struct server_brick *brick)
{
@ -299,7 +359,7 @@ int handler_thread(void *data)
mars_global,
NULL,
true,
NULL,
_set_server_bio_params,
NULL,
10 * HZ,
path,

View File

@ -247,6 +247,18 @@ int _set_aio_params(struct mars_brick *_brick, void *private)
return 1;
}
static
int _set_aio_params_nocache(struct mars_brick *_brick, void *private)
{
int res;
res = _set_aio_params(_brick, private);
if (_brick->type == (void*)&aio_brick_type) {
struct aio_brick *aio_brick = (void*)_brick;
aio_brick->linear_cache_size = CONFIG_MARS_LINEAR_CACHE_SIZE;
}
return res;
}
static
int _set_bio_params(struct mars_brick *_brick, void *private)
{
@ -274,6 +286,16 @@ int _set_bio_params(struct mars_brick *_brick, void *private)
}
static
int _set_bio_params_nocache(struct mars_brick *_brick, void *private)
{
if (_brick->type == (void*)&aio_brick_type) {
return _set_aio_params_nocache(_brick, private);
}
return _set_bio_params(_brick, private);
}
static
int _set_if_params(struct mars_brick *_brick, void *private)
{
@ -655,7 +677,7 @@ int __make_copy(
make_brick_all(global,
NULL,
false,
_set_bio_params,
_set_bio_params_nocache,
NULL,
10 * HZ,
NULL,
@ -1690,7 +1712,7 @@ int make_log_init(void *buf, struct mars_dent *dent)
make_brick_all(global,
aio_dent,
false,
_set_aio_params,
_set_aio_params_nocache,
NULL,
10 * HZ,
aio_path,