Skip to content

Commit

Permalink
Add runtime profiler
Browse files Browse the repository at this point in the history
Based on our observation, a high percentage of true hotspots involve
loops or backward jumps, but the number of IR is unstable within these
true hotspots.

Therefore, we believe our profiler can use three indices to detect
hotspots:

1. Backward jump
2. Loop
3. Used frequency

Close: sysprog21#189
  • Loading branch information
qwe661234 committed Jan 27, 2024
1 parent 844e9fc commit b5a22d8
Show file tree
Hide file tree
Showing 8 changed files with 125 additions and 66 deletions.
8 changes: 0 additions & 8 deletions src/cache.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,6 @@
#include "mpool.h"
#include "utils.h"

/* Currently, THRESHOLD is set to identify hot spots. Once the using frequency
* for a block exceeds the THRESHOLD, the tier-1 JIT compiler process is
* triggered.
* FIXME: Implement effective profiler to detect hot spots, instead of simply
* relying on THRESHOLD.
*/
#define THRESHOLD 4096

static uint32_t cache_size, cache_size_bits;
static struct mpool *cache_mp;

Expand Down
6 changes: 6 additions & 0 deletions src/cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@
#include <stdbool.h>
#include <stdint.h>

/* Currently, THRESHOLD is set to identify hot spots. Once the using frequency
* for a block exceeds the THRESHOLD, the tier-1 JIT compiler process is
* triggered.
*/
#define THRESHOLD 4096

struct cache;

/** cache_create - crate a new cache
Expand Down
33 changes: 29 additions & 4 deletions src/emulate.c
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,7 @@ static block_t *block_alloc(riscv_t *rv)
block->translatable = true;
block->hot = false;
block->backward = false;
block->loop = false;
INIT_LIST_HEAD(&block->list);
#endif
return block;
Expand Down Expand Up @@ -383,6 +384,11 @@ static bool is_branch_taken = false;
/* record the program counter of the previous block */
static uint32_t last_pc = 0;

#if RV32_HAS(JIT)
static set_t pc_set;
static bool loop = false;
#endif

/* Interpreter-based execution path */
#define RVOP(inst, code, asm) \
static bool do_##inst(riscv_t *rv, rv_insn_t *ir, uint64_t cycle, \
Expand Down Expand Up @@ -1040,6 +1046,22 @@ static block_t *block_find_or_translate(riscv_t *rv)
}

#if RV32_HAS(JIT)
static bool runtime_profiler(riscv_t *rv, block_t *block)
{
/* Based on our observation, a high percentage of true hotspots involve high
* using frequency, loops or backward jumps. Therefore, we believe our
* profiler can use three indices to detect hotspots */
uint32_t freq = cache_freq(rv->block_cache, block->pc_start);
/* to profile the block after chaining, the block should be executed first
*/
if (freq >= 2 && (block->backward || block->loop))
return true;
/* using frequency exceeds predetermined threshold */
if (freq == THRESHOLD)
return true;
return false;
}

typedef void (*exec_block_func_t)(riscv_t *rv, uintptr_t);
#endif

Expand Down Expand Up @@ -1117,17 +1139,16 @@ void rv_step(riscv_t *rv, int32_t cycles)
prev = NULL;
continue;
} /* check if using frequency of block exceed threshold */
else if (block->translatable &&
((block->backward &&
cache_freq(rv->block_cache, block->pc_start) >= 1024) ||
cache_hot(rv->block_cache, block->pc_start))) {
else if (block->translatable && runtime_profiler(rv, block)) {
block->hot = true;
block->offset = jit_translate(rv, block);
((exec_block_func_t) state->buf)(
rv, (uintptr_t) (state->buf + block->offset));
prev = NULL;
continue;
}
set_reset(&pc_set);
loop = false;
#endif
/* execute the block by interpreter */
const rv_insn_t *ir = block->ir_head;
Expand All @@ -1136,6 +1157,10 @@ void rv_step(riscv_t *rv, int32_t cycles)
prev = NULL;
break;
}
#if RV32_HAS(JIT)
if (loop && !block->loop)
block->loop = true;
#endif
prev = block;
}
}
Expand Down
54 changes: 0 additions & 54 deletions src/jit.c
Original file line number Diff line number Diff line change
Expand Up @@ -1163,60 +1163,6 @@ static void muldivmod(struct jit_state *state,
}
#endif /* RV32_HAS(EXT_M) */

#define SET_SIZE_BITS 10
#define SET_SIZE (1 << SET_SIZE_BITS)
#define SET_SLOTS_SIZE 32
HASH_FUNC_IMPL(set_hash, SET_SIZE_BITS, 1 << SET_SIZE_BITS);

/* The set consists of SET_SIZE buckets, with each bucket containing
* SET_SLOTS_SIZE slots.
*/
typedef struct {
uint32_t table[SET_SIZE][SET_SLOTS_SIZE];
} set_t;

/**
* set_reset - clear a set
* @set: a pointer points to target set
*/
static inline void set_reset(set_t *set)
{
memset(set, 0, sizeof(set_t));
}

/**
* set_add - insert a new element into the set
* @set: a pointer points to target set
* @key: the key of the inserted entry
*/
static bool set_add(set_t *set, uint32_t key)
{
const uint32_t index = set_hash(key);
uint8_t count = 0;
while (set->table[index][count]) {
if (set->table[index][count++] == key)
return false;
}

set->table[index][count] = key;
return true;
}

/**
* set_has - check whether the element exist in the set or not
* @set: a pointer points to target set
* @key: the key of the inserted entry
*/
static bool set_has(set_t *set, uint32_t key)
{
const uint32_t index = set_hash(key);
for (uint8_t count = 0; set->table[index][count]; count++) {
if (set->table[index][count] == key)
return true;
}
return false;
}

