[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH v9 01/10] Add cache handling functions
From: |
Anthony Liguori |
Subject: |
Re: [Qemu-devel] [PATCH v9 01/10] Add cache handling functions |
Date: |
Wed, 18 Apr 2012 12:19:20 -0500 |
User-agent: |
Mozilla/5.0 (X11; Linux x86_64; rv:11.0) Gecko/20120329 Thunderbird/11.0.1 |
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.
+{
+ 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
+ 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.
+ 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.
+ 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.
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;
[Qemu-devel] [PATCH v9 04/10] Add host_from_stream_offset_versioned function, Orit Wasserman, 2012/04/11