Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Periodic checkpoint generation #15

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
Add this line to qflex/qemu/hmp-commands.hx

```
ERST
{
.name = "flexus-start-periodic-ckpt",
.args_type = "dirname:F? checkpoint_interval:i? sample_size:i?",
.params = "dirname checkpoint_interval sample_size",
.help = "Start periodic checkpoint generation with optional checkpoint_interval and sample_size",
.cmd = hmp_flexus_start_periodic_ckpt
},
SRST
``flexus-start-periodic-ckpt`` *tag*
Qflex specific, save uArch state as checkpoints on the disk.
The tag is a directory the checkpoint will be save to.
```
69 changes: 69 additions & 0 deletions libqflex/libqflex-hmp-cmds.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@
#include "libqflex-module.h"
#include "libqflex.h"

// add these?

#include "middleware/libqflex/plugins/trace/trace.h"
#include "libqflex-module.h"
#include "libqflex.h"
#include "qapi/qmp/qdict.h"
#include "qapi/qmp/qobject.h"

void
hmp_flexus_save_measure(Monitor *mon, const QDict *qdict) {
if (! qemu_libqflex_state.is_configured)
Expand Down Expand Up @@ -74,4 +82,65 @@ hmp_flexus_load_ckpt(Monitor* mon, const QDict* qdict)
libqflex_load_ckpt(folder_name);

hmp_handle_error(mon, err);
}

// Functions to call periodic checkpoint

// Structure for Monitor and QDict
typedef struct {
Monitor *mon;
const QDict *qdict;
int checkpoint_interval;
int sample_size;
} FlexusCkptData;

static QEMUTimer *flexus_ckpt_timer = NULL;
static void flexus_ckpt_timer_cb(void *opaque); // Timer
static int last_instruction_count = 0;

static void flexus_ckpt_timer_cb(void *opaque) {
FlexusCkptData *data = (FlexusCkptData *)opaque;
int current_instruction_count = instruction_count;
int instruction_diff = current_instruction_count - last_instruction_count;

// Cannot trigger the checkpoint generation for every instruction,
// so approximate this by checking the instruction count by every given second.
// Currently it checks the instruction count every 10000 ms but this is adjustable.
if (instruction_diff >= data->checkpoint_interval && current_instruction_count <= data->sample_size * data->checkpoint_interval + 0.5 * data->checkpoint_interval) {
// keep generating checkpoint until it reaches the target sample_size
hmp_flexus_save_ckpt(data->mon, data->qdict);
last_instruction_count = current_instruction_count;
}

// Reschedule the timer to run again in 10 seconds.
timer_mod(flexus_ckpt_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 10000);
}

void hmp_flexus_start_periodic_ckpt(Monitor *mon, const QDict *qdict) {
static const int DEFAULT_CHECKPOINT_INTERVAL = 1000000;
static const int DEFAULT_SAMPLE_SIZE = 30;

if (!qemu_libqflex_state.is_configured) {
monitor_printf(mon, "qflex seems to not be initialized, periodic checkpoint saving makes no sense\n");
return;
}

if (flexus_ckpt_timer) {
timer_del(flexus_ckpt_timer);
flexus_ckpt_timer = NULL; // Reset the timer pointer
}

FlexusCkptData *data = g_malloc(sizeof(FlexusCkptData));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good 'Ol memory leak ?

Copy link
Contributor

@branylagaffe branylagaffe Jul 24, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason why this cannot be a global variable ?

data->mon = mon;
data->qdict = qdict;

// Retrieve optional arguments for checkpoint_interval and sample_size
data->checkpoint_interval = qdict_haskey(qdict, "checkpoint_interval") ? qdict_get_int(qdict, "checkpoint_interval") : DEFAULT_CHECKPOINT_INTERVAL;
data->sample_size = qdict_haskey(qdict, "sample_size") ? qdict_get_int(qdict, "sample_size") : DEFAULT_SAMPLE_SIZE;

// Initialize the last_instruction_count
last_instruction_count = instruction_count;

flexus_ckpt_timer = timer_new_ms(QEMU_CLOCK_REALTIME, flexus_ckpt_timer_cb, data);
timer_mod(flexus_ckpt_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 10000); // 10 seconds
}
2 changes: 2 additions & 0 deletions libqflex/libqflex.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

#include "libqflex-legacy-api.h"

extern int instruction_count;

extern struct libqflex_state_t qemu_libqflex_state;

/**
Expand Down
19 changes: 15 additions & 4 deletions libqflex/plugins/trace/trace.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@
#include "middleware/libqflex/libqflex-legacy-api.h"
#include "trace.h"

// Add this

#include "middleware/libqflex/libqflex.h"


// Ensure that the plugin run only against the version
// it was compiled for
Expand Down Expand Up @@ -46,9 +50,15 @@ trans_free(gpointer data)
* @param vaddr OPage virtual address.
* @param userdata Generic translation info.
*/

int instruction_count = 0;

static void
dispatch_memory_access(unsigned int vcpu_index, qemu_plugin_meminfo_t info, uint64_t vaddr, void* userdata)
{
if (vcpu_index == 0) {
instruction_count++;
}

trace_insn_t* insn = (trace_insn_t*) userdata;

Expand All @@ -67,10 +77,8 @@ dispatch_memory_access(unsigned int vcpu_index, qemu_plugin_meminfo_t info, uint

// ─────────────────────────────────────────────────────────────────────


struct qemu_plugin_hwaddr* hwaddr = qemu_plugin_get_hwaddr(info, vaddr);


memory_transaction_t tr = {0};

tr.io = (hwaddr && qemu_plugin_hwaddr_is_io(hwaddr));
Expand All @@ -85,7 +93,6 @@ dispatch_memory_access(unsigned int vcpu_index, qemu_plugin_meminfo_t info, uint
tr.s.atomic = mem_info.is_atomic;
tr.s.type = mem_info.is_store ? QEMU_Trans_Store : QEMU_Trans_Load;


flexus_api.trace_mem(vcpu_index, &tr);
}

Expand All @@ -101,9 +108,12 @@ dispatch_memory_access(unsigned int vcpu_index, qemu_plugin_meminfo_t info, uint
static void
dispatch_instruction(unsigned int vcpu_index, void* userdata)
{
if (vcpu_index == 0) {
instruction_count++;
}

trace_insn_t* insn = (trace_insn_t*) userdata;
g_assert(insn->target_pc_va);
//g_assert(insn->target_pc_va);

MemTxAttrs attrs;
branch_type_t br_type;
Expand All @@ -124,6 +134,7 @@ dispatch_instruction(unsigned int vcpu_index, void* userdata)
flexus_api.trace_mem(vcpu_index, &tr);
}


/**
* Get called on every instruction translation
*/
Expand Down