lru cache now works as intended
This commit is contained in:
parent
8c1f4f5ee2
commit
5455449bf9
@ -1,6 +1,6 @@
|
|||||||
CC = gcc
|
CC = gcc
|
||||||
LDFLAGS = -lm -lgrapheme -lSDL2 -lGLEW -lGL
|
LDFLAGS = -lm -lgrapheme -lSDL2 -lGLEW -lGL
|
||||||
CFLAGS = -ggdb3 -Wall -Wextra -pedantic -fno-omit-frame-pointer
|
CFLAGS = -ggdb3 -Wall -Wextra -pedantic -std=c11 -Wno-unused-function -fno-omit-frame-pointer
|
||||||
|
|
||||||
.PHONY: clean all
|
.PHONY: clean all
|
||||||
all: test
|
all: test
|
||||||
@ -12,5 +12,5 @@ ren.o: ren.c util.h font.h ren.h generic_stack.h
|
|||||||
util.o: util.c util.h
|
util.o: util.c util.h
|
||||||
test: font.o main.o ren.o util.o
|
test: font.o main.o ren.o util.o
|
||||||
${CC} ${LDFLAGS} -o test font.o main.o ren.o util.o
|
${CC} ${LDFLAGS} -o test font.o main.o ren.o util.o
|
||||||
clean:
|
clean:
|
||||||
rm -f test font.o main.o ren.o util.o
|
rm -f test font.o main.o ren.o util.o
|
||||||
|
@ -62,7 +62,7 @@ int font_load(struct font_atlas *atlas, const char *path, int size)
|
|||||||
dump_file(path, &(atlas->file), &(atlas->file_size));
|
dump_file(path, &(atlas->file), &(atlas->file_size));
|
||||||
|
|
||||||
err = stbtt_InitFont(&(PRIV(atlas)->stb), (unsigned char *)atlas->file, 0);
|
err = stbtt_InitFont(&(PRIV(atlas)->stb), (unsigned char *)atlas->file, 0);
|
||||||
ERROR(err == 0, -1);
|
if (err == 0) return -1;
|
||||||
|
|
||||||
int ascent, descent, linegap, baseline;
|
int ascent, descent, linegap, baseline;
|
||||||
int x0,y0,x1,y1;
|
int x0,y0,x1,y1;
|
||||||
|
@ -5,26 +5,26 @@
|
|||||||
#include "generic_hash.h"
|
#include "generic_hash.h"
|
||||||
|
|
||||||
#define CACHE_SIZE 512
|
#define CACHE_SIZE 512
|
||||||
#define CACHE_NCYCLES (CACHE_SIZE/2)
|
#define CACHE_NCYCLES (CACHE_SIZE*2/3)
|
||||||
#define CACHE_BSIZE (((CACHE_SIZE+0x3f)&(~0x3f))>>6)
|
#define CACHE_BSIZE (((CACHE_SIZE+0x3f)&(~0x3f))>>6)
|
||||||
#define CACHE_BRESET(b) for (int i = 0; i < CACHE_BSIZE; b[i++] = 0);
|
#define CACHE_BRESET(b) for (int i = 0; i < CACHE_BSIZE; b[i++] = 0);
|
||||||
#define CACHE_BSET(b, x) b[(x)>>6] |= (uint64_t)1<<((x)%64)
|
#define CACHE_BSET(b, x) b[(x)>>6] |= (uint64_t)1<<((x)&63)
|
||||||
#define CACHE_BTEST(b, x) (b[(x)>>6]&((uint64_t)1<<((x)%64)))
|
#define CACHE_BTEST(b, x) (b[(x)>>6]&((uint64_t)1<<((x)&63)))
|
||||||
|
|
||||||
// FIXME: this cache implementation is not really generic since it expects an unsigned
|
// FIXME: this cache implementation is not really generic since it expects an unsigned
|
||||||
// as the code and not a generic type
|
// as the code and not a generic type
|
||||||
|
|
||||||
// FIXME: when resetting the bitmap all references to overwritten elements are
|
|
||||||
// invalidated, this really means that
|
|
||||||
// 1) we get data mismatches
|
|
||||||
// 2) this is not a good LRU cache
|
|
||||||
|
|
||||||
#define CACHE_SET(c, x) \
|
#define CACHE_USED(c, x) \
|
||||||
{ \
|
{ \
|
||||||
if (++(c->cycles) > CACHE_NCYCLES) { \
|
if (++(c->cycles) > CACHE_NCYCLES) { \
|
||||||
CACHE_BRESET(c->bitmap); \
|
for (int i = 0; i < CACHE_BSIZE; i++) { \
|
||||||
c->cycles=0;} \
|
c->present[i] &= c->used[i]; \
|
||||||
CACHE_BSET(c->bitmap, x); \
|
c->used[i] = 0; \
|
||||||
|
} \
|
||||||
|
c->cycles = 0; \
|
||||||
|
} \
|
||||||
|
CACHE_BSET(c->used, x); \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -33,18 +33,21 @@ HASH_DECL(name##table, uint32_t, uint32_t, hashfn, cmpfn) \
|
|||||||
struct name { \
|
struct name { \
|
||||||
struct name##table_ref *table; \
|
struct name##table_ref *table; \
|
||||||
type *array; \
|
type *array; \
|
||||||
uint64_t *bitmap; \
|
uint64_t *present, *used; \
|
||||||
int cycles; \
|
int cycles; \
|
||||||
}; \
|
}; \
|
||||||
\
|
\
|
||||||
\
|
\
|
||||||
|
/* FIXME: check for allocation errors */ \
|
||||||
struct name name##_init(void) \
|
struct name name##_init(void) \
|
||||||
{ \
|
{ \
|
||||||
struct name##table_ref *t = name##table_create(CACHE_SIZE); \
|
struct name##table_ref *t = name##table_create(CACHE_SIZE); \
|
||||||
type *a = malloc(sizeof(type)*CACHE_SIZE); \
|
type *a = malloc(sizeof(type)*CACHE_SIZE); \
|
||||||
uint64_t *b = malloc(sizeof(uint64_t)*CACHE_BSIZE); \
|
uint64_t *p = malloc(sizeof(uint64_t)*CACHE_BSIZE); \
|
||||||
CACHE_BRESET(b); \
|
uint64_t *u = malloc(sizeof(uint64_t)*CACHE_BSIZE); \
|
||||||
return (struct name){ .table = t, .array = a, .bitmap = b, 0}; \
|
CACHE_BRESET(p); \
|
||||||
|
CACHE_BRESET(u); \
|
||||||
|
return (struct name){.table=t, .array=a, .present=p, .used=u, 0}; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
\
|
\
|
||||||
@ -53,7 +56,8 @@ void name##_free(struct name *cache) \
|
|||||||
if (cache) { \
|
if (cache) { \
|
||||||
name##table_destroy(cache->table); \
|
name##table_destroy(cache->table); \
|
||||||
free(cache->array); \
|
free(cache->array); \
|
||||||
free(cache->bitmap); \
|
free(cache->present); \
|
||||||
|
free(cache->used); \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
@ -66,21 +70,25 @@ const type * name##_search(struct name *cache, uint32_t code) \
|
|||||||
/* MISS */ \
|
/* MISS */ \
|
||||||
if (!r || !cmpfn(code, r->code)) \
|
if (!r || !cmpfn(code, r->code)) \
|
||||||
return NULL; \
|
return NULL; \
|
||||||
|
/* MISS, the data is not valid (not present) */ \
|
||||||
|
if (!CACHE_BTEST(cache->present, r->data)) \
|
||||||
|
return NULL; \
|
||||||
/* HIT, set as recently used */ \
|
/* HIT, set as recently used */ \
|
||||||
CACHE_SET(cache, r->data); \
|
CACHE_USED(cache, r->data); \
|
||||||
return (&cache->array[r->data]); \
|
return (&cache->array[r->data]); \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
\
|
\
|
||||||
|
/* Look for a free spot in the present bitmap and return its index */ \
|
||||||
int name##_get(struct name *cache) \
|
int name##_get(struct name *cache) \
|
||||||
{ \
|
{ \
|
||||||
if (!cache) return -1; \
|
if (!cache) return -1; \
|
||||||
int x = 0; \
|
int x = 0; \
|
||||||
for (int b = 0; b < CACHE_BSIZE; b++) { \
|
for (int b = 0; b < CACHE_BSIZE; b++) { \
|
||||||
if (cache->bitmap[b] == 0) x = 64; \
|
if (cache->present[b] == 0) x = 64; \
|
||||||
else x = __builtin_clzll(cache->bitmap[b]); \
|
else x = __builtin_clzll(cache->present[b]); \
|
||||||
x = 64-x; \
|
x = 64-x; \
|
||||||
if (!CACHE_BTEST(cache->bitmap, x+64*b)) \
|
if (!CACHE_BTEST(cache->present, x+64*b)) \
|
||||||
return x+64*b; \
|
return x+64*b; \
|
||||||
} \
|
} \
|
||||||
return 0; \
|
return 0; \
|
||||||
@ -93,9 +101,12 @@ const type * name##_insert(struct name *cache, const type *g, uint32_t code, int
|
|||||||
type *spot = NULL; \
|
type *spot = NULL; \
|
||||||
/* x is the index to the cache array, it has to come from the user */ \
|
/* x is the index to the cache array, it has to come from the user */ \
|
||||||
/* check if the spot is free */ \
|
/* check if the spot is free */ \
|
||||||
if (x < 0 || CACHE_BTEST(cache->bitmap, x)) \
|
if (x < 0 || CACHE_BTEST(cache->present, x)) \
|
||||||
return NULL; \
|
return NULL; \
|
||||||
CACHE_SET(cache, x) \
|
/* Set used and present */ \
|
||||||
|
CACHE_USED(cache, x) \
|
||||||
|
CACHE_BSET(cache->present, x); \
|
||||||
|
CACHE_BSET(cache->used, x); \
|
||||||
spot = &(cache->array[x]); \
|
spot = &(cache->array[x]); \
|
||||||
*spot = *g; \
|
*spot = *g; \
|
||||||
struct name##table_entry e = { .code = code, .data = x}; \
|
struct name##table_entry e = { .code = code, .data = x}; \
|
||||||
|
@ -16,7 +16,8 @@ rm -f objlist
|
|||||||
cat > Makefile << EOF
|
cat > Makefile << EOF
|
||||||
CC = gcc
|
CC = gcc
|
||||||
LDFLAGS = -lm -lgrapheme -lSDL2 -lGLEW -lGL
|
LDFLAGS = -lm -lgrapheme -lSDL2 -lGLEW -lGL
|
||||||
CFLAGS = -ggdb3 -Wall -Wextra -pedantic -fno-omit-frame-pointer
|
CFLAGS = -ggdb3 -Wall -Wextra -pedantic -std=c11 \
|
||||||
|
-Wno-unused-function -fno-omit-frame-pointer
|
||||||
|
|
||||||
.PHONY: clean all
|
.PHONY: clean all
|
||||||
all: test
|
all: test
|
||||||
@ -30,7 +31,7 @@ done
|
|||||||
|
|
||||||
mainrule='test: '
|
mainrule='test: '
|
||||||
linkcmd=' ${CC} ${LDFLAGS} -o test '
|
linkcmd=' ${CC} ${LDFLAGS} -o test '
|
||||||
cleanrule='clean:
|
cleanrule='clean:
|
||||||
rm -f test '
|
rm -f test '
|
||||||
while IFS="" read -r line; do
|
while IFS="" read -r line; do
|
||||||
mainrule="$mainrule $line"
|
mainrule="$mainrule $line"
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
#ifndef _UTIL_H
|
#ifndef _UTIL_H
|
||||||
#define _UTIL_H
|
#define _UTIL_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
#define ERROR(expr, ret, ...) if (expr) { __VA_ARGS__; return ret; }
|
|
||||||
|
|
||||||
|
|
||||||
void * emalloc(unsigned long int size);
|
void * emalloc(unsigned long int size);
|
||||||
@ -18,4 +17,18 @@ void print_byte(unsigned char byte);
|
|||||||
void stopwatch_start(void);
|
void stopwatch_start(void);
|
||||||
double stopwatch_get(void);
|
double stopwatch_get(void);
|
||||||
|
|
||||||
|
#define TIME_SEC(f) \
|
||||||
|
{ \
|
||||||
|
stopwatch_start(); \
|
||||||
|
f; \
|
||||||
|
printf("\"%s\" took %f seconds", #f, stopwatch_get()); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define TIME_MS(f) \
|
||||||
|
{ \
|
||||||
|
stopwatch_start(); \
|
||||||
|
f; \
|
||||||
|
printf("\"%s\" took %f ms", #f, stopwatch_get()*1000.0f); \
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user