mirror of
https://github.com/dingusdev/dingusppc.git
synced 2025-01-11 20:29:46 +00:00
Add TLB profiling.
This commit is contained in:
parent
089645e830
commit
a8f400287a
@ -46,7 +46,8 @@ void (*mmu_exception_handler)(Except_Type exception_type, uint32_t srr1_bits);
|
|||||||
PPC_BAT_entry ibat_array[4] = {{0}};
|
PPC_BAT_entry ibat_array[4] = {{0}};
|
||||||
PPC_BAT_entry dbat_array[4] = {{0}};
|
PPC_BAT_entry dbat_array[4] = {{0}};
|
||||||
|
|
||||||
//#define MMU_PROFILING // enable MMU profiling
|
#define MMU_PROFILING // uncomment this to enable MMU profiling
|
||||||
|
#define TLB_PROFILING // uncomment this to enable SoftTLB profiling
|
||||||
|
|
||||||
/* MMU profiling */
|
/* MMU profiling */
|
||||||
#ifdef MMU_PROFILING
|
#ifdef MMU_PROFILING
|
||||||
@ -135,6 +136,51 @@ public:
|
|||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* SoftTLB profiling. */
|
||||||
|
#ifdef TLB_PROFILING
|
||||||
|
|
||||||
|
/* global variables for lightweight SoftTLB profiling */
|
||||||
|
uint64_t num_primary_tlb_hits = 0; // number of hits in the primary TLB
|
||||||
|
uint64_t num_secondary_tlb_hits = 0; // number of hits in the secondary TLB
|
||||||
|
uint64_t num_tlb_refills = 0; // number of TLB refills
|
||||||
|
uint64_t num_entry_replacements = 0; // number of entry replacements
|
||||||
|
|
||||||
|
#include "utils/profiler.h"
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
class TLBProfile : public BaseProfile {
|
||||||
|
public:
|
||||||
|
TLBProfile() : BaseProfile("PPC:MMU:TLB") {};
|
||||||
|
|
||||||
|
void populate_variables(std::vector<ProfileVar>& vars) {
|
||||||
|
vars.clear();
|
||||||
|
|
||||||
|
vars.push_back({.name = "Number of hits in the primary TLB",
|
||||||
|
.format = ProfileVarFmt::DEC,
|
||||||
|
.value = num_primary_tlb_hits});
|
||||||
|
|
||||||
|
vars.push_back({.name = "Number of hits in the secondary TLB",
|
||||||
|
.format = ProfileVarFmt::DEC,
|
||||||
|
.value = num_secondary_tlb_hits});
|
||||||
|
|
||||||
|
vars.push_back({.name = "Number of TLB refills",
|
||||||
|
.format = ProfileVarFmt::DEC,
|
||||||
|
.value = num_tlb_refills});
|
||||||
|
|
||||||
|
vars.push_back({.name = "Number of replaced TLB entries",
|
||||||
|
.format = ProfileVarFmt::DEC,
|
||||||
|
.value = num_entry_replacements});
|
||||||
|
};
|
||||||
|
|
||||||
|
void reset() {
|
||||||
|
num_primary_tlb_hits = 0;
|
||||||
|
num_secondary_tlb_hits = 0;
|
||||||
|
num_tlb_refills = 0;
|
||||||
|
num_entry_replacements = 0;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
/** Temporary TLB test variables. */
|
/** Temporary TLB test variables. */
|
||||||
bool MemAccessType; // true - memory, false - I/O
|
bool MemAccessType; // true - memory, false - I/O
|
||||||
bool Unaligned_crosspage = false;
|
bool Unaligned_crosspage = false;
|
||||||
@ -767,6 +813,9 @@ static TLBEntry* tlb2_target_entry(uint32_t gp_va)
|
|||||||
tlb_entry[3].lru_bits = 0x3;
|
tlb_entry[3].lru_bits = 0x3;
|
||||||
return &tlb_entry[3];
|
return &tlb_entry[3];
|
||||||
} else { // no invalid blocks, replace an existing one according with the hLRU policy
|
} else { // no invalid blocks, replace an existing one according with the hLRU policy
|
||||||
|
#ifdef TLB_PROFILING
|
||||||
|
num_entry_replacements++;
|
||||||
|
#endif
|
||||||
if (tlb_entry[0].lru_bits == 0) {
|
if (tlb_entry[0].lru_bits == 0) {
|
||||||
// update LRU bits
|
// update LRU bits
|
||||||
tlb_entry[0].lru_bits = 0x3;
|
tlb_entry[0].lru_bits = 0x3;
|
||||||
@ -1126,15 +1175,26 @@ inline T mmu_read_vmem(uint32_t guest_va) {
|
|||||||
// look up guest virtual address in the primary TLB
|
// look up guest virtual address in the primary TLB
|
||||||
tlb1_entry = &pCurTLB1[(guest_va >> PAGE_SIZE_BITS) & tlb_size_mask];
|
tlb1_entry = &pCurTLB1[(guest_va >> PAGE_SIZE_BITS) & tlb_size_mask];
|
||||||
if (tlb1_entry->tag == tag) { // primary TLB hit -> fast path
|
if (tlb1_entry->tag == tag) { // primary TLB hit -> fast path
|
||||||
|
#ifdef TLB_PROFILING
|
||||||
|
num_primary_tlb_hits++;
|
||||||
|
#endif
|
||||||
host_va = (uint8_t *)(tlb1_entry->host_va_offset + guest_va);
|
host_va = (uint8_t *)(tlb1_entry->host_va_offset + guest_va);
|
||||||
} else {
|
} else {
|
||||||
// primary TLB miss -> look up address in the secondary TLB
|
// primary TLB miss -> look up address in the secondary TLB
|
||||||
tlb2_entry = lookup_secondary_tlb(guest_va, tag);
|
tlb2_entry = lookup_secondary_tlb(guest_va, tag);
|
||||||
if (tlb2_entry == nullptr) {
|
if (tlb2_entry == nullptr) {
|
||||||
|
#ifdef TLB_PROFILING
|
||||||
|
num_tlb_refills++;
|
||||||
|
#endif
|
||||||
// secondary TLB miss ->
|
// secondary TLB miss ->
|
||||||
// perform full address translation and refill the secondary TLB
|
// perform full address translation and refill the secondary TLB
|
||||||
tlb2_entry = tlb2_refill(guest_va, 0);
|
tlb2_entry = tlb2_refill(guest_va, 0);
|
||||||
}
|
}
|
||||||
|
#ifdef TLB_PROFILING
|
||||||
|
else {
|
||||||
|
num_secondary_tlb_hits++;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (tlb2_entry->flags & TLBFlags::PAGE_MEM) { // is it a real memory region?
|
if (tlb2_entry->flags & TLBFlags::PAGE_MEM) { // is it a real memory region?
|
||||||
// refill the primary TLB
|
// refill the primary TLB
|
||||||
@ -1143,6 +1203,9 @@ inline T mmu_read_vmem(uint32_t guest_va) {
|
|||||||
tlb1_entry->host_va_offset = tlb2_entry->host_va_offset;
|
tlb1_entry->host_va_offset = tlb2_entry->host_va_offset;
|
||||||
host_va = (uint8_t *)(tlb1_entry->host_va_offset + guest_va);
|
host_va = (uint8_t *)(tlb1_entry->host_va_offset + guest_va);
|
||||||
} else { // otherwise, it's an access to a memory-mapped device
|
} else { // otherwise, it's an access to a memory-mapped device
|
||||||
|
#ifdef MMU_PROFILING
|
||||||
|
iomem_reads_total++;
|
||||||
|
#endif
|
||||||
return (
|
return (
|
||||||
tlb2_entry->reg_desc->devobj->read(tlb2_entry->reg_desc->start,
|
tlb2_entry->reg_desc->devobj->read(tlb2_entry->reg_desc->start,
|
||||||
guest_va - tlb2_entry->reg_desc->start, sizeof(T))
|
guest_va - tlb2_entry->reg_desc->start, sizeof(T))
|
||||||
@ -1150,6 +1213,10 @@ inline T mmu_read_vmem(uint32_t guest_va) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef MMU_PROFILING
|
||||||
|
dmem_reads_total++;
|
||||||
|
#endif
|
||||||
|
|
||||||
// handle unaligned memory accesses
|
// handle unaligned memory accesses
|
||||||
if (sizeof(T) > 1 && (guest_va & (sizeof(T) - 1))) {
|
if (sizeof(T) > 1 && (guest_va & (sizeof(T) - 1))) {
|
||||||
return read_unaligned(guest_va, host_va, sizeof(T));
|
return read_unaligned(guest_va, host_va, sizeof(T));
|
||||||
@ -1185,6 +1252,9 @@ inline void mmu_write_vmem(uint32_t guest_va, T value) {
|
|||||||
// look up guest virtual address in the primary TLB
|
// look up guest virtual address in the primary TLB
|
||||||
tlb1_entry = &pCurTLB1[(guest_va >> PAGE_SIZE_BITS) & tlb_size_mask];
|
tlb1_entry = &pCurTLB1[(guest_va >> PAGE_SIZE_BITS) & tlb_size_mask];
|
||||||
if (tlb1_entry->tag == tag) { // primary TLB hit -> fast path
|
if (tlb1_entry->tag == tag) { // primary TLB hit -> fast path
|
||||||
|
#ifdef TLB_PROFILING
|
||||||
|
num_primary_tlb_hits++;
|
||||||
|
#endif
|
||||||
if (!(tlb1_entry->flags & TLBFlags::PAGE_WRITABLE)) {
|
if (!(tlb1_entry->flags & TLBFlags::PAGE_WRITABLE)) {
|
||||||
ppc_state.spr[SPR::DSISR] = 0x08000000 | (1 << 25);
|
ppc_state.spr[SPR::DSISR] = 0x08000000 | (1 << 25);
|
||||||
ppc_state.spr[SPR::DAR] = guest_va;
|
ppc_state.spr[SPR::DAR] = guest_va;
|
||||||
@ -1209,10 +1279,18 @@ inline void mmu_write_vmem(uint32_t guest_va, T value) {
|
|||||||
// primary TLB miss -> look up address in the secondary TLB
|
// primary TLB miss -> look up address in the secondary TLB
|
||||||
tlb2_entry = lookup_secondary_tlb(guest_va, tag);
|
tlb2_entry = lookup_secondary_tlb(guest_va, tag);
|
||||||
if (tlb2_entry == nullptr) {
|
if (tlb2_entry == nullptr) {
|
||||||
|
#ifdef TLB_PROFILING
|
||||||
|
num_tlb_refills++;
|
||||||
|
#endif
|
||||||
// secondary TLB miss ->
|
// secondary TLB miss ->
|
||||||
// perform full address translation and refill the secondary TLB
|
// perform full address translation and refill the secondary TLB
|
||||||
tlb2_entry = tlb2_refill(guest_va, 1);
|
tlb2_entry = tlb2_refill(guest_va, 1);
|
||||||
}
|
}
|
||||||
|
#ifdef TLB_PROFILING
|
||||||
|
else {
|
||||||
|
num_secondary_tlb_hits++;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!(tlb2_entry->flags & TLBFlags::PAGE_WRITABLE)) {
|
if (!(tlb2_entry->flags & TLBFlags::PAGE_WRITABLE)) {
|
||||||
LOG_F(WARNING, "DSI Exception in mmu_write_vmem! PC=0x%08X", ppc_state.pc);
|
LOG_F(WARNING, "DSI Exception in mmu_write_vmem! PC=0x%08X", ppc_state.pc);
|
||||||
@ -1238,6 +1316,9 @@ inline void mmu_write_vmem(uint32_t guest_va, T value) {
|
|||||||
//MemAccessType = true;
|
//MemAccessType = true;
|
||||||
//MemAddr = (uint64_t)host_va;
|
//MemAddr = (uint64_t)host_va;
|
||||||
} else { // otherwise, it's an access to a memory-mapped device
|
} else { // otherwise, it's an access to a memory-mapped device
|
||||||
|
#ifdef MMU_PROFILING
|
||||||
|
iomem_writes_total++;
|
||||||
|
#endif
|
||||||
tlb2_entry->reg_desc->devobj->write(tlb2_entry->reg_desc->start,
|
tlb2_entry->reg_desc->devobj->write(tlb2_entry->reg_desc->start,
|
||||||
guest_va - tlb2_entry->reg_desc->start, value, sizeof(T));
|
guest_va - tlb2_entry->reg_desc->start, value, sizeof(T));
|
||||||
//MemAccessType = false;
|
//MemAccessType = false;
|
||||||
@ -1247,6 +1328,10 @@ inline void mmu_write_vmem(uint32_t guest_va, T value) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef MMU_PROFILING
|
||||||
|
dmem_writes_total++;
|
||||||
|
#endif
|
||||||
|
|
||||||
// handle unaligned memory accesses
|
// handle unaligned memory accesses
|
||||||
if (sizeof(T) > 1 && (guest_va & (sizeof(T) - 1))) {
|
if (sizeof(T) > 1 && (guest_va & (sizeof(T) - 1))) {
|
||||||
write_unaligned(guest_va, host_va, value, sizeof(T));
|
write_unaligned(guest_va, host_va, value, sizeof(T));
|
||||||
@ -1285,6 +1370,9 @@ static uint32_t read_unaligned(uint32_t guest_va, uint8_t *host_va, uint32_t siz
|
|||||||
|
|
||||||
// is it a misaligned cross-page read?
|
// is it a misaligned cross-page read?
|
||||||
if (((guest_va & 0xFFF) + size) > 0x1000) {
|
if (((guest_va & 0xFFF) + size) > 0x1000) {
|
||||||
|
#ifdef MMU_PROFILING
|
||||||
|
unaligned_crossp_r++;
|
||||||
|
#endif
|
||||||
// Break such a memory access into multiple, bytewise accesses.
|
// Break such a memory access into multiple, bytewise accesses.
|
||||||
// Because such accesses suffer a performance penalty, they will be
|
// Because such accesses suffer a performance penalty, they will be
|
||||||
// presumably very rare so don't waste time optimizing the code below.
|
// presumably very rare so don't waste time optimizing the code below.
|
||||||
@ -1292,6 +1380,9 @@ static uint32_t read_unaligned(uint32_t guest_va, uint8_t *host_va, uint32_t siz
|
|||||||
result = (result << 8) | mmu_read_vmem<uint8_t>(guest_va);
|
result = (result << 8) | mmu_read_vmem<uint8_t>(guest_va);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
#ifdef MMU_PROFILING
|
||||||
|
unaligned_reads++;
|
||||||
|
#endif
|
||||||
switch(size) {
|
switch(size) {
|
||||||
case 2:
|
case 2:
|
||||||
return READ_WORD_BE_U(host_va);
|
return READ_WORD_BE_U(host_va);
|
||||||
@ -1309,8 +1400,9 @@ static void write_unaligned(uint32_t guest_va, uint8_t *host_va, uint32_t value,
|
|||||||
{
|
{
|
||||||
// is it a misaligned cross-page write?
|
// is it a misaligned cross-page write?
|
||||||
if (((guest_va & 0xFFF) + size) > 0x1000) {
|
if (((guest_va & 0xFFF) + size) > 0x1000) {
|
||||||
Unaligned_crosspage = true;
|
#ifdef MMU_PROFILING
|
||||||
|
unaligned_crossp_w++;
|
||||||
|
#endif
|
||||||
// Break such a memory access into multiple, bytewise accesses.
|
// Break such a memory access into multiple, bytewise accesses.
|
||||||
// Because such accesses suffer a performance penalty, they will be
|
// Because such accesses suffer a performance penalty, they will be
|
||||||
// presumably very rare so don't waste time optimizing the code below.
|
// presumably very rare so don't waste time optimizing the code below.
|
||||||
@ -1321,8 +1413,9 @@ static void write_unaligned(uint32_t guest_va, uint8_t *host_va, uint32_t value,
|
|||||||
mmu_write_vmem<uint8_t>(guest_va, (value >> shift) & 0xFF);
|
mmu_write_vmem<uint8_t>(guest_va, (value >> shift) & 0xFF);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Unaligned_crosspage = false;
|
#ifdef MMU_PROFILING
|
||||||
#if 1
|
unaligned_writes++;
|
||||||
|
#endif
|
||||||
switch(size) {
|
switch(size) {
|
||||||
case 2:
|
case 2:
|
||||||
WRITE_WORD_BE_U(host_va, value);
|
WRITE_WORD_BE_U(host_va, value);
|
||||||
@ -1334,7 +1427,6 @@ static void write_unaligned(uint32_t guest_va, uint8_t *host_va, uint32_t value,
|
|||||||
WRITE_QWORD_BE_U(host_va, value);
|
WRITE_QWORD_BE_U(host_va, value);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1580,7 +1672,12 @@ void ppc_mmu_init() {
|
|||||||
mmu_change_mode();
|
mmu_change_mode();
|
||||||
|
|
||||||
#ifdef MMU_PROFILING
|
#ifdef MMU_PROFILING
|
||||||
gProfilerObj->register_profile("PPC_MMU",
|
gProfilerObj->register_profile("PPC:MMU",
|
||||||
std::unique_ptr<BaseProfile>(new MMUProfile()));
|
std::unique_ptr<BaseProfile>(new MMUProfile()));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef TLB_PROFILING
|
||||||
|
gProfilerObj->register_profile("PPC:MMU:TLB",
|
||||||
|
std::unique_ptr<BaseProfile>(new TLBProfile()));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user