ExecutionGroup FindStealingTarget() { var startIndex = m_Rand.Next(0, m_ExecutionGroups.Length - 1); ExecutionGroup executionGroup = null; for (var i = 0; i < m_ExecutionGroups.Length; ++i) { var index = startIndex++ % m_ExecutionGroups.Length; var group = m_ExecutionGroups[index]; // Cannot steal from cooperative execution group for now. // This will guarantee that main thread actors stay on the main thread. if (!group.IsCooperative && group.LoadFactor > k_MinRemoteLoadToSteal && group.m_ActorStates.Count > 1) { executionGroup = group; break; } } // May return null return(executionGroup); }
public void SaveExecutionGroup(ExecutionGroup executionGroup) { executionGroup.Name = CleanResourceName(executionGroup.Name); string resourcePath = Path.Combine(configurationService.ExecutionGroupsDirectory, $"{executionGroup.Name}.json"); EnsurePath(configurationService.ExecutionGroupsDirectory); SaveResource(executionGroup, resourcePath); }
public void SaveExecutionGroupTest() { ExecutionGroup group = TestHelper.GetSingleExecutionGroup(); service.SaveExecutionGroup(group); ExecutionGroup result = TestHelper.GetCreatedExecutionGroup(config, "Test_Script.json"); result.Should().NotBeNull(); }
/// <summary> /// Constructor. /// </summary> public ExecutionGroupCommand( AsyncCommandManager commandManager, ExecutionGroup executionGroup, IAsyncCommand originalCommand) { this.commandManager = commandManager; ExecutionGroup = executionGroup; OriginalCommand = originalCommand; OriginalCommand.CanExecuteChanged += (s, e) => RaiseCanExecuteChanged(); }
/// <summary> /// Add execution group. /// </summary> /// <param name="exectionGroupCallback">Execution group callback.</param> /// <param name="lock">Lock.</param> /// <returns>Command manager.</returns> public IAsyncCommandManager AddGroup(Action <IAsyncCommandGroup> exectionGroupCallback, GroupLockBehavior @lock = GroupLockBehavior.LockAllGroups) { var executionGroup = new ExecutionGroup( commandManager: this, @lock: @lock); exectionGroupCallback(executionGroup); executionGroups.Add(executionGroup); return(this); }
public Scheduler(int nbLogicalCores) { // Add +1 for fake ExecutionGroup to send the Add/Remove one at a time, but from any thread. m_ExecutionGroups = new ExecutionGroup[nbLogicalCores + 1]; for (var i = 0; i < nbLogicalCores + 1; ++i) { m_ExecutionGroups[i] = new ExecutionGroup(i, nbLogicalCores + 1, 0.3f, m_ExecutionGroups); } // Set it as cooperative, it will never execute. m_FakeExecutionGroup = m_ExecutionGroups[nbLogicalCores]; m_FakeExecutionGroup.IsCooperative = true; }
public void RemoveExecutionGroupTest() { ExecutionGroup group = TestHelper.GetSingleExecutionGroup(); business.SaveExecutionGroup(group).Wait(); ExecutionGroup inserted = TestHelper.GetCreatedExecutionGroup(config, "Test_Script.json"); inserted.Should().NotBeNull(); business.RemoveExecutionGroup(inserted.Name).Wait(); ExecutionGroup result = TestHelper.GetCreatedExecutionGroup(config, "Test_Script.json"); result.Should().BeNull(); }
/// <summary> /// Sets the initial state of a <see cref="ProgressStepViewModel"/> /// </summary> /// <param name="viewModel">The <see cref="ProgressStepViewModel"/> instance to initialize</param> /// <param name="group">The logical group which the <see cref="ProgressStepViewModel"/> represent</param> private static void InitializeStep(ProgressStepViewModel viewModel, ExecutionGroup group) { ThreadHelper.ThrowIfNotOnUIThread(); IProgressStep first = group.Steps.First(); IProgressStep nonHiddenStep = group.Steps.FirstOrDefault(s => !s.Hidden); Debug.Assert(nonHiddenStep != null, "The execution group has no visible steps"); viewModel.DisplayText = nonHiddenStep.DisplayText; viewModel.ExecutionState = first.ExecutionState; viewModel.Progress.SetUpperBoundLimitedValue(first.Progress); viewModel.ProgressDetailText = first.ProgressDetailText; viewModel.Progress.IsIndeterminate = group.Steps.Any(s => s.Indeterminate); }
public static ExecutionGroup GetCreatedExecutionGroup(IConfigurationService config, string groupName) { ExecutionGroup result = null; if (File.Exists(Path.Combine(config.ExecutionGroupsDirectory, groupName))) { using (StreamReader reader = new StreamReader(Path.Combine(config.ExecutionGroupsDirectory, groupName))) { string file = reader.ReadToEnd(); reader.Close(); result = JsonSerializer.Deserialize <ExecutionGroup>(file); } } return(result); }
/// <summary> /// Steps could be hidden which means that they won't be visible. In that case the progress needs to be scaled /// to accommodate for those steps and also the visual indicator that a step is running needs be conceptually /// correct - which means that all the hidden steps needed to be aggregated to a non-hidden one for visualization /// purposes. /// </summary> /// <param name="steps">The set of <see cref="IProgressStep"/> that need to group</param> /// <returns>An array of <see cref="ExecutionGroup"/> that represent the grouping of the actual steps</returns> internal static ExecutionGroup[] GroupToExecutionUnits(IEnumerable <IProgressStep> steps) { Debug.Assert(steps.All(s => s.ImpactsProgress), "Expecting only steps which impact the progress"); int numberOfExecutionUnits = steps.Count(s => !s.Hidden); ExecutionGroup[] groups = new ExecutionGroup[numberOfExecutionUnits]; for (int i = 0; i < numberOfExecutionUnits; i++) { groups[i] = new ExecutionGroup(); } // In case no visible steps return an empty array if (groups.Length == 0) { return(groups); } int prevUnit = 0, currentUnit = 0; foreach (IProgressStep step in steps) { // Hidden steps are normally added to the previous visible, unless it // is the case in which the hidden steps are first, in which they will be added // to the following visible if (step.Hidden) { groups[prevUnit].Steps.Add(step); } else { Debug.Assert(currentUnit < groups.Length, "Expecting the current unit not to overflow"); groups[currentUnit].Steps.Add(step); prevUnit = currentUnit; currentUnit++; } } return(groups); }
void SendRemoveActorResponse(ExecutionGroup source, ActorState actorState) { m_IncomingMessages[source.m_Index].TryEnqueue(CreateRemoveActorResponseMessage(source, actorState)); m_HasPendingIncomingMessages = true; // No need to Signal(), it's processed when the client Add() a new actor to the scheduler }
public IExecutionGroup AddGroup() { var group = new ExecutionGroup( this ); _executables.Add( group ); return group; }
protected ExecutionGroup( ExecutionGroup parent ) { _parent = parent; _executables = new List<Executable>(); }
public ThreadMessage(MessageType type, ExecutionGroup source, ActorState actorState) { Type = type; Source = source; ActorState = actorState; }
static ThreadMessage CreateRemoveActorResponseMessage(ExecutionGroup source, ActorState actorState) { return(new ThreadMessage(MessageType.RemoveActorResponse, source, actorState)); }
public ActorState(ExecutionGroup executionGroup, Actor <object> instance, bool isReady) { ExecutionGroup = executionGroup; Instance = instance; IsReady = isReady; }
/// <summary> /// Steps could be hidden which means that they won't be visible. In that case the progress needs to be scaled /// to accommodate for those steps and also the visual indicator that a step is running needs be conceptually /// correct - which means that all the hidden steps needed to be aggregated to a non-hidden one for visualization /// purposes. /// </summary> /// <param name="steps">The set of <see cref="IProgressStep"/> that need to group</param> /// <returns>An array of <see cref="ExecutionGroup"/> that represent the grouping of the actual steps</returns> internal static ExecutionGroup[] GroupToExecutionUnits(IEnumerable<IProgressStep> steps) { Debug.Assert(steps.All(s => s.ImpactsProgress), "Expecting only steps which impact the progress"); int numberOfExecutionUnits = steps.Count(s => !s.Hidden); ExecutionGroup[] groups = new ExecutionGroup[numberOfExecutionUnits]; for (int i = 0; i < numberOfExecutionUnits; i++) { groups[i] = new ExecutionGroup(); } // In case no visible steps return an empty array if (groups.Length == 0) { return groups; } int prevUnit = 0, currentUnit = 0; foreach (IProgressStep step in steps) { // Hidden steps are normally added to the previous visible, unless it // is the case in which the hidden steps are first, in which they will be added // to the following visible if (step.Hidden) { groups[prevUnit].Steps.Add(step); } else { Debug.Assert(currentUnit < groups.Length, "Expecting the current unit not to overflow"); groups[currentUnit].Steps.Add(step); prevUnit = currentUnit; currentUnit++; } } return groups; }
public void SendRemoveActor(ExecutionGroup source, ActorState actorState) { m_IncomingMessages[source.m_Index].TryEnqueue(CreateRemoveActorMessage(source, actorState)); m_HasPendingIncomingMessages = true; Signal(); }
void SendStealActorResponse(ExecutionGroup source, ActorState actorState) { m_IncomingMessages[source.m_Index].TryEnqueue(CreateStealActorResponseMessage(source, actorState)); m_HasPendingIncomingMessages = true; Signal(); }
static ThreadMessage CreateAddActorMessage(ExecutionGroup source, ActorState actorState) { return(new ThreadMessage(MessageType.AddActor, source, actorState)); }
/// <summary> /// Updates the <see cref="ProgressStepViewModel"/> with the current step changes. /// The <see cref="ProgressStepViewModel"/> represents a <see cref="ExecutionGroup"/> /// of one visible step and zero or more hidden steps. The progress in <see cref="ProgressStepViewModel"/> /// is used as the sub progress and it will be indeterminate if there's one indeterminate /// <see cref="IProgressStep"/> in <see cref="ExecutionGroup"/>, otherwise the sub progress /// will be relative to the number of steps in <see cref="ExecutionGroup"/>. /// </summary> /// <param name="e">Execution update</param> private void UpdateViewModelStep(StepExecutionChangedEventArgs e) { ThreadHelper.ThrowIfNotOnUIThread(); ProgressStepViewModel vm = this.progressStepToViewModelMapping[e.Step]; ExecutionGroup executionGroup = this.viewModelToExecutionGroupMapping[vm]; bool isLastStep = e.Step == executionGroup.Steps.Last(); double groupCompletionPercentange = GetCompletedStepCount(executionGroup.Steps) / (double)executionGroup.Steps.Count; this.CurrentExecutingGroup = executionGroup; executionGroup.ExecutingStep = e.Step; // Update the step VM // Progress update: Indeterminate step progress should remain as it was // and the determinate step progress should be updated switch (e.State) { case StepExecutionState.NotStarted: Debug.Fail("Unexpected transition to NotStarted"); if (!vm.Progress.IsIndeterminate) { vm.Progress.SetUpperBoundLimitedValue(0); } break; case StepExecutionState.Executing: if (!vm.Progress.IsIndeterminate) { Debug.Assert(!executionGroup.Steps.Any(s => s.Indeterminate), "Not expecting any Indeterminate steps"); vm.Progress.SetUpperBoundLimitedValue(groupCompletionPercentange + (e.Progress / (double)executionGroup.Steps.Count)); } vm.ExecutionState = e.State; vm.ProgressDetailText = e.ProgressDetailText; break; default: Debug.Assert(ProgressControllerHelper.IsFinalState(e.State), "Unexpected non-final state", "State: {0}", e.State); if (!vm.Progress.IsIndeterminate) { vm.Progress.SetUpperBoundLimitedValue(groupCompletionPercentange); } // Succeeded state which is not the last will indicate // that the group is still executing if (e.State == StepExecutionState.Succeeded && !isLastStep) { vm.ExecutionState = StepExecutionState.Executing; } else { vm.ExecutionState = e.State; } executionGroup.ExecutingStep = null; if (isLastStep) { vm.ProgressDetailText = null; this.CurrentExecutingGroup = null; } break; } vm.ProgressDetailText = e.ProgressDetailText; }
static ThreadMessage CreateStealActorMessage(ExecutionGroup source) { return(new ThreadMessage(MessageType.StealActor, source, null)); }
/// <summary> /// Get execution groups to lock for the given execution group. /// </summary> /// <param name="executionGroup">Execition group.</param> /// <returns>Enumerable of execution groups that shall be locked.</returns> IEnumerable <ExecutionGroup> GetExecutionGroupsToLock(ExecutionGroup executionGroup) { if (executionGroup.Lock == GroupLockBehavior.LockNothing) { return new ExecutionGroup[] { } } ; if (executionGroup.Lock == GroupLockBehavior.LockThisGroup) { return new ExecutionGroup[] { executionGroup } } ; IList <ExecutionGroup> executionGroupsToLock = new List <ExecutionGroup>(); foreach (var ex in executionGroups) { if (ReferenceEquals(ex, executionGroup)) { if (executionGroup.Lock == GroupLockBehavior.LockAllOtherGroups) { continue; } } executionGroupsToLock.Add(ex); } return(executionGroupsToLock); } #region Locking / Unlocking /// <summary> /// Lock execution group. /// </summary> /// <param name="executionGroup">Execution group to lock.</param> void LockExecutionGroup(ExecutionGroup executionGroup) { var groups = GetExecutionGroupsToLock(executionGroup); groups.ForEach(group => Interlocked.Increment(ref group.LockedCounter)); groups.ForEach(group => RaiseCanExecuteChangedForExecutionGroup(group)); } /// <summary> /// Unlock execution group. /// </summary> /// <param name="executionGroup">Execution group to unlock.</param> void UnlockExecutionGroup(ExecutionGroup executionGroup) { var groups = GetExecutionGroupsToLock(executionGroup); groups.ForEach(group => Interlocked.Decrement(ref group.LockedCounter)); groups.ForEach(group => RaiseCanExecuteChangedForExecutionGroup(group)); } #endregion /// <summary> /// Raise CanExecuteChanged for the given execution group. /// </summary> /// <param name="executionGroup">Execution group.</param> void RaiseCanExecuteChangedForExecutionGroup(ExecutionGroup executionGroup) { foreach (var executionGroupCommand in executionGroup.Commands) { try { executionGroupCommand.RaiseCanExecuteChanged(); } catch (Exception) { if (settings.IgnoreExceptionsFromCommands) { return; } throw; } } } #region CanExecute / Execute /// <summary> /// Can execute command from execution group. /// </summary> /// <param name="command">Execution group command.</param> /// <param name="parameter">Command parameter.</param> /// <returns>True, if the command can execute; false otherwise.</returns> bool CanExecuteCommandFromExecutionGroup(ExecutionGroupCommand command, object parameter) { // Check if execution group allows the command to execute. if (command.ExecutionGroup.LockedCounter > 0) { return(false); } // Check if we should ignore the individual can execute method. if (settings.IgnoreIndividualCanExecute) { return(true); } try { return(command.OriginalCommand.CanExecute(parameter)); } catch (Exception) { // If an exception is thrown, and we should ignore it, // then we will simply say the command shall not be called. if (settings.IgnoreExceptionsFromCommands) { return(false); } throw; } } /// <summary> /// Execute command from execution group. /// </summary> /// <param name="command">Execution group command.</param> /// <param name="parameter">Command parameter.</param> /// <returns>Task.</returns> async Task ExecuteCommandFromExecutionGroupAsync(ExecutionGroupCommand command, object parameter) { if (settings.VerifyCanExecuteBeforeExecution) { if (!command.OriginalCommand.CanExecute(parameter)) { return; } } try { LockExecutionGroup(command.ExecutionGroup); await command.OriginalCommand .ExecuteAsync(parameter) .ConfigureAwait(settings.ContinueOnCapturedContext); } catch (Exception) { if (settings.IgnoreExceptionsFromCommands) { return; } throw; } finally { UnlockExecutionGroup(command.ExecutionGroup); } }