source: branches/HeuristicLab.DebugEngine/DebugEngine.cs @ 4871

Last change on this file since 4871 was 4871, checked in by epitzer, 9 years ago

Refactoring and modularization of DebugEngine (#47)

File size: 9.9 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Linq;
24using System.Collections.Generic;
25using HeuristicLab.Common;
26using HeuristicLab.Core;
27using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
28using HeuristicLab.Collections;
29using System.Threading;
30
31namespace HeuristicLab.DebugEngine {
32
33  [StorableClass]
34  [Item("Debug Engine", "Engine for debugging algorithms.")]
35  public class DebugEngine : Executable, IEngine {
36
37
38    #region Construction and Cloning
39   
40    [StorableConstructor]
41    protected DebugEngine(bool deserializing) : base(deserializing) {
42      pausePending = stopPending = false;
43      timer = new System.Timers.Timer(100);
44      timer.AutoReset = true;
45      timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
46    }
47    protected DebugEngine(DebugEngine original, Cloner cloner) : base(original, cloner) {
48      if (original.ExecutionState == ExecutionState.Started) throw new InvalidOperationException(string.Format("Clone not allowed in execution state \"{0}\".", ExecutionState));
49      Log = cloner.Clone(original.Log);
50      ExecutionStack = cloner.Clone(original.ExecutionStack);
51      pausePending = original.pausePending;
52      stopPending = original.stopPending;
53      timer = new System.Timers.Timer(100);
54      timer.AutoReset = true;
55      timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
56      this.currentOperation = cloner.Clone(original.currentOperation);
57      this.currentOperator = cloner.Clone(original.currentOperator);
58    }
59    public DebugEngine()
60      : base() {
61      Log = new Log();
62      ExecutionStack = new ExecutionStack();
63      pausePending = stopPending = false;
64      timer = new System.Timers.Timer(100);
65      timer.AutoReset = true;
66      timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
67    }
68
69    public override IDeepCloneable Clone(Cloner cloner) {
70      return new DebugEngine(this, cloner);
71    }
72
73    #endregion
74
75    #region Fields and Properties
76
77    [Storable]
78    public ILog Log { get; protected set; }
79
80    [Storable]
81    public ExecutionStack ExecutionStack { get; protected set; }
82
83    private bool pausePending, stopPending;
84    private DateTime lastUpdateTime;
85    private System.Timers.Timer timer;
86     
87    [Storable]
88    private IOperator currentOperator;
89
90    [Storable]
91    private bool ignoreNextBreakpoint;
92
93    [Storable]
94    private IOperation currentOperation;
95    public virtual IOperation CurrentOperation {
96      get { return currentOperation; }
97      private set {
98        if (value == currentOperation)
99          return;
100        currentOperation = value;
101        OnOperationChanged(value);
102      }
103    }
104
105    public virtual IAtomicOperation CurrentAtomicOperation {
106      get { return CurrentOperation as IAtomicOperation; }
107    }
108
109    public virtual IExecutionContext CurrentExecutionContext {
110      get { return CurrentOperation as IExecutionContext;  }
111    }
112
113    #endregion
114
115    #region Events
116
117    public event EventHandler<OperationChangedEventArgs> CurrentOperationChanged;
118
119    protected virtual void OnOperationChanged(IOperation newOperation) {
120      EventHandler<OperationChangedEventArgs> handler = CurrentOperationChanged;
121      if (handler != null) {
122        handler(this, new OperationChangedEventArgs(newOperation));
123      }
124    }
125
126    #endregion
127
128    #region Std Methods
129    public sealed override void Prepare() {
130      base.Prepare();
131      ExecutionStack.Clear();
132      ignoreNextBreakpoint = false;
133      CurrentOperation = null;
134      OnPrepared();
135    }
136    public void Prepare(IOperation initialOperation) {
137      base.Prepare();
138      ExecutionStack.Clear();
139      if (initialOperation != null)
140        ExecutionStack.Add(initialOperation);
141      ignoreNextBreakpoint = false;
142      CurrentOperation = null;
143      OnPrepared();
144    }
145    protected override void OnPrepared() {
146      Log.LogMessage("Engine prepared");
147      base.OnPrepared();
148    }
149
150    public virtual void Step() {
151      OnStarted();
152      lastUpdateTime = DateTime.Now;
153      ignoreNextBreakpoint = true;
154      timer.Start();
155      ProcessNextOperation();     
156      timer.Stop();
157      ExecutionTime += DateTime.Now - lastUpdateTime;
158      ignoreNextBreakpoint = false;
159      OnPaused();
160    }
161
162    public override void Start() {
163      base.Start();
164      CurrentOperation = null;
165      ThreadPool.QueueUserWorkItem(new WaitCallback(Run), null);
166    }
167   
168    protected override void OnStarted() {
169      Log.LogMessage("Engine started");
170      base.OnStarted();
171    }
172
173    public override void Pause() {
174      base.Pause();
175      pausePending = true;
176      if (currentOperator != null) currentOperator.Abort();
177    }
178
179    protected override void OnPaused() {
180      Log.LogMessage("Engine paused");
181      base.OnPaused();
182    }
183
184    public override void Stop() {
185      CurrentOperation = null;
186      base.Stop();
187      stopPending = true;
188      if (currentOperator != null) currentOperator.Abort();
189      ignoreNextBreakpoint = false;
190      if (ExecutionState == ExecutionState.Paused) OnStopped();
191    }
192   
193    protected override void OnStopped() {
194      Log.LogMessage("Engine stopped");
195      base.OnStopped();
196    }
197
198    protected override void OnExceptionOccurred(Exception exception) {
199      Log.LogException(exception);
200      base.OnExceptionOccurred(exception);
201    }
202
203    private void Run(object state) {
204      OnStarted();
205      pausePending = stopPending = false;
206
207      lastUpdateTime = DateTime.Now;
208      timer.Start();
209      while (!pausePending && !stopPending && CanContinue) {
210        ProcessNextOperation();
211      }
212      timer.Stop();
213      ExecutionTime += DateTime.Now - lastUpdateTime;
214
215      if (pausePending) OnPaused();
216      else OnStopped();
217    }
218
219    private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) {
220      DateTime now = DateTime.Now;
221      ExecutionTime += now - lastUpdateTime;
222      lastUpdateTime = now;
223    }
224    #endregion
225
226    #region Methods
227
228    public virtual bool CanContinue {
229      get { return CurrentOperation != null || ExecutionStack.Count > 0; }
230    }
231
232    /// <summary>
233    /// Deals with the next operation, if it is an <see cref="AtomicOperation"/> it is executed,
234    /// if it is a <see cref="CompositeOperation"/> its single operations are pushed on the execution stack.
235    /// </summary>
236    /// <remarks>If an error occurs during the execution the operation is aborted and the operation
237    /// is pushed on the stack again.<br/>
238    /// If the execution was successful <see cref="EngineBase.OnOperationExecuted"/> is called.</remarks>
239    protected virtual void ProcessNextOperation() {
240      try {
241        IAtomicOperation atomicOperation = CurrentOperation as IAtomicOperation;
242        OperationCollection operations = CurrentOperation as OperationCollection;
243        if (atomicOperation != null && operations != null)
244          throw new InvalidOperationException("Current operation is both atomic and an operation collection");
245
246        if (atomicOperation != null) {
247          Log.LogMessage(string.Format("Performing atomic operation {0}", Name(atomicOperation)));
248          PerformAtomicOperation(atomicOperation);
249        } else if (operations != null) {
250          Log.LogMessage("Expanding operation collection");
251          ExpandOperationCollection(operations);
252        } else if (ExecutionStack.Count > 0) {
253          Log.LogMessage("Poping execution stack");
254          CurrentOperation = ExecutionStack.Last();
255          ExecutionStack.RemoveAt(ExecutionStack.Count - 1);
256        } else {
257          Log.LogMessage("Nothing to do");
258        }
259      } catch (Exception x) {
260        OnExceptionOccurred(x);
261      }
262    }
263
264    protected virtual void PerformAtomicOperation(IAtomicOperation operation) {
265      if (operation != null) {
266        if (operation.Operator.Breakpoint) {
267          if (ignoreNextBreakpoint) {
268            ignoreNextBreakpoint = false;
269          } else {
270            ignoreNextBreakpoint = true;
271            Log.LogMessage(string.Format("Breaking before: {0}", Name(operation)));
272            Pause();
273            return;
274          }
275        }
276        try {
277          currentOperator = operation.Operator;
278          IOperation successor = operation.Operator.Execute((IExecutionContext)operation);
279          CurrentOperation = null;
280          currentOperator = null;
281          if (successor != null) {
282            ExecutionStack.Add(successor);
283          }
284        } catch (Exception ex) {
285          OnExceptionOccurred(new OperatorExecutionException(operation.Operator, ex));
286          Pause();
287        }
288      }
289    }
290
291    protected virtual void ExpandOperationCollection(OperationCollection operations) {
292      ExecutionStack.AddRange(operations.Reverse());
293      CurrentOperation = null;
294    }
295
296    protected virtual string Name(IAtomicOperation operation) {
297      return string.IsNullOrEmpty(operation.Operator.Name) ? operation.Operator.ItemName : operation.Operator.Name;
298    }
299
300    #endregion
301  }
302}
Note: See TracBrowser for help on using the repository browser.