source: trunk/CrypPlugins/WorkspaceManager/Execution/ExecutionEngine.cs @ 1627

Last change on this file since 1627 was 1627, checked in by kopal, 11 years ago

Added

  • UpdateGuiInterval (interval for updating the gui elements during execution)
  • CheckInterval (interval for checking plugins being executable)
File size: 14.9 KB
Line 
1/*                             
2   Copyright 2010 Nils Kopal, Viktor M.
3
4   Licensed under the Apache License, Version 2.0 (the "License");
5   you may not use this file except in compliance with the License.
6   You may obtain a copy of the License at
7
8       http://www.apache.org/licenses/LICENSE-2.0
9
10   Unless required by applicable law or agreed to in writing, software
11   distributed under the License is distributed on an "AS IS" BASIS,
12   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   See the License for the specific language governing permissions and
14   limitations under the License.
15*/
16
17using System;
18using System.Collections.Generic;
19using System.Linq;
20using System.Text;
21
22using WorkspaceManager.Model;
23using System.Threading;
24using System.Collections;
25using Cryptool.PluginBase;
26using System.Reflection;
27using Gears4Net;
28using System.Windows.Threading;
29
30namespace WorkspaceManager.Execution
31{
32    /// <summary>
33    /// Engine to execute a model of the WorkspaceManager
34    /// This class needs a WorkspaceManager to be instantiated
35    /// To run an execution process it also needs a WorkspaceModel
36    ///
37    /// This class uses Gears4Net to execute the plugins
38    /// </summary>
39    public class ExecutionEngine
40    {
41        private WorkspaceManager WorkspaceManagerEditor;
42        private Scheduler[] schedulers;
43        private WorkspaceModel workspaceModel;
44
45        public long CheckInterval { get; set; }
46        public long GuiUpdateInterval { get; set; }
47
48        /// <summary>
49        /// Creates a new ExecutionEngine
50        /// </summary>
51        /// <param name="workspaceManagerEditor"></param>
52        public ExecutionEngine(WorkspaceManager workspaceManagerEditor)
53        {
54            WorkspaceManagerEditor = workspaceManagerEditor;
55        }
56
57        /// <summary>
58        /// Is this ExecutionEngine running?
59        /// </summary>
60        public bool IsRunning
61        {
62            get;
63            private set;
64        }
65
66        /// <summary>
67        /// Execute the given Model
68        /// </summary>
69        /// <param name="workspaceModel"></param>
70        public void Execute(WorkspaceModel workspaceModel)
71        {
72            this.workspaceModel = workspaceModel;
73
74            if (!IsRunning)
75            {
76                IsRunning = true;
77
78                //Here we create n = "ProcessorsCount * 2" Gears4Net schedulers
79                //We do this, because measurements showed that we get the best performance if we
80                //use this amount of schedulers
81                schedulers = new Scheduler[System.Environment.ProcessorCount*2];
82                for(int i=0;i<System.Environment.ProcessorCount*2;i++){
83                    schedulers[i] = new WinFormsScheduler("Scheduler" + i);
84                }
85
86                //We have to reset all states of PluginModels, ConnectorModels and ConnectionModels:
87                workspaceModel.resetStates();
88
89                //The UpdateGuiProtocol is a kind of "daemon" which will update the view elements if necessary
90                UpdateGuiProtocol updateGuiProtocol = new UpdateGuiProtocol(schedulers[0], workspaceModel, this);
91                schedulers[0].AddProtocol(updateGuiProtocol);
92                updateGuiProtocol.Start();
93
94                //The CheckExecutableProtocl is also a kind of "daemon" which will check from time to time if a
95                //plugin can be executed again
96                CheckExecutableProtocol checkExecutableProtocol = new CheckExecutableProtocol(schedulers[0], workspaceModel, this);
97                schedulers[0].AddProtocol(checkExecutableProtocol);
98                checkExecutableProtocol.Start();
99
100                //Here we create for each PluginModel an own PluginProtocol
101                //By using round-robin we give each protocol to another scheduler to gain
102                //a good average load balancing of the schedulers
103                int counter=0;
104                foreach (PluginModel pluginModel in workspaceModel.AllPluginModels)
105                {
106                    PluginProtocol pluginProtocol = new PluginProtocol(schedulers[counter], pluginModel,this);
107                    pluginModel.PluginProtocol = pluginProtocol;
108                    schedulers[counter].AddProtocol(pluginProtocol);
109                    pluginModel.checkExecutable(pluginProtocol);
110                    pluginProtocol.Start();
111                    counter = (counter + 1) % (System.Environment.ProcessorCount*2);
112                }
113            }
114        }     
115     
116        /// <summary>
117        /// Stop the execution process:
118        /// calls shutdown on all schedulers + calls stop() on each plugin
119        /// </summary>
120        public void Stop()
121        {
122            //First stop all Gears4Net Schedulers
123            foreach (Scheduler scheduler in schedulers)
124            {
125                scheduler.Shutdown();
126            }
127            //Secondly stop alle plugins
128            foreach(PluginModel pluginModel in workspaceModel.AllPluginModels)
129            {
130                pluginModel.Plugin.Stop();
131            }
132            IsRunning = false;
133        }
134
135        /// <summary>
136        /// Pause the execution
137        /// </summary>
138        public void Pause()
139        {
140            //not implemented yet
141        }
142
143        /// <summary>
144        /// Use the logger of the WorkspaceManagerEditor
145        /// </summary>
146        /// <param name="message"></param>
147        /// <param name="level"></param>
148        public void GuiLogMessage(string message, NotificationLevel level)
149        {           
150            WorkspaceManagerEditor.GuiLogMessage(message, level);
151        }           
152    }
153
154    /// <summary>
155    /// Message send to scheduler for a Plugin to trigger the PreExecution
156    /// </summary>
157    public class MessagePreExecution : MessageBase
158    {
159        public PluginModel PluginModel;
160    }
161
162    /// <summary>
163    /// Message send to scheduler for a Plugin to trigger the Execution
164    /// </summary>
165    public class MessageExecution : MessageBase
166    {
167        public PluginModel PluginModel;
168    }
169
170    /// <summary>
171    /// Message send to scheduler for a Plugin to trigger the PostExecution
172    /// </summary>
173    public class MessagePostExecution : MessageBase
174    {
175        public PluginModel PluginModel;
176    }
177
178    /// <summary>
179    /// A Protocol for updating the GUI in time intervals
180    /// </summary>
181    public class UpdateGuiProtocol : ProtocolBase
182    {
183        private WorkspaceModel workspaceModel;
184        private ExecutionEngine executionEngine;     
185
186        /// <summary>
187        /// Create a new protocol. Each protocol requires a scheduler which provides
188        /// a thread for execution.
189        /// </summary>
190        /// <param name="scheduler"></param>
191        public UpdateGuiProtocol(Scheduler scheduler, WorkspaceModel workspaceModel, ExecutionEngine executionEngine)
192            : base(scheduler)
193        {
194            this.workspaceModel = workspaceModel;
195            this.executionEngine = executionEngine;           
196        }
197
198        /// <summary>
199        /// The main function of the protocol
200        /// </summary>
201        /// <param name="stateMachine"></param>
202        /// <returns></returns>
203        public override System.Collections.Generic.IEnumerator<ReceiverBase> Execute(AbstractStateMachine stateMachine)
204        {
205            while (this.executionEngine.IsRunning)
206            {
207                yield return Timeout(this.executionEngine.GuiUpdateInterval, HandleUpdateGui);
208            }
209        }
210
211        /// <summary>
212        /// Handler function for a message.
213        /// This handler must not block, because it executes inside the thread of the scheduler.
214        /// </summary>
215        /// <param name="msg"></param>
216        private void HandleUpdateGui()
217        {
218            //Get the gui Thread
219            this.workspaceModel.WorkspaceManagerEditor.Presentation.Dispatcher.Invoke(DispatcherPriority.Normal, (SendOrPostCallback)delegate
220            {
221                foreach (PluginModel pluginModel in workspaceModel.AllPluginModels)
222                {
223                    if (pluginModel.GuiNeedsUpdate)
224                    {
225                        //executionEngine.GuiLogMessage("UpdateGui for \"" + pluginModel.Name + "\"", NotificationLevel.Debug);
226                        pluginModel.GuiNeedsUpdate = false;
227                        pluginModel.paint();
228                        if (pluginModel.UpdateableView != null)
229                        {
230                            pluginModel.UpdateableView.update();
231                        }
232                    }
233                }
234                foreach (ConnectionModel connectionModel in workspaceModel.AllConnectionModels)
235                {
236                    if (connectionModel.GuiNeedsUpdate)
237                    {
238                        if (connectionModel.UpdateableView != null)
239                        {
240                            connectionModel.UpdateableView.update();
241                        }
242                    }
243                }
244            }
245            , null);
246        }
247    }
248
249    /// <summary>
250    /// A Protocol for checking if plugins are executable in time intervals
251    /// </summary>
252    public class CheckExecutableProtocol : ProtocolBase
253    {
254        private WorkspaceModel workspaceModel;
255        private ExecutionEngine executionEngine;
256     
257        /// <summary>
258        /// Create a new protocol. Each protocol requires a scheduler which provides
259        /// a thread for execution.
260        /// </summary>
261        /// <param name="scheduler"></param>
262        public CheckExecutableProtocol(Scheduler scheduler, WorkspaceModel workspaceModel, ExecutionEngine executionEngine)
263            : base(scheduler)
264        {
265            this.workspaceModel = workspaceModel;
266            this.executionEngine = executionEngine;
267        }
268
269        /// <summary>
270        /// The main function of the protocol
271        /// </summary>
272        /// <param name="stateMachine"></param>
273        /// <returns></returns>
274        public override System.Collections.Generic.IEnumerator<ReceiverBase> Execute(AbstractStateMachine stateMachine)
275        {
276            while (this.executionEngine.IsRunning)
277            {
278                yield return Timeout(this.executionEngine.CheckInterval, HandleCheckExecutable);
279            }
280        }
281
282        /// <summary>
283        /// Handler function for a message.
284        /// This handler must not block, because it executes inside the thread of the scheduler.
285        /// </summary>
286        /// <param name="msg"></param>
287        private void HandleCheckExecutable()
288        {
289            foreach (PluginModel pluginModel in workspaceModel.AllPluginModels)
290            {
291                pluginModel.checkExecutable(pluginModel.PluginProtocol);
292            }
293        }
294       
295    }
296
297    /// <summary>
298    /// A Protocol for a PluginModel
299    /// </summary>
300    public class PluginProtocol : ProtocolBase
301    {
302        private PluginModel pluginModel;
303        private ExecutionEngine executionEngine;
304
305        /// <summary>
306        /// Create a new protocol. Each protocol requires a scheduler which provides
307        /// a thread for execution.
308        /// </summary>
309        /// <param name="scheduler"></param>
310        public PluginProtocol(Scheduler scheduler, PluginModel pluginModel,ExecutionEngine executionEngine)
311            : base(scheduler)
312        {
313            this.pluginModel = pluginModel;
314            this.executionEngine = executionEngine;
315        }
316
317        /// <summary>
318        /// The main function of the protocol
319        ///
320        /// states are here:
321        ///
322        ///     PreExecution -> Execution -> PostExecution
323        ///        /\                           |
324        ///         |---------------------------|
325        ///         
326        /// </summary>
327        /// <param name="stateMachine"></param>
328        /// <returns></returns>
329        public override System.Collections.Generic.IEnumerator<ReceiverBase> Execute(AbstractStateMachine stateMachine)
330        {
331            while (this.executionEngine.IsRunning)
332            {
333                yield return Receive<MessagePreExecution>(null, this.HandlePreExecute);
334                MessageExecution msg_exec = new MessageExecution();
335                msg_exec.PluginModel = this.pluginModel;
336                this.BroadcastMessageReliably(msg_exec);
337                yield return Receive<MessageExecution>(null, this.HandleExecute);
338                MessagePostExecution msg_post = new MessagePostExecution();
339                msg_post.PluginModel = this.pluginModel;
340                this.BroadcastMessageReliably(msg_post);
341                yield return Receive<MessagePostExecution>(null, this.HandlePostExecute);
342            }
343        }
344
345        /// <summary>
346        /// Call the pre execution function of the wrapped IPlugin
347        /// </summary>
348        /// <param name="msg"></param>
349        private void HandlePreExecute(MessagePreExecution msg)
350        {
351            //executionEngine.GuiLogMessage("HandlePreExecute for \"" + msg.PluginModel.Name + "\"", NotificationLevel.Debug);
352            msg.PluginModel.Plugin.PreExecution();
353        }
354
355        /// <summary>
356        /// Call the execution function of the wrapped IPlugin
357        /// </summary>
358        /// <param name="msg"></param>
359        private void HandleExecute(MessageExecution msg)
360        {
361            //executionEngine.GuiLogMessage("HandleExecute for \"" + msg.PluginModel.Name + "\"", NotificationLevel.Debug);
362            //Fill the plugins Inputs with data
363            foreach (ConnectorModel connectorModel in pluginModel.InputConnectors)
364            {
365                if (connectorModel.HasData)
366                {
367                    PropertyInfo propertyInfo = pluginModel.Plugin.GetType().GetProperty(connectorModel.PropertyName);
368                    propertyInfo.SetValue(pluginModel.Plugin, connectorModel.Data, null);
369                    connectorModel.HasLastData = true;
370                    connectorModel.LastData = connectorModel.Data;
371                    connectorModel.Data = null;
372                    connectorModel.HasData = false;
373                    connectorModel.InputConnection.Active = false;                   
374                }
375            }
376           
377            msg.PluginModel.Plugin.Execute();
378                       
379        }
380
381        /// <summary>
382        /// Call the post execution function of the wrapped IPlugin
383        /// </summary>
384        /// <param name="msg"></param>
385        private void HandlePostExecute(MessagePostExecution msg)
386        {
387            //executionEngine.GuiLogMessage("HandlePostExecute for \"" + msg.PluginModel.Name + "\"", NotificationLevel.Debug);
388            msg.PluginModel.Plugin.PostExecution();
389                     
390        }
391    }
392}
Note: See TracBrowser for help on using the repository browser.