/// <summary> /// Executes the experiment. /// </summary> /// <param name="progress">The progress.</param> public void ExecuteExperiment(IProgress progress) { try { bool successful = true; string endMessage = Messages.ExperimentRunnerSuccessMessage; OnExperimentStarted(); if (m_runnableExperiment.IsEmpty == false) { if (progress != null) { progress.Reset(); progress.NumSteps = m_runnableExperiment.Nodes.Count; // Start at 1 so user can tell something is happening. progress.Increment(); progress.CurrentStatus = Messages.ProgressExperimentProcessing; } // collection of nodes currently executing ActiveNodesList currentActiveNodesList = new ActiveNodesList(m_runnableExperiment.TerminateExperimentExecutionResetEvent); // collection of nodes pending to be started Queue <RunnableNode> pendingNodesToBeRun = new Queue <RunnableNode>(); // enqueue start node pendingNodesToBeRun.Enqueue(m_runnableExperiment.StartNode); bool end = false; while (!end) //until end component is not completed { //activate all pending nodes while (pendingNodesToBeRun.Count > 0) { RunnableNode node = pendingNodesToBeRun.Dequeue(); if (currentActiveNodesList.Contains(node) == false) { RunnableNodeThreadArgs args = new RunnableNodeThreadArgs { ExperimentRunner = this }; var resetEvent = node.Run(args); currentActiveNodesList.Add(node, resetEvent); } } if (currentActiveNodesList.Count > 0) { //wait for any node to be completed int index = WaitHandle.WaitAny(currentActiveNodesList.NodeResetEvents); //the index 0 is the termination signal... if the index is higher than zero then process the completed node if (index > 0) { RunnableNode completedNode = currentActiveNodesList.TakeOutNode(index); if (progress != null) { progress.Increment(); } // if experiment runner reaches end node, then prepare to exit the experiment runner if (completedNode.Equals(m_runnableExperiment.EndNode)) { end = true; // if there are any other nodes still running other than end node if (currentActiveNodesList.Count > 1) { successful = false; endMessage = Messages.ExperimentRunnerErrorMessage; TerminateExperimentExecution(); //send signal terminate in case sth else in sub level experiment is running NLog.LogManager.GetCurrentClassLogger().Error(Messages.ExperimentRunnerEarlyTerminationErrorMessage); } } else { // send one token to all successor nodes foreach (RunnableNode successorNode in completedNode.NextNodes) { //sends token; method will return true if successor node is ready to be run bool readyToRun = successorNode.SendToken(); if (readyToRun) { //add node to the pending nodes to be activated pendingNodesToBeRun.Enqueue(successorNode); } } } } else { //EXECUTED ON SIGNAL TERMINATED // If any node signal TERMINATE for any reason, we shut down the experiment and stop processing new nodes. end = true; successful = false; endMessage = Messages.ExperimentExecutionTerminated; System.Diagnostics.Trace.WriteLine("TERMINATED!"); } } else { end = true; successful = false; endMessage = Messages.ExperimentRunnerInfiniteWaitDetected; TerminateExperimentExecution(); //send signal terminate in case sth else in sub level experiment is running System.Diagnostics.Trace.WriteLine("Infinite wait detected!"); } } // while(!end) //wait if there are any still running threads, only in case if experiment runner ended on termination foreach (RunnableNode n in currentActiveNodesList.Nodes) { //Blocks this thread until all node threads terminate. n.JoinNodeThread(); } } else // if (m_runnableExperiment.IsEmpty == false) { #if DEBUG NLog.LogManager.GetCurrentClassLogger().Debug("RunnableExperiment is empty"); #endif successful = false; endMessage = Messages.ExperimentRunnerErrorMessage; } if (progress != null) { progress.Reset(); if (!successful) { progress.SetError(true); } progress.CurrentStatus = endMessage; } } finally { if (m_disposeRunnableExperiment == true) { // destroy components app domain... note the app domain should not be destroyed by sub level experiments TraceLab.Core.Components.LibraryHelper.DestroyDomain(m_runnableExperiment.ComponentsAppDomain); //dispose entire experiment - it disposes all subexperiments as well. m_runnableExperiment.Dispose(); } OnExperimentFinished(); } }
/// <summary> /// Executes the experiment. /// </summary> /// <param name="progress">The progress.</param> public void ExecuteExperiment(IProgress progress) { try { bool successful = true; string endMessage = Messages.ExperimentRunnerSuccessMessage; OnExperimentStarted(); if (m_runnableExperiment.IsEmpty == false) { if (progress != null) { progress.Reset(); progress.NumSteps = m_runnableExperiment.Nodes.Count; // Start at 1 so user can tell something is happening. progress.Increment(); progress.CurrentStatus = Messages.ProgressExperimentProcessing; } // collection of nodes currently executing ActiveNodesList currentActiveNodesList = new ActiveNodesList(m_runnableExperiment.TerminateExperimentExecutionResetEvent); // collection of nodes pending to be started Queue<RunnableNode> pendingNodesToBeRun = new Queue<RunnableNode>(); // enqueue start node pendingNodesToBeRun.Enqueue(m_runnableExperiment.StartNode); bool end = false; while (!end) //until end component is not completed { //activate all pending nodes while (pendingNodesToBeRun.Count > 0) { RunnableNode node = pendingNodesToBeRun.Dequeue(); if (currentActiveNodesList.Contains(node) == false) { RunnableNodeThreadArgs args = new RunnableNodeThreadArgs { ExperimentRunner = this }; var resetEvent = node.Run(args); currentActiveNodesList.Add(node, resetEvent); } } if (currentActiveNodesList.Count > 0) { //wait for any node to be completed int index = WaitHandle.WaitAny(currentActiveNodesList.NodeResetEvents); //the index 0 is the termination signal... if the index is higher than zero then process the completed node if (index > 0) { RunnableNode completedNode = currentActiveNodesList.TakeOutNode(index); if (progress != null) { progress.Increment(); } // if experiment runner reaches end node, then prepare to exit the experiment runner if (completedNode.Equals(m_runnableExperiment.EndNode)) { end = true; // if there are any other nodes still running other than end node if (currentActiveNodesList.Count > 1) { successful = false; endMessage = Messages.ExperimentRunnerErrorMessage; TerminateExperimentExecution(); //send signal terminate in case sth else in sub level experiment is running NLog.LogManager.GetCurrentClassLogger().Error(Messages.ExperimentRunnerEarlyTerminationErrorMessage); } } else { // send one token to all successor nodes foreach (RunnableNode successorNode in completedNode.NextNodes) { //sends token; method will return true if successor node is ready to be run bool readyToRun = successorNode.SendToken(); if (readyToRun) { //add node to the pending nodes to be activated pendingNodesToBeRun.Enqueue(successorNode); } } } } else { //EXECUTED ON SIGNAL TERMINATED // If any node signal TERMINATE for any reason, we shut down the experiment and stop processing new nodes. end = true; successful = false; endMessage = Messages.ExperimentExecutionTerminated; System.Diagnostics.Trace.WriteLine("TERMINATED!"); } } else { end = true; successful = false; endMessage = Messages.ExperimentRunnerInfiniteWaitDetected; TerminateExperimentExecution(); //send signal terminate in case sth else in sub level experiment is running System.Diagnostics.Trace.WriteLine("Infinite wait detected!"); } } // while(!end) //wait if there are any still running threads, only in case if experiment runner ended on termination foreach (RunnableNode n in currentActiveNodesList.Nodes) { //Blocks this thread until all node threads terminate. n.JoinNodeThread(); } } else // if (m_runnableExperiment.IsEmpty == false) { #if DEBUG NLog.LogManager.GetCurrentClassLogger().Debug("RunnableExperiment is empty"); #endif successful = false; endMessage = Messages.ExperimentRunnerErrorMessage; } if (progress != null) { progress.Reset(); if (!successful) { progress.SetError(true); } progress.CurrentStatus = endMessage; } } finally { if (m_disposeRunnableExperiment == true) { // destroy components app domain... note the app domain should not be destroyed by sub level experiments TraceLab.Core.Components.LibraryHelper.DestroyDomain(m_runnableExperiment.ComponentsAppDomain); //dispose entire experiment - it disposes all subexperiments as well. m_runnableExperiment.Dispose(); } OnExperimentFinished(); } }