2009-04-14 20:21:05 +00:00
|
|
|
#include "../check_includes.h"
|
2007-03-10 01:29:43 +00:00
|
|
|
|
2007-06-11 21:36:57 +00:00
|
|
|
#include <stasis/transactional.h>
|
|
|
|
#include <stasis/replacementPolicy.h>
|
|
|
|
#include <stasis/doubleLinkedList.h>
|
2009-04-14 20:21:05 +00:00
|
|
|
|
2007-03-10 01:29:43 +00:00
|
|
|
#include <assert.h>
|
|
|
|
|
|
|
|
#define LOG_NAME "check_replacementPolicy.log"
|
|
|
|
|
|
|
|
#define OBJECT_COUNT 1000
|
|
|
|
#define OP_COUNT 10000000
|
|
|
|
|
2010-03-31 22:37:42 +00:00
|
|
|
#define LONG_COUNT 100000000UL
|
|
|
|
#define SHORT_COUNT 10000000UL
|
|
|
|
|
|
|
|
#define THREAD_COUNT 10
|
|
|
|
|
2007-03-11 07:53:32 +00:00
|
|
|
typedef struct LL_ENTRY(node_t) node_t;
|
|
|
|
|
2009-04-14 20:21:05 +00:00
|
|
|
typedef struct tracker {
|
2010-03-31 22:37:42 +00:00
|
|
|
pageid_t val; // Must be pageid_t. Otherwise, there will be mismatches inside of concurrentWrapper's hash.
|
2007-03-11 07:53:32 +00:00
|
|
|
intptr_t key;
|
2007-03-10 01:29:43 +00:00
|
|
|
int inCache;
|
2010-03-31 22:37:42 +00:00
|
|
|
pthread_mutex_t mut;
|
2007-03-10 01:29:43 +00:00
|
|
|
} tracker;
|
2010-03-31 22:37:42 +00:00
|
|
|
static pthread_mutex_t cached_count_mutex = PTHREAD_MUTEX_INITIALIZER;
|
|
|
|
static int threaded = 0;
|
|
|
|
static int cachedCount = 0;
|
2007-03-11 07:53:32 +00:00
|
|
|
|
2009-04-14 20:21:05 +00:00
|
|
|
static node_t * getKey(void * page, void * ignore) {
|
2007-03-11 07:53:32 +00:00
|
|
|
tracker * p = page;
|
|
|
|
return (node_t*)p->key;
|
|
|
|
}
|
2009-04-14 20:21:05 +00:00
|
|
|
static void setKey(void * page, node_t * n, void * ignore) {
|
2007-03-11 07:53:32 +00:00
|
|
|
tracker * p = page;
|
|
|
|
p->key = (intptr_t) n;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-03-31 22:37:42 +00:00
|
|
|
tracker * t;
|
|
|
|
void randomSetup() {
|
2007-03-10 01:29:43 +00:00
|
|
|
time_t seed = time(0);
|
|
|
|
printf("\nSeed = %ld\n", seed);
|
|
|
|
srandom(seed);
|
|
|
|
|
2010-03-31 22:37:42 +00:00
|
|
|
cachedCount = 0;
|
2009-04-14 20:21:05 +00:00
|
|
|
|
2010-03-31 22:37:42 +00:00
|
|
|
t = calloc(OBJECT_COUNT, sizeof(tracker));
|
2009-04-14 20:21:05 +00:00
|
|
|
for(int i = 0; i < OBJECT_COUNT; i++) {
|
2007-03-13 09:56:39 +00:00
|
|
|
t[i].val = i;
|
2007-03-10 01:29:43 +00:00
|
|
|
}
|
2010-03-31 22:37:42 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
void randomTeardown() {
|
|
|
|
free(t);
|
|
|
|
}
|
|
|
|
|
|
|
|
void randomTest(replacementPolicy * lru, unsigned long count) {
|
|
|
|
|
|
|
|
unsigned long progress_indicator = count / 10;
|
|
|
|
|
|
|
|
for(unsigned long j = 0; j < count /*100000000UL*/; j++) {
|
|
|
|
if(0 == (j % progress_indicator)) { printf("."); fflush(stdout); }
|
2007-03-10 01:29:43 +00:00
|
|
|
int op = myrandom(100);
|
|
|
|
|
|
|
|
int i = myrandom(OBJECT_COUNT);
|
2009-04-14 20:21:05 +00:00
|
|
|
if(op < 10) {
|
2007-03-10 01:29:43 +00:00
|
|
|
// TOGGLE IN CACHE
|
2010-03-31 22:37:42 +00:00
|
|
|
pthread_mutex_lock(&t[i].mut);
|
2009-04-14 20:21:05 +00:00
|
|
|
if(!t[i].inCache) {
|
2010-03-31 22:37:42 +00:00
|
|
|
lru->insert(lru, &t[i]);
|
|
|
|
t[i].inCache = 1;
|
|
|
|
pthread_mutex_lock(&cached_count_mutex);
|
|
|
|
cachedCount ++;
|
|
|
|
pthread_mutex_unlock(&cached_count_mutex);
|
2009-04-14 20:21:05 +00:00
|
|
|
} else {
|
2010-03-31 22:37:42 +00:00
|
|
|
void * v = lru->remove(lru, &t[i]);
|
|
|
|
assert(v == &t[i]);
|
|
|
|
t[i].inCache = 0;
|
|
|
|
pthread_mutex_lock(&cached_count_mutex);
|
|
|
|
cachedCount --;
|
|
|
|
pthread_mutex_unlock(&cached_count_mutex);
|
2007-03-10 01:29:43 +00:00
|
|
|
}
|
2010-03-31 22:37:42 +00:00
|
|
|
pthread_mutex_unlock(&t[i].mut);
|
2009-04-14 20:21:05 +00:00
|
|
|
} else if(op < 30) {
|
2007-03-10 01:29:43 +00:00
|
|
|
// Get stale + remove
|
|
|
|
tracker * tr = lru->getStale(lru);
|
2009-04-14 20:21:05 +00:00
|
|
|
if( tr ) {
|
2010-03-31 22:37:42 +00:00
|
|
|
pthread_mutex_lock(&t[tr->val].mut);
|
|
|
|
if(tr->inCache) {
|
|
|
|
assert(tr == &t[tr->val]);
|
|
|
|
tr = lru->remove(lru, tr);
|
|
|
|
assert(tr == &t[tr->val]);
|
|
|
|
tr->inCache = 0;
|
|
|
|
pthread_mutex_lock(&cached_count_mutex);
|
|
|
|
if(!threaded) assert(cachedCount != 0);
|
|
|
|
cachedCount --;
|
|
|
|
pthread_mutex_unlock(&cached_count_mutex);
|
|
|
|
}
|
|
|
|
pthread_mutex_unlock(&t[tr->val].mut);
|
2009-04-14 20:21:05 +00:00
|
|
|
} else {
|
2010-03-31 22:37:42 +00:00
|
|
|
if(!threaded) {
|
|
|
|
assert(cachedCount == 0);
|
|
|
|
}
|
2007-03-10 01:29:43 +00:00
|
|
|
}
|
2009-04-14 20:21:05 +00:00
|
|
|
} else if(op < 50) {
|
2007-03-10 01:29:43 +00:00
|
|
|
// Get stale
|
|
|
|
tracker * tr = lru->getStale(lru);
|
2009-04-14 20:21:05 +00:00
|
|
|
if(tr) {
|
2010-03-31 22:37:42 +00:00
|
|
|
pthread_mutex_lock(&t[tr->val].mut);
|
|
|
|
if(!threaded) assert(tr->inCache);
|
|
|
|
assert(tr == &t[tr->val]);
|
|
|
|
if(!threaded) assert(cachedCount != 0);
|
|
|
|
pthread_mutex_unlock(&t[tr->val].mut);
|
2009-04-14 20:21:05 +00:00
|
|
|
} else {
|
2010-03-31 22:37:42 +00:00
|
|
|
if(!threaded) assert(cachedCount == 0);
|
2007-03-10 01:29:43 +00:00
|
|
|
}
|
2009-04-14 20:21:05 +00:00
|
|
|
} else {
|
2007-03-10 01:29:43 +00:00
|
|
|
// Hit
|
2010-03-31 22:37:42 +00:00
|
|
|
pthread_mutex_lock(&t[i].mut);
|
2007-03-11 07:53:32 +00:00
|
|
|
if(t[i].inCache) lru->hit(lru, &t[i]);
|
2010-03-31 22:37:42 +00:00
|
|
|
pthread_mutex_unlock(&t[i].mut);
|
2007-03-10 01:29:43 +00:00
|
|
|
}
|
|
|
|
}
|
2007-03-11 07:53:32 +00:00
|
|
|
}
|
|
|
|
START_TEST(replacementPolicyLRURandomTest) {
|
|
|
|
replacementPolicy * lru = lruFastInit(getKey, setKey, 0);
|
2010-03-31 22:37:42 +00:00
|
|
|
threaded = 0;
|
|
|
|
randomSetup();
|
|
|
|
randomTest(lru, LONG_COUNT);
|
|
|
|
lru->deinit(lru);
|
|
|
|
randomTeardown();
|
2007-03-11 07:53:32 +00:00
|
|
|
} END_TEST
|
|
|
|
START_TEST(replacementPolicyLRUFastRandomTest) {
|
|
|
|
replacementPolicy * lru = lruFastInit(getKey, setKey, 0);
|
2010-03-31 22:37:42 +00:00
|
|
|
threaded = 0;
|
|
|
|
randomSetup();
|
|
|
|
randomTest(lru, LONG_COUNT);
|
|
|
|
lru->deinit(lru);
|
|
|
|
randomTeardown();
|
|
|
|
} END_TEST
|
|
|
|
START_TEST(replacementPolicyThreadsafeRandomTest) {
|
|
|
|
replacementPolicy * lru = lruFastInit(getKey, setKey, 0);
|
|
|
|
replacementPolicy * tsLru = replacementPolicyThreadsafeWrapperInit(lru);
|
|
|
|
threaded = 0;
|
|
|
|
randomSetup();
|
|
|
|
randomTest(tsLru, LONG_COUNT);
|
|
|
|
tsLru->deinit(tsLru);
|
|
|
|
randomTeardown();
|
|
|
|
|
|
|
|
} END_TEST
|
|
|
|
START_TEST(replacementPolicyConcurrentRandomTest) {
|
|
|
|
int LRU_COUNT = OBJECT_COUNT / 51;
|
|
|
|
replacementPolicy * lru[LRU_COUNT];
|
|
|
|
for(int i = 0; i < LRU_COUNT; i++) {
|
|
|
|
lru[i] = lruFastInit(getKey, setKey, 0);
|
|
|
|
}
|
|
|
|
threaded = 0;
|
|
|
|
replacementPolicy * cwLru = replacementPolicyConcurrentWrapperInit(lru, LRU_COUNT);
|
|
|
|
randomSetup();
|
|
|
|
randomTest(cwLru, SHORT_COUNT);
|
|
|
|
cwLru->deinit(cwLru);
|
|
|
|
randomTeardown();
|
|
|
|
} END_TEST
|
|
|
|
|
|
|
|
replacementPolicy * worker_lru;
|
|
|
|
unsigned long worker_count;
|
|
|
|
void * randomTestWorker(void * arg) {
|
|
|
|
randomTest(worker_lru, worker_count);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
START_TEST(replacementPolicyThreadsafeThreadTest) {
|
|
|
|
replacementPolicy * lru = lruFastInit(getKey, setKey, 0);
|
|
|
|
replacementPolicy * tsLru = replacementPolicyThreadsafeWrapperInit(lru);
|
|
|
|
threaded = 1;
|
|
|
|
worker_lru = tsLru;
|
|
|
|
worker_count = LONG_COUNT / THREAD_COUNT;
|
|
|
|
pthread_t threads[THREAD_COUNT];
|
|
|
|
randomSetup();
|
|
|
|
for(int i = 0; i < THREAD_COUNT; i++) {
|
|
|
|
pthread_create(&threads[i], 0, randomTestWorker, 0);
|
|
|
|
}
|
|
|
|
for(int i = 0; i < THREAD_COUNT; i++) {
|
|
|
|
pthread_join(threads[i], 0);
|
|
|
|
}
|
|
|
|
tsLru->deinit(tsLru);
|
|
|
|
randomTeardown();
|
|
|
|
} END_TEST
|
|
|
|
START_TEST(replacementPolicyConcurrentThreadTest) {
|
|
|
|
int LRU_COUNT = OBJECT_COUNT / 51;
|
|
|
|
replacementPolicy * lru[LRU_COUNT];
|
|
|
|
for(int i = 0; i < LRU_COUNT; i++) {
|
|
|
|
lru[i] = lruFastInit(getKey, setKey, 0);
|
|
|
|
}
|
|
|
|
replacementPolicy * cwLru = replacementPolicyConcurrentWrapperInit(lru, THREAD_COUNT);
|
|
|
|
threaded = 1;
|
|
|
|
worker_lru = cwLru;
|
|
|
|
worker_count = LONG_COUNT / THREAD_COUNT;
|
|
|
|
pthread_t threads[THREAD_COUNT];
|
|
|
|
randomSetup();
|
|
|
|
for(int i = 0; i < THREAD_COUNT; i++) {
|
|
|
|
pthread_create(&threads[i], 0, randomTestWorker, 0);
|
|
|
|
}
|
|
|
|
for(int i = 0; i < THREAD_COUNT; i++) {
|
|
|
|
pthread_join(threads[i], 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
cwLru->deinit(cwLru);
|
|
|
|
randomTeardown();
|
2007-03-10 01:29:43 +00:00
|
|
|
} END_TEST
|
|
|
|
|
|
|
|
Suite * check_suite(void) {
|
2010-03-31 22:37:42 +00:00
|
|
|
Suite *s = suite_create("replacementPolicy");
|
2007-03-10 01:29:43 +00:00
|
|
|
/* Begin a new test */
|
|
|
|
TCase *tc = tcase_create("multithreaded");
|
|
|
|
tcase_set_timeout(tc, 1200); // twenty minute timeout
|
|
|
|
/* Sub tests are added, one per line, here */
|
2009-04-14 20:21:05 +00:00
|
|
|
tcase_add_test(tc, replacementPolicyLRURandomTest);
|
|
|
|
tcase_add_test(tc, replacementPolicyLRUFastRandomTest);
|
2010-03-31 22:37:42 +00:00
|
|
|
tcase_add_test(tc, replacementPolicyThreadsafeRandomTest);
|
|
|
|
tcase_add_test(tc, replacementPolicyConcurrentRandomTest);
|
|
|
|
tcase_add_test(tc, replacementPolicyThreadsafeThreadTest);
|
|
|
|
tcase_add_test(tc, replacementPolicyConcurrentThreadTest);
|
|
|
|
|
2007-03-10 01:29:43 +00:00
|
|
|
|
|
|
|
/* --------------------------------------------- */
|
2009-04-14 20:21:05 +00:00
|
|
|
|
2007-03-10 01:29:43 +00:00
|
|
|
tcase_add_checked_fixture(tc, setup, teardown);
|
|
|
|
|
|
|
|
|
|
|
|
suite_add_tcase(s, tc);
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "../check_setup.h"
|