Переглянути джерело

Change cache replacement algorithm to Least Recenrtly Used

main
PaulStoffregen 9 роки тому
джерело
коміт
d9c6f87cee
4 змінених файлів з 139 додано та 99 видалено
  1. +6
    -7
      SD_t3.h
  2. +108
    -85
      cache_t3.cpp
  3. +2
    -0
      card_t3.cpp
  4. +23
    -7
      file_t3.cpp

+ 6
- 7
SD_t3.h Переглянути файл

@@ -213,25 +213,24 @@ private:
// no longer exists.
SDCache(void) { item = NULL; }
~SDCache(void) { release(); }
typedef struct {
typedef struct cache_struct {
SDClass::sector_t data;
uint32_t lba;
cache_struct * next;
uint8_t usagecount;
uint8_t priority;
uint8_t flags;
} cache_t;
SDClass::sector_t * read(uint32_t lba, bool is_fat=false);
bool read(uint32_t lba, void *buffer);
SDClass::sector_t * alloc(uint32_t lba);
void priority(signed int n);
void priority(uint32_t lba, signed int n);
cache_t * get(uint32_t lba, bool allocate=true);
void dirty(void);
void flush(void);
void release(void);
cache_t * find(uint32_t lba);
cache_t * empty();
cache_t * item;
static cache_t *cache_list;
static cache_t cache[SD_CACHE_SIZE];
static void init(void);
static void print_cache(void);
friend class SDClass;
friend class File;
};

+ 108
- 85
cache_t3.cpp Переглянути файл

@@ -31,6 +31,7 @@
#define cache_t SDCache::cache_t
#define sector_t SDClass::sector_t

cache_t *SDCache::cache_list = NULL;
cache_t SDCache::cache[SD_CACHE_SIZE];

#define CACHE_FLAG_HAS_DATA 1
@@ -50,6 +51,22 @@ static void print_sector(const void *data)
}
#endif

void SDCache::print_cache(void)
{
#if 0
const cache_t *end=cache+SD_CACHE_SIZE;
for (cache_t *c = cache; c < end; c++) {
Serial.printf(" cache index %u, lba= %u, ucount=%u, flags=%u\n",
c - cache, c->lba, c->usagecount, c->flags);
}
Serial.print(" cache order:");
for (cache_t *c = cache_list; c; c = c->next) {
Serial.printf(" %u ->", c - cache);
}
Serial.println();
#endif
}

// Read a sector into the cache. If the sector is already cached,
// of course no actual read occurs. This is the primary function
// used to access the SD card.
@@ -64,34 +81,26 @@ sector_t * SDCache::read(uint32_t lba, bool is_fat)
//Serial.printf("cache read: lba = %d\n", lba);
SPI.beginTransaction(SD_SPI_SPEED);
// does the cache already have the sector?
cache_t *c = find(lba);
cache_t *c = get(lba);
if (c) {
ret = &c->data;
} else {
c = empty();
if (c != NULL) {
// TODO: if dirty, write to SD card
if (c->flags & CACHE_FLAG_HAS_DATA) {
//Serial.printf(" cache hit, lba=%u\n", lba);
ret = &c->data;
} else {
if (SDClass::sd_read(lba, &c->data)) {
item = c;
c->lba = lba;
c->usagecount = 1;
c->flags = CACHE_FLAG_HAS_DATA;
if (is_fat) c->flags |= CACHE_FLAG_IS_FAT;
ret = &c->data;
#ifdef PRINT_SECTORS
Serial.printf("cache read %u\n", lba);
print_sector(&c->data);
#endif
//Serial.printf(" cache miss, lba=%u\n", lba);
} else {
//Serial.printf(" cache miss: read error, lba=%u\n", lba);
}
}
} else {
//Serial.printf(" cache full & all in use\n", lba);
}
//if (c) slot = c - cache, ucount = c->usagecount;
SPI.endTransaction();
//if (ret) {
//Serial.printf("read %u, %u, slot %u\n", lba, ucount, slot);
//} else {
//Serial.printf("read %u, FAIL\n", lba);
//}
//print_cache();
return ret;
}

@@ -105,47 +114,99 @@ bool SDCache::read(uint32_t lba, void *buffer)
bool ret = true;

SPI.beginTransaction(SD_SPI_SPEED);
cache_t *c = find(lba);
if (!c) ret = SDClass::sd_read(lba, buffer);
cache_t *c = get(lba, false);
if (!c || !(c->flags & CACHE_FLAG_HAS_DATA)) {
ret = SDClass::sd_read(lba, buffer);
}
SPI.endTransaction();
if (c) memcpy(buffer, &c->data, 512);
if (c) {
if ((c->flags & CACHE_FLAG_HAS_DATA)) {
memcpy(buffer, &c->data, 512);
release();
return true;
}
release();
}
return ret;
}


sector_t * SDCache::alloc(uint32_t lba)
// locate a sector in the cache.
cache_t * SDCache::get(uint32_t lba, bool allocate)
{
cache_t *c, *p=NULL, *last=NULL, *plast=NULL;

return NULL;
}

