コード例 #1
0
ファイル: shd-worker.c プロジェクト: 4sp1r3/shadow
gpointer worker_runSerial(WorkLoad* workload) {
    utility_assert(workload);
    Worker* worker = _worker_getPrivate();

    Event* nextEvent = eventqueue_peek(worker->serialEventQueue);
    if(nextEvent) {
        worker->clock_now = SIMTIME_INVALID;
        worker->clock_last = 0;

        /* process all events in the priority queue */
        while(nextEvent &&
            (shadowevent_getTime(nextEvent) < slave_getExecuteWindowEnd(worker->slave)) &&
            (shadowevent_getTime(nextEvent) < slave_getEndTime(worker->slave)))
        {
            /* get next event */
            nextEvent = eventqueue_pop(worker->serialEventQueue);
            worker->cached_event = nextEvent;
            worker->cached_node = shadowevent_getNode(nextEvent);

            /* ensure priority */
            worker->clock_now = shadowevent_getTime(worker->cached_event);
//          engine->clock = worker->clock_now;
            utility_assert(worker->clock_now >= worker->clock_last);

            gboolean complete = shadowevent_run(worker->cached_event);
            if(complete) {
                shadowevent_free(worker->cached_event);
            }
            worker->cached_event = NULL;
            worker->cached_node = NULL;
            worker->clock_last = worker->clock_now;
            worker->clock_now = SIMTIME_INVALID;

            nextEvent = eventqueue_peek(worker->serialEventQueue);
        }
    }

    slave_setKilled(worker->slave, TRUE);

    /* in single thread mode, we must free the nodes */
    GList* hosts = workload->hosts;
    while(hosts) {
        worker->cached_node = hosts->data;
        host_freeAllApplications(worker->cached_node);
        worker->cached_node = NULL;
        hosts = hosts->next;
    }

    g_list_foreach(workload->hosts, (GFunc) host_free, NULL);

    return NULL;
}
コード例 #2
0
ファイル: shd-worker.c プロジェクト: icbaker/shadow
static guint _worker_processNode(Worker* worker, Node* node, SimulationTime barrier) {
	/* update cache, reset clocks */
	worker->cached_node = node;
	worker->clock_last = SIMTIME_INVALID;
	worker->clock_now = SIMTIME_INVALID;
	worker->clock_barrier = barrier;

	/* lock the node */
	node_lock(worker->cached_node);

	EventQueue* eventq = node_getEvents(worker->cached_node);
	Event* nextEvent = eventqueue_peek(eventq);

	/* process all events in the nodes local queue */
	guint nEventsProcessed = 0;
	while(nextEvent && (nextEvent->time < worker->clock_barrier))
	{
		worker->cached_event = eventqueue_pop(eventq);
		MAGIC_ASSERT(worker->cached_event);

		/* make sure we don't jump backward in time */
		worker->clock_now = worker->cached_event->time;
		if(worker->clock_last != SIMTIME_INVALID) {
			g_assert(worker->clock_now >= worker->clock_last);
		}

		/* do the local task */
		gboolean complete = shadowevent_run(worker->cached_event);

		/* update times */
		worker->clock_last = worker->clock_now;
		worker->clock_now = SIMTIME_INVALID;

		/* finished event can now be destroyed */
		if(complete) {
			shadowevent_free(worker->cached_event);
			nEventsProcessed++;
		}

		/* get the next event, or NULL will tell us to break */
		nextEvent = eventqueue_peek(eventq);
	}

	/* unlock, clear cache */
	node_unlock(worker->cached_node);
	worker->cached_node = NULL;
	worker->cached_event = NULL;

	return nEventsProcessed;
}
コード例 #3
0
ファイル: shd-engine.c プロジェクト: ln5/shadow
static gint _engine_distributeEvents(Engine* engine) {
	MAGIC_ASSERT(engine);

	GList* nodeList = internetwork_getAllNodes(engine->internet);

	/* assign nodes to the worker threads so they get processed */
	GSList* listArray[engine->config->nWorkerThreads];
	memset(listArray, 0, engine->config->nWorkerThreads * sizeof(GSList*));
	gint counter = 0;

	GList* item = g_list_first(nodeList);
	while(item) {
		Node* node = item->data;

		gint i = counter % engine->config->nWorkerThreads;
		listArray[i] = g_slist_append(listArray[i], node);

		counter++;
		item = g_list_next(item);
	}

	/* we will track when workers finish processing their nodes */
	engine->processingLatch = countdownlatch_new(engine->config->nWorkerThreads + 1);
	/* after the workers finish processing, wait for barrier update */
	engine->barrierLatch = countdownlatch_new(engine->config->nWorkerThreads + 1);

	/* start up the workers */
	GSList* workerThreads = NULL;
	for(gint i = 0; i < engine->config->nWorkerThreads; i++) {
		GString* name = g_string_new(NULL);
		g_string_printf(name, "worker-%i", (i+1));
		GThread* t = g_thread_new(name->str, (GThreadFunc)worker_run, (gpointer)listArray[i]);
		workerThreads = g_slist_append(workerThreads, t);
		g_string_free(name, TRUE);
	}

	/* process all events in the priority queue */
	while(engine->executeWindowStart < engine->endTime)
	{
		/* wait for the workers to finish processing nodes before we touch them */
		countdownlatch_countDownAwait(engine->processingLatch);

		/* we are in control now, the workers are waiting at barrierLatch */
		message("execution window [%lu--%lu] ran %u events from %u active nodes",
				engine->executeWindowStart, engine->executeWindowEnd,
				engine->numEventsCurrentInterval,
				engine->numNodesWithEventsCurrentInterval);

		/* check if we should take 1 step ahead or fast-forward our execute window.
		 * since looping through all the nodes to find the minimum event is
		 * potentially expensive, we use a heuristic of only trying to jump ahead
		 * if the last interval had only a few events in it. */
		if(engine->numEventsCurrentInterval < 10) {
			/* we had no events in that interval, lets try to fast forward */
			SimulationTime minNextEventTime = SIMTIME_INVALID;

			item = g_list_first(nodeList);
			while(item) {
				Node* node = item->data;
				EventQueue* eventq = node_getEvents(node);
				Event* nextEvent = eventqueue_peek(eventq);
				if(nextEvent && (nextEvent->time < minNextEventTime)) {
					minNextEventTime = nextEvent->time;
				}
				item = g_list_next(item);
			}

			/* fast forward to the next event */
			engine->executeWindowStart = minNextEventTime;
		} else {
			/* we still have events, lets just step one interval */
			engine->executeWindowStart = engine->executeWindowEnd;
		}

		/* make sure we dont run over the end */
		engine->executeWindowEnd = engine->executeWindowStart + engine->minTimeJump;
		if(engine->executeWindowEnd > engine->endTime) {
			engine->executeWindowEnd = engine->endTime;
		}

		/* reset for next round */
		countdownlatch_reset(engine->processingLatch);
		engine->numEventsCurrentInterval = 0;
		engine->numNodesWithEventsCurrentInterval = 0;

		/* if we are done, make sure the workers know about it */
		if(engine->executeWindowStart >= engine->endTime) {
			engine->killed = TRUE;
		}

		/* release the workers for the next round, or to exit */
		countdownlatch_countDownAwait(engine->barrierLatch);
		countdownlatch_reset(engine->barrierLatch);
	}

	/* wait for the threads to finish their cleanup */
	GSList* threadItem = workerThreads;
	while(threadItem) {
		GThread* t = threadItem->data;
		g_thread_join(t);
		g_thread_unref(t);
		threadItem = g_slist_next(threadItem);
	}
	g_slist_free(workerThreads);

	for(gint i = 0; i < engine->config->nWorkerThreads; i++) {
		g_slist_free(listArray[i]);
	}

	countdownlatch_free(engine->processingLatch);
	countdownlatch_free(engine->barrierLatch);

	/* frees the list struct we own, but not the nodes it holds (those were
	 * taken care of by the workers) */
	g_list_free(nodeList);

	return 0;
}
コード例 #4
0
ファイル: shd-slave.c プロジェクト: 4sp1r3/shadow
void slave_runParallel(Slave* slave) {
    MAGIC_ASSERT(slave);

    GList* nodeList = _slave_getAllHosts(slave);

    /* assign nodes to the worker threads so they get processed */
    WorkLoad workArray[slave->nWorkers];
    memset(workArray, 0, slave->nWorkers * sizeof(WorkLoad));
    gint counter = 0;

    GList* item = g_list_first(nodeList);
    while(item) {
        Host* node = item->data;

        gint i = counter % slave->nWorkers;
        workArray[i].hosts = g_list_append(workArray[i].hosts, node);

        counter++;
        item = g_list_next(item);
    }

    /* we will track when workers finish processing their nodes */
    slave->processingLatch = countdownlatch_new(slave->nWorkers + 1);
    /* after the workers finish processing, wait for barrier update */
    slave->barrierLatch = countdownlatch_new(slave->nWorkers + 1);

    /* start up the workers */
    GSList* workerThreads = NULL;
    for(gint i = 0; i < slave->nWorkers; i++) {
        GString* name = g_string_new(NULL);
        g_string_printf(name, "worker-%i", (i+1));

        workArray[i].slave = slave;
        workArray[i].master = slave->master;

        GThread* t = g_thread_new(name->str, (GThreadFunc)worker_runParallel, &(workArray[i]));
        workerThreads = g_slist_append(workerThreads, t);

        g_string_free(name, TRUE);
    }

    message("started %i worker threads", slave->nWorkers);

    /* process all events in the priority queue */
    while(master_getExecuteWindowStart(slave->master) < master_getEndTime(slave->master))
    {
        /* wait for the workers to finish processing nodes before we touch them */
        countdownlatch_countDownAwait(slave->processingLatch);

        /* we are in control now, the workers are waiting at barrierLatch */
        info("execution window [%"G_GUINT64_FORMAT"--%"G_GUINT64_FORMAT"] ran %u events from %u active nodes",
                master_getExecuteWindowStart(slave->master), master_getExecuteWindowEnd(slave->master),
                slave->numEventsCurrentInterval, slave->numNodesWithEventsCurrentInterval);

        /* check if we should take 1 step ahead or fast-forward our execute window.
         * since looping through all the nodes to find the minimum event is
         * potentially expensive, we use a heuristic of only trying to jump ahead
         * if the last interval had only a few events in it. */
        SimulationTime minNextEventTime = SIMTIME_INVALID;
        if(slave->numEventsCurrentInterval < 10) {
            /* we had no events in that interval, lets try to fast forward */
            item = g_list_first(nodeList);

            /* fast forward to the next event, the new window start will be the next event time */
            while(item) {
                Host* node = item->data;
                EventQueue* eventq = host_getEvents(node);
                Event* nextEvent = eventqueue_peek(eventq);
                SimulationTime nextEventTime = shadowevent_getTime(nextEvent);
                if(nextEvent && (nextEventTime < minNextEventTime)) {
                    minNextEventTime = nextEventTime;
                }
                item = g_list_next(item);
            }

            if(minNextEventTime == SIMTIME_INVALID) {
                minNextEventTime = master_getExecuteWindowEnd(slave->master);
            }
        } else {
            /* we still have events, lets just step one interval,
             * consider the next event as the previous window end */
            minNextEventTime = master_getExecuteWindowEnd(slave->master);
        }

        /* notify master that we finished this round, and what our next event is */
        master_slaveFinishedCurrentWindow(slave->master, minNextEventTime);

        /* reset for next round */
        countdownlatch_reset(slave->processingLatch);
        slave->numEventsCurrentInterval = 0;
        slave->numNodesWithEventsCurrentInterval = 0;

        /* release the workers for the next round, or to exit */
        countdownlatch_countDownAwait(slave->barrierLatch);
        countdownlatch_reset(slave->barrierLatch);
    }

    message("waiting for %i worker threads to finish", slave->nWorkers);

    /* wait for the threads to finish their cleanup */
    GSList* threadItem = workerThreads;
    while(threadItem) {
        GThread* t = threadItem->data;
        /* the join will consume the reference, so unref is not needed */
        g_thread_join(t);
        threadItem = g_slist_next(threadItem);
    }
    g_slist_free(workerThreads);

    message("%i worker threads finished", slave->nWorkers);

    for(gint i = 0; i < slave->nWorkers; i++) {
        WorkLoad w = workArray[i];
        g_list_free(w.hosts);
    }

    countdownlatch_free(slave->processingLatch);
    countdownlatch_free(slave->barrierLatch);

    /* frees the list struct we own, but not the nodes it holds (those were
     * taken care of by the workers) */
    g_list_free(nodeList);
}