RangeTracker seems to be working; still need to write unit tests for its return value.

This commit is contained in:
Sears Russell 2007-02-06 02:32:01 +00:00
parent 3b1135ea2f
commit fe30fbbd74
3 changed files with 444 additions and 40 deletions

View file

@ -19,12 +19,20 @@ void rangeTrackerDeinit(rangeTracker * rt);
/**
Add a new range
@return a null terminated array of newly-pinned, quantized ranges
@return a null terminated array of newly-pinned, quantized ranges.
This array might contain ranges that were already pinned, and/or
ones that overlap (this aspect of the behavior is intentionally
left unspecified).
*/
range ** rangeTrackerAdd(rangeTracker * rt, const range * r);
/**
Remove a range
@return a null terminated array of newly-unpinned, quantized ranges
Remove a range
@return a null terminated array of unpinned, quantized ranges.
@see rangeTrackerAdd for a discussion of approximations that may
be applied to rangeTrackerRemove's return value.
*/
range ** rangeTrackerRemove(rangeTracker * rt, const range * r);

View file

@ -55,17 +55,22 @@ static void rangeTrackerDelta(rangeTracker * rt, const range * r, int delta) {
transition * t = (transition *)RB_ENTRY(lookup)(RB_LULTEQ, &key, rt->ranges);
if(t) {
assert(t->delta);
assert(t->pins >= 0);
assert(t->pins + t->delta >= 0);
if(t->pos != r->start) {
int newpins = t->pins + t->delta;
t = malloc(sizeof(transition));
t->pos = r->start;
t->delta = delta;
t->pins = newpins;
assert(newpins >= 0);
RB_ENTRY(search)(t, rt->ranges); // insert
curpin = t->pins + t->delta;
} else {
t->delta += delta;
curpin = t->pins + t->delta;
assert(curpin >= 0);
if(t->delta == 0) {
RB_ENTRY(delete)(t, rt->ranges);
key.pos = t->pos;
@ -81,6 +86,7 @@ static void rangeTrackerDelta(rangeTracker * rt, const range * r, int delta) {
t->pins = 0;
RB_ENTRY(search)(t, rt->ranges); // insert
curpin = t->pins + t->delta;
assert(curpin >= 0);
}
// t is now set; iterate over the tree until we reach a transition
@ -97,6 +103,7 @@ static void rangeTrackerDelta(rangeTracker * rt, const range * r, int delta) {
assert(t->delta);
assert(t->pins == curpin);
curpin = t->pins + t->delta;
assert(curpin >= 0);
}
if(!t || t->pos != r->stop) {
// Need to allocate new transition
@ -104,6 +111,7 @@ static void rangeTrackerDelta(rangeTracker * rt, const range * r, int delta) {
t->pos = r->stop;
t->delta = 0-delta;
t->pins = curpin;
assert(curpin >= 0);
RB_ENTRY(search)(t, rt->ranges); // insert
} else {
// Found existing transition at end of range.
@ -120,8 +128,260 @@ static void rangeTrackerDelta(rangeTracker * rt, const range * r, int delta) {
}
}
range ** rangeTrackerAdd(rangeTracker * rt, const range * r) {
rangeTrackerDelta(rt, r, 1);
static range ** rangeTrackerToArray(rangeTracker * rt) {
// count ranges.
int range_count = 0;
const transition * t;
int in_range = 0;
RBLIST * list = RB_ENTRY(openlist) (rt->ranges);
while((t = RB_ENTRY(readlist)(list))) {
if(!(t->pins + t->delta)) {
// end of a range.
in_range = 0;
range_count++;
} else {
in_range = 1;
}
}
RB_ENTRY(closelist)(list);
if(in_range) {
range_count++;
}
range ** ret = calloc(range_count + 1, sizeof(range *));
int next_range = 0;
in_range = 0;
list = RB_ENTRY(openlist) (rt->ranges);
t = RB_ENTRY(readlist)(list);
if(!t) {
assert(range_count == 0);
RB_ENTRY(closelist)(list);
return ret;
} else {
assert(!t->pins);
assert(t->delta);
assert(! ret[next_range] );
ret[next_range] = malloc(sizeof(range));
ret[next_range]->start = t->pos;
in_range = 1;
}
while((t = RB_ENTRY(readlist)(list))) {
if(t->pins + t->delta) {
if(!in_range) {
assert(! ret[next_range]);
ret[next_range] = malloc(sizeof(range));
ret[next_range]->start = t->pos;
in_range = 1;
}
} else {
// end of range.
assert(in_range);
ret[next_range]->stop = t->pos;
in_range = 0;
next_range ++;
}
}
RB_ENTRY(closelist)(list);
assert(next_range == range_count);
return ret;
}
static inline long roundDown(long x, long quant) {
return (x / quant) * quant;
}
static inline long roundUp(long x, long quant) {
return (((x-1) / quant) + 1) * quant;
}
/**
@return a set of ranges that are pinned, and that overlap the request range.
*/
static rangeTracker * pinnedRanges(const rangeTracker * rt, const range * request, rangeTracker * ret, int delta) {
transition key;
const transition * t;
key.pos = roundDown(request->start, rt->quantization);
t = rblookup(RB_LUGTEQ, &key, rt->ranges);
if(!t) {
// No ranges after request->start, so no ranges can overlap.
return ret;
}
long range_start;
// zero if we just encountered the end of a range. The range runs from
// range_start to putative_range_stop. It is possible that a new range
// begins on the page that putative_range_stop falls on, so we do not
// output the range without looking at the next transition.
int in_range;
// This is only meaningful if in_range = 0.
long putative_range_stop;
if(t) {
if(roundDown(t->pos, rt->quantization) >= roundUp(request->stop, rt->quantization)) {
if(t->pins) {
// entire range is pinned.
range tmp_r;
tmp_r.start = roundDown(request->start, rt->quantization);
tmp_r.stop = roundUp(request->stop, rt->quantization);
assert(tmp_r.start >= roundDown(request->start, rt->quantization) && tmp_r.stop <= roundUp(request->stop, rt->quantization));
rangeTrackerDelta(ret, &tmp_r, delta);
// printf("0 %s\n", rangeToString(&tmp_r));
} else {
// none of the range is pinned.
}
return ret;
}
if(t->pins) {
// The beginning of request is a range.
range_start = roundDown(request->start, rt->quantization);
if(0 == t->pins + t->delta) {
in_range = 0;
// even though we're not in range, we need to see if the next
// transition starts a range on the same page before returning a
// new range.
putative_range_stop = roundUp(t->pos, rt->quantization);
} else {
in_range = 1;
}
} else {
// The beginning of the request is not a range.
range_start = roundDown(t->pos, rt->quantization);
in_range = 1;
assert(t->delta);
}
}
while((t = rblookup(RB_LUGREAT, t, rt->ranges))) {
assert(t->delta);
if(roundUp(t->pos, rt->quantization) >= roundUp(request->stop, rt->quantization)) {
if(in_range) {
// if we're in range, part of the last page must be pinned.
in_range = 0;
putative_range_stop = roundUp(request->stop, rt->quantization);
} else {
// is this transition in the last page? If so, part of the last page must be pinned.
if(t->pos < roundUp(request->stop, rt->quantization)) {
// in_range == 0
assert(t->pins == 0);
range_start = roundDown(t->pos, rt->quantization);
putative_range_stop = roundUp(request->stop, rt->quantization);
}
}
break;
}
if(t->pins) {
assert(in_range);
if(!(t->pins + t->delta)) {
putative_range_stop = roundUp(t->pos, rt->quantization);
in_range = 0;
}
} else { // ! t->pins
assert(!in_range);
if(putative_range_stop < roundDown(t->pos, rt->quantization)) {
// output a new range
range tmp_r;
tmp_r.start = range_start;
tmp_r.stop = putative_range_stop;
if(tmp_r.start != tmp_r.stop) {
assert(tmp_r.start >= roundDown(request->start, rt->quantization) && tmp_r.stop <= roundUp(request->stop, rt->quantization));
rangeTrackerDelta(ret, &tmp_r, delta);
// printf("1 %s\n", rangeToString(&tmp_r));
}
range_start = roundDown(t->pos, rt->quantization);
} else {
// extend old range.
}
in_range = 1;
}
}
assert(!in_range);
range tmp_r;
tmp_r.start = range_start;
tmp_r.stop = putative_range_stop;
if(tmp_r.start != tmp_r.stop) {
assert(tmp_r.start >= roundDown(request->start, rt->quantization) && tmp_r.stop <= roundUp(request->stop, rt->quantization));
rangeTrackerDelta(ret, &tmp_r, delta);
// printf("2 %s\n", rangeToString(&tmp_r));
}
return ret;
}
range ** rangeTrackerAdd(rangeTracker * rt, const range * rng) {
// printf("pinnedRanges before add %s\n", rangeToString(rng));
rangeTracker * ret = rangeTrackerInit(rt->quantization);
pinnedRanges(rt, rng, ret, 1);
rangeTrackerDelta(rt, rng, 1);
// printf("pinnedRanges after add\n");
rangeTracker * ret2 = rangeTrackerInit(rt->quantization);
pinnedRanges(rt, rng, ret2, 1);
range ** ret_arry = rangeTrackerToArray(ret);
// remove the first array from the second...
int i = 0;
while(ret_arry[i]) {
rangeTrackerDelta(ret2, ret_arry[i], -1);
// while we're at it, deinit the first range tracker
rangeTrackerDelta(ret, ret_arry[i], -1);
free(ret_arry[i]);
i++;
}
free(ret_arry);
rangeTrackerDeinit(ret);
i = 0;
ret_arry = rangeTrackerToArray(ret2);
while(ret_arry[i]) {
rangeTrackerDelta(ret2, ret_arry[i], -1);
i++;
}
rangeTrackerDeinit(ret2);
return ret_arry;
/* // Need to return pinned ranges that overlap r.
transition key;
const transition * t;
key.pos = rng->start;
t = rblookup(RB_LULTEQ, &key, rt->ranges); // could be less than if the new range touches an existing range.
assert(t);
range r;
int in_range = 1;
r.start = roundDown(t->pos, rt->quantization);
while((t = rblookup(RB_LUGREAT, t, rt->ranges))) {
if(!(t->pins + t->delta)) {
assert(in_range);
in_range = 0;
r.stop = roundUp(t->pos, rt->quantization);
// printf("add range: [%lld-%lld]\n", (long long)r.start, (long long)r.stop);
} else if(!in_range) {
assert(t->pins == 0);
in_range = 1;
r.start = roundDown(t->pos, rt->quantization);
}
if(t->pos >= rng->stop) { break; }
} */
}
/**
@ -129,8 +389,96 @@ range ** rangeTrackerAdd(rangeTracker * rt, const range * r) {
@return a null terminated array of newly-unpinned, quantized ranges
*/
range ** rangeTrackerRemove(rangeTracker * rt, const range * r) {
rangeTrackerDelta(rt, r, -1);
range ** rangeTrackerRemove(rangeTracker * rt, const range * rang) {
rangeTracker * ret = rangeTrackerInit(rt->quantization);
// printf("pinnedRanges, before del %s\n", rangeToString(rang));
pinnedRanges(rt, rang, ret, 1);
rangeTrackerDelta(rt, rang, -1);
// printf("pinnedRanges, after del\n");
pinnedRanges(rt, rang, ret, -1);
range ** ret_arry = rangeTrackerToArray(ret);
int i = 0;
while(ret_arry[i]) {
rangeTrackerDelta(ret, ret_arry[i], -1);
i++;
}
rangeTrackerDeinit(ret);
return ret_arry;
/* // Need to return completely unpinned ranges that overlap r.
range bigger;
bigger.start = roundDown(rang->start, rt->quantization);
bigger.stop = roundUp(rang->stop, rt->quantization);
transition key;
key.pos = bigger.start;
int unpinned_range = 0;
range r;
const transition * t = RB_ENTRY(lookup)(RB_LUGTEQ, &key, rt->ranges);
long last_end = bigger.start;
// special case beginning of range
if(! t) {
t = RB_ENTRY(lookup)(RB_LULESS, &key, rt->ranges);
if(!t || 0 == t->pins + t->delta) {
// printf("A %s\n", rangeToString(&bigger));
return;
}
} else if(t->pins == 0) {
r.start = bigger.start;
r.stop = roundDown(t->pos, rt->quantization);
if(r.start < r.stop) {
// printf("0 %s\n", rangeToString(&r));
}
unpinned_range = 1;
assert(0 != t->pins + t->delta);
t = RB_ENTRY(lookup)(RB_LUGREAT, t, rt->ranges);
}
if(t) {
unpinned_range = (0 == t->pins + t->delta);
}
while(t) {
if(t->pins == 0) {
// XXX don't care if range bleeds outside of initially pinned range (for now; the difference could be huge in sparse applications)
r.start = roundUp(last_end, rt->quantization);
r.stop = roundDown(t->pos, rt->quantization);
assert(unpinned_range);
if(r.start < r.stop) {
// printf("B %s\n", rangeToString(&r));
} else {
// printf(".. %s bigger = %s\n", rangeToString(&r), rangeToString(&bigger));
}
}
// break after processing transition that runs over the edge...
if(t->pos >= bigger.stop) { break; }
last_end = t->pos;
unpinned_range = (0 == t->pins + t->delta);
t = RB_ENTRY(lookup)(RB_LUGREAT, t, rt->ranges);
}
if(! t && unpinned_range) {
r.start = roundUp(last_end, rt->quantization);
r.stop = bigger.stop;
if(r.start < r.stop) {
// printf("C %s\n", rangeToString(&r));
}
}
// plan: (1) Write roundDown, roundUp macros
// enumerate pinned pages before and after operation. (Note that we need to round down and up to get stuff outside the range, but on common pages)
// return before - after, or after - before, depending on whether this is an add or a remove.
*/
}
const transition ** rangeTrackerEnumerate(rangeTracker * rt) {
@ -169,3 +517,4 @@ char * transitionToString(const transition * t) {
assert(err !=-1);
return ret;
}

View file

@ -3,6 +3,8 @@
#include <lladd/transactional.h>
#define LOG_NAME "check_rangeTracker.log"
#define QUANTIZATION 7
#include <lladd/io/rangeTracker.h>
#include "../check_includes.h"
@ -18,6 +20,12 @@ long myrandom(long x) {
return (long)((r/max));
}
void rangeTrackerFreeRet(range ** ret) {
for(int i = 0; ret[i]; i++) {
free(ret[i]);
}
free(ret);
}
void printRT(rangeTracker * rt) {
const transition ** ts = rangeTrackerEnumerate(rt);
int i = 0;
@ -30,7 +38,7 @@ void printRT(rangeTracker * rt) {
}
START_TEST(rangeTracker_smokeTest) {
rangeTracker * rt = rangeTrackerInit(512);
rangeTracker * rt = rangeTrackerInit(QUANTIZATION);
const transition ** ts = rangeTrackerEnumerate(rt);
@ -45,7 +53,8 @@ START_TEST(rangeTracker_smokeTest) {
r.start = 10;
r.stop = 100;
rangeTrackerAdd(rt, &r);
rangeTrackerFreeRet(rangeTrackerAdd(rt, &r));
// printRT(rt);
@ -60,10 +69,12 @@ START_TEST(rangeTracker_smokeTest) {
ts[1]->pos == 100&& ts[1]->delta == -1 && ts[1]->pins == 1 && !ts[2]);
free(ts);
r.start = 20;
r.stop = 80;
rangeTrackerRemove(rt, &r);
rangeTrackerFreeRet(rangeTrackerRemove(rt, &r));
// printRT(rt);
@ -80,10 +91,11 @@ START_TEST(rangeTracker_smokeTest) {
ts[3]->pos == 100&& ts[3]->delta == -1 && ts[3]->pins == 1 && !ts[4]);
rangeTrackerAdd(rt, &r);
rangeTrackerFreeRet(rangeTrackerAdd(rt, &r));
// printRT(rt);
free(ts);
ts = rangeTrackerEnumerate(rt);
// 10 20 80 90 100
@ -95,10 +107,10 @@ START_TEST(rangeTracker_smokeTest) {
assert(ts[0]->pos == 10 && ts[0]->delta == 1 && ts[0]->pins == 0 &&
ts[1]->pos == 100&& ts[1]->delta == -1 && ts[1]->pins == 1 && !ts[2]);
rangeTrackerAdd(rt, &r);
rangeTrackerFreeRet(rangeTrackerAdd(rt, &r));
// printRT(rt);
free(ts);
ts = rangeTrackerEnumerate(rt);
// 10 20 80 90 100
@ -111,8 +123,8 @@ START_TEST(rangeTracker_smokeTest) {
ts[2]->pos == 80 && ts[2]->delta == -1 && ts[2]->pins == 2 &&
ts[3]->pos == 100&& ts[3]->delta == -1 && ts[3]->pins == 1 && !ts[4]);
rangeTrackerRemove(rt, &r);
free(ts);
rangeTrackerFreeRet(rangeTrackerRemove(rt, &r));
ts = rangeTrackerEnumerate(rt);
// 10 20 80 90 100
@ -123,7 +135,9 @@ START_TEST(rangeTracker_smokeTest) {
assert(ts[0]->pos == 10 && ts[0]->delta == 1 && ts[0]->pins == 0 &&
ts[1]->pos == 100&& ts[1]->delta == -1 && ts[1]->pins == 1 && !ts[2]);
rangeTrackerRemove(rt, &r);
free(ts);
rangeTrackerFreeRet(rangeTrackerRemove(rt, &r));
// printRT(rt);
@ -138,13 +152,13 @@ START_TEST(rangeTracker_smokeTest) {
ts[1]->pos == 20 && ts[1]->delta == -1 && ts[1]->pins == 1 &&
ts[2]->pos == 80 && ts[2]->delta == 1 && ts[2]->pins == 0 &&
ts[3]->pos == 100&& ts[3]->delta == -1 && ts[3]->pins == 1 && !ts[4]);
free(ts);
r.start = 80;
r.stop = 90;
rangeTrackerAdd(rt, &r);
rangeTrackerFreeRet(rangeTrackerAdd(rt, &r));
// printRT(rt);
@ -161,10 +175,11 @@ START_TEST(rangeTracker_smokeTest) {
ts[2]->pos == 80 && ts[2]->delta == 2 && ts[2]->pins == 0 &&
ts[3]->pos == 90 && ts[3]->delta == -1 && ts[3]->pins == 2 &&
ts[4]->pos == 100&& ts[4]->delta == -1 && ts[4]->pins == 1 && !ts[5]);
free(ts);
r.start = 80;
r.stop = 100;
rangeTrackerRemove(rt, &r);
rangeTrackerFreeRet(rangeTrackerRemove(rt, &r));
// printRT(rt);
ts = rangeTrackerEnumerate(rt);
@ -180,10 +195,10 @@ START_TEST(rangeTracker_smokeTest) {
ts[2]->pos == 80 && ts[2]->delta == 1 && ts[2]->pins == 0 &&
ts[3]->pos == 90 && ts[3]->delta == -1 && ts[3]->pins == 1 && !ts[4]);
free(ts);
r.start = 10;
r.stop = 20;
rangeTrackerRemove(rt, &r);
rangeTrackerFreeRet(rangeTrackerRemove(rt, &r));
// printRT(rt);
ts = rangeTrackerEnumerate(rt);
@ -196,12 +211,12 @@ START_TEST(rangeTracker_smokeTest) {
assert(ts[0]->pos == 80 && ts[0]->delta == 1 && ts[0]->pins == 0 &&
ts[1]->pos == 90 && ts[1]->delta == -1 && ts[1]->pins == 1 && !ts[2]);
free(ts);
r.start = 80;
r.stop = 90;
rangeTrackerRemove(rt, &r);
rangeTrackerFreeRet(rangeTrackerRemove(rt, &r));
// printRT(rt);
ts = rangeTrackerEnumerate(rt);
@ -210,16 +225,16 @@ START_TEST(rangeTracker_smokeTest) {
// | | | | |
// | | | | |
// | | | | |
assert(!ts[0]);
free(ts);
rangeTrackerDeinit(rt);
}
END_TEST
#define RANGE_SIZE 1000
#define ITERATIONS 1000
#define RANGE_COUNT 100
#define ITERATIONS 10000 //1000
#define RANGE_COUNT 1000 // 100
void randomRange(range * r) {
long start = myrandom(RANGE_SIZE-1);
long len = 1+myrandom(RANGE_SIZE - start - 1);
@ -261,42 +276,64 @@ START_TEST (rangeTracker_randomTest) {
gettimeofday(&time,0);
long seed = time.tv_usec + time.tv_sec * 1000000;
long seed = time.tv_usec + time.tv_sec * 1000000;// 1170727703805787; //
printf("\nSeed = %ld\n", seed);
srandom(seed);
range ** r_arry;
range * ranges = malloc(sizeof(range) * RANGE_COUNT);
int * pins = calloc(RANGE_COUNT, sizeof(int));
rangeTracker * rt = rangeTrackerInit(512);
rangeTracker * rt = rangeTrackerInit(QUANTIZATION);
for(long i = 0; i < RANGE_COUNT; i++) {
randomRange(&(ranges[i]));
}
char * bitmask = calloc(RANGE_SIZE, sizeof(char));
char * s;
for(long i = 0; i < ITERATIONS; i++) {
int range = myrandom(RANGE_COUNT);
switch(myrandom(3)) {
case 0: { // add range
rangeTrackerAdd(rt, &ranges[range]);
s = rangeToString(&ranges[range]);
printf("pin %s\n", s);
free(s);
r_arry = rangeTrackerAdd(rt, &ranges[range]);
for(int i = 0; r_arry[i]; i++) {
s = rangeToString(r_arry[i]);
printf(" add returned %s\n", s);
free(s);
free(r_arry[i]);
}
free(r_arry);
pins[range]++;
checkRangeTrackerConsistency(rt);
break;
}
case 1: { // del range
if(pins[range]) {
rangeTrackerRemove(rt, &ranges[range]);
s = rangeToString(&ranges[range]);
printf("unpin %s\n", s);
free(s);
r_arry = rangeTrackerRemove(rt, &ranges[range]);
for(int i = 0; r_arry[i]; i++) {
s = rangeToString(r_arry[i]);
printf(" del returned %s\n", s);
free(s);
free(r_arry[i]);
}
free(r_arry);
pins[range]--;
}
checkRangeTrackerConsistency(rt);
break;
}
case 2: { // change range
for(long i = 0; i < RANGE_COUNT; i++) {
if(!pins[i]) {
randomRange(&ranges[i]);
if(!myrandom(100)) {
for(long i = 0; i < RANGE_COUNT; i++) {
if(!pins[i]) {
randomRange(&ranges[i]);
}
}
}
break;
@ -308,13 +345,23 @@ START_TEST (rangeTracker_randomTest) {
for(long i = 0; i < RANGE_COUNT; i++) {
while(pins[i]) {
rangeTrackerRemove(rt, &ranges[i]);
s = rangeToString(&ranges[i]);
printf("unpin %s\n", s);
free(s);
range ** r_arry = rangeTrackerRemove(rt, &ranges[i]);
for(int i = 0; r_arry[i]; i++) {
s = rangeToString(r_arry[i]);
printf(" del returned %s\n", s);
free(s);
free(r_arry[i]);
}
free(r_arry);
pins[i]--;
}
}
free (bitmask);
free (ranges);
free (pins);
rangeTrackerDeinit(rt);
} END_TEST