qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH v9 01/10] Add cache handling functions


From: Orit Wasserman
Subject: Re: [Qemu-devel] [PATCH v9 01/10] Add cache handling functions
Date: Thu, 19 Apr 2012 09:32:05 +0300
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:11.0) Gecko/20120329 Thunderbird/11.0.1

On 04/18/2012 08:19 PM, Anthony Liguori wrote:
> On 04/11/2012 01:49 PM, Orit Wasserman wrote:
>> Add LRU page cache mechanism.
>> The page are accessed by their address.
>>
>> Signed-off-by: Orit Wasserman<address@hidden>
>> Signed-off-by: Benoit Hudzia<address@hidden>
>> Signed-off-by: Petter Svard<address@hidden>
>> Signed-off-by: Aidan Shribman<address@hidden>
>> ---
>>   arch_init.c |  220 
>> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>   1 files changed, 220 insertions(+), 0 deletions(-)
>>
>> diff --git a/arch_init.c b/arch_init.c
>> index 595badf..2e534f1 100644
>> --- a/arch_init.c
>> +++ b/arch_init.c
>> @@ -28,6 +28,7 @@
>>   #include<sys/types.h>
>>   #include<sys/mman.h>
>>   #endif
>> +#include<assert.h>
>>   #include "config.h"
>>   #include "monitor.h"
>>   #include "sysemu.h"
>> @@ -44,6 +45,14 @@
>>   #include "exec-memory.h"
>>   #include "hw/pcspk.h"
>>
>> +#ifdef DEBUG_ARCH_INIT
>> +#define DPRINTF(fmt, ...) \
>> +    do { fprintf(stdout, "arch_init: " fmt, ## __VA_ARGS__); } while (0)
>> +#else
>> +#define DPRINTF(fmt, ...) \
>> +    do { } while (0)
>> +#endif
>> +
>>   #ifdef TARGET_SPARC
>>   int graphic_width = 1024;
>>   int graphic_height = 768;
>> @@ -127,6 +136,217 @@ static int is_dup_page(uint8_t *page)
>>       return 1;
>>   }
>>
>> +/***********************************************************/
>> +/* Page cache for storing previous pages as basis for XBZRLE compression */
>> +#define CACHE_N_WAY 2 /* 2-way assossiative cache */
>> +
>> +typedef struct CacheItem {
>> +    ram_addr_t it_addr;
>> +    unsigned long it_age;
>> +    uint8_t *it_data;
>> +} CacheItem;
>> +
>> +typedef struct CacheBucket {
>> +    CacheItem bkt_item[CACHE_N_WAY];
>> +} CacheBucket;
>> +
>> +static CacheBucket *page_cache;
>> +static int64_t cache_num_buckets;
>> +static uint64_t cache_max_item_age;
>> +static int64_t cache_num_items;
>> +
>> +static void cache_init(int64_t num_buckets);
>> +static void cache_fini(void);
>> +static int cache_is_cached(ram_addr_t addr);
>> +static int cache_get_oldest(CacheBucket *buck);
>> +static int cache_get_newest(CacheBucket *buck, ram_addr_t addr);
>> +static void cache_insert(ram_addr_t id, uint8_t *pdata, int use_buffer);
>> +static unsigned long cache_get_cache_pos(ram_addr_t address);
>> +static CacheItem *cache_item_get(unsigned long pos, int item);
>> +static void cache_resize(int64_t new_size);
>> +
>> +/***********************************************************/
>> +/* XBRLE page cache implementation */
>> +static CacheItem *cache_item_get(unsigned long pos, int item)
>> +{
>> +    assert(page_cache);
>> +    return&page_cache[pos].bkt_item[item];
>> +}
>> +
>> +static void cache_init(int64_t num_bytes)
> 
> If we're caching pages, let's take a num_pages argument.  Then we can avoid 
> TARGET_PAGE_SIZE and move this to it's own cache.c file and build it once.
> 
> Let's also make a proper header (include/qemu/cache.h) and document the 
> public functions.  I really am not convinced we need a custom data structure 
> here but if we're going to add one, we should make at least a small attempt 
> to make it reusable.

I will look again into glib to see if I can find a data structure I can use.
If not, I will add the cache.h/cache.c and the documentation.

> 
>> +{
>> +    int i;
>> +
>> +    cache_num_items = 0;
>> +    cache_max_item_age = 0;
>> +    cache_num_buckets = num_bytes / (TARGET_PAGE_SIZE * CACHE_N_WAY);
>> +    assert(cache_num_buckets);
> 
> use g_assert instead and drop the explicit include of assert.h
> 
>> +    DPRINTF("Setting cache buckets to %lu\n", cache_num_buckets);
>> +
>> +    assert(!page_cache);
> 
> return page_cache instead of using a global
OK 
> 
>> +    page_cache = (CacheBucket *)g_malloc((cache_num_buckets) *
>> +            sizeof(CacheBucket));
>> +
>> +    for (i = 0; i<  cache_num_buckets; i++) {
>> +        int j;
>> +        for (j = 0; j<  CACHE_N_WAY; j++) {
>> +            CacheItem *it = cache_item_get(i, j);
>> +            it->it_data = NULL;
>> +            it->it_age = 0;
>> +            it->it_addr = -1;
>> +        }
>> +    }
>> +}
>> +
>> +static void cache_fini(void)
>> +{
>> +    int i;
> 
> 
> Take page_cache as an argument here.
OK
> 
>> +    assert(page_cache);
>> +
>> +    for (i = 0; i<  cache_num_buckets; i++) {
>> +        int j;
>> +        for (j = 0; j<  CACHE_N_WAY; j++) {
>> +            CacheItem *it = cache_item_get(i, j);
>> +            g_free(it->it_data);
>> +            it->it_data = 0;
>> +        }
>> +    }
>> +
>> +    g_free(page_cache);
>> +    page_cache = NULL;
>> +}
>> +
>> +static unsigned long cache_get_cache_pos(ram_addr_t address)
>> +{
>> +    unsigned long pos;
>> +
>> +    assert(cache_num_buckets);
> 
> And here, etc.
OK
> 
>> +    pos = (address/TARGET_PAGE_SIZE)&  (cache_num_buckets - 1);
>> +    return pos;
>> +}
>> +
>> +static int cache_get_newest(CacheBucket *buck, ram_addr_t addr)
>> +{
>> +    unsigned long big = 0;
>> +    int big_pos = -1;
>> +    int j;
>> +
>> +    assert(page_cache);
>> +
>> +    for (j = 0; j<  CACHE_N_WAY; j++) {
>> +        CacheItem *it =&buck->bkt_item[j];
>> +
>> +        if (it->it_addr != addr) {
>> +            continue;
>> +        }
>> +
>> +        if (!j || it->it_age>  big) {
>> +            big = it->it_age;
>> +            big_pos = j;
>> +        }
>> +    }
>> +
>> +    return big_pos;
>> +}
>> +
>> +static int cache_get_oldest(CacheBucket *buck)
>> +{
>> +    unsigned long small = 0;
>> +    int small_pos = -1;
>> +    int j;
>> +
>> +    assert(page_cache);
>> +
>> +    for (j = 0; j<  CACHE_N_WAY; j++) {
>> +        CacheItem *it =&buck->bkt_item[j];
>> +
>> +        if (!j || it->it_age<   small) {
>> +            small = it->it_age;
>> +            small_pos = j;
>> +        }
>> +    }
>> +
>> +    return small_pos;
>> +}
>> +
>> +static int cache_is_cached(ram_addr_t addr)
>> +{
>> +    unsigned long pos = cache_get_cache_pos(addr);
>> +
>> +    assert(page_cache);
>> +    CacheBucket *bucket =&page_cache[pos];
>> +    return cache_get_newest(bucket, addr);
>> +}
>> +
>> +static void cache_insert(unsigned long addr, uint8_t *pdata, int use_buffer)
>> +{
>> +    unsigned long pos;
>> +    int slot = -1;
>> +    CacheBucket *bucket;
>> +
>> +    pos = cache_get_cache_pos(addr);
>> +    assert(page_cache);
>> +    bucket =&page_cache[pos];
>> +    slot = cache_get_oldest(bucket); /* evict LRU */
>> +
>> +    /* actual update of entry */
>> +    CacheItem *it = cache_item_get(pos, slot);
> 
> This is done a lot.  We don't use C99 declarations in QEMU.  Please move all 
> the variable declarations to the top of the functions.
OK

Thanks,
Orit

> 
> Regards,
> 
> Anthony Liguori
> 
> 
>> +    if (!it->it_data) {
>> +        if (!use_buffer) {
>> +            it->it_data = g_malloc(TARGET_PAGE_SIZE);
>> +        }
>> +        cache_num_items++;
>> +    }
>> +
>> +    if (!use_buffer) {
>> +        memcpy(it->it_data, pdata, TARGET_PAGE_SIZE);
>> +    } else {
>> +        it->it_data = pdata;
>> +    }
>> +    it->it_age = ++cache_max_item_age;
>> +    it->it_addr = addr;
>> +}
>> +
>> +void cache_resize(int64_t new_size)
>> +{
>> +    int64_t new_num_buckets = new_size/(TARGET_PAGE_SIZE * CACHE_N_WAY);
>> +    CacheBucket *old_page_cache = page_cache;
>> +    int i;
>> +    int64_t old_num_buckets = cache_num_buckets;
>> +
>> +    /* same size */
>> +    if (new_num_buckets == cache_num_buckets) {
>> +        return;
>> +    }
>> +    /* cache was not inited */
>> +    if (page_cache == NULL) {
>> +        return;
>> +    }
>> +
>> +    /* create a new cache */
>> +    page_cache = NULL;
>> +    cache_init(new_size);
>> +
>> +    /* move all data from old cache */
>> +    for (i = 0; i<  old_num_buckets; i++) {
>> +        int j;
>> +        for (j = 0; j<  CACHE_N_WAY; j++) {
>> +            CacheItem *it =&old_page_cache[i].bkt_item[j];
>> +            if (it->it_addr != -1) {
>> +                /* check for collision , if there is keep the first value */
>> +                if (cache_is_cached(it->it_addr) != -1) {
>> +                    g_free(it->it_data);
>> +                } else {
>> +                    cache_insert(it->it_addr, it->it_data, 1);
>> +                }
>> +            }
>> +        }
>> +    }
>> +
>> +    g_free(old_page_cache);
>> +}
>> +
>>   static RAMBlock *last_block;
>>   static ram_addr_t last_offset;
>>
> 




reply via email to

[Prev in Thread] Current Thread [Next in Thread]