Skip to content
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
23 changes: 23 additions & 0 deletions src/ROOT-Sim.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,24 @@ extern void ScheduleNewEvent(lp_id_t receiver, simtime_t timestamp, unsigned eve

extern void SetState(void *new_state);

/**
* @brief Marks a memory region as dirty for incremental checkpointing.
*
* This function is injected at compile time by the software instrumentation
* tool before every memory-write instruction in the model code. It marks the
* corresponding blocks in the buddy system's dirty bitmap, so that only the
* dirtied blocks are saved in the next incremental checkpoint.
*
* LP-visible memory lives in the buddy system's base_mem[] buffer; writes to
* the longest[] allocation tree are tracked separately by buddy_malloc() and
* buddy_free() via direct bitmap_set() calls. Therefore, this function only
* needs to handle writes whose addresses fall within base_mem[].
*
* @param ptr A pointer to the start of the memory region being written to.
* @param size The size of the memory region being written to, in bytes.
*/
extern void WriteMemory(const void *ptr, const size_t size);

/**
* @brief Allocates rollbackable memory
*
Expand Down Expand Up @@ -193,6 +211,11 @@ struct simulation_configuration {
const char *stats_file;
/// The checkpointing interval
unsigned ckpt_interval;
/// If set, incremental checkpointing is enabled
bool incremental_ckpt;
/// Period (in number of checkpoints) at which a full checkpoint is forced when incremental
/// checkpointing is enabled. If zero, full checkpoints are only taken at LP initialization.
unsigned full_ckpt_period;
/// If set, worker threads are bound to physical cores
bool core_binding;
/// Specify what synchronization algorithm we are using
Expand Down
1 change: 1 addition & 0 deletions src/log/stats.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ const char *const stats_names[] = {
[STATS_CKPT] = "checkpoints",
[STATS_CKPT_TIME] = "checkpoints time",
[STATS_CKPT_SIZE] = "checkpoints size",
[STATS_CKPT_INCR_SIZE] = "incremental checkpoints size",
[STATS_MSG_SILENT] = "silent messages",
[STATS_MSG_SILENT_TIME] = "silent messages time",
[STATS_MSG_ANTI] = "anti messages",
Expand Down
2 changes: 2 additions & 0 deletions src/log/stats.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ enum stats_thread_type {
STATS_CKPT_TIME,
/// The size of LPs checkpoints
STATS_CKPT_SIZE,
/// The actual size of incremental checkpoints (smaller than full_ckpt_size)
STATS_CKPT_INCR_SIZE,
/// The count of messages processed in coasting forward, i.e. silently executed messages
STATS_MSG_SILENT,
/// The time taken to carry out silent processing activities
Expand Down
5 changes: 5 additions & 0 deletions src/lp/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,11 @@ static inline void checkpoint_take(struct lp_ctx *lp)
const timer_uint t = timer_hr_new();
model_allocator_checkpoint_take(&lp->mm_state, array_count(lp->p.pes));
stats_take(STATS_CKPT_SIZE, lp->mm_state.full_ckpt_size);
if(global_config.incremental_ckpt) {
struct mm_log last = array_peek(lp->mm_state.logs);
if(is_log_incremental(last))
stats_take(STATS_CKPT_INCR_SIZE, log_get_ckpt(last)->incr_ckpt_size);
}
stats_take(STATS_CKPT, 1);
stats_take(STATS_CKPT_TIME, timer_hr_value(t));
}
Expand Down
52 changes: 32 additions & 20 deletions src/mm/buddy/buddy.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ void buddy_init(struct buddy_state *self)
self->longest[idx] = node_size;
node_size -= is_power_of_2(idx + 2);
}
memset(self->dirty, 0, sizeof(self->dirty));
}


Expand Down Expand Up @@ -61,19 +62,16 @@ void *buddy_malloc(struct buddy_state *self, const uint_fast8_t req_blks_exp)

/* update the *longest* value back */
self->longest[idx] = 0;
#ifdef ROOTSIM_INCREMENTAL
bitmap_set(self->dirty, idx >> B_BLOCK_EXP);
#endif
if(global_config.incremental_ckpt)
bitmap_set(self->dirty, idx >> B_BLOCK_EXP);

const uint_fast32_t offset = ((idx + 1) << node_size) - (1 << B_TOTAL_EXP);

while(idx) {
idx = buddy_parent(idx);
self->longest[idx] =
max(self->longest[buddy_left_child(idx)], self->longest[buddy_right_child(idx)]);
#ifdef ROOTSIM_INCREMENTAL
bitmap_set(self->dirty, idx >> B_BLOCK_EXP);
#endif
self->longest[idx] = max(self->longest[buddy_left_child(idx)], self->longest[buddy_right_child(idx)]);
if(global_config.incremental_ckpt)
bitmap_set(self->dirty, idx >> B_BLOCK_EXP);
}

return ((char *)self->base_mem) + offset;
Expand Down Expand Up @@ -102,16 +100,16 @@ uint_fast32_t buddy_free(struct buddy_state *self, void *ptr)

self->longest[idx] = node_size;
const uint_fast32_t ret = (uint_fast32_t)1U << node_size;
#ifdef ROOTSIM_INCREMENTAL
bitmap_set(self->dirty, idx >> B_BLOCK_EXP);
if(global_config.incremental_ckpt) {
bitmap_set(self->dirty, idx >> B_BLOCK_EXP);

uint_fast32_t bitmap_idx = (1 << (node_size - B_BLOCK_EXP)) - 1;
offset += (1 << (B_TOTAL_EXP - 2 * B_BLOCK_EXP + 1));
// Track freed blocks content because full checkpoints don't
do {
bitmap_set(self->dirty, offset + bitmap_idx);
} while(bitmap_idx--);
#endif
uint_fast32_t bitmap_idx = (1 << (node_size - B_BLOCK_EXP)) - 1;
offset += (1 << (B_TOTAL_EXP - 2 * B_BLOCK_EXP + 1));
// Track freed blocks content because full checkpoints don't
do {
bitmap_set(self->dirty, offset + bitmap_idx);
} while(bitmap_idx--);
}

while(idx) {
idx = buddy_parent(idx);
Expand All @@ -124,9 +122,8 @@ uint_fast32_t buddy_free(struct buddy_state *self, void *ptr)
} else {
self->longest[idx] = max(left_long, right_long);
}
#ifdef ROOTSIM_INCREMENTAL
bitmap_set(self->dirty, i >> B_BLOCK_EXP);
#endif
if(global_config.incremental_ckpt)
bitmap_set(self->dirty, idx >> B_BLOCK_EXP);
++node_size;
}
return ret;
Expand Down Expand Up @@ -178,6 +175,21 @@ struct buddy_realloc_res buddy_best_effort_realloc(const struct buddy_state *sel
return ret;
}

/**
* @brief Resets the dirty bitmap of a buddy system.
*
* Clears all dirty-tracking bits so that the next incremental checkpoint
* will only record blocks dirtied after this call. This should be called
* after every checkpoint (full or incremental) when incremental checkpointing
* is enabled.
*
* @param self Pointer to the `buddy_state` structure.
*/
void buddy_dirty_reset(struct buddy_state *self)
{
memset(self->dirty, 0, sizeof(self->dirty));
}

/**
* @brief Marks a memory region as dirty for incremental checkpointing.
*
Expand Down
2 changes: 2 additions & 0 deletions src/mm/buddy/buddy.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ static_assert(offsetof(struct buddy_state, longest) ==
extern void buddy_init(struct buddy_state *self);
extern void *buddy_malloc(struct buddy_state *self, uint_fast8_t req_blks_exp);
extern uint_fast32_t buddy_free(struct buddy_state *self, void *ptr);
extern void buddy_dirty_reset(struct buddy_state *self);
extern void buddy_dirty_mark(const struct buddy_state *self, const void *ptr, size_t size);

/**
* @brief Represents the result of a best-effort reallocation in the buddy system.
Expand Down
Loading
Loading