X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Fdcache.c;h=12d1a4b9c2478b68a3ce62b1e422c0d91ad7f25c;hb=2dd4d4224afba558be14b39e2886ba47b2132678;hp=e1386e0180f61b081eddaccfa4166b813b584687;hpb=d5cd603472bb4b3c14782728aa55bbafdfe783e8;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/dcache.c b/gdb/dcache.c index e1386e0180..12d1a4b9c2 100644 --- a/gdb/dcache.c +++ b/gdb/dcache.c @@ -1,7 +1,6 @@ /* Caching code for GDB, the GNU debugger. - Copyright (C) 1992, 1993, 1995, 1996, 1998, 1999, 2000, 2001, 2003, 2007, - 2008, 2009, 2010 Free Software Foundation, Inc. + Copyright (C) 1992-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -21,12 +20,16 @@ #include "defs.h" #include "dcache.h" #include "gdbcmd.h" -#include "gdb_string.h" +#include #include "gdbcore.h" -#include "target.h" +#include "target-dcache.h" #include "inferior.h" #include "splay-tree.h" +/* Commands with a prefix of `{set,show} dcache'. */ +static struct cmd_list_element *dcache_set_list = NULL; +static struct cmd_list_element *dcache_show_list = NULL; + /* The data cache could lead to incorrect results because it doesn't know about volatile variables, thus making it impossible to debug functions which use memory mapped I/O devices. Set the nocache @@ -71,36 +74,37 @@ /* The maximum number of lines stored. The total size of the cache is equal to DCACHE_SIZE times LINE_SIZE. */ -#define DCACHE_SIZE 4096 +#define DCACHE_DEFAULT_SIZE 4096 +static unsigned dcache_size = DCACHE_DEFAULT_SIZE; -/* The size of a cache line. Smaller values reduce the time taken to +/* The default size of a cache line. Smaller values reduce the time taken to read a single byte and make the cache more granular, but increase overhead and reduce the effectiveness of the cache as a prefetcher. */ -#define LINE_SIZE_POWER 6 -#define LINE_SIZE (1 << LINE_SIZE_POWER) +#define DCACHE_DEFAULT_LINE_SIZE 64 +static unsigned dcache_line_size = DCACHE_DEFAULT_LINE_SIZE; /* Each cache block holds LINE_SIZE bytes of data starting at a multiple-of-LINE_SIZE address. */ -#define LINE_SIZE_MASK ((LINE_SIZE - 1)) -#define XFORM(x) ((x) & LINE_SIZE_MASK) -#define MASK(x) ((x) & ~LINE_SIZE_MASK) +#define LINE_SIZE_MASK(dcache) ((dcache->line_size - 1)) +#define XFORM(dcache, x) ((x) & LINE_SIZE_MASK (dcache)) +#define MASK(dcache, x) ((x) & ~LINE_SIZE_MASK (dcache)) struct dcache_block { - /* for least-recently-allocated and free lists */ + /* For least-recently-allocated and free lists. */ struct dcache_block *prev; struct dcache_block *next; CORE_ADDR addr; /* address of data */ - gdb_byte data[LINE_SIZE]; /* bytes at given address */ int refs; /* # hits */ + gdb_byte data[1]; /* line_size bytes at given address */ }; struct dcache_struct { splay_tree tree; - struct dcache_block *oldest; /* least-recently-allocated list */ + struct dcache_block *oldest; /* least-recently-allocated list. */ /* The free list is maintained identically to OLDEST to simplify the code: we only need one set of accessors. */ @@ -108,6 +112,7 @@ struct dcache_struct /* The number of in-use lines in the cache. */ int size; + CORE_ADDR line_size; /* current line_size. */ /* The ptid of last inferior to use cache or null_ptid. */ ptid_t ptid; @@ -134,8 +139,6 @@ show_dcache_enabled_p (struct ui_file *file, int from_tty, fprintf_filtered (file, _("Deprecated remotecache flag is %s.\n"), value); } -static DCACHE *last_cache; /* Used by info dcache */ - /* Add BLOCK to circular block list BLIST, behind the block at *BLIST. *BLIST is not updated (unless it was previously NULL of course). This is for the least-recently-allocated list's sake: @@ -207,6 +210,26 @@ for_each_block (struct dcache_block **blist, block_func *func, void *param) while (*blist && db != *blist); } +/* BLOCK_FUNC routine for dcache_free. */ + +static void +free_block (struct dcache_block *block, void *param) +{ + xfree (block); +} + +/* Free a data cache. */ + +void +dcache_free (DCACHE *dcache) +{ + splay_tree_delete (dcache->tree); + for_each_block (&dcache->oldest, free_block, NULL); + for_each_block (&dcache->freelist, free_block, NULL); + xfree (dcache); +} + + /* BLOCK_FUNC function for dcache_invalidate. This doesn't remove the block from the oldest list on purpose. dcache_invalidate will do it later. */ @@ -230,6 +253,16 @@ dcache_invalidate (DCACHE *dcache) dcache->oldest = NULL; dcache->size = 0; dcache->ptid = null_ptid; + + if (dcache->line_size != dcache_line_size) + { + /* We've been asked to use a different line size. + All of our freelist blocks are now the wrong size, so free them. */ + + for_each_block (&dcache->freelist, free_block, dcache); + dcache->freelist = NULL; + dcache->line_size = dcache_line_size; + } } /* Invalidate the line associated with ADDR. */ @@ -257,7 +290,7 @@ dcache_hit (DCACHE *dcache, CORE_ADDR addr) struct dcache_block *db; splay_tree_node node = splay_tree_lookup (dcache->tree, - (splay_tree_key) MASK (addr)); + (splay_tree_key) MASK (dcache, addr)); if (!node) return NULL; @@ -281,7 +314,7 @@ dcache_read_line (DCACHE *dcache, struct dcache_block *db) int reg_len; struct mem_region *region; - len = LINE_SIZE; + len = dcache->line_size; memaddr = db->addr; myaddr = db->data; @@ -303,8 +336,8 @@ dcache_read_line (DCACHE *dcache, struct dcache_block *db) len -= reg_len; continue; } - - res = target_read (¤t_target, TARGET_OBJECT_RAW_MEMORY, + + res = target_read (current_target.beneath, TARGET_OBJECT_RAW_MEMORY, NULL, myaddr, memaddr, reg_len); if (res < reg_len) return 0; @@ -325,7 +358,7 @@ dcache_alloc (DCACHE *dcache, CORE_ADDR addr) { struct dcache_block *db; - if (dcache->size >= DCACHE_SIZE) + if (dcache->size >= dcache_size) { /* Evict the least recently allocated line. */ db = dcache->oldest; @@ -339,12 +372,13 @@ dcache_alloc (DCACHE *dcache, CORE_ADDR addr) if (db) remove_block (&dcache->freelist, db); else - db = xmalloc (sizeof (struct dcache_block)); + db = xmalloc (offsetof (struct dcache_block, data) + + dcache->line_size); dcache->size++; } - db->addr = MASK (addr); + db->addr = MASK (dcache, addr); db->refs = 0; /* Put DB at the end of the list, it's the newest. */ @@ -374,7 +408,7 @@ dcache_peek_byte (DCACHE *dcache, CORE_ADDR addr, gdb_byte *ptr) return 0; } - *ptr = db->data[XFORM (addr)]; + *ptr = db->data[XFORM (dcache, addr)]; return 1; } @@ -395,7 +429,7 @@ dcache_poke_byte (DCACHE *dcache, CORE_ADDR addr, gdb_byte *ptr) struct dcache_block *db = dcache_hit (dcache, addr); if (db) - db->data[XFORM (addr)] = *ptr; + db->data[XFORM (dcache, addr)] = *ptr; return 1; } @@ -417,7 +451,6 @@ DCACHE * dcache_init (void) { DCACHE *dcache; - int i; dcache = (DCACHE *) xmalloc (sizeof (*dcache)); @@ -428,33 +461,12 @@ dcache_init (void) dcache->oldest = NULL; dcache->freelist = NULL; dcache->size = 0; + dcache->line_size = dcache_line_size; dcache->ptid = null_ptid; - last_cache = dcache; return dcache; } -/* BLOCK_FUNC routine for dcache_free. */ - -static void -free_block (struct dcache_block *block, void *param) -{ - free (block); -} - -/* Free a data cache. */ - -void -dcache_free (DCACHE *dcache) -{ - if (last_cache == dcache) - last_cache = NULL; - - splay_tree_delete (dcache->tree); - for_each_block (&dcache->oldest, free_block, NULL); - for_each_block (&dcache->freelist, free_block, NULL); - xfree (dcache); -} /* Read or write LEN bytes from inferior memory at MEMADDR, transferring to or from debugger address MYADDR. Write to inferior if SHOULD_WRITE is @@ -474,6 +486,7 @@ dcache_xfer_memory (struct target_ops *ops, DCACHE *dcache, int i; int res; int (*xfunc) (DCACHE *dcache, CORE_ADDR addr, gdb_byte *ptr); + xfunc = should_write ? dcache_poke_byte : dcache_peek_byte; /* If this is a different inferior from what we've recorded, @@ -533,30 +546,33 @@ void dcache_update (DCACHE *dcache, CORE_ADDR memaddr, gdb_byte *myaddr, int len) { int i; + for (i = 0; i < len; i++) dcache_poke_byte (dcache, memaddr + i, myaddr + i); } +/* Print DCACHE line INDEX. */ + static void -dcache_print_line (int index) +dcache_print_line (DCACHE *dcache, int index) { splay_tree_node n; struct dcache_block *db; int i, j; - if (!last_cache) + if (dcache == NULL) { printf_filtered (_("No data cache available.\n")); return; } - n = splay_tree_min (last_cache->tree); + n = splay_tree_min (dcache->tree); for (i = index; i > 0; --i) { if (!n) break; - n = splay_tree_successor (last_cache->tree, n->key); + n = splay_tree_successor (dcache->tree, n->key); } if (!n) @@ -568,28 +584,31 @@ dcache_print_line (int index) db = (struct dcache_block *) n->value; printf_filtered (_("Line %d: address %s [%d hits]\n"), - index, paddress (target_gdbarch, db->addr), db->refs); + index, paddress (target_gdbarch (), db->addr), db->refs); - for (j = 0; j < LINE_SIZE; j++) + for (j = 0; j < dcache->line_size; j++) { printf_filtered ("%02x ", db->data[j]); - /* Print a newline every 16 bytes (48 characters) */ - if ((j % 16 == 15) && (j != LINE_SIZE - 1)) + /* Print a newline every 16 bytes (48 characters). */ + if ((j % 16 == 15) && (j != dcache->line_size - 1)) printf_filtered ("\n"); } printf_filtered ("\n"); } +/* Parse EXP and show the info about DCACHE. */ + static void -dcache_info (char *exp, int tty) +dcache_info_1 (DCACHE *dcache, char *exp) { splay_tree_node n; - int i, refcount, lineno; + int i, refcount; if (exp) { char *linestart; + i = strtol (exp, &linestart, 10); if (linestart == exp || i < 0) { @@ -597,25 +616,27 @@ dcache_info (char *exp, int tty) return; } - dcache_print_line (i); + dcache_print_line (dcache, i); return; } - printf_filtered (_("Dcache line width %d, maximum size %d\n"), - LINE_SIZE, DCACHE_SIZE); + printf_filtered (_("Dcache %u lines of %u bytes each.\n"), + dcache_size, + dcache ? (unsigned) dcache->line_size + : dcache_line_size); - if (!last_cache || ptid_equal (last_cache->ptid, null_ptid)) + if (dcache == NULL || ptid_equal (dcache->ptid, null_ptid)) { printf_filtered (_("No data cache available.\n")); return; } printf_filtered (_("Contains data for %s\n"), - target_pid_to_str (last_cache->ptid)); + target_pid_to_str (dcache->ptid)); refcount = 0; - n = splay_tree_min (last_cache->tree); + n = splay_tree_min (dcache->tree); i = 0; while (n) @@ -623,16 +644,62 @@ dcache_info (char *exp, int tty) struct dcache_block *db = (struct dcache_block *) n->value; printf_filtered (_("Line %d: address %s [%d hits]\n"), - i, paddress (target_gdbarch, db->addr), db->refs); + i, paddress (target_gdbarch (), db->addr), db->refs); i++; refcount += db->refs; - n = splay_tree_successor (last_cache->tree, n->key); + n = splay_tree_successor (dcache->tree, n->key); } printf_filtered (_("Cache state: %d active lines, %d hits\n"), i, refcount); } +static void +dcache_info (char *exp, int tty) +{ + dcache_info_1 (target_dcache_get (), exp); +} + +static void +set_dcache_size (char *args, int from_tty, + struct cmd_list_element *c) +{ + if (dcache_size == 0) + { + dcache_size = DCACHE_DEFAULT_SIZE; + error (_("Dcache size must be greater than 0.")); + } + target_dcache_invalidate (); +} + +static void +set_dcache_line_size (char *args, int from_tty, + struct cmd_list_element *c) +{ + if (dcache_line_size < 2 + || (dcache_line_size & (dcache_line_size - 1)) != 0) + { + unsigned d = dcache_line_size; + dcache_line_size = DCACHE_DEFAULT_LINE_SIZE; + error (_("Invalid dcache line size: %u (must be power of 2)."), d); + } + target_dcache_invalidate (); +} + +static void +set_dcache_command (char *arg, int from_tty) +{ + printf_unfiltered ( + "\"set dcache\" must be followed by the name of a subcommand.\n"); + help_list (dcache_set_list, "set dcache ", -1, gdb_stdout); +} + +static void +show_dcache_command (char *args, int from_tty) +{ + cmd_show_list (dcache_show_list, from_tty, ""); +} + void _initialize_dcache (void) { @@ -654,4 +721,28 @@ Print information on the dcache performance.\n\ With no arguments, this command prints the cache configuration and a\n\ summary of each line in the cache. Use \"info dcache to dump\"\n\ the contents of a given line.")); + + add_prefix_cmd ("dcache", class_obscure, set_dcache_command, _("\ +Use this command to set number of lines in dcache and line-size."), + &dcache_set_list, "set dcache ", /*allow_unknown*/0, &setlist); + add_prefix_cmd ("dcache", class_obscure, show_dcache_command, _("\ +Show dcachesettings."), + &dcache_show_list, "show dcache ", /*allow_unknown*/0, &showlist); + + add_setshow_zuinteger_cmd ("line-size", class_obscure, + &dcache_line_size, _("\ +Set dcache line size in bytes (must be power of 2)."), _("\ +Show dcache line size."), + NULL, + set_dcache_line_size, + NULL, + &dcache_set_list, &dcache_show_list); + add_setshow_zuinteger_cmd ("size", class_obscure, + &dcache_size, _("\ +Set number of dcache lines."), _("\ +Show number of dcache lines."), + NULL, + set_dcache_size, + NULL, + &dcache_set_list, &dcache_show_list); }