mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-10 23:32:09 +00:00
new cache allocation scheme. still a couple warts, but at least now there's something to work with, and more importantly, there won't be cache movement anywhere near as often.
This commit is contained in:
parent
e5b972529b
commit
4cab5b90e6
2 changed files with 252 additions and 246 deletions
|
@ -135,8 +135,8 @@ void *Cache_Alloc (cache_user_t *c, int size, const char *name);
|
||||||
void Cache_Report (void);
|
void Cache_Report (void);
|
||||||
void Cache_Add (cache_user_t *c, void *object, cache_loader_t loader);
|
void Cache_Add (cache_user_t *c, void *object, cache_loader_t loader);
|
||||||
void Cache_Remove (cache_user_t *c);
|
void Cache_Remove (cache_user_t *c);
|
||||||
void *Cache_Get (cache_user_t *c);
|
|
||||||
void *Cache_TryGet (cache_user_t *c);
|
void *Cache_TryGet (cache_user_t *c);
|
||||||
|
void *Cache_Get (cache_user_t *c);
|
||||||
void Cache_Release (cache_user_t *c);
|
void Cache_Release (cache_user_t *c);
|
||||||
int Cache_ReadLock (cache_user_t *c);
|
int Cache_ReadLock (cache_user_t *c);
|
||||||
|
|
||||||
|
|
496
libs/util/zone.c
496
libs/util/zone.c
|
@ -50,7 +50,8 @@ static __attribute__ ((used)) const char rcsid[] =
|
||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
|
|
||||||
static void Cache_FreeLow (int new_low_hunk);
|
static void Cache_FreeLow (int new_low_hunk);
|
||||||
static void Cache_FreeHigh (int new_high_hunk);
|
static void Cache_Profile (void);
|
||||||
|
static qboolean Cache_FreeLRU (void);
|
||||||
|
|
||||||
#define ZONEID 0x1d4a11
|
#define ZONEID 0x1d4a11
|
||||||
#define HUNK_SENTINAL 0x1df001ed
|
#define HUNK_SENTINAL 0x1df001ed
|
||||||
|
@ -405,6 +406,30 @@ Hunk_Print (qboolean all)
|
||||||
Sys_Printf ("%8i total blocks\n", totalblocks);
|
Sys_Printf ("%8i total blocks\n", totalblocks);
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
static void
|
||||||
|
Hunk_FreeToHighMark (int mark)
|
||||||
|
{
|
||||||
|
if (hunk_tempactive) {
|
||||||
|
hunk_tempactive = false;
|
||||||
|
Hunk_FreeToHighMark (hunk_tempmark);
|
||||||
|
}
|
||||||
|
if (mark < 0 || mark > hunk_high_used)
|
||||||
|
Sys_Error ("Hunk_FreeToHighMark: bad mark %i", mark);
|
||||||
|
memset (hunk_base + hunk_size - hunk_high_used, 0, hunk_high_used - mark);
|
||||||
|
hunk_high_used = mark;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
Hunk_HighMark (void)
|
||||||
|
{
|
||||||
|
if (hunk_tempactive) {
|
||||||
|
hunk_tempactive = false;
|
||||||
|
Hunk_FreeToHighMark (hunk_tempmark);
|
||||||
|
}
|
||||||
|
|
||||||
|
return hunk_high_used;
|
||||||
|
}
|
||||||
|
|
||||||
VISIBLE void *
|
VISIBLE void *
|
||||||
Hunk_AllocName (int size, const char *name)
|
Hunk_AllocName (int size, const char *name)
|
||||||
{
|
{
|
||||||
|
@ -419,11 +444,17 @@ Hunk_AllocName (int size, const char *name)
|
||||||
|
|
||||||
size = sizeof (hunk_t) + ((size + 15) & ~15);
|
size = sizeof (hunk_t) + ((size + 15) & ~15);
|
||||||
|
|
||||||
if (hunk_size - hunk_low_used - hunk_high_used < size)
|
if (hunk_size - hunk_low_used - hunk_high_used < size) {
|
||||||
|
Hunk_HighMark();
|
||||||
|
Cache_FreeLRU ();
|
||||||
|
}
|
||||||
|
if (hunk_size - hunk_low_used - hunk_high_used < size) {
|
||||||
|
Cache_Profile ();
|
||||||
Sys_Error
|
Sys_Error
|
||||||
("Not enough RAM allocated. Try starting using \"-mem 16\" on "
|
("Not enough RAM allocated. Try starting using \"-mem 16\" on "
|
||||||
"the %s command line. (%d - %d - %d < %d)",
|
"the %s command line. (%d - %d - %d < %d)",
|
||||||
PROGRAM, hunk_size, hunk_low_used, hunk_high_used, size);
|
PROGRAM, hunk_size, hunk_low_used, hunk_high_used, size);
|
||||||
|
}
|
||||||
|
|
||||||
h = (hunk_t *) (hunk_base + hunk_low_used);
|
h = (hunk_t *) (hunk_base + hunk_low_used);
|
||||||
hunk_low_used += size;
|
hunk_low_used += size;
|
||||||
|
@ -460,37 +491,11 @@ Hunk_FreeToLowMark (int mark)
|
||||||
hunk_low_used = mark;
|
hunk_low_used = mark;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
Hunk_FreeToHighMark (int mark)
|
|
||||||
{
|
|
||||||
if (hunk_tempactive) {
|
|
||||||
hunk_tempactive = false;
|
|
||||||
Hunk_FreeToHighMark (hunk_tempmark);
|
|
||||||
}
|
|
||||||
if (mark < 0 || mark > hunk_high_used)
|
|
||||||
Sys_Error ("Hunk_FreeToHighMark: bad mark %i", mark);
|
|
||||||
memset (hunk_base + hunk_size - hunk_high_used, 0, hunk_high_used - mark);
|
|
||||||
hunk_high_used = mark;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
Hunk_HighMark (void)
|
|
||||||
{
|
|
||||||
if (hunk_tempactive) {
|
|
||||||
hunk_tempactive = false;
|
|
||||||
Hunk_FreeToHighMark (hunk_tempmark);
|
|
||||||
}
|
|
||||||
|
|
||||||
return hunk_high_used;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *
|
static void *
|
||||||
Hunk_HighAllocName (int size, const char *name)
|
Hunk_HighAlloc (int size)
|
||||||
{
|
{
|
||||||
hunk_t *h;
|
|
||||||
|
|
||||||
if (size < 0)
|
if (size < 0)
|
||||||
Sys_Error ("Hunk_HighAllocName: bad size: %i", size);
|
Sys_Error ("Hunk_HighAlloc: bad size: %i", size);
|
||||||
|
|
||||||
if (hunk_tempactive) {
|
if (hunk_tempactive) {
|
||||||
Hunk_FreeToHighMark (hunk_tempmark);
|
Hunk_FreeToHighMark (hunk_tempmark);
|
||||||
|
@ -500,7 +505,7 @@ Hunk_HighAllocName (int size, const char *name)
|
||||||
Hunk_Check ();
|
Hunk_Check ();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
size = sizeof (hunk_t) + ((size + 15) & ~15);
|
size = ((size + 15) & ~15);
|
||||||
|
|
||||||
if (hunk_size - hunk_low_used - hunk_high_used < size) {
|
if (hunk_size - hunk_low_used - hunk_high_used < size) {
|
||||||
Sys_Printf ("Hunk_HighAlloc: failed on %i bytes\n", size);
|
Sys_Printf ("Hunk_HighAlloc: failed on %i bytes\n", size);
|
||||||
|
@ -508,15 +513,8 @@ Hunk_HighAllocName (int size, const char *name)
|
||||||
}
|
}
|
||||||
|
|
||||||
hunk_high_used += size;
|
hunk_high_used += size;
|
||||||
Cache_FreeHigh (hunk_high_used);
|
|
||||||
|
|
||||||
h = (hunk_t *) (hunk_base + hunk_size - hunk_high_used);
|
return (void *) (hunk_base + hunk_size - hunk_high_used);
|
||||||
|
|
||||||
h->size = size;
|
|
||||||
h->sentinal = HUNK_SENTINAL;
|
|
||||||
strncpy (h->name, name, 8);
|
|
||||||
|
|
||||||
return (void *) (h + 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -541,7 +539,7 @@ Hunk_TempAlloc (int size)
|
||||||
|
|
||||||
hunk_tempmark = Hunk_HighMark ();
|
hunk_tempmark = Hunk_HighMark ();
|
||||||
|
|
||||||
buf = Hunk_HighAllocName (size, "temp");
|
buf = Hunk_HighAlloc (size);
|
||||||
|
|
||||||
hunk_tempactive = true;
|
hunk_tempactive = true;
|
||||||
|
|
||||||
|
@ -550,19 +548,19 @@ Hunk_TempAlloc (int size)
|
||||||
|
|
||||||
/* CACHE MEMORY */
|
/* CACHE MEMORY */
|
||||||
|
|
||||||
typedef struct cache_system_s {
|
typedef struct cache_system_s cache_system_t;
|
||||||
cache_user_t *user;
|
struct cache_system_s {
|
||||||
|
cache_system_t *prev, *next;
|
||||||
|
cache_system_t *lru_prev, *lru_next; // for LRU flushing
|
||||||
char name[16];
|
char name[16];
|
||||||
int size; // including this header
|
size_t size; // including this header
|
||||||
int readlock;
|
int readlock;
|
||||||
struct cache_system_s *prev, *next;
|
cache_user_t *user;
|
||||||
struct cache_system_s *lru_prev, *lru_next; // for LRU flushing
|
};
|
||||||
} cache_system_t;
|
|
||||||
|
|
||||||
static cache_system_t cache_head;
|
static cache_system_t cache_head;
|
||||||
|
|
||||||
static cache_system_t *Cache_TryAlloc (int size, qboolean nobottom);
|
static cache_system_t *Cache_TryAlloc (size_t size, qboolean nobottom);
|
||||||
static void Cache_Profile (void);
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
Cache_Move (cache_system_t * c)
|
Cache_Move (cache_system_t * c)
|
||||||
|
@ -597,46 +595,22 @@ Cache_FreeLow (int new_low_hunk)
|
||||||
cache_system_t *c;
|
cache_system_t *c;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
c = cache_head.next;
|
c = cache_head.prev;
|
||||||
if (c == &cache_head)
|
if (c == &cache_head)
|
||||||
return; // nothing in cache at all
|
return; // nothing in cache at all
|
||||||
if ((byte *) c >= hunk_base + new_low_hunk)
|
if ((byte *) c >= hunk_base + new_low_hunk)
|
||||||
return; // there is space to grow the hunk
|
return; // there is space to grow the hunk
|
||||||
|
Sys_Error ("FIXME: Cache_FreeLow: not enough memory");
|
||||||
Cache_Move (c); // reclaim the space
|
Cache_Move (c); // reclaim the space
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
Cache_FreeHigh
|
|
||||||
|
|
||||||
Throw things out until the hunk can be expanded to the given point
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
Cache_FreeHigh (int new_high_hunk)
|
|
||||||
{
|
|
||||||
cache_system_t *c, *prev;
|
|
||||||
|
|
||||||
prev = NULL;
|
|
||||||
while (1) {
|
|
||||||
c = cache_head.prev;
|
|
||||||
if (c == &cache_head)
|
|
||||||
return; // nothing in cache at all
|
|
||||||
if ((byte *) c + c->size <= hunk_base + hunk_size - new_high_hunk)
|
|
||||||
return; // there is space to grow the hunk
|
|
||||||
if (c == prev)
|
|
||||||
Cache_Free (c->user); // didn't move out of the way
|
|
||||||
else {
|
|
||||||
Cache_Move (c); // try to move it
|
|
||||||
prev = c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
Cache_UnlinkLRU (cache_system_t * cs)
|
Cache_UnlinkLRU (cache_system_t * cs)
|
||||||
{
|
{
|
||||||
if (!cs->lru_next || !cs->lru_prev)
|
if (!cs->lru_next || !cs->lru_prev)
|
||||||
Sys_Error ("Cache_UnlinkLRU: NULL link");
|
Sys_Error ("Cache_UnlinkLRU: NULL link: %s %p %p",
|
||||||
|
cs->name, cs->lru_next, cs->lru_prev);
|
||||||
|
|
||||||
cs->lru_next->lru_prev = cs->lru_prev;
|
cs->lru_next->lru_prev = cs->lru_prev;
|
||||||
cs->lru_prev->lru_next = cs->lru_next;
|
cs->lru_prev->lru_next = cs->lru_next;
|
||||||
|
@ -648,7 +622,8 @@ static inline void
|
||||||
Cache_MakeLRU (cache_system_t * cs)
|
Cache_MakeLRU (cache_system_t * cs)
|
||||||
{
|
{
|
||||||
if (cs->lru_next || cs->lru_prev)
|
if (cs->lru_next || cs->lru_prev)
|
||||||
Sys_Error ("Cache_MakeLRU: active link");
|
Sys_Error ("Cache_MakeLRU: active link: %s %p %p",
|
||||||
|
cs->name, cs->lru_next, cs->lru_prev);
|
||||||
|
|
||||||
cache_head.lru_next->lru_prev = cs;
|
cache_head.lru_next->lru_prev = cs;
|
||||||
cs->lru_next = cache_head.lru_next;
|
cs->lru_next = cache_head.lru_next;
|
||||||
|
@ -656,12 +631,27 @@ Cache_MakeLRU (cache_system_t * cs)
|
||||||
cache_head.lru_next = cs;
|
cache_head.lru_next = cs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
check_cache (void)
|
||||||
|
{
|
||||||
|
cache_system_t *cs;
|
||||||
|
|
||||||
|
for (cs = cache_head.prev; cs != &cache_head; cs = cs->prev)
|
||||||
|
if (cs->prev != &cache_head
|
||||||
|
&& (byte *) cs + cs->size != (byte *) cs->prev)
|
||||||
|
Sys_Error ("inconsistent cache %p %p %d %d", cs, cs->prev,
|
||||||
|
(int)cs->size,
|
||||||
|
(int) ((char *)cs->prev - (char *)cs));
|
||||||
|
}
|
||||||
|
|
||||||
static qboolean
|
static qboolean
|
||||||
Cache_FreeLRU (void)
|
Cache_FreeLRU (void)
|
||||||
{
|
{
|
||||||
cache_system_t *cs;
|
cache_system_t *cs;
|
||||||
|
|
||||||
for (cs = cache_head.lru_prev; cs->readlock; cs = cs->lru_prev)
|
check_cache ();
|
||||||
|
for (cs = cache_head.lru_prev;
|
||||||
|
cs != &cache_head && cs->readlock; cs = cs->lru_prev)
|
||||||
;
|
;
|
||||||
if (cs == &cache_head)
|
if (cs == &cache_head)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -669,6 +659,16 @@ Cache_FreeLRU (void)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
link_cache_system (cache_system_t *new, cache_system_t *cs)
|
||||||
|
{
|
||||||
|
new->next = cs;
|
||||||
|
new->prev = cs->prev;
|
||||||
|
cs->prev->next = new;
|
||||||
|
cs->prev = new;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Cache_TryAlloc
|
Cache_TryAlloc
|
||||||
|
|
||||||
|
@ -676,195 +676,58 @@ Cache_FreeLRU (void)
|
||||||
Size should already include the header and padding
|
Size should already include the header and padding
|
||||||
*/
|
*/
|
||||||
static cache_system_t *
|
static cache_system_t *
|
||||||
Cache_TryAlloc (int size, qboolean nobottom)
|
Cache_TryAlloc (size_t size, qboolean nobottom)
|
||||||
{
|
{
|
||||||
cache_system_t *cs, *new;
|
cache_system_t *cs, *new;
|
||||||
|
|
||||||
// is the cache completely empty?
|
// is the cache completely empty?
|
||||||
|
|
||||||
if (!nobottom && cache_head.prev == &cache_head) {
|
if (!nobottom && cache_head.prev == &cache_head) {
|
||||||
if (hunk_size - hunk_high_used - hunk_low_used < size) {
|
new = (cache_system_t *) Hunk_HighAlloc (size);
|
||||||
Sys_Printf ("Cache_TryAlloc: %i is greater then free hunk", size);
|
if (!new)
|
||||||
return NULL;
|
return 0;
|
||||||
}
|
memset (new, 0, size);
|
||||||
|
|
||||||
new = (cache_system_t *) (hunk_base + hunk_low_used);
|
|
||||||
memset (new, 0, sizeof (*new));
|
|
||||||
new->size = size;
|
new->size = size;
|
||||||
|
|
||||||
cache_head.prev = cache_head.next = new;
|
cache_head.prev = cache_head.next = new;
|
||||||
new->prev = new->next = &cache_head;
|
new->prev = new->next = &cache_head;
|
||||||
|
|
||||||
Cache_MakeLRU (new);
|
Cache_MakeLRU (new);
|
||||||
return new;
|
return new;
|
||||||
}
|
}
|
||||||
|
|
||||||
// search from the bottom up for space
|
// search for space in existing cache
|
||||||
|
for (cs = cache_head.next; cs != &cache_head; cs = cs->next) {
|
||||||
new = (cache_system_t *) (hunk_base + hunk_low_used);
|
if (cs->user)
|
||||||
cs = cache_head.next;
|
continue; // block isn't free
|
||||||
|
if (cs->size >= size) {
|
||||||
do {
|
// found a big enough free block. If possible, carve it up for
|
||||||
if (!nobottom || cs != cache_head.next) {
|
// later reuse, using the upper portion of the block for the
|
||||||
if ((byte *) cs - (byte *) new >= size) { // found space
|
// newly allocated block.
|
||||||
memset (new, 0, sizeof (*new));
|
new = cs;
|
||||||
|
if (size - cs->size >= sizeof (cache_system_t)) {
|
||||||
|
new = (cache_system_t *) ((char *) cs + cs->size - size);
|
||||||
|
memset (new, 0, size);
|
||||||
new->size = size;
|
new->size = size;
|
||||||
|
cs->size -= size;
|
||||||
new->next = cs;
|
link_cache_system (new, cs);
|
||||||
new->prev = cs->prev;
|
|
||||||
cs->prev->next = new;
|
|
||||||
cs->prev = new;
|
|
||||||
|
|
||||||
Cache_MakeLRU (new);
|
|
||||||
|
|
||||||
return new;
|
|
||||||
}
|
}
|
||||||
|
Cache_MakeLRU (new);
|
||||||
|
return new;
|
||||||
}
|
}
|
||||||
// continue looking
|
}
|
||||||
new = (cache_system_t *) ((byte *) cs + cs->size);
|
|
||||||
cs = cs->next;
|
|
||||||
|
|
||||||
} while (cs != &cache_head);
|
if (nobottom)
|
||||||
|
return 0;
|
||||||
|
|
||||||
// try to allocate one at the very end
|
// didn't find a free block, so make a new one.
|
||||||
if (hunk_base + hunk_size - hunk_high_used - (byte *) new >= size) {
|
new = Hunk_HighAlloc (size);
|
||||||
memset (new, 0, sizeof (*new));
|
if (new) {
|
||||||
|
memset (new, 0, size);
|
||||||
new->size = size;
|
new->size = size;
|
||||||
|
link_cache_system (new, &cache_head);
|
||||||
new->next = &cache_head;
|
|
||||||
new->prev = cache_head.prev;
|
|
||||||
cache_head.prev->next = new;
|
|
||||||
cache_head.prev = new;
|
|
||||||
|
|
||||||
Cache_MakeLRU (new);
|
Cache_MakeLRU (new);
|
||||||
|
|
||||||
return new;
|
return new;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL; // couldn't allocate
|
return 0; // couldn't allocate
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Cache_Flush
|
|
||||||
|
|
||||||
Throw everything out, so new data will be demand cached
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
Cache_Flush (void)
|
|
||||||
{
|
|
||||||
while (cache_head.next != &cache_head) {
|
|
||||||
if (!cache_head.next->user->data)
|
|
||||||
Sys_Error ("Cache_Flush: user/system out of sync for "
|
|
||||||
"'%s' with %d size",
|
|
||||||
cache_head.next->name, cache_head.next->size);
|
|
||||||
Cache_Free (cache_head.next->user); // reclaim the space
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
Cache_Print (void)
|
|
||||||
{
|
|
||||||
cache_system_t *cd;
|
|
||||||
|
|
||||||
for (cd = cache_head.next; cd != &cache_head; cd = cd->next) {
|
|
||||||
Sys_Printf ("%8i : %s\n", cd->size, cd->name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VISIBLE void
|
|
||||||
Cache_Report (void)
|
|
||||||
{
|
|
||||||
Sys_DPrintf ("%4.1f megabyte data cache\n",
|
|
||||||
(hunk_size - hunk_high_used -
|
|
||||||
hunk_low_used) / (float) (1024 * 1024));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
Cache_Init (void)
|
|
||||||
{
|
|
||||||
cache_head.next = cache_head.prev = &cache_head;
|
|
||||||
cache_head.lru_next = cache_head.lru_prev = &cache_head;
|
|
||||||
|
|
||||||
Cmd_AddCommand ("cache_flush", Cache_Flush, "Clears the current game "
|
|
||||||
"cache");
|
|
||||||
Cmd_AddCommand ("cache_profile", Cache_Profile, "Prints a profile of "
|
|
||||||
"the current cache");
|
|
||||||
Cmd_AddCommand ("cache_print", Cache_Print, "Prints out items in the "
|
|
||||||
"cache");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Cache_Free
|
|
||||||
|
|
||||||
Frees the memory and removes it from the LRU list
|
|
||||||
*/
|
|
||||||
VISIBLE void
|
|
||||||
Cache_Free (cache_user_t *c)
|
|
||||||
{
|
|
||||||
cache_system_t *cs;
|
|
||||||
|
|
||||||
if (!c->data)
|
|
||||||
Sys_Error ("Cache_Free: not allocated");
|
|
||||||
|
|
||||||
cs = ((cache_system_t *) c->data) - 1;
|
|
||||||
|
|
||||||
Sys_DPrintf ("Cache_Free: freeing '%s'\n", cs->name);
|
|
||||||
|
|
||||||
cs->prev->next = cs->next;
|
|
||||||
cs->next->prev = cs->prev;
|
|
||||||
cs->next = cs->prev = NULL;
|
|
||||||
|
|
||||||
c->data = NULL;
|
|
||||||
|
|
||||||
Cache_UnlinkLRU (cs);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
VISIBLE void *
|
|
||||||
Cache_Check (cache_user_t *c)
|
|
||||||
{
|
|
||||||
cache_system_t *cs;
|
|
||||||
|
|
||||||
if (!c->data)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
cs = ((cache_system_t *) c->data) - 1;
|
|
||||||
|
|
||||||
// move to head of LRU
|
|
||||||
Cache_UnlinkLRU (cs);
|
|
||||||
Cache_MakeLRU (cs);
|
|
||||||
|
|
||||||
return c->data;
|
|
||||||
}
|
|
||||||
|
|
||||||
VISIBLE void *
|
|
||||||
Cache_Alloc (cache_user_t *c, int size, const char *name)
|
|
||||||
{
|
|
||||||
cache_system_t *cs;
|
|
||||||
|
|
||||||
if (c->data)
|
|
||||||
Sys_Error ("Cache_Alloc: already allocated");
|
|
||||||
|
|
||||||
if (size <= 0)
|
|
||||||
Sys_Error ("Cache_Alloc: size %i", size);
|
|
||||||
|
|
||||||
size = (size + sizeof (cache_system_t) + 15) & ~15;
|
|
||||||
|
|
||||||
// find memory for it
|
|
||||||
while (1) {
|
|
||||||
cs = Cache_TryAlloc (size, false);
|
|
||||||
if (cs) {
|
|
||||||
strncpy (cs->name, name, sizeof (cs->name) - 1);
|
|
||||||
c->data = (void *) (cs + 1);
|
|
||||||
cs->user = c;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// free the least recently used cachedat
|
|
||||||
if (!Cache_FreeLRU())
|
|
||||||
Sys_Error ("Cache_Alloc: out of memory");
|
|
||||||
}
|
|
||||||
|
|
||||||
return Cache_Check (c);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -900,6 +763,149 @@ Cache_Profile (void)
|
||||||
" %d per allocation\n", total, count, total / count);
|
" %d per allocation\n", total, count, total / count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
Cache_Print (void)
|
||||||
|
{
|
||||||
|
cache_system_t *cd;
|
||||||
|
|
||||||
|
for (cd = cache_head.next; cd != &cache_head; cd = cd->next) {
|
||||||
|
Sys_Printf ("%8d : %s\n", (int) cd->size, cd->name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
Cache_Init (void)
|
||||||
|
{
|
||||||
|
cache_head.next = cache_head.prev = &cache_head;
|
||||||
|
cache_head.lru_next = cache_head.lru_prev = &cache_head;
|
||||||
|
cache_head.user = (cache_user_t *) 1; // make it look allocated
|
||||||
|
cache_head.readlock = 1; // don't try to free or move it
|
||||||
|
|
||||||
|
Cmd_AddCommand ("cache_flush", Cache_Flush, "Clears the current game "
|
||||||
|
"cache");
|
||||||
|
Cmd_AddCommand ("cache_profile", Cache_Profile, "Prints a profile of "
|
||||||
|
"the current cache");
|
||||||
|
Cmd_AddCommand ("cache_print", Cache_Print, "Prints out items in the "
|
||||||
|
"cache");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Cache_Flush
|
||||||
|
|
||||||
|
Throw everything out, so new data will be demand cached
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
Cache_Flush (void)
|
||||||
|
{
|
||||||
|
while (cache_head.next != &cache_head) {
|
||||||
|
if (!cache_head.next->user->data)
|
||||||
|
Sys_Error ("Cache_Flush: user/system out of sync for "
|
||||||
|
"'%s' with %d size",
|
||||||
|
cache_head.next->name, (int) cache_head.next->size);
|
||||||
|
Cache_Free (cache_head.next->user); // reclaim the space
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VISIBLE void *
|
||||||
|
Cache_Check (cache_user_t *c)
|
||||||
|
{
|
||||||
|
cache_system_t *cs;
|
||||||
|
|
||||||
|
if (!c->data)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
cs = ((cache_system_t *) c->data) - 1;
|
||||||
|
|
||||||
|
// move to head of LRU
|
||||||
|
Cache_UnlinkLRU (cs);
|
||||||
|
Cache_MakeLRU (cs);
|
||||||
|
|
||||||
|
return c->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Cache_Free
|
||||||
|
|
||||||
|
Frees the memory and removes it from the LRU list
|
||||||
|
*/
|
||||||
|
VISIBLE void
|
||||||
|
Cache_Free (cache_user_t *c)
|
||||||
|
{
|
||||||
|
cache_system_t *cs;
|
||||||
|
|
||||||
|
if (!c->data)
|
||||||
|
Sys_Error ("Cache_Free: not allocated");
|
||||||
|
|
||||||
|
cs = ((cache_system_t *) c->data) - 1;
|
||||||
|
|
||||||
|
if (cs->readlock)
|
||||||
|
Sys_Error ("Cache_Free: attempt to free locked block");
|
||||||
|
|
||||||
|
Sys_DPrintf ("Cache_Free: freeing '%s' %p\n", cs->name, cs);
|
||||||
|
|
||||||
|
Cache_UnlinkLRU (cs);
|
||||||
|
|
||||||
|
//check_cache ();
|
||||||
|
cs->user = 0;
|
||||||
|
if (!cs->prev->user) {
|
||||||
|
cs->size += cs->prev->size;
|
||||||
|
cs->prev->prev->next = cs;
|
||||||
|
cs->prev = cs->prev->prev;
|
||||||
|
}
|
||||||
|
if (!cs->next->user) {
|
||||||
|
cs = cs->next;
|
||||||
|
cs->size += cs->prev->size;
|
||||||
|
cs->prev->prev->next = cs;
|
||||||
|
cs->prev = cs->prev->prev;
|
||||||
|
}
|
||||||
|
if (cs->next == &cache_head) {
|
||||||
|
cs->next->prev = cs->prev;
|
||||||
|
cs->prev->next = cs->next;
|
||||||
|
Hunk_FreeToHighMark (hunk_high_used - cs->size);
|
||||||
|
}
|
||||||
|
//check_cache ();
|
||||||
|
|
||||||
|
c->data = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
VISIBLE void *
|
||||||
|
Cache_Alloc (cache_user_t *c, int size, const char *name)
|
||||||
|
{
|
||||||
|
cache_system_t *cs;
|
||||||
|
|
||||||
|
if (c->data)
|
||||||
|
Sys_Error ("Cache_Alloc: already allocated");
|
||||||
|
|
||||||
|
if (size <= 0)
|
||||||
|
Sys_Error ("Cache_Alloc: size %i", size);
|
||||||
|
|
||||||
|
size = (size + sizeof (cache_system_t) + 15) & ~15;
|
||||||
|
|
||||||
|
// find memory for it
|
||||||
|
while (1) {
|
||||||
|
cs = Cache_TryAlloc (size, false);
|
||||||
|
if (cs) {
|
||||||
|
strncpy (cs->name, name, sizeof (cs->name) - 1);
|
||||||
|
c->data = (void *) (cs + 1);
|
||||||
|
cs->user = c;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// free the least recently used cachedat
|
||||||
|
if (!Cache_FreeLRU())
|
||||||
|
Sys_Error ("Cache_Alloc: out of memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Cache_Check (c);
|
||||||
|
}
|
||||||
|
|
||||||
|
VISIBLE void
|
||||||
|
Cache_Report (void)
|
||||||
|
{
|
||||||
|
Sys_DPrintf ("%4.1f megabyte data cache\n",
|
||||||
|
(hunk_size - hunk_high_used -
|
||||||
|
hunk_low_used) / (float) (1024 * 1024));
|
||||||
|
}
|
||||||
|
|
||||||
VISIBLE void
|
VISIBLE void
|
||||||
Cache_Add (cache_user_t *c, void *object, cache_loader_t loader)
|
Cache_Add (cache_user_t *c, void *object, cache_loader_t loader)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue