From e3f5ca3fd3726e67046afbd03e48e9cd7294b835 Mon Sep 17 00:00:00 2001 From: Gabriel Corona Date: Fri, 5 Dec 2014 16:05:50 +0100 Subject: [PATCH 1/1] [mc] Multiple .so support for region snapshots The region snapshoting logic can handle a variable number of .so files: * add more informations to the snapshot regions, * the type (heap, library/executable); * the correspoding library/executable; * the type of storage (dense/flat, chunked/sparse or privatised) and the type-specific variables are defined in an enum (variant/tagged enum). * SMPI privatisation snapshot regions are stored as children of a parent snapshot region Limitation: * we might want to use a more modular/extensible approach OO for the snapshot region storage type instead of variant-based approach; * SMPI can currently only handle privatisation for the local variables of the executable so this is only supported in the MC as well for this reason but otherwise the MC is ready to support the SMPI privatisation of libraries. --- src/mc/mc_checkpoint.c | 248 ++++++++++++++++++++++-------------- src/mc/mc_compare.cpp | 64 +++++++--- src/mc/mc_diff.c | 30 +++-- src/mc/mc_object_info.h | 6 + src/mc/mc_page_snapshot.cpp | 37 ++++-- src/mc/mc_snapshot.c | 50 ++++---- src/mc/mc_snapshot.h | 143 ++++++++++++++------- 7 files changed, 366 insertions(+), 212 deletions(-) diff --git a/src/mc/mc_checkpoint.c b/src/mc/mc_checkpoint.c index cd4310a1df..0f3cb094a7 100644 --- a/src/mc/mc_checkpoint.c +++ b/src/mc/mc_checkpoint.c @@ -67,59 +67,64 @@ static void local_variable_free_voidp(void *v) 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 @@ -130,7 +135,7 @@ static mc_mem_region_t mc_region_new_dense(int type, void *start_addr, void* per * @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); @@ -149,67 +154,124 @@ static mc_mem_region_t MC_region_new(int type, void *start_addr, void* permanent * @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; } } @@ -219,7 +281,6 @@ static void MC_get_memory_regions(mc_snapshot_t snapshot) * */ 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); @@ -618,8 +679,8 @@ static void MC_get_current_fd(mc_snapshot_t snapshot){ 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) { @@ -657,30 +718,20 @@ mc_snapshot_t MC_take_snapshot(int num_state) 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 @@ -691,7 +742,13 @@ void MC_restore_snapshot(mc_snapshot_t snapshot) 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); @@ -706,16 +763,19 @@ void MC_restore_snapshot(mc_snapshot_t snapshot) }; 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) diff --git a/src/mc/mc_compare.cpp b/src/mc/mc_compare.cpp index c5395acc33..ca13c3e002 100644 --- a/src/mc/mc_compare.cpp +++ b/src/mc/mc_compare.cpp @@ -260,6 +260,32 @@ static int compare_global_variables(mc_object_info_t object_info, 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; @@ -357,8 +383,6 @@ static int compare_local_variables(int process_index, int snapshot_compare(void *state1, void *state2) { - mc_process_t process = &mc_model_checker->process; - mc_snapshot_t s1, s2; int num1, num2; @@ -547,10 +571,22 @@ int snapshot_compare(void *state1, void *state2) }; #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); @@ -558,20 +594,10 @@ int snapshot_compare(void *state1, void *state2) #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"); diff --git a/src/mc/mc_diff.c b/src/mc/mc_diff.c index 2566334954..089a9b2cd0 100644 --- a/src/mc/mc_diff.c +++ b/src/mc/mc_diff.c @@ -415,9 +415,21 @@ void reset_heap_information() } -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 */ @@ -434,8 +446,8 @@ int mmalloc_compare_heap(mc_snapshot_t snapshot1, mc_snapshot_t snapshot2) 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); @@ -776,8 +788,8 @@ static int compare_heap_area_without_type(struct s_mc_diff *state, int process_i 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) { @@ -881,8 +893,8 @@ top: 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: @@ -1204,8 +1216,8 @@ int compare_heap_area(int process_index, void *area1, void *area2, mc_snapshot_t } - 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)); diff --git a/src/mc/mc_object_info.h b/src/mc/mc_object_info.h index 57a83a8e2d..ea7775336a 100644 --- a/src/mc/mc_object_info.h +++ b/src/mc/mc_object_info.h @@ -73,6 +73,12 @@ struct s_mc_object_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: diff --git a/src/mc/mc_page_snapshot.cpp b/src/mc/mc_page_snapshot.cpp index 499e5f210f..dcf0d9bbc8 100644 --- a/src/mc/mc_page_snapshot.cpp +++ b/src/mc/mc_page_snapshot.cpp @@ -159,15 +159,16 @@ static void mc_read_pagemap(uint64_t* pagemap, size_t page_start, size_t page_co // ***** 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"); @@ -181,14 +182,18 @@ mc_mem_region_t mc_region_new_sparse(int type, void *start_addr, void* permanent 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) @@ -205,9 +210,13 @@ 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); diff --git a/src/mc/mc_snapshot.c b/src/mc/mc_snapshot.c index 97c4017b0e..5746848cd4 100644 --- a/src/mc/mc_snapshot.c +++ b/src/mc/mc_snapshot.c @@ -23,35 +23,29 @@ * */ 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; @@ -131,8 +125,10 @@ int mc_snapshot_region_memcmp( // 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; @@ -219,11 +215,11 @@ static void test_snapshot(bool sparse_checkpoint) { // 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 *
  • flat/dense snapshots are a simple copy of the region;
  • *
  • sparse/per-page snapshots are snaapshots which shared * identical pages.
  • + *
  • privatized (SMPI global variable privatisation). * + * + * 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. @@ -52,18 +80,24 @@ typedef struct s_mc_mem_region{ * */ 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); @@ -78,7 +112,7 @@ static inline __attribute__((always_inline)) 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); } @@ -115,19 +149,30 @@ void* mc_translate_address(uintptr_t addr, mc_snapshot_t snapshot, int process_i 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); + } } } @@ -153,9 +198,9 @@ typedef struct s_fd_infos{ 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; @@ -234,11 +279,6 @@ size_t* mc_take_page_snapshot_region(void* data, size_t page_count, uint64_t* pa 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); @@ -285,26 +325,31 @@ void* mc_snapshot_read_region(void* addr, mc_mem_region_t region, void* target, 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"); } } -- 2.20.1