void SerialScheduleNewEvent(unsigned int rcv, simtime_t stamp, unsigned int event_type, void *event_content, unsigned int event_size) { msg_t *event; // Sanity checks if(stamp < current_lvt) { rootsim_error(true, "LP %d is trying to send events in the past. Current time: %f, scheduled time: %f\n", current_lp, current_lvt, stamp); } if(event_size > MAX_EVENT_SIZE) { rootsim_error(true, "Trying to schedule an event too large. Maximum size is %d, requested is %d. Recompile changing MAX_EVENT_SIZE\n", MAX_EVENT_SIZE, event_size); } // Populate the message data structure event = rsalloc(sizeof(msg_t)); bzero(event, sizeof(msg_t)); event->sender = current_lp; event->receiver = rcv; event->timestamp = stamp; event->send_time = current_lvt; event->type = event_type; event->size = event_size; memcpy(event->event_content, event_content, event_size); // Put the event in the Calenda Queue calqueue_put(stamp, event); }
static void setup_numa_nodes(void) { unsigned int i; numa_nodes = rsalloc(sizeof(int) * n_cores); for(i = 0; i < n_cores; i++) { numa_nodes[i] = query_numa_node(i); } }
void serial_init(int argc, char **argv, int app_arg) { register unsigned int t; // Initialize the calendar queue calqueue_init(); // TODO: qua è necessario inizializzare il sottosistema delle statistiche, utilizzando il nuovo approccio (da pensare) // Initialize the per LP variables serial_states = rsalloc(sizeof(void *) * n_prc_tot); serial_completed_simulation = rsalloc(sizeof(bool) * n_prc_tot); bzero(serial_states, sizeof(void *) * n_prc_tot); bzero(serial_completed_simulation, sizeof(bool) * n_prc_tot); // Sanity check on the number of LPs if(n_prc_tot == 0) { rootsim_error(true, "You must specify the total number of Logical Processes\n"); } // We must pass the application-level args to the LP in the INIT event. // Skip all the NULL args (if any) while (argv[app_arg] != NULL && (argv[app_arg][0] == '\0' || argv[app_arg][0] == ' ')) { app_arg++; } // Generate the INIT events for all the LPs for (t = 0; t < n_prc_tot; t++) { // Copy the relevant string pointers to the INIT event payload if((argc - app_arg) > 0) { SerialScheduleNewEvent(t, 0.0, INIT, &argv[app_arg], (argc - app_arg) * sizeof(char *)); } else { SerialScheduleNewEvent(t, 0.0, INIT, NULL, 0); } } // No LP is scheduled now current_lp = IDLE_PROCESS; }
void calqueue_put(double timestamp, void *payload) { int i; calqueue_node *new_node, *traverse; // Fill the node entry new_node = rsalloc(sizeof(calqueue_node)); new_node->timestamp = timestamp; new_node->payload = payload; new_node->next = NULL; // Calculate the number of the bucket in which to place the new entry i = (int)(timestamp / (double)cwidth); // Virtual bucket i = i % nbuckets; // Actual bucket // Grab the head of events list in bucket i traverse = calendar[i]; // Put at the head of the list, if appropriate if(traverse == NULL || traverse->timestamp > timestamp) { new_node->next = traverse; calendar[i] = new_node; } else { // Find the correct place in list while(traverse->next != NULL && traverse->next->timestamp <= timestamp) traverse = traverse->next; // Place the new event new_node->next = traverse->next; traverse->next = new_node; } // Update queue size qsize++; // Double the calendar size if needed if(qsize > top_threshold && nbuckets < MAXNBUCKETS) { resize(2 * nbuckets); } }
/** * This function creates a full log of the current simulation states and returns a pointer to it. * The algorithm behind this function is based on packing of the really allocated memory chunks into * a contiguous memory area, exploiting some threshold-based approach to fasten it up even more. * The contiguous copy is performed precomputing the size of the full log, and then scanning it * using a pointer for storing the relevant information. * * For further information, please see the paper: * R. Toccaceli, F. Quaglia * DyMeLoR: Dynamic Memory Logger and Restorer Library for Optimistic Simulation Objects * with Generic Memory Layout * Proceedings of the 22nd Workshop on Principles of Advanced and Distributed Simulation * 2008 * * To fully understand the changes in this function to support the incremental logging as well, * please point to the paper: * A. Pellegrini, R. Vitali, F. Quaglia * Di-DyMeLoR: Logging only Dirty Chunks for Efficient Management of Dynamic Memory Based * Optimistic Simulation Objects * Proceedings of the 23rd Workshop on Principles of Advanced and Distributed Simulation * 2009 * * @author Roberto Toccaceli * @author Francesco Quaglia * @author Alessandro Pellegrini * @author Roberto Vitali * * @param lid The logical process' local identifier * @return A pointer to a malloc()'d memory area which contains the full log of the current simulation state, * along with the relative meta-data which can be used to perform a restore operation. * * @todo must be declared static. This will entail changing the logic in gvt.c to save a state before rebuilding. */ void *log_full(int lid) { void *ptr, *ckpt; int i, j, k, idx, bitmap_blocks; size_t size, chunk_size; malloc_area * m_area; // Timers for self-tuning of the simulation platform timer checkpoint_timer; timer_start(checkpoint_timer); size = sizeof(malloc_state) + sizeof(seed_type) + m_state[lid]->busy_areas * sizeof(malloc_area) + m_state[lid]->bitmap_size + m_state[lid]->total_log_size; // This code is in a malloc-wrapper package, so here we call the real malloc ckpt = rsalloc(size); if(ckpt == NULL) rootsim_error(true, "(%d) Unable to acquire memory for ckptging the current state (memory exhausted?)"); ptr = ckpt; // Copy malloc_state in the ckpt memcpy(ptr, m_state[lid], sizeof(malloc_state)); ptr = (void *)((char *)ptr + sizeof(malloc_state)); ((malloc_state*)ckpt)->timestamp = current_lvt; ((malloc_state*)ckpt)->is_incremental = 0; // Copy the per-LP Seed State (to make the numerical library rollbackable and PWD) memcpy(ptr, &LPS[lid]->seed, sizeof(seed_type)); ptr = (void *)((char *)ptr + sizeof(seed_type)); for(i = 0; i < m_state[lid]->num_areas; i++){ m_area = &m_state[lid]->areas[i]; // Copy the bitmap bitmap_blocks = m_area->num_chunks / NUM_CHUNKS_PER_BLOCK; if (bitmap_blocks < 1) bitmap_blocks = 1; // Check if there is at least one chunk used in the area if(m_area->alloc_chunks == 0){ m_area->dirty_chunks = 0; m_area->state_changed = 0; if (m_area->use_bitmap != NULL) { for(j = 0; j < bitmap_blocks; j++) m_area->dirty_bitmap[j] = 0; } continue; } // Copy malloc_area into the ckpt memcpy(ptr, m_area, sizeof(malloc_area)); ptr = (void*)((char*)ptr + sizeof(malloc_area)); memcpy(ptr, m_area->use_bitmap, bitmap_blocks * BLOCK_SIZE); ptr = (void*)((char*)ptr + bitmap_blocks * BLOCK_SIZE); chunk_size = m_area->chunk_size; RESET_BIT_AT(chunk_size, 0); // ckpt Mode bit RESET_BIT_AT(chunk_size, 1); // Lock bit // Check whether the area should be completely copied (not on a per-chunk basis) // using a threshold-based heuristic if(CHECK_LOG_MODE_BIT(m_area)){ // If the malloc_area is almost (over a threshold) full, copy it entirely memcpy(ptr, m_area->area, m_area->num_chunks * chunk_size); ptr = (void*)((char*)ptr + m_area->num_chunks * chunk_size); } else { // Copy only the allocated chunks for(j = 0; j < bitmap_blocks; j++){ // Check the allocation bitmap on a per-block basis, to enhance scan speed if(m_area->use_bitmap[j] == 0) { // Empty (no-chunks-allocated) block: skip to the next continue; } else { // At least one chunk is allocated: per-bit scan of the block is required for(k = 0; k < NUM_CHUNKS_PER_BLOCK; k++){ if(CHECK_BIT_AT(m_area->use_bitmap[j], k)){ idx = j * NUM_CHUNKS_PER_BLOCK + k; memcpy(ptr, (void*)((char*)m_area->area + (idx * chunk_size)), chunk_size); ptr = (void*)((char*)ptr + chunk_size); } } } } } // Reset Dirty Bitmap, as there is a full ckpt in the chain now m_area->dirty_chunks = 0; m_area->state_changed = 0; bzero((void *)m_area->dirty_bitmap, bitmap_blocks * BLOCK_SIZE); } // For each m_area in m_state // Sanity check if ((char *)ckpt + size != ptr){ rootsim_error(false, "Actual (full) ckpt size different from the estimated one! ckpt = %p size = %x (%d), ptr = %p\n", ckpt, size, size, ptr); } m_state[lid]->dirty_areas = 0; m_state[lid]->dirty_bitmap_size = 0; m_state[lid]->total_inc_size = 0; int checkpoint_time = timer_value_micro(checkpoint_timer); statistics_post_lp_data(lid, STAT_CKPT_TIME, (double)checkpoint_time); statistics_post_lp_data(lid, STAT_CKPT_MEM, (double)size); return ckpt; }