Skip to content

Commit

Permalink
i#2006 generalize drcachesim: refactor memref_t to use a union
Browse files Browse the repository at this point in the history
Refactors memref_t, now that it is no longer a wire format, to use a union
of structs to clarify which data is available for which type.

Review-URL: https://codereview.appspot.com/310640043
  • Loading branch information
derekbruening committed Oct 27, 2016
1 parent e48dbd9 commit 96a6614
Show file tree
Hide file tree
Showing 9 changed files with 125 additions and 97 deletions.
59 changes: 44 additions & 15 deletions clients/drcachesim/common/memref.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,27 +44,56 @@
typedef int_least64_t memref_pid_t;
typedef int_least64_t memref_tid_t;

typedef struct _memref_t {
// Each trace entry is one of the following.
// Although the pc of each data reference is provided, the trace also guarantees that
// an instruction entry immediately precedes the data references that it is
// responsible for, with no intervening trace entries.

struct _memref_data_t {
// TRACE_TYPE_READ, TRACE_TYPE_WRITE, and TRACE_TYPE_PREFETCH*:
// data references.
trace_type_t type;
memref_pid_t pid;
memref_tid_t tid;
addr_t addr;
size_t size;
addr_t pc;
};

// The types are shared with trace_entry_t, but the types
// TRACE_TYPE_INSTR_BUNDLE, TRACE_TYPE_*_FLUSH_END, TRACE_TYPE_THREAD, and
// TRACE_TYPE_PID never show up here and are only found in trace_entry_t.
// The reader_t class places their data into other parts of memref_t.
unsigned short type; // trace_type_t

// Fields below here are not valid for TRACE_TYPE_THREAD_EXIT.

struct _memref_instr_t {
// TRACE_TYPE_INSTR: instruction fetch.
trace_type_t type;
memref_pid_t pid;
memref_tid_t tid;
addr_t addr;
size_t size;
addr_t addr; // Data or instruction address.
};

// The pc field is only used for read, write, and prefetch entries.
// XXX: should we remove it from here and have the simulator compute it
// from instr entries? Though if the user turns off icache simulation
// it may be better to keep it as a field here and have the reader
// fill it in for us.
struct _memref_flush_t {
// TRACE_TYPE_INSTR_FLUSH, TRACE_TYPE_DATA_FLUSH: explicit cache flush.
trace_type_t type;
memref_pid_t pid;
memref_tid_t tid;
addr_t addr;
size_t size;
addr_t pc;
};

struct _memref_thread_exit_t {
// TRACE_TYPE_THREAD_EXIT.
trace_type_t type;
memref_pid_t pid;
memref_tid_t tid;
};

typedef union _memref_t {
// The C standard allows us to reference the type field of any of these, and the
// addr and size fields of data, instr, or flush generically if known to be one
// of those types, due to the shared fields in our union of structs.
struct _memref_data_t data;
struct _memref_instr_t instr;
struct _memref_flush_t flush;
struct _memref_thread_exit_t exit;
} memref_t;

#endif /* _MEMREF_H_ */
52 changes: 25 additions & 27 deletions clients/drcachesim/reader/reader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,53 +85,51 @@ reader_t::operator++()
case TRACE_TYPE_PREFETCH_WRITE:
case TRACE_TYPE_PREFETCH_INSTR:
have_memref = true;
cur_ref.pid = cur_pid;
cur_ref.tid = cur_tid;
cur_ref.type = input_entry->type;
cur_ref.size = input_entry->size;
cur_ref.addr = input_entry->addr;
cur_ref.data.pid = cur_pid;
cur_ref.data.tid = cur_tid;
cur_ref.data.type = (trace_type_t) input_entry->type;
cur_ref.data.size = input_entry->size;
cur_ref.data.addr = input_entry->addr;
// The trace stream always has the instr fetch first, which we
// use to obtain the PC for subsequent data references.
cur_ref.pc = cur_pc;
cur_ref.data.pc = cur_pc;
break;
case TRACE_TYPE_INSTR:
have_memref = true;
cur_ref.pid = cur_pid;
cur_ref.tid = cur_tid;
cur_ref.type = input_entry->type;
cur_ref.size = input_entry->size;
cur_ref.instr.pid = cur_pid;
cur_ref.instr.tid = cur_tid;
cur_ref.instr.type = (trace_type_t) input_entry->type;
cur_ref.instr.size = input_entry->size;
cur_pc = input_entry->addr;
cur_ref.addr = cur_pc;
cur_ref.pc = cur_pc;
next_pc = cur_pc + cur_ref.size;
cur_ref.instr.addr = cur_pc;
next_pc = cur_pc + cur_ref.instr.size;
break;
case TRACE_TYPE_INSTR_BUNDLE:
have_memref = true;
// The trace stream always has the instr fetch first, which we
// use to compute the starting PC for the subsequent instructions.
cur_ref.size = input_entry->length[bundle_idx++];
cur_ref.instr.size = input_entry->length[bundle_idx++];
cur_pc = next_pc;
cur_ref.pc = cur_pc;
cur_ref.addr = cur_pc;
next_pc = cur_pc + cur_ref.size;
cur_ref.instr.addr = cur_pc;
next_pc = cur_pc + cur_ref.instr.size;
// input_entry->size stores the number of instrs in this bundle
assert(input_entry->size <= sizeof(input_entry->length));
if (bundle_idx == input_entry->size)
bundle_idx = 0;
break;
case TRACE_TYPE_INSTR_FLUSH:
case TRACE_TYPE_DATA_FLUSH:
cur_ref.pid = cur_pid;
cur_ref.tid = cur_tid;
cur_ref.type = input_entry->type;
cur_ref.size = input_entry->size;
cur_ref.addr = input_entry->addr;
if (cur_ref.size != 0)
cur_ref.flush.pid = cur_pid;
cur_ref.flush.tid = cur_tid;
cur_ref.flush.type = (trace_type_t) input_entry->type;
cur_ref.flush.size = input_entry->size;
cur_ref.flush.addr = input_entry->addr;
if (cur_ref.flush.size != 0)
have_memref = true;
break;
case TRACE_TYPE_INSTR_FLUSH_END:
case TRACE_TYPE_DATA_FLUSH_END:
cur_ref.size = input_entry->addr - cur_ref.addr;
cur_ref.flush.size = input_entry->addr - cur_ref.flush.addr;
have_memref = true;
break;
case TRACE_TYPE_THREAD:
Expand All @@ -142,9 +140,9 @@ reader_t::operator++()
cur_tid = (memref_tid_t) input_entry->addr;
cur_pid = tid2pid[cur_tid];
// We do pass this to the caller but only some fields are valid:
cur_ref.pid = cur_pid;
cur_ref.tid = cur_tid;
cur_ref.type = input_entry->type;
cur_ref.exit.pid = cur_pid;
cur_ref.exit.tid = cur_tid;
cur_ref.exit.type = (trace_type_t) input_entry->type;
have_memref = true;
break;
case TRACE_TYPE_PID:
Expand Down
7 changes: 4 additions & 3 deletions clients/drcachesim/simulator/cache.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* **********************************************************
* Copyright (c) 2015 Google, Inc. All rights reserved.
* Copyright (c) 2015-2016 Google, Inc. All rights reserved.
* **********************************************************/

/*
Expand Down Expand Up @@ -64,8 +64,9 @@ cache_t::request(const memref_t &memref_in)
void
cache_t::flush(const memref_t &memref)
{
addr_t tag = compute_tag(memref.addr);
addr_t final_tag = compute_tag(memref.addr + memref.size - 1/*no overflow*/);
addr_t tag = compute_tag(memref.flush.addr);
addr_t final_tag = compute_tag(memref.flush.addr +
memref.flush.size - 1/*no overflow*/);
last_tag = TAG_INVALID;
for (; tag <= final_tag; ++tag) {
int block_idx = compute_block_idx(tag);
Expand Down
32 changes: 16 additions & 16 deletions clients/drcachesim/simulator/cache_simulator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,40 +142,40 @@ cache_simulator_t::process_memref(const memref_t &memref)
// not practical to measure which core each thread actually
// ran on for each memref.
int core;
if (memref.tid == last_thread)
if (memref.data.tid == last_thread)
core = last_core;
else {
core = core_for_thread(memref.tid);
last_thread = memref.tid;
core = core_for_thread(memref.data.tid);
last_thread = memref.data.tid;
last_core = core;
}

if (memref.type == TRACE_TYPE_INSTR ||
memref.type == TRACE_TYPE_PREFETCH_INSTR)
if (memref.instr.type == TRACE_TYPE_INSTR ||
memref.instr.type == TRACE_TYPE_PREFETCH_INSTR)
icaches[core]->request(memref);
else if (memref.type == TRACE_TYPE_READ ||
memref.type == TRACE_TYPE_WRITE ||
else if (memref.data.type == TRACE_TYPE_READ ||
memref.data.type == TRACE_TYPE_WRITE ||
// We may potentially handle prefetches differently.
// TRACE_TYPE_PREFETCH_INSTR is handled above.
type_is_prefetch(memref.type))
type_is_prefetch(memref.data.type))
dcaches[core]->request(memref);
else if (memref.type == TRACE_TYPE_INSTR_FLUSH)
else if (memref.flush.type == TRACE_TYPE_INSTR_FLUSH)
icaches[core]->flush(memref);
else if (memref.type == TRACE_TYPE_DATA_FLUSH)
else if (memref.flush.type == TRACE_TYPE_DATA_FLUSH)
dcaches[core]->flush(memref);
else if (memref.type == TRACE_TYPE_THREAD_EXIT) {
handle_thread_exit(memref.tid);
else if (memref.exit.type == TRACE_TYPE_THREAD_EXIT) {
handle_thread_exit(memref.exit.tid);
last_thread = 0;
} else {
ERRMSG("unhandled memref type");
return false;
}

if (op_verbose.get_value() >= 3) {
std::cerr << "::" << memref.pid << "." << memref.tid << ":: " <<
" @" << (void *)memref.pc <<
" " << trace_type_names[memref.type] << " " <<
(void *)memref.addr << " x" << memref.size << std::endl;
std::cerr << "::" << memref.data.pid << "." << memref.data.tid << ":: " <<
" @" << (void *)memref.data.pc <<
" " << trace_type_names[memref.data.type] << " " <<
(void *)memref.data.addr << " x" << memref.data.size << std::endl;
}

// process counters for warmup and simulated references
Expand Down
4 changes: 2 additions & 2 deletions clients/drcachesim/simulator/cache_stats.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* **********************************************************
* Copyright (c) 2015 Google, Inc. All rights reserved.
* Copyright (c) 2015-2016 Google, Inc. All rights reserved.
* **********************************************************/

/*
Expand Down Expand Up @@ -43,7 +43,7 @@ void
cache_stats_t::access(const memref_t &memref, bool hit)
{
// handle prefetching requests
if (type_is_prefetch(memref.type)) {
if (type_is_prefetch(memref.data.type)) {
if (hit)
num_prefetch_hits++;
else
Expand Down
10 changes: 5 additions & 5 deletions clients/drcachesim/simulator/caching_device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,9 @@ caching_device_t::request(const memref_t &memref_in)
// We support larger sizes to improve the IPC perf.
// This means that one memref could touch multiple blocks.
// We treat each block separately for statistics purposes.
addr_t final_addr = memref_in.addr + memref_in.size - 1/*avoid overflow*/;
addr_t final_addr = memref_in.data.addr + memref_in.data.size - 1/*avoid overflow*/;
addr_t final_tag = compute_tag(final_addr);
addr_t tag = compute_tag(memref_in.addr);
addr_t tag = compute_tag(memref_in.data.addr);

// Optimization: check last tag if single-block
if (tag == final_tag && tag == last_tag) {
Expand All @@ -111,7 +111,7 @@ caching_device_t::request(const memref_t &memref_in)
int block_idx = compute_block_idx(tag);

if (tag + 1 <= final_tag)
memref.size = ((tag + 1) << block_size_bits) - memref.addr;
memref.data.size = ((tag + 1) << block_size_bits) - memref.data.addr;

for (way = 0; way < associativity; ++way) {
if (get_caching_device_block(block_idx, way).tag == tag) {
Expand Down Expand Up @@ -140,8 +140,8 @@ caching_device_t::request(const memref_t &memref_in)

if (tag + 1 <= final_tag) {
addr_t next_addr = (tag + 1) << block_size_bits;
memref.addr = next_addr;
memref.size = final_addr - next_addr + 1/*undo the -1*/;
memref.data.addr = next_addr;
memref.data.size = final_addr - next_addr + 1/*undo the -1*/;
}
// Optimization: remember last tag
last_tag = tag;
Expand Down
14 changes: 7 additions & 7 deletions clients/drcachesim/simulator/tlb.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* **********************************************************
* Copyright (c) 2015 Google, Inc. All rights reserved.
* Copyright (c) 2015-2016 Google, Inc. All rights reserved.
* **********************************************************/

/*
Expand Down Expand Up @@ -56,10 +56,10 @@ tlb_t::request(const memref_t &memref_in)
// We support larger sizes to improve the IPC perf.
// This means that one memref could touch multiple blocks.
// We treat each block separately for statistics purposes.
addr_t final_addr = memref_in.addr + memref_in.size - 1/*avoid overflow*/;
addr_t final_addr = memref_in.data.addr + memref_in.data.size - 1/*avoid overflow*/;
addr_t final_tag = compute_tag(final_addr);
addr_t tag = compute_tag(memref_in.addr);
memref_pid_t pid = memref_in.pid;
addr_t tag = compute_tag(memref_in.data.addr);
memref_pid_t pid = memref_in.data.pid;

// Optimization: check last tag and pid if single-block
if (tag == final_tag && tag == last_tag && pid == last_pid) {
Expand All @@ -81,7 +81,7 @@ tlb_t::request(const memref_t &memref_in)
int block_idx = compute_block_idx(tag);

if (tag + 1 <= final_tag)
memref.size = ((tag + 1) << block_size_bits) - memref.addr;
memref.data.size = ((tag + 1) << block_size_bits) - memref.data.addr;

for (way = 0; way < associativity; ++way) {
if (get_caching_device_block(block_idx, way).tag == tag &&
Expand Down Expand Up @@ -112,8 +112,8 @@ tlb_t::request(const memref_t &memref_in)

if (tag + 1 <= final_tag) {
addr_t next_addr = (tag + 1) << block_size_bits;
memref.addr = next_addr;
memref.size = final_addr - next_addr + 1/*undo the -1*/;
memref.data.addr = next_addr;
memref.data.size = final_addr - next_addr + 1/*undo the -1*/;
}
// Optimization: remember last tag and pid
last_tag = tag;
Expand Down
30 changes: 15 additions & 15 deletions clients/drcachesim/simulator/tlb_simulator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,37 +129,37 @@ tlb_simulator_t::process_memref(const memref_t &memref)
// not practical to measure which core each thread actually
// ran on for each memref.
int core;
if (memref.tid == last_thread)
if (memref.data.tid == last_thread)
core = last_core;
else {
core = core_for_thread(memref.tid);
last_thread = memref.tid;
core = core_for_thread(memref.data.tid);
last_thread = memref.data.tid;
last_core = core;
}

if (memref.type == TRACE_TYPE_INSTR)
if (memref.instr.type == TRACE_TYPE_INSTR)
itlbs[core]->request(memref);
else if (memref.type == TRACE_TYPE_READ ||
memref.type == TRACE_TYPE_WRITE)
else if (memref.data.type == TRACE_TYPE_READ ||
memref.data.type == TRACE_TYPE_WRITE)
dtlbs[core]->request(memref);
else if (memref.type == TRACE_TYPE_THREAD_EXIT) {
handle_thread_exit(memref.tid);
else if (memref.exit.type == TRACE_TYPE_THREAD_EXIT) {
handle_thread_exit(memref.exit.tid);
last_thread = 0;
}
else if (type_is_prefetch(memref.type) ||
memref.type == TRACE_TYPE_INSTR_FLUSH ||
memref.type == TRACE_TYPE_DATA_FLUSH) {
else if (type_is_prefetch(memref.data.type) ||
memref.flush.type == TRACE_TYPE_INSTR_FLUSH ||
memref.flush.type == TRACE_TYPE_DATA_FLUSH) {
// TLB simulator ignores prefetching and cache flushing
} else {
ERRMSG("unhandled memref type");
return false;
}

if (op_verbose.get_value() >= 3) {
std::cerr << "::" << memref.pid << "." << memref.tid << ":: " <<
" @" << (void *)memref.pc <<
" " << trace_type_names[memref.type] << " " <<
(void *)memref.addr << " x" << memref.size << std::endl;
std::cerr << "::" << memref.data.pid << "." << memref.data.tid << ":: " <<
" @" << (void *)memref.data.pc <<
" " << trace_type_names[memref.data.type] << " " <<
(void *)memref.data.addr << " x" << memref.data.size << std::endl;
}

// process counters for warmup and simulated references
Expand Down
Loading

0 comments on commit 96a6614

Please sign in to comment.