static void prepare_translate(struct jit_state *state)
{
#if defined(__x86_64__)
Expand Down
1 change: 1 addition & 0 deletions src/riscv_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ typedef struct block {
uint32_t offset;
bool
translatable; /**< Determine the block has RV32AF insturctions or not */
bool loop; /**< Determine the block has loop or not */
struct list_head list;
#endif
} block_t;
Expand Down
18 changes: 18 additions & 0 deletions src/rv32_template.c
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,8 @@ RVOP(
if (taken) {
#if RV32_HAS(JIT)
cache_get(rv->block_cache, PC, true);
if (!set_add(&pc_set, PC))
loop = true;
if (cache_hot(rv->block_cache, PC))
goto end_insn;
#endif
Expand Down Expand Up @@ -248,6 +250,8 @@ RVOP(
IIF(RV32_HAS(JIT)) \
({ \
cache_get(rv->block_cache, PC + 4, true); \
if (!set_add(&pc_set, PC + 4)) \
loop = true; \
if (cache_hot(rv->block_cache, PC + 4)) \
goto nextop; \
}, ); \
Expand All @@ -265,6 +269,8 @@ RVOP(
IIF(RV32_HAS(JIT)) \
({ \
cache_get(rv->block_cache, PC, true); \
if (!set_add(&pc_set, PC)) \
loop = true; \
if (cache_hot(rv->block_cache, PC)) \
goto end_insn; \
}, ); \
Expand Down Expand Up @@ -1850,6 +1856,8 @@ RVOP(
if (taken) {
#if RV32_HAS(JIT)
cache_get(rv->block_cache, PC, true);
if (!set_add(&pc_set, PC))
loop = true;
if (cache_hot(rv->block_cache, PC))
goto end_insn;
#endif
Expand Down Expand Up @@ -2011,6 +2019,8 @@ RVOP(
if (taken) {
#if RV32_HAS(JIT)
cache_get(rv->block_cache, PC, true);
if (!set_add(&pc_set, PC))
loop = true;
if (cache_hot(rv->block_cache, PC))
goto end_insn;
#endif
Expand Down Expand Up @@ -2044,6 +2054,8 @@ RVOP(
goto nextop;
#if RV32_HAS(JIT)
cache_get(rv->block_cache, PC + 2, true);
if (!set_add(&pc_set, PC + 2))
loop = true;
if (cache_hot(rv->block_cache, PC + 2))
goto nextop;
#endif
Expand All @@ -2057,6 +2069,8 @@ RVOP(
if (taken) {
#if RV32_HAS(JIT)
cache_get(rv->block_cache, PC, true);
if (!set_add(&pc_set, PC))
loop = true;
if (cache_hot(rv->block_cache, PC))
goto end_insn;
#endif
Expand Down Expand Up @@ -2099,6 +2113,8 @@ RVOP(
goto nextop;
#if RV32_HAS(JIT)
cache_get(rv->block_cache, PC + 2, true);
if (!set_add(&pc_set, PC + 2))
loop = true;
if (cache_hot(rv->block_cache, PC + 2))
goto nextop;
#endif
Expand All @@ -2112,6 +2128,8 @@ RVOP(
if (taken) {
#if RV32_HAS(JIT)
cache_get(rv->block_cache, PC, true);
if (!set_add(&pc_set, PC))
loop = true;
if (cache_hot(rv->block_cache, PC))
goto end_insn;
#endif
Expand Down
40 changes: 40 additions & 0 deletions src/utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -164,3 +164,43 @@ char *sanitize_path(const char *input)

return ret;
}

HASH_FUNC_IMPL(set_hash, SET_SIZE_BITS, 1 << SET_SIZE_BITS);

void set_reset(set_t *set)
{
memset(set, 0, sizeof(set_t));
}

/**
* set_add - insert a new element into the set
* @set: a pointer points to target set
* @key: the key of the inserted entry
*/
bool set_add(set_t *set, uint32_t key)
{
const uint32_t index = set_hash(key);
uint8_t count = 0;
while (set->table[index][count]) {
if (set->table[index][count++] == key)
return false;
}

set->table[index][count] = key;
return true;
}

/**
* set_has - check whether the element exist in the set or not
* @set: a pointer points to target set
* @key: the key of the inserted entry
*/
bool set_has(set_t *set, uint32_t key)
{
const uint32_t index = set_hash(key);
for (uint8_t count = 0; set->table[index][count]; count++) {
if (set->table[index][count] == key)
return true;
}
return false;
}
31 changes: 31 additions & 0 deletions src/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,3 +118,34 @@ static inline void list_del_init(struct list_head *node)
&entry->member != (head); \
entry = safe, safe = list_entry(safe->member.next, type, member))
#endif

#define SET_SIZE_BITS 10
#define SET_SIZE (1 << SET_SIZE_BITS)
#define SET_SLOTS_SIZE 32

/* The set consists of SET_SIZE buckets, with each bucket containing
* SET_SLOTS_SIZE slots.
*/
typedef struct {
uint32_t table[SET_SIZE][SET_SLOTS_SIZE];
} set_t;

/**
* set_reset - clear a set
* @set: a pointer points to target set
*/
void set_reset(set_t *set);

/**
* set_add - insert a new element into the set
* @set: a pointer points to target set
* @key: the key of the inserted entry
*/
bool set_add(set_t *set, uint32_t key);

/**
* set_has - check whether the element exist in the set or not
* @set: a pointer points to target set
* @key: the key of the inserted entry
*/
bool set_has(set_t *set, uint32_t key);

0 comments on commit b5a22d8

Please sign in to comment.