profiler: Keep track of fast/slow path for jitted memory access

This commit is contained in:
Fabian 2018-09-02 21:09:13 -05:00
parent b70a5c081a
commit bf895ff1b2
4 changed files with 120 additions and 40 deletions

View file

@ -30,18 +30,18 @@ const print_stats = {
"RUN_FROM_CACHE",
"RUN_FROM_CACHE_STEPS",
"TRIGGER_CPU_EXCEPTION",
"SAFE_READ32_FAST",
"SAFE_READ32_SLOW_PAGE_CROSSED",
"SAFE_READ32_SLOW_NOT_VALID",
"SAFE_READ32_SLOW_NOT_USER",
"SAFE_READ32_SLOW_IN_MAPPED_RANGE",
"SAFE_WRITE32_FAST",
"SAFE_WRITE32_SLOW_PAGE_CROSSED",
"SAFE_WRITE32_SLOW_NOT_VALID",
"SAFE_WRITE32_SLOW_NOT_USER",
"SAFE_WRITE32_SLOW_IN_MAPPED_RANGE",
"SAFE_WRITE32_SLOW_READ_ONLY",
"SAFE_WRITE32_SLOW_HAS_CODE",
"SAFE_READ_FAST",
"SAFE_READ_SLOW_PAGE_CROSSED",
"SAFE_READ_SLOW_NOT_VALID",
"SAFE_READ_SLOW_NOT_USER",
"SAFE_READ_SLOW_IN_MAPPED_RANGE",
"SAFE_WRITE_FAST",
"SAFE_WRITE_SLOW_PAGE_CROSSED",
"SAFE_WRITE_SLOW_NOT_VALID",
"SAFE_WRITE_SLOW_NOT_USER",
"SAFE_WRITE_SLOW_IN_MAPPED_RANGE",
"SAFE_WRITE_SLOW_READ_ONLY",
"SAFE_WRITE_SLOW_HAS_CODE",
"DO_RUN",
"DO_MANY_CYCLES",
"CYCLE_INTERNAL",

View file

@ -2,6 +2,7 @@ use cpu::BitSize;
use global_pointers;
use jit::JitContext;
use modrm;
use profiler;
use regs;
use tlb::{TLB_GLOBAL, TLB_HAS_CODE, TLB_NO_USER, TLB_READONLY, TLB_VALID};
use wasmgen::module_init;
@ -281,6 +282,11 @@ fn gen_safe_read(ctx: &mut JitContext, bits: BitSize) {
// Pseudo:
// if(can_use_fast_path) leave_on_stack(mem8[entry & ~0xFFF ^ address]);
builder.instruction_body.if_i32();
if cfg!(feature = "profiler") {
gen_profiler_stat_increment(builder, profiler::stat::S_SAFE_READ_FAST);
}
builder.instruction_body.get_local(&entry_local);
builder.instruction_body.const_i32(!0xFFF);
builder.instruction_body.and_i32();
@ -313,6 +319,12 @@ fn gen_safe_read(ctx: &mut JitContext, bits: BitSize) {
// }
builder.instruction_body.else_();
if cfg!(feature = "profiler") {
builder.instruction_body.get_local(&address_local);
builder.instruction_body.get_local(&entry_local);
gen_call_fn2(builder, "report_safe_read_jit_slow");
}
builder
.instruction_body
.const_i32(global_pointers::PREVIOUS_IP as i32);
@ -410,14 +422,16 @@ fn gen_safe_write(
// phys_addr = entry & ~0xFFF ^ address;
builder.instruction_body.if_void();
if cfg!(feature = "profiler") {
gen_profiler_stat_increment(builder, profiler::stat::S_SAFE_WRITE_FAST);
}
builder.instruction_body.get_local(&entry_local);
builder.instruction_body.const_i32(!0xFFF);
builder.instruction_body.and_i32();
builder.instruction_body.get_local(&address_local);
builder.instruction_body.xor_i32();
builder.free_local(entry_local);
// Pseudo:
// /* continued within can_use_fast_path branch */
// mem8[phys_addr] = value;
@ -447,6 +461,12 @@ fn gen_safe_write(
// }
builder.instruction_body.else_();
if cfg!(feature = "profiler") {
builder.instruction_body.get_local(&address_local);
builder.instruction_body.get_local(&entry_local);
gen_call_fn2(builder, "report_safe_write_jit_slow");
}
builder
.instruction_body
.const_i32(global_pointers::PREVIOUS_IP as i32);
@ -486,6 +506,8 @@ fn gen_safe_write(
builder.instruction_body.block_end();
builder.instruction_body.block_end();
builder.free_local(entry_local);
}
pub fn gen_clear_prefixes(ctx: &mut JitContext) {
@ -840,6 +862,11 @@ pub fn gen_safe_read_write(
// Pseudo:
// if(can_use_fast_path) leave_on_stack(mem8[entry & ~0xFFF ^ address]);
ctx.builder.instruction_body.if_void();
if cfg!(feature = "profiler") {
gen_profiler_stat_increment(ctx.builder, profiler::stat::S_SAFE_WRITE_FAST);
}
ctx.builder.instruction_body.get_local(&entry_local);
ctx.builder.instruction_body.const_i32(!0xFFF);
ctx.builder.instruction_body.and_i32();
@ -864,8 +891,6 @@ pub fn gen_safe_read_write(
},
}
ctx.builder.free_local(entry_local);
f(ctx);
match bits {
@ -891,6 +916,12 @@ pub fn gen_safe_read_write(
// }
ctx.builder.instruction_body.else_();
if cfg!(feature = "profiler") {
ctx.builder.instruction_body.get_local(&address_local);
ctx.builder.instruction_body.get_local(&entry_local);
gen_call_fn2(ctx.builder, "report_safe_write_jit_slow");
}
ctx.builder
.instruction_body
.const_i32(global_pointers::PREVIOUS_IP as i32);
@ -920,4 +951,11 @@ pub fn gen_safe_read_write(
ctx.builder.instruction_body.block_end();
ctx.builder.instruction_body.block_end();
ctx.builder.free_local(entry_local);
}
pub fn gen_profiler_stat_increment(builder: &mut WasmBuilder, stat: profiler::stat) {
let addr = unsafe { profiler::stat_array.as_mut_ptr().offset(stat as isize) } as u32;
gen_increment_variable(builder, addr, 1)
}

View file

@ -1060,7 +1060,7 @@ pub unsafe fn safe_read32s(mut address: i32) -> Result<i32, ()> {
let mut info_bits: i32 = entry & 4095 & !TLB_READONLY & !TLB_GLOBAL & !TLB_HAS_CODE;
if info_bits == TLB_VALID && address & 4095 <= 4096 - 4 {
if false {
profiler::stat_increment(S_SAFE_READ32_FAST);
profiler::stat_increment(S_SAFE_READ_FAST);
}
// - not in memory mapped area
// - can be accessed from any cpl
@ -1071,16 +1071,16 @@ pub unsafe fn safe_read32s(mut address: i32) -> Result<i32, ()> {
else {
if false {
if address & 4095 > 4096 - 4 {
profiler::stat_increment(S_SAFE_READ32_SLOW_PAGE_CROSSED);
profiler::stat_increment(S_SAFE_READ_SLOW_PAGE_CROSSED);
}
else if info_bits & TLB_VALID == 0 {
profiler::stat_increment(S_SAFE_READ32_SLOW_NOT_VALID);
profiler::stat_increment(S_SAFE_READ_SLOW_NOT_VALID);
}
else if 0 != info_bits & TLB_NO_USER {
profiler::stat_increment(S_SAFE_READ32_SLOW_NOT_USER);
profiler::stat_increment(S_SAFE_READ_SLOW_NOT_USER);
}
else if 0 != info_bits & TLB_IN_MAPPED_RANGE {
profiler::stat_increment(S_SAFE_READ32_SLOW_IN_MAPPED_RANGE);
profiler::stat_increment(S_SAFE_READ_SLOW_IN_MAPPED_RANGE);
}
else {
dbg_assert!(0 != 0);
@ -1090,6 +1090,48 @@ pub unsafe fn safe_read32s(mut address: i32) -> Result<i32, ()> {
};
}
#[no_mangle]
#[cfg(feature = "profiler")]
pub fn report_safe_read_jit_slow(address: u32, entry: i32) {
if entry & TLB_VALID == 0 {
profiler::stat_increment(S_SAFE_READ_SLOW_NOT_VALID);
}
else if entry & TLB_IN_MAPPED_RANGE != 0 {
profiler::stat_increment(S_SAFE_READ_SLOW_IN_MAPPED_RANGE);
}
else if address & 0xFFF > 0x1000 - 4 {
profiler::stat_increment(S_SAFE_READ_SLOW_PAGE_CROSSED);
}
else {
// NOT_USER is not possible since gen_safe_read generates a mask for cpl0
dbg_assert!(false);
}
}
#[no_mangle]
#[cfg(feature = "profiler")]
pub fn report_safe_write_jit_slow(address: u32, entry: i32) {
if entry & TLB_VALID == 0 {
profiler::stat_increment(S_SAFE_WRITE_SLOW_NOT_VALID);
}
else if entry & TLB_IN_MAPPED_RANGE != 0 {
profiler::stat_increment(S_SAFE_WRITE_SLOW_IN_MAPPED_RANGE);
}
else if entry & TLB_HAS_CODE != 0 {
profiler::stat_increment(S_SAFE_WRITE_SLOW_HAS_CODE);
}
else if entry & TLB_READONLY != 0 {
profiler::stat_increment(S_SAFE_WRITE_SLOW_READ_ONLY);
}
else if address & 0xFFF > 0x1000 - 4 {
profiler::stat_increment(S_SAFE_WRITE_SLOW_PAGE_CROSSED);
}
else {
// NOT_USER is not possible since gen_safe_write generates a mask for for cpl0
dbg_assert!(false);
}
}
pub unsafe fn safe_read32s_slow(mut addr: i32) -> Result<i32, ()> {
if addr & 4095 >= 4093 {
return Ok(safe_read16(addr)? | safe_read16(addr + 2)? << 16);
@ -1210,7 +1252,7 @@ pub unsafe fn safe_write32(mut address: i32, mut value: i32) -> Result<(), ()> {
entry & 4095 & !TLB_GLOBAL & !if *cpl as i32 == 3 { 0 } else { TLB_NO_USER };
if info_bits == TLB_VALID && address & 4095 <= 4096 - 4 {
if false {
profiler::stat_increment(S_SAFE_WRITE32_FAST);
profiler::stat_increment(S_SAFE_WRITE_FAST);
}
// - allowed to write in user-mode
// - not in memory mapped area
@ -1223,22 +1265,22 @@ pub unsafe fn safe_write32(mut address: i32, mut value: i32) -> Result<(), ()> {
else {
if false {
if address & 4095 > 4096 - 4 {
profiler::stat_increment(S_SAFE_WRITE32_SLOW_PAGE_CROSSED);
profiler::stat_increment(S_SAFE_WRITE_SLOW_PAGE_CROSSED);
}
else if info_bits & TLB_VALID == 0 {
profiler::stat_increment(S_SAFE_WRITE32_SLOW_NOT_VALID);
profiler::stat_increment(S_SAFE_WRITE_SLOW_NOT_VALID);
}
else if 0 != info_bits & TLB_NO_USER {
profiler::stat_increment(S_SAFE_WRITE32_SLOW_NOT_USER);
profiler::stat_increment(S_SAFE_WRITE_SLOW_NOT_USER);
}
else if 0 != info_bits & TLB_IN_MAPPED_RANGE {
profiler::stat_increment(S_SAFE_WRITE32_SLOW_IN_MAPPED_RANGE);
profiler::stat_increment(S_SAFE_WRITE_SLOW_IN_MAPPED_RANGE);
}
else if 0 != info_bits & TLB_READONLY {
profiler::stat_increment(S_SAFE_WRITE32_SLOW_READ_ONLY);
profiler::stat_increment(S_SAFE_WRITE_SLOW_READ_ONLY);
}
else if 0 != info_bits & TLB_HAS_CODE {
profiler::stat_increment(S_SAFE_WRITE32_SLOW_HAS_CODE);
profiler::stat_increment(S_SAFE_WRITE_SLOW_HAS_CODE);
}
else {
dbg_assert!(0 != 0);

View file

@ -20,19 +20,19 @@ pub enum stat {
S_TRIGGER_CPU_EXCEPTION,
S_SAFE_READ32_FAST,
S_SAFE_READ32_SLOW_PAGE_CROSSED,
S_SAFE_READ32_SLOW_NOT_VALID,
S_SAFE_READ32_SLOW_NOT_USER,
S_SAFE_READ32_SLOW_IN_MAPPED_RANGE,
S_SAFE_READ_FAST,
S_SAFE_READ_SLOW_PAGE_CROSSED,
S_SAFE_READ_SLOW_NOT_VALID,
S_SAFE_READ_SLOW_NOT_USER,
S_SAFE_READ_SLOW_IN_MAPPED_RANGE,
S_SAFE_WRITE32_FAST,
S_SAFE_WRITE32_SLOW_PAGE_CROSSED,
S_SAFE_WRITE32_SLOW_NOT_VALID,
S_SAFE_WRITE32_SLOW_NOT_USER,
S_SAFE_WRITE32_SLOW_IN_MAPPED_RANGE,
S_SAFE_WRITE32_SLOW_READ_ONLY,
S_SAFE_WRITE32_SLOW_HAS_CODE,
S_SAFE_WRITE_FAST,
S_SAFE_WRITE_SLOW_PAGE_CROSSED,
S_SAFE_WRITE_SLOW_NOT_VALID,
S_SAFE_WRITE_SLOW_NOT_USER,
S_SAFE_WRITE_SLOW_IN_MAPPED_RANGE,
S_SAFE_WRITE_SLOW_READ_ONLY,
S_SAFE_WRITE_SLOW_HAS_CODE,
S_DO_RUN,
S_DO_MANY_CYCLES,