[PATCH 05/10] Invalidate or shrink dcache when setting is changed.

Yao Qi
2013-11-03T05:56:55Z

Nowadays, when cache size or line size is changed by command,
'target_dcache' is invalidated. It is too conservative. We can
optimize in the following ways,

- Don't have to invalidate dcache immediately after cache size or
line size is changed. We can postpone the invalidation to the moment
using 'target_dcache'.
- Don't have to invalidate dcache if the cache size is changed. If
cache size is changed to the value which is still greater than
dcache's size, nothing should be done. If change to the value
which is less than dcache's size, just evict cache lines.

This is what this patch does.

gdb:

2013-11-02 Yao Qi <yao@codesourcery.com>

* dcache.c (dcache_evict): New function.
(dcache_shrink): New function.
(dcache_invalidate_p): New function.
(dcache_alloc): Call dcache_evict.
(set_dcache_size): Remove call target_dcache_invalidate.
(set_dcache_line_size): Likewise.
* dcache.h (dcache_shrink): Declare.
(dcache_invalidate_p): Declare.
* target-dcache.c (target_dcache_get): Invalidate and shrink
cache if necessary.
(target_dcache_get_or_init): Likewise.

gdb/doc:

2013-11-02 Yao Qi <yao@codesourcery.com>

* gdb.texinfo (Caching Target Data): Update document of
commands 'set dcache size' and 'set dcache line-size'.
---
gdb/dcache.c | 47 ++++++++++++++++++++++++++++++++++++++---------
gdb/dcache.h | 4 ++++
gdb/doc/gdb.texinfo | 7 +++++--
gdb/target-dcache.c | 17 ++++++++++++++++-
4 files changed, 63 insertions(+), 12 deletions(-)

diff --git a/gdb/dcache.c b/gdb/dcache.c
index 5b32629..09ff2db 100644
--- a/gdb/dcache.c
+++ b/gdb/dcache.c
@@ -243,6 +243,43 @@ invalidate_block (struct dcache_block *block, void *param)
append_block (&dcache->freelist, block);
}

+/* Evict the cache line decided by the eviction algorithm. Return the
+ evicted cache line. */
+
+static struct dcache_block *
+dcache_evict (DCACHE *dcache)
+{
+ /* Evict the least recently allocated line. */
+ struct dcache_block *db = dcache->oldest;
+
+ remove_block (&dcache->oldest, db);
+ splay_tree_remove (dcache->tree, (splay_tree_key) db->addr);
+
+ return db;
+}
+
+/* Shrink DCACHE if it is over-sized. */
+
+void
+dcache_shrink (DCACHE *dcache)
+{
+ while (dcache->size > dcache_size)
+ {
+ struct dcache_block *db = dcache_evict (dcache);
+
+ free_block (db, NULL);
+ dcache->size--;
+ }
+}
+
+/* Return true if DCACHE should be invalidated. */
+
+int
+dcache_invalidate_p (DCACHE *dcache)
+{
+ return (dcache->line_size != dcache_line_size);
+}
+
/* Free all the data cache blocks, thus discarding all cached data. */

void
@@ -359,13 +396,7 @@ dcache_alloc (DCACHE *dcache, CORE_ADDR addr)
struct dcache_block *db;

if (dcache->size >= dcache_size)
- {
- /* Evict the least recently allocated line. */
- db = dcache->oldest;
- remove_block (&dcache->oldest, db);
-
- splay_tree_remove (dcache->tree, (splay_tree_key) db->addr);
- }
+ db = dcache_evict (dcache);
else
{
db = dcache->freelist;
@@ -669,7 +700,6 @@ set_dcache_size (char *args, int from_tty,
dcache_size = DCACHE_DEFAULT_SIZE;
error (_("Dcache size must be greater than 0."));
}
- target_dcache_invalidate ();
}

static void
@@ -683,7 +713,6 @@ set_dcache_line_size (char *args, int from_tty,
dcache_line_size = DCACHE_DEFAULT_LINE_SIZE;
error (_("Invalid dcache line size: %u (must be power of 2)."), d);
}
- target_dcache_invalidate ();
}

static void
diff --git a/gdb/dcache.h b/gdb/dcache.h
index 720a887..101c2ce 100644
--- a/gdb/dcache.h
+++ b/gdb/dcache.h
@@ -40,4 +40,8 @@ int dcache_xfer_memory (struct target_ops *ops, DCACHE *cache, CORE_ADDR mem,
void dcache_update (DCACHE *dcache, CORE_ADDR memaddr, gdb_byte *myaddr,
int len);

+void dcache_shrink (DCACHE *dcache);
+
+int dcache_invalidate_p (DCACHE *dcache);
+
#endif /* DCACHE_H */
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 4d72983..561243b 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -10863,13 +10863,16 @@ printed in hex.
@item set dcache size @var{size}
@cindex dcache size
@kindex set dcache size
-Set maximum number of entries in dcache (dcache depth above).
+Set maximum number of entries in dcache (dcache depth above). When
+the dcache is being used, its size is greater than this setting, it
+is shrunk.

@item set dcache line-size @var{line-size}
@cindex dcache line-size
@kindex set dcache line-size
Set number of bytes each dcache entry caches (dcache width above).
-Must be a power of 2.
+Must be a power of 2. When the dcache is being used, its width is
+different from this setting, it is invalidated.

@item show dcache size
@kindex show dcache size
diff --git a/gdb/target-dcache.c b/gdb/target-dcache.c
index bf04679..28f1aa6 100644
--- a/gdb/target-dcache.c
+++ b/gdb/target-dcache.c
@@ -45,6 +45,14 @@ target_dcache_invalidate (void)
DCACHE *
target_dcache_get (void)
{
+ if (target_dcache_init_p ())
+ {
+ if (dcache_invalidate_p (target_dcache))
+ dcache_invalidate (target_dcache);
+
+ dcache_shrink (target_dcache);
+ }
+
return target_dcache;
}

@@ -54,7 +62,14 @@ target_dcache_get (void)
DCACHE *
target_dcache_get_or_init (void)
{
- if (!target_dcache_init_p ())
+ if (target_dcache_init_p ())
+ {
+ if (dcache_invalidate_p (target_dcache))
+ dcache_invalidate (target_dcache);
+
+ dcache_shrink (target_dcache);
+ }
+ else
target_dcache = dcache_init ();

return target_dcache;
--
1.7.7.6