예제 #1
0
            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);
            }
예제 #2
0
        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);
        }
예제 #3
0
        public void SaveExecutionGroupTest()
        {
            ExecutionGroup group = TestHelper.GetSingleExecutionGroup();

            service.SaveExecutionGroup(group);
            ExecutionGroup result = TestHelper.GetCreatedExecutionGroup(config, "Test_Script.json");

            result.Should().NotBeNull();
        }
예제 #4
0
            /// <summary>
            /// Constructor.
            /// </summary>
            public ExecutionGroupCommand(
                AsyncCommandManager commandManager,
                ExecutionGroup executionGroup,
                IAsyncCommand originalCommand)
            {
                this.commandManager = commandManager;
                ExecutionGroup      = executionGroup;
                OriginalCommand     = originalCommand;

                OriginalCommand.CanExecuteChanged += (s, e) => RaiseCanExecuteChanged();
            }
예제 #5
0
        /// <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);
        }
예제 #6
0
        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;
        }
예제 #7
0
        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();
        }
예제 #8
0
        /// <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);
        }
예제 #9
0
        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);
        }
예제 #10
0
        /// <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);
        }
예제 #11
0
 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
 }
예제 #12
0
			public IExecutionGroup AddGroup()
			{
				var group = new ExecutionGroup( this );

				_executables.Add( group );

				return group;
			}
예제 #13
0
			protected ExecutionGroup( ExecutionGroup parent )
			{
				_parent = parent;
				_executables = new List<Executable>();
			}
예제 #14
0
 public ThreadMessage(MessageType type, ExecutionGroup source, ActorState actorState)
 {
     Type       = type;
     Source     = source;
     ActorState = actorState;
 }
예제 #15
0
 static ThreadMessage CreateRemoveActorResponseMessage(ExecutionGroup source, ActorState actorState)
 {
     return(new ThreadMessage(MessageType.RemoveActorResponse, source, actorState));
 }
예제 #16
0
 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;
        }
예제 #18
0
 public void SendRemoveActor(ExecutionGroup source, ActorState actorState)
 {
     m_IncomingMessages[source.m_Index].TryEnqueue(CreateRemoveActorMessage(source, actorState));
     m_HasPendingIncomingMessages = true;
     Signal();
 }
예제 #19
0
 void SendStealActorResponse(ExecutionGroup source, ActorState actorState)
 {
     m_IncomingMessages[source.m_Index].TryEnqueue(CreateStealActorResponseMessage(source, actorState));
     m_HasPendingIncomingMessages = true;
     Signal();
 }
예제 #20
0
 static ThreadMessage CreateAddActorMessage(ExecutionGroup source, ActorState actorState)
 {
     return(new ThreadMessage(MessageType.AddActor, source, actorState));
 }
예제 #21
0
        /// <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;
        }
예제 #22
0
 static ThreadMessage CreateStealActorMessage(ExecutionGroup source)
 {
     return(new ThreadMessage(MessageType.StealActor, source, null));
 }
        /// <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);
        }
예제 #24
0
        /// <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);
            }
        }