void SDCache::priority(signed int n)
{
if (!item) return;
if (n > 0) {
__disable_irq();
signed int pri = (int)(item->priority) + n;
if (pri > 255) pri = 255;
item->priority = pri;
__enable_irq();
} else {
__disable_irq();
signed int pri = (int)(item->priority) + n;
if (pri < 0) pri = 0;
item->priority = pri;
__enable_irq();
// TODO: move initialization to a function called when the SD card is initialized
if (cache_list == NULL) init();
// have we already acquired a cache entry?
if (item) {
// if it's the desired block, use it
if (item->lba == lba) return item;
// if not, release our hold on it
release();
}
__disable_irq();
c = cache_list;
do {
if (c->lba == lba) {
if (p) {
p->next = c->next;
c->next = cache_list;
cache_list = c;
}
c->usagecount++;
__enable_irq();
item = c;
return item;
}
if (c->usagecount == 0) {
plast = p;
last = c;
}
p = c;
c = c->next;
} while (c);
if (allocate && last) {
if (plast) {
plast->next = last->next;
last->next = cache_list;
cache_list = last;
}
last->usagecount = 1;
// TODO: flush if dirty
last->lba = lba;
last->flags = 0;
item = last;
}
__enable_irq();
return item;
}

void SDCache::priority(uint32_t lba, signed int n)

void SDCache::init(void)
{
// TODO: if any a specific sector is cached, adjust its priority
cache_t *c = cache;
cache_t *end = c + SD_CACHE_SIZE;
//Serial.println("cache init");
__disable_irq();
do {
c->lba = 0xFFFFFFFF;
c->usagecount = 0;
c->flags = 0;
c->next = c + 1;
c = c + 1;
} while (c < end);
c--;
c->next = NULL;
cache_list = cache;
__enable_irq();
}


void SDCache::dirty(void)
{
__disable_irq();
item->usagecount |= CACHE_FLAG_IS_DIRTY;
item->flags |= CACHE_FLAG_IS_DIRTY;
__enable_irq();
}

@@ -163,49 +224,11 @@ void SDCache::release(void)
}
}

cache_t * SDCache::find(uint32_t lba)
{
//Serial.printf("SDCache::find, lba=%n\n", lba);
// have we already acquired a cache entry?
if (item) {
//Serial.printf(" item exists, lba=%d\n", item->lba);
// if it's the desired block, use it
if (item->lba == lba) return item;
// if not, release our hold on it
//Serial.printf("cache find release\n");
item->usagecount--;
item = NULL;
}
// does the cache already have the sector we want?
const cache_t *end=cache+SD_CACHE_SIZE;
for (cache_t *c = cache; c < end; c++) {
if ((c->flags) && (c->lba == lba)) {
//Serial.printf(" item found\n");
item = c;
c->usagecount++;
return c;
}
}
//Serial.printf(" item not found\n");
// the desired sector isn't in the cache
return NULL;
}

cache_t * SDCache::empty(void)
{
const cache_t *end=cache+SD_CACHE_SIZE;
cache_t *useme = NULL;
uint32_t lowest_priority = 0xFF;

for (cache_t *c = cache; c < end; c++) {
if (c->usagecount == 0 && c->priority < lowest_priority) {
useme = c;
lowest_priority = c->priority;
if (lowest_priority == 0) break;
}
}
return useme;
}




#endif
#endif

+ 2
- 0
card_t3.cpp Переглянути файл

@@ -94,6 +94,7 @@ bool SDClass::sd_read(uint32_t addr, void * data)
uint8_t r1 = recv_r1();
if (r1 != 0) {
end_cmd();
//Serial.println(" sd_read fail r1");
return false;
}
while (1) {
@@ -102,6 +103,7 @@ bool SDClass::sd_read(uint32_t addr, void * data)
if (token == 0xFE) break;
if (token != 0xFF) {
end_cmd();
//Serial.println(" sd_read fail token");
return false;
}
// TODO: timeout

+ 23
- 7
file_t3.cpp Переглянути файл

@@ -99,6 +99,9 @@ int File::read(void *buf, uint32_t size)
uint8_t *dest = (uint8_t *)buf;
uint32_t lba = custer_to_sector(current_cluster);
uint32_t sindex = cluster_offset(offset);

//Serial.printf(" read %u at %u (%X)\n", size, offset, offset);

lba += sindex >> 9;
sindex &= 511;
if (sindex) {
@@ -106,13 +109,16 @@ int File::read(void *buf, uint32_t size)
do {
SDCache cache;
sector_t *sector = cache.read(lba);
if (!sector) return 0;
if (!sector) {
//Serial.println(" read err1, unable to read");
return 0;
}
uint32_t n = 512 - sindex;
if (size < n) {
// read does not consume all of the sector
memcpy(dest, sector->u8 + sindex, size);
offset += size;
cache.priority(+1);
//cache.priority(+1);
return size;
} else {
// read fully consumes this sector
@@ -120,11 +126,14 @@ int File::read(void *buf, uint32_t size)
dest += n;
count = n;
offset += n;
cache.priority(-1);
//cache.priority(-1);
}
} while (0);
if (is_new_cluster(++lba)) {
if (!next_cluster()) return count;
if (!next_cluster()) {
//Serial.print(" read err1, next cluster");
return count;
}
}
if (count >= size) return count;
}
@@ -136,11 +145,14 @@ int File::read(void *buf, uint32_t size)
if (n < 512) {
// only part of a sector is needed
sector_t *sector = cache.read(lba);
if (!sector) return count;
if (!sector) {
//Serial.println(" read err2, unable to read");
return count;
}
memcpy(dest, sector->u8, n);
offset += n;
count += n;
cache.priority(+1);
//cache.priority(+1);
return count;
} else {
// a full sector is required
@@ -151,7 +163,10 @@ int File::read(void *buf, uint32_t size)
}
} while (0);
if (is_new_cluster(++lba)) {
if (!next_cluster()) return count;
if (!next_cluster()) {
//Serial.print(" read err2, next cluster");
return count;
}
}
if (count >= size) return count;
}
@@ -162,6 +177,7 @@ bool File::seek(uint32_t pos)
if (type > FILE_WRITE) return false;
if (pos > length) return false;

//Serial.printf(" seek to %u\n", pos);
uint32_t save_cluster = current_cluster;
uint32_t count;
// TODO: if moving to a new lba, lower cache priority

Завантаження…
Відмінити
Зберегти