void master_slaveFinishedCurrentWindow(Master* master, SimulationTime minNextEventTime) { MAGIC_ASSERT(master); utility_assert(minNextEventTime != SIMTIME_INVALID); /* TODO: once we get multiple slaves, we have to block them here * until they have all notified us that they are finished */ /* update our detected min jump time */ master->minJumpTime = master->nextMinJumpTime; /* update the next interval window based on next event times */ SimulationTime newStart = minNextEventTime; SimulationTime newEnd = minNextEventTime + master_getMinTimeJump(master); /* update the new window end as one interval past the new window start, * making sure we dont run over the experiment end time */ if(newEnd > master->endTime) { newEnd = master->endTime; } /* if we are done, make sure the workers know about it */ if(newStart >= newEnd) { master_setKilled(master, TRUE); } /* finally, set the new values */ master->executeWindowStart = newStart; master->executeWindowEnd = newEnd; }
SimulationTime slave_getMinTimeJump(Slave* slave) { MAGIC_ASSERT(slave); _slave_lock(slave); SimulationTime jump = master_getMinTimeJump(slave->master); _slave_unlock(slave); return jump; }
void master_run(Master* master) { MAGIC_ASSERT(master); guint slaveSeed = (guint)random_nextInt(master->random); Slave* slave = slave_new(master, master->config, slaveSeed); /* hook in our logging system. stack variable used to avoid errors * during cleanup below. */ GLogLevelFlags configuredLogLevel = configuration_getLogLevel(master->config); g_log_set_default_handler(logging_handleLog, &(configuredLogLevel)); GDateTime* dt_now = g_date_time_new_now_local(); gchar* dt_format = g_date_time_format(dt_now, "%F %H:%M:%S"); message("Shadow v%s initialized at %s using GLib v%u.%u.%u", SHADOW_VERSION, dt_format, (guint)GLIB_MAJOR_VERSION, (guint)GLIB_MINOR_VERSION, (guint)GLIB_MICRO_VERSION); g_date_time_unref(dt_now); g_free(dt_format); /* store parsed actions from each user-configured simulation script */ GQueue* actions = g_queue_new(); Parser* xmlParser = parser_new(); /* parse built-in examples, or input files */ gboolean success = TRUE; if(master->config->runFileExample) { GString* file = example_getFileExampleContents(); success = parser_parseContents(xmlParser, file->str, file->len, actions); g_string_free(file, TRUE); } else { /* parse all given input XML files */ while(success && g_queue_get_length(master->config->inputXMLFilenames) > 0) { GString* filename = g_queue_pop_head(master->config->inputXMLFilenames); success = parser_parseFile(xmlParser, filename, actions); } } parser_free(xmlParser); /* if there was an error parsing, bounce out */ if(success) { message("successfully parsed Shadow XML input!"); } else { g_queue_free(actions); error("error parsing Shadow XML input!"); } /* * loop through actions that were created from parsing. this will create * all the nodes, networks, applications, etc., and add an application * start event for each node to bootstrap the simulation. Note that the * plug-in libraries themselves are not loaded until a worker needs it, * since each worker will need its own private version. */ while(g_queue_get_length(actions) > 0) { Action* a = g_queue_pop_head(actions); runnable_run(a); runnable_free(a); } g_queue_free(actions); /* start running */ gint nWorkers = configuration_getNWorkerThreads(master->config); debug("starting %i-threaded engine (main + %i workers)", (nWorkers + 1), nWorkers); /* simulation mode depends on configured number of workers */ if(nWorkers > 0) { /* multi threaded, manage the other workers */ master->executeWindowStart = 0; SimulationTime jump = master_getMinTimeJump(master); master->executeWindowEnd = jump; master->nextMinJumpTime = jump; slave_runParallel(slave); } else { /* single threaded, we are the only worker */ master->executeWindowStart = 0; master->executeWindowEnd = G_MAXUINT64; slave_runSerial(slave); } debug("engine finished, cleaning up..."); slave_free(slave); }