local_variable_free((local_variable_t) * (void **) v);
}
-void MC_region_destroy(mc_mem_region_t reg)
+void MC_region_destroy(mc_mem_region_t region)
{
- if (!reg)
+ if (!region)
return;
-
- //munmap(reg->data, reg->size);
- xbt_free(reg->data);
- if (reg->page_numbers) {
- mc_free_page_snapshot_region(reg->page_numbers, mc_page_count(reg->size));
+ switch(region->storage_type) {
+ case MC_REGION_STORAGE_TYPE_NONE:
+ break;
+ case MC_REGION_STORAGE_TYPE_FLAT:
+ xbt_free(region->flat.data);
+ break;
+ case MC_REGION_STORAGE_TYPE_CHUNKED:
+ mc_free_page_snapshot_region(region->chunked.page_numbers, mc_page_count(region->size));
+ xbt_free(region->chunked.page_numbers);
+ break;
+ case MC_REGION_STORAGE_TYPE_PRIVATIZED:
+ {
+ size_t regions_count = region->privatized.regions_count;
+ for (size_t i=0; i!=regions_count; ++i) {
+ MC_region_destroy(region->privatized.regions[i]);
+ }
+ free(region->privatized.regions);
+ break;
+ }
}
- xbt_free(reg);
+ xbt_free(region);
}
void MC_free_snapshot(mc_snapshot_t snapshot)
{
- unsigned int i;
- for (i = 0; i < NB_REGIONS; i++) {
- MC_region_destroy(snapshot->regions[i]);
+ for (size_t i = 0; i < snapshot->snapshot_regions_count; i++) {
+ MC_region_destroy(snapshot->snapshot_regions[i]);
}
-
+ xbt_free(snapshot->snapshot_regions);
xbt_free(snapshot->stack_sizes);
xbt_dynar_free(&(snapshot->stacks));
xbt_dynar_free(&(snapshot->to_ignore));
xbt_dynar_free(&snapshot->ignored_data);
-
- if (snapshot->privatization_regions) {
- size_t n = xbt_dynar_length(snapshot->enabled_processes);
- for (i = 0; i != n; ++i) {
- MC_region_destroy(snapshot->privatization_regions[i]);
- }
- xbt_free(snapshot->privatization_regions);
- }
-
xbt_free(snapshot);
}
/******************************* Snapshot regions ********************************/
/*********************************************************************************/
-static mc_mem_region_t mc_region_new_dense(int type, void *start_addr, void* permanent_addr, size_t size, mc_mem_region_t ref_reg)
+static mc_mem_region_t mc_region_new_dense(
+ mc_region_type_t region_type,
+ void *start_addr, void* permanent_addr, size_t size, mc_mem_region_t ref_reg)
{
- mc_mem_region_t new_reg = xbt_new(s_mc_mem_region_t, 1);
- new_reg->start_addr = start_addr;
- new_reg->permanent_addr = permanent_addr;
- new_reg->data = NULL;
- new_reg->size = size;
- new_reg->page_numbers = NULL;
- new_reg->data = xbt_malloc(size);
- memcpy(new_reg->data, permanent_addr, size);
+ mc_mem_region_t region = xbt_new(s_mc_mem_region_t, 1);
+ region->region_type = region_type;
+ region->storage_type = MC_REGION_STORAGE_TYPE_FLAT;
+ region->start_addr = start_addr;
+ region->permanent_addr = permanent_addr;
+ region->size = size;
+ region->flat.data = xbt_malloc(size);
+ memcpy(region->flat.data, permanent_addr, size);
XBT_DEBUG("New region : type : %d, data : %p (real addr %p), size : %zu",
- type, new_reg->data, permanent_addr, size);
- return new_reg;
-
+ region_type, region->flat.data, permanent_addr, size);
+ return region;
}
/** @brief Take a snapshot of a given region
* @param size Size of the data*
* @param ref_reg Reference corresponding region
*/
-static mc_mem_region_t MC_region_new(int type, void *start_addr, void* permanent_addr, size_t size, mc_mem_region_t ref_reg)
+static mc_mem_region_t MC_region_new(mc_region_type_t type, void *start_addr, void* permanent_addr, size_t size, mc_mem_region_t ref_reg)
{
if (_sg_mc_sparse_checkpoint) {
return mc_region_new_sparse(type, start_addr, permanent_addr, size, ref_reg);
* @param reg Target region
* @param reg_reg Current region (if not NULL), used for lazy per page restoration
*/
-static void MC_region_restore(mc_mem_region_t reg, mc_mem_region_t ref_reg)
+static void MC_region_restore(mc_mem_region_t region, mc_mem_region_t ref_region)
{
- /*FIXME: check if start_addr is still mapped, if it is not, then map it
- before copying the data */
- if (!reg->page_numbers) {
- memcpy(reg->permanent_addr, reg->data, reg->size);
- } else {
- mc_region_restore_sparse(reg, ref_reg);
+ switch(region->storage_type) {
+ case MC_REGION_STORAGE_TYPE_NONE:
+ default:
+ xbt_die("Storage type not supported");
+ break;
+
+ case MC_REGION_STORAGE_TYPE_FLAT:
+ memcpy(region->permanent_addr, region->flat.data, region->size);
+ break;
+
+ case MC_REGION_STORAGE_TYPE_CHUNKED:
+ mc_region_restore_sparse(region, ref_region);
+ break;
+
+ case MC_REGION_STORAGE_TYPE_PRIVATIZED:
+ {
+ bool has_ref_regions = ref_region &&
+ ref_region->storage_type == MC_REGION_STORAGE_TYPE_PRIVATIZED;
+ size_t process_count = region->privatized.regions_count;
+ for (size_t i = 0; i < process_count; i++) {
+ MC_region_restore(region->privatized.regions[i],
+ has_ref_regions ? ref_region->privatized.regions[i] : NULL);
+ }
+ break;
+ }
}
- return;
}
-static void MC_snapshot_add_region(mc_snapshot_t snapshot, int type,
- void *start_addr, void* permanent_addr, size_t size)
+static inline
+void* MC_privatization_address(mc_process_t process, int process_index)
+{
+ xbt_assert(process_index >= 0);
+ return smpi_privatisation_regions[process_index].address;
+}
+static mc_mem_region_t MC_region_new_privatized(
+ mc_region_type_t region_type, void *start_addr, void* permanent_addr, size_t size,
+ mc_mem_region_t ref_reg)
{
- mc_mem_region_t ref_reg =
- mc_model_checker->parent_snapshot ? mc_model_checker->parent_snapshot->regions[type] : NULL;
- mc_mem_region_t new_reg = MC_region_new(type, start_addr, permanent_addr, size, ref_reg);
- snapshot->regions[type] = new_reg;
+ size_t process_count = smpi_process_count();
+ mc_mem_region_t region = xbt_new(s_mc_mem_region_t, 1);
+ region->region_type = region_type;
+ region->storage_type = MC_REGION_STORAGE_TYPE_PRIVATIZED;
+ region->start_addr = start_addr;
+ region->permanent_addr = permanent_addr;
+ region->size = size;
+ region->privatized.regions_count = process_count;
+ region->privatized.regions = xbt_new(mc_mem_region_t, process_count);
+
+ for (size_t i = 0; i < process_count; i++) {
+ mc_mem_region_t ref_subreg = NULL;
+ if (ref_reg && ref_reg->storage_type == MC_REGION_STORAGE_TYPE_PRIVATIZED)
+ ref_subreg = ref_reg->privatized.regions[i];
+ region->privatized.regions[i] =
+ MC_region_new(region_type, start_addr,
+ MC_privatization_address(&mc_model_checker->process, i), size,
+ ref_subreg);
+ }
+
+ return region;
+}
+
+static void MC_snapshot_add_region(int index, mc_snapshot_t snapshot, mc_region_type_t type,
+ mc_object_info_t object_info,
+ void *start_addr, void* permanent_addr, size_t size)
+{
+ if (type == MC_REGION_TYPE_DATA)
+ xbt_assert(object_info, "Missing object info for object.");
+ else if (type == MC_REGION_TYPE_HEAP)
+ xbt_assert(!object_info, "Unexpected object info for heap region.");
+
+ mc_mem_region_t ref_reg = NULL;
+ if (mc_model_checker->parent_snapshot)
+ ref_reg = mc_model_checker->parent_snapshot->snapshot_regions[index];
+
+ mc_mem_region_t region;
+ const bool privatization_aware = object_info && MC_object_info_executable(object_info);
+ if (privatization_aware && smpi_privatize_global_variables && smpi_process_count())
+ region = MC_region_new_privatized(type, start_addr, permanent_addr, size, ref_reg);
+ else
+ region = MC_region_new(type, start_addr, permanent_addr, size, ref_reg);
+
+ region->object_info = object_info;
+ snapshot->snapshot_regions[index] = region;
return;
}
static void MC_get_memory_regions(mc_snapshot_t snapshot)
{
- mc_process_t process = &mc_model_checker->process;
+ const mc_process_t process = &mc_model_checker->process;
+ const size_t n = process->object_infos_size;
+
+ snapshot->snapshot_regions_count = n + 1;
+ snapshot->snapshot_regions = xbt_new0(mc_mem_region_t, n + 1);
+
+ for (size_t i = 0; i!=n; ++i) {
+ mc_object_info_t object_info = mc_model_checker->process.object_infos[i];
+ MC_snapshot_add_region(i, snapshot, MC_REGION_TYPE_DATA, object_info,
+ object_info->start_rw, object_info->start_rw,
+ object_info->end_rw - object_info->start_rw);
+ }
void *start_heap = std_heap->base;
void *end_heap = std_heap->breakval;
- MC_snapshot_add_region(snapshot, 0, start_heap, start_heap,
- (char *) end_heap - (char *) start_heap);
+ MC_snapshot_add_region(n, snapshot, MC_REGION_TYPE_HEAP, NULL,
+ start_heap, start_heap,
+ (char *) end_heap - (char *) start_heap);
snapshot->heap_bytes_used = mmalloc_get_bytes_used(std_heap);
- snapshot->privatization_regions = NULL;
-
- MC_snapshot_add_region(snapshot, 1,
- process->libsimgrid_info->start_rw, process->libsimgrid_info->start_rw,
- process->libsimgrid_info->end_rw - process->libsimgrid_info->start_rw);
#ifdef HAVE_SMPI
- size_t i;
if (smpi_privatize_global_variables && smpi_process_count()) {
- // Snapshot the global variable of the application separately for each
- // simulated process:
- snapshot->privatization_regions =
- xbt_new(mc_mem_region_t, smpi_process_count());
- for (i = 0; i < smpi_process_count(); i++) {
- mc_mem_region_t ref_reg =
- mc_model_checker->parent_snapshot ? mc_model_checker->parent_snapshot->privatization_regions[i] : NULL;
- snapshot->privatization_regions[i] =
- MC_region_new(-1, process->binary_info->start_rw, smpi_privatisation_regions[i].address, size_data_exe, ref_reg);
- }
snapshot->privatization_index = smpi_loaded_page;
- snapshot->regions[2] = NULL;
} else
#endif
{
- MC_snapshot_add_region(snapshot, 2,
- process->binary_info->start_rw, process->binary_info->start_rw,
- process->binary_info->end_rw - process->binary_info->start_rw);
- snapshot->privatization_regions = NULL;
- snapshot->privatization_index = -1;
+ snapshot->privatization_index = MC_NO_PROCESS_INDEX;
}
}
* */
void MC_find_object_address(memory_map_t maps, mc_object_info_t result)
{
-
unsigned int i = 0;
s_map_region_t reg;
const char *name = basename(result->file_name);
mc_snapshot_t MC_take_snapshot(int num_state)
{
-
mc_snapshot_t snapshot = xbt_new0(s_mc_snapshot_t, 1);
+
snapshot->enabled_processes = xbt_dynar_new(sizeof(int), NULL);
smx_process_t process;
xbt_swag_foreach(process, simix_global->process_list) {
return snapshot;
}
-void MC_restore_snapshot(mc_snapshot_t snapshot)
+static inline
+void MC_restore_snapshot_regions(mc_snapshot_t snapshot)
{
mc_snapshot_t parent_snapshot = mc_model_checker->parent_snapshot;
- int new_fd;
- unsigned int i;
- for (i = 0; i < NB_REGIONS; i++) {
+ const size_t n = snapshot->snapshot_regions_count;
+ for (size_t i = 0; i < n; i++) {
// For privatized, variables we decided it was not necessary to take the snapshot:
- if (snapshot->regions[i])
- MC_region_restore(snapshot->regions[i],
- parent_snapshot ? parent_snapshot->regions[i] : NULL);
+ if (snapshot->snapshot_regions[i])
+ MC_region_restore(snapshot->snapshot_regions[i],
+ parent_snapshot ? parent_snapshot->snapshot_regions[i] : NULL);
}
#ifdef HAVE_SMPI
- if (snapshot->privatization_regions) {
- // Restore the global variables of the application separately for each
- // simulated process:
- for (i = 0; i < smpi_process_count(); i++) {
- if (snapshot->privatization_regions[i]) {
- MC_region_restore(snapshot->privatization_regions[i],
- parent_snapshot ? parent_snapshot->privatization_regions[i] : NULL);
- }
- }
- }
if(snapshot->privatization_index >= 0) {
// We just rewrote the global variables.
// The privatisation segment SMPI thinks
smpi_really_switch_data_segment(snapshot->privatization_index);
}
#endif
+}
+static inline
+void MC_restore_snapshot_fds(mc_snapshot_t snapshot)
+{
+ int new_fd;
+ size_t i;
for(i=0; i < snapshot->total_fd; i++){
new_fd = open(snapshot->current_fd[i]->filename, snapshot->current_fd[i]->flags);
};
lseek(snapshot->current_fd[i]->number, snapshot->current_fd[i]->current_position, SEEK_SET);
}
+}
+void MC_restore_snapshot(mc_snapshot_t snapshot)
+{
+ MC_restore_snapshot_regions(snapshot);
+ MC_restore_snapshot_fds(snapshot);
if (_sg_mc_sparse_checkpoint && _sg_mc_soft_dirty) {
mc_softdirty_reset();
}
-
MC_snapshot_ignore_restore(snapshot);
if (_sg_mc_sparse_checkpoint && _sg_mc_soft_dirty) {
mc_model_checker->parent_snapshot = snapshot;
}
-
}
mc_snapshot_t simcall_HANDLER_mc_snapshot(smx_simcall_t simcall)
mc_snapshot_t snapshot2)
{
xbt_assert(r1 && r2, "Missing region.");
+
+#ifdef HAVE_SMPI
+ if (r1->storage_type == MC_REGION_STORAGE_TYPE_PRIVATIZED) {
+ xbt_assert(process_index >= 0);
+ if (r2->storage_type != MC_REGION_STORAGE_TYPE_PRIVATIZED) {
+ return 1;
+ }
+
+ size_t process_count = smpi_process_count();
+ xbt_assert(process_count == r1->privatized.regions_count
+ && process_count == r2->privatized.regions_count);
+
+ // Compare the global variables separately for each simulates process:
+ for (size_t process_index = 0; process_index < process_count; process_index++) {
+ int is_diff = compare_global_variables(object_info, process_index,
+ r1->privatized.regions[process_index], r2->privatized.regions[process_index],
+ snapshot1, snapshot2);
+ if (is_diff) return 1;
+ }
+ return 0;
+ }
+#else
+ xbt_assert(r1->storage_type != MC_REGION_STORAGE_TYPE_PRIVATIZED);
+#endif
+ xbt_assert(r2->storage_type != MC_REGION_STORAGE_TYPE_PRIVATIZED);
+
struct mc_compare_state state;
xbt_dynar_t variables;
int snapshot_compare(void *state1, void *state2)
{
- mc_process_t process = &mc_model_checker->process;
-
mc_snapshot_t s1, s2;
int num1, num2;
};
#endif
- mc_object_info_t object_infos[] = { NULL, process->libsimgrid_info, process->binary_info };
+ size_t regions_count = s1->snapshot_regions_count;
+ // TODO, raise a difference instead?
+ xbt_assert(regions_count == s2->snapshot_regions_count);
+
+ for (size_t k = 0; k != regions_count; ++k) {
+ mc_mem_region_t region1 = s1->snapshot_regions[k];
+ mc_mem_region_t region2 = s2->snapshot_regions[k];
+
+ // Preconditions:
+ if (region1->region_type != MC_REGION_TYPE_DATA)
+ continue;
+
+ xbt_assert(region1->region_type == region2->region_type);
+ xbt_assert(region1->object_info == region2->object_info);
- int k = 0;
- for (k = 2; k != 0; --k) {
+ xbt_assert(region1->object_info);
#ifdef MC_DEBUG
if (is_diff == 0)
xbt_os_walltimer_stop(timer);
#endif
/* Compare global variables */
-#ifdef HAVE_SMPI
- if (object_infos[k] == process->binary_info && smpi_privatize_global_variables) {
- // Compare the global variables separately for each simulates process:
- for (int process_index = 0; process_index < smpi_process_count(); process_index++) {
- is_diff =
- compare_global_variables(object_infos[k], process_index,
- s1->privatization_regions[process_index], s2->privatization_regions[process_index], s1, s2);
- if (is_diff) break;
- }
- }
- else
-#endif
- is_diff =
- compare_global_variables(object_infos[k], MC_NO_PROCESS_INDEX, s1->regions[k], s2->regions[k], s1, s2);
+ is_diff =
+ compare_global_variables(region1->object_info, MC_NO_PROCESS_INDEX,
+ region1, region2,
+ s1, s2);
if (is_diff != 0) {
XBT_TRACE3(mc, state_diff, num1, num2, "Different global variables");
}
-int mmalloc_compare_heap(mc_snapshot_t snapshot1, mc_snapshot_t snapshot2)
+// TODO, have a robust way to find it in O(1)
+static inline
+mc_mem_region_t MC_get_heap_region(mc_snapshot_t snapshot)
{
+ size_t n = snapshot->snapshot_regions_count;
+ for (size_t i=0; i!=n; ++i) {
+ mc_mem_region_t region = snapshot->snapshot_regions[i];
+ if (region->region_type == MC_REGION_TYPE_HEAP)
+ return region;
+ }
+ xbt_die("No heap region");
+}
+int mmalloc_compare_heap(mc_snapshot_t snapshot1, mc_snapshot_t snapshot2)
+{
struct s_mc_diff *state = mc_diff_info;
/* Start comparison */
malloc_info heapinfo_temp1, heapinfo_temp2;
malloc_info heapinfo_temp2b;
- mc_mem_region_t heap_region1 = snapshot1->regions[0];
- mc_mem_region_t heap_region2 = snapshot2->regions[0];
+ mc_mem_region_t heap_region1 = MC_get_heap_region(snapshot1);
+ mc_mem_region_t heap_region2 = MC_get_heap_region(snapshot2);
// This is in snapshot do not use them directly:
malloc_info* heapinfos1 = mc_snapshot_read_pointer(&std_heap->heapinfo, snapshot1, MC_NO_PROCESS_INDEX);
int pointer_align, res_compare;
ssize_t ignore1, ignore2;
- mc_mem_region_t heap_region1 = snapshot1->regions[0];
- mc_mem_region_t heap_region2 = snapshot2->regions[0];
+ mc_mem_region_t heap_region1 = MC_get_heap_region(snapshot1);
+ mc_mem_region_t heap_region2 = MC_get_heap_region(snapshot2);
while (i < size) {
dw_type_t member;
void *addr_pointed1, *addr_pointed2;;
- mc_mem_region_t heap_region1 = snapshot1->regions[0];
- mc_mem_region_t heap_region2 = snapshot2->regions[0];
+ mc_mem_region_t heap_region1 = MC_get_heap_region(snapshot1);
+ mc_mem_region_t heap_region2 = MC_get_heap_region(snapshot2);
switch (type->type) {
case DW_TAG_unspecified_type:
}
- mc_mem_region_t heap_region1 = snapshot1->regions[0];
- mc_mem_region_t heap_region2 = snapshot2->regions[0];
+ mc_mem_region_t heap_region1 = MC_get_heap_region(snapshot1);
+ mc_mem_region_t heap_region2 = MC_get_heap_region(snapshot2);
malloc_info* heapinfo1 = mc_snapshot_read_region(&heapinfos1[block1], heap_region1, &heapinfo_temp1, sizeof(malloc_info));
malloc_info* heapinfo2 = mc_snapshot_read_region(&heapinfos2[block2], heap_region2, &heapinfo_temp2, sizeof(malloc_info));
xbt_dynar_t functions_index;
};
+static inline __attribute__ ((always_inline))
+bool MC_object_info_executable(mc_object_info_t info)
+{
+ return info->flags & MC_OBJECT_INFO_EXECUTABLE;
+}
+
/** Find the DWARF offset for this ELF object
*
* An offset is applied to address found in DWARF:
// ***** High level API
-mc_mem_region_t mc_region_new_sparse(int type, void *start_addr, void* permanent_addr, size_t size, mc_mem_region_t ref_reg)
+mc_mem_region_t mc_region_new_sparse(mc_region_type_t region_type,
+ void *start_addr, void* permanent_addr, size_t size,
+ mc_mem_region_t ref_reg)
{
- mc_mem_region_t new_reg = xbt_new(s_mc_mem_region_t, 1);
-
- new_reg->start_addr = start_addr;
- new_reg->permanent_addr = permanent_addr;
- new_reg->data = NULL;
- new_reg->size = size;
- new_reg->page_numbers = NULL;
+ mc_mem_region_t region = xbt_new(s_mc_mem_region_t, 1);
+ region->region_type = region_type;
+ region->storage_type = MC_REGION_STORAGE_TYPE_CHUNKED;
+ region->start_addr = start_addr;
+ region->permanent_addr = permanent_addr;
+ region->size = size;
xbt_assert((((uintptr_t)start_addr) & (xbt_pagesize-1)) == 0,
"Not at the beginning of a page");
mc_read_pagemap(pagemap, mc_page_number(NULL, permanent_addr), page_count);
}
+ size_t* reg_page_numbers = NULL;
+ if (ref_reg!=NULL && ref_reg->storage_type == MC_REGION_STORAGE_TYPE_CHUNKED)
+ reg_page_numbers = ref_reg->chunked.page_numbers;
+
// Take incremental snapshot:
- new_reg->page_numbers = mc_take_page_snapshot_region(permanent_addr, page_count, pagemap,
- ref_reg==NULL ? NULL : ref_reg->page_numbers);
+ region->chunked.page_numbers = mc_take_page_snapshot_region(
+ permanent_addr, page_count, pagemap, reg_page_numbers);
if(pagemap) {
mfree(mc_heap, pagemap);
}
- return new_reg;
+ return region;
}
void mc_region_restore_sparse(mc_mem_region_t reg, mc_mem_region_t ref_reg)
mc_read_pagemap(pagemap, mc_page_number(NULL, reg->permanent_addr), page_count);
}
- // Incremental per-page snapshot restoration:
- mc_restore_page_snapshot_region(reg->permanent_addr, page_count, reg->page_numbers,
- pagemap, ref_reg ? ref_reg->page_numbers : NULL);
+ // Incremental per-page snapshot restoration:s
+ size_t* reg_page_numbers = NULL;
+ if (ref_reg && ref_reg->storage_type == MC_REGION_STORAGE_TYPE_CHUNKED)
+ reg_page_numbers = ref_reg->chunked.page_numbers;
+
+ mc_restore_page_snapshot_region(reg->permanent_addr, page_count, reg->chunked.page_numbers,
+ pagemap, reg_page_numbers);
if(pagemap) {
free(pagemap);
* */
mc_mem_region_t mc_get_snapshot_region(void* addr, mc_snapshot_t snapshot, int process_index)
{
-#ifdef HAVE_SMPI
- if (snapshot->privatization_regions) {
-
- if (process_index < 0) {
+ size_t n = snapshot->snapshot_regions_count;
+ for (size_t i = 0; i != n; ++i) {
+ mc_mem_region_t region = snapshot->snapshot_regions[i];
+ if (!(region && mc_region_contain(region, addr)))
+ continue;
- mc_mem_region_t region = snapshot->privatization_regions[0];
- if( mc_region_contain(region, addr) ) {
+ if (region->storage_type == MC_REGION_STORAGE_TYPE_PRIVATIZED) {
+#ifdef HAVE_SMPI
+ if (process_index < 0) {
xbt_die("Missing process index");
}
-
- } else {
- if (process_index >= smpi_process_count()) {
+ if (process_index >= region->privatized.regions_count) {
xbt_die("Invalid process index");
}
-
- mc_mem_region_t region = snapshot->privatization_regions[process_index];
- if( mc_region_contain(region, addr) ) {
- return region;
- }
-
- }
- }
+ mc_mem_region_t priv_region = region->privatized.regions[process_index];
+ xbt_assert(mc_region_contain(priv_region, addr));
+ return priv_region;
+#else
+ xbt_die("Privatized region in a non SMPI build (this should not happen)");
#endif
-
- for (size_t i = 0; i != NB_REGIONS; ++i) {
- mc_mem_region_t region = snapshot->regions[i];
- if ( region && mc_region_contain(region, addr) ) {
- return region;
}
+
+ return region;
}
return NULL;
// Using alloca() for large allocations may trigger stack overflow:
// use malloc if the buffer is too big.
bool stack_alloc = size < 64;
- void* buffer1a = (region1==NULL || region1->data) ? NULL : stack_alloc ? alloca(size) : malloc(size);
- void* buffer2a = (region2==NULL || region2->data) ? NULL : stack_alloc ? alloca(size) : malloc(size);
+ const bool region1_need_buffer = region1==NULL || region1->storage_type==MC_REGION_STORAGE_TYPE_FLAT;
+ const bool region2_need_buffer = region2==NULL || region2->storage_type==MC_REGION_STORAGE_TYPE_FLAT;
+ void* buffer1a = region1_need_buffer ? NULL : stack_alloc ? alloca(size) : malloc(size);
+ void* buffer2a = region2_need_buffer ? NULL : stack_alloc ? alloca(size) : malloc(size);
void* buffer1 = mc_snapshot_read_region(addr1, region1, buffer1a, size);
void* buffer2 = mc_snapshot_read_region(addr2, region2, buffer2a, size);
int res;
// Init memory and take snapshots:
init_memory(source, byte_size);
- mc_mem_region_t region0 = mc_region_new_sparse(0, source, source, byte_size, NULL);
+ mc_mem_region_t region0 = mc_region_new_sparse(MC_REGION_TYPE_UNKNOWN, source, source, byte_size, NULL);
for(int i=0; i<n; i+=2) {
init_memory((char*) source + i*xbt_pagesize, xbt_pagesize);
}
- mc_mem_region_t region = mc_region_new_sparse(0, source, source, byte_size, NULL);
+ mc_mem_region_t region = mc_region_new_sparse(MC_REGION_TYPE_UNKNOWN, source, source, byte_size, NULL);
void* destination = mmap(NULL, byte_size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
xbt_assert(source!=MAP_FAILED, "Could not allocate destination memory");
if (n==1) {
xbt_test_add("Read pointer for %i page(s)", n);
memcpy(source, &mc_model_checker, sizeof(void*));
- mc_mem_region_t region2 = mc_region_new_sparse(0, source, source, byte_size, NULL);
+ mc_mem_region_t region2 = mc_region_new_sparse(MC_REGION_TYPE_UNKNOWN, source, source, byte_size, NULL);
xbt_test_assert(mc_snapshot_read_pointer_region(source, region2) == mc_model_checker,
"Mismtach in mc_snapshot_read_pointer_region()");
MC_region_destroy(region2);
// ***** Snapshot region
-#define NB_REGIONS 3 /* binary data (data + BSS) (type = 2), libsimgrid data (data + BSS) (type = 1), std_heap (type = 0)*/
+typedef enum e_mc_region_type_t {
+ MC_REGION_TYPE_UNKNOWN = 0,
+ MC_REGION_TYPE_HEAP = 1,
+ MC_REGION_TYPE_DATA = 2
+} mc_region_type_t;
+
+// TODO, use OO instead of this
+typedef enum e_mc_region_storeage_type_t {
+ MC_REGION_STORAGE_TYPE_NONE = 0,
+ MC_REGION_STORAGE_TYPE_FLAT = 1,
+ MC_REGION_STORAGE_TYPE_CHUNKED = 2,
+ MC_REGION_STORAGE_TYPE_PRIVATIZED = 3
+} mc_region_storage_type_t;
/** @brief Copy/snapshot of a given memory region
*
- * Two types of region snapshots exist:
+ * Different types of region snapshot storage types exist:
* <ul>
* <li>flat/dense snapshots are a simple copy of the region;</li>
* <li>sparse/per-page snapshots are snaapshots which shared
* identical pages.</li>
+ * <li>privatized (SMPI global variable privatisation).
* </ul>
+ *
+ * This is handled with a variant based approch:
+ *
+ * * `storage_type` identified the type of storage;
+ * * an anonymous enum is used to distinguish the relevant types for
+ * each type.
*/
-typedef struct s_mc_mem_region{
+typedef struct s_mc_mem_region s_mc_mem_region_t, *mc_mem_region_t;
+
+struct s_mc_mem_region {
+ mc_region_type_t region_type;
+ mc_region_storage_type_t storage_type;
+ mc_object_info_t object_info;
+
/** @brief Virtual address of the region in the simulated process */
void *start_addr;
+ /** @brief Size of the data region in bytes */
+ size_t size;
+
/** @brief Permanent virtual address of the region
*
* This is usually the same address as the simuilated process address.
* */
void *permanent_addr;
- /** @brief Copy of the snapshot for flat snapshots regions (NULL otherwise) */
- void *data;
-
- /** @brief Size of the data region in bytes */
- size_t size;
-
- /** @brief Pages indices in the page store for per-page snapshots (NULL otherwise) */
- size_t* page_numbers;
+ union {
+ struct {
+ /** @brief Copy of the snapshot for flat snapshots regions (NULL otherwise) */
+ void *data;
+ } flat;
+ struct {
+ /** @brief Pages indices in the page store for per-page snapshots (NULL otherwise) */
+ size_t* page_numbers;
+ } chunked;
+ struct {
+ size_t regions_count;
+ mc_mem_region_t* regions;
+ } privatized;
+ };
-} s_mc_mem_region_t, *mc_mem_region_t;
+};
-mc_mem_region_t mc_region_new_sparse(int type, void *start_addr, void* data_addr, size_t size, mc_mem_region_t ref_reg);
+mc_mem_region_t mc_region_new_sparse(mc_region_type_t type, void *start_addr, void* data_addr, size_t size, mc_mem_region_t ref_reg);
void MC_region_destroy(mc_mem_region_t reg);
void mc_region_restore_sparse(mc_mem_region_t reg, mc_mem_region_t ref_reg);
void* mc_translate_address_region(uintptr_t addr, mc_mem_region_t region)
{
size_t pageno = mc_page_number(region->start_addr, (void*) addr);
- size_t snapshot_pageno = region->page_numbers[pageno];
+ size_t snapshot_pageno = region->chunked.page_numbers[pageno];
const void* snapshot_page = mc_page_store_get_page(mc_model_checker->pages, snapshot_pageno);
return (char*) snapshot_page + mc_page_offset((void*) addr);
}
return (void *) addr;
}
- // Flat snapshot:
- else if (region->data) {
- uintptr_t offset = addr - (uintptr_t) region->start_addr;
- return (void *) ((uintptr_t) region->data + offset);
- }
+ switch (region->storage_type) {
+ case MC_REGION_STORAGE_TYPE_NONE:
+ default:
+ xbt_die("Storage type not supported");
+
+ case MC_REGION_STORAGE_TYPE_FLAT:
+ {
+ uintptr_t offset = addr - (uintptr_t) region->start_addr;
+ return (void *) ((uintptr_t) region->flat.data + offset);
+ }
- // Per-page snapshot:
- else if (region->page_numbers) {
+ case MC_REGION_STORAGE_TYPE_CHUNKED:
return mc_translate_address_region(addr, region);
- }
- else {
- xbt_die("No data for this memory region");
+ case MC_REGION_STORAGE_TYPE_PRIVATIZED:
+ {
+ xbt_assert(process_index >=0,
+ "Missing process index for privatized region");
+ xbt_assert((size_t) process_index < region->privatized.regions_count,
+ "Out of range process index");
+ mc_mem_region_t subregion = region->privatized.regions[process_index];
+ xbt_assert(subregion, "Missing memory region for process %i", process_index);
+ return mc_translate_address(addr, snapshot, process_index);
+ }
}
}
struct s_mc_snapshot{
size_t heap_bytes_used;
- mc_mem_region_t regions[NB_REGIONS];
+ mc_mem_region_t* snapshot_regions;
+ size_t snapshot_regions_count;
xbt_dynar_t enabled_processes;
- mc_mem_region_t* privatization_regions;
int privatization_index;
size_t *stack_sizes;
xbt_dynar_t stacks;
void mc_free_page_snapshot_region(size_t* pagenos, size_t page_count);
void mc_restore_page_snapshot_region(void* start_addr, size_t page_count, size_t* pagenos, uint64_t* pagemap, size_t* reference_pagenos);
-static inline __attribute__((always_inline))
-bool mc_snapshot_region_linear(mc_mem_region_t region) {
- return !region || !region->data;
-}
-
void* mc_snapshot_read_fragmented(void* addr, mc_mem_region_t region, void* target, size_t size);
void* mc_snapshot_read(void* addr, mc_snapshot_t snapshot, int process_index, void* target, size_t size);
xbt_assert(mc_region_contain(region, addr),
"Trying to read out of the region boundary.");
- // Linear memory region:
- if (region->data) {
- return (char*) region->data + offset;
- }
-
- // Fragmented memory region:
- else if (region->page_numbers) {
- // Last byte of the region:
- void* end = (char*) addr + size - 1;
- if( mc_same_page(addr, end) ) {
- // The memory is contained in a single page:
- return mc_translate_address_region((uintptr_t) addr, region);
- } else {
- // The memory spans several pages:
- return mc_snapshot_read_fragmented(addr, region, target, size);
+ switch (region->storage_type) {
+ case MC_REGION_STORAGE_TYPE_NONE:
+ default:
+ xbt_die("Storage type not supported");
+
+ case MC_REGION_STORAGE_TYPE_FLAT:
+ return (char*) region->flat.data + offset;
+
+ case MC_REGION_STORAGE_TYPE_CHUNKED:
+ {
+ // Last byte of the region:
+ void* end = (char*) addr + size - 1;
+ if( mc_same_page(addr, end) ) {
+ // The memory is contained in a single page:
+ return mc_translate_address_region((uintptr_t) addr, region);
+ } else {
+ // The memory spans several pages:
+ return mc_snapshot_read_fragmented(addr, region, target, size);
+ }
}
- }
- else {
- xbt_die("No data available for this region");
+ // We currently do not pass the process_index to this function so we assume
+ // that the privatized region has been resolved in the callers:
+ case MC_REGION_STORAGE_TYPE_PRIVATIZED:
+ xbt_die("Storage type not supported");
}
}