Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 4993 was 4993, checked in by epitzer, 14 years ago

Create own class for OperatorTrace, remove unnecessary event handlers, prevent flickering while stepping, permanently highlight execution context's scope (#47)

File size: 11.2 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.Collections.Generic;
24using System.Linq;
25using System.Threading;
26using HeuristicLab.Common;
27using HeuristicLab.Core;
28using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
29
30namespace HeuristicLab.DebugEngine {
31
32  [StorableClass]
33  [Item("Debug Engine", "Engine for debugging algorithms.")]
34  public class DebugEngine : Executable, IEngine {
35
36    #region Construction and Cloning
37
38    [StorableConstructor]
39    protected DebugEngine(bool deserializing)
40      : base(deserializing) {
41      pausePending = stopPending = false;
42      InitializeTimer();
43    }
44
45    protected DebugEngine(DebugEngine original, Cloner cloner)
46      : base(original, cloner) {
47      if (original.ExecutionState == ExecutionState.Started) throw new InvalidOperationException(string.Format("Clone not allowed in execution state \"{0}\".", ExecutionState));
48      Log = cloner.Clone(original.Log);
49      ExecutionStack = cloner.Clone(original.ExecutionStack);
50      OperatorTrace = cloner.Clone(original.OperatorTrace);
51      operatorParents = original.operatorParents.ToDictionary(kvp => cloner.Clone(kvp.Key), kvp => cloner.Clone(kvp.Value));
52      pausePending = original.pausePending;
53      stopPending = original.stopPending;
54      InitializeTimer();
55      currentOperation = cloner.Clone(original.currentOperation);
56      currentOperator = cloner.Clone(original.currentOperator);
57    }
58    public DebugEngine()
59      : base() {
60      Log = new Log();
61      ExecutionStack = new ExecutionStack();
62      OperatorTrace = new OperatorTrace();
63      operatorParents = new Dictionary<IAtomicOperation, IAtomicOperation>();
64      pausePending = stopPending = false;
65      InitializeTimer();
66    }
67
68    public override IDeepCloneable Clone(Cloner cloner) {
69      return new DebugEngine(this, cloner);
70    }
71
72    private void InitializeTimer() {
73      timer = new System.Timers.Timer(100);
74      timer.AutoReset = true;
75      timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
76    }
77
78    #endregion
79
80    #region Fields and Properties
81
82    [Storable]
83    public ILog Log { get; protected set; }
84
85    [Storable]
86    public ExecutionStack ExecutionStack { get; protected set; }
87
88    [Storable]
89    public OperatorTrace OperatorTrace { get; private set; }
90
91    private bool pausePending, stopPending;
92    private DateTime lastUpdateTime;
93    private System.Timers.Timer timer;
94
95    [Storable]
96    private IOperator currentOperator;
97
98    [Storable]
99    private IOperation currentOperation;
100    public virtual IOperation CurrentOperation {
101      get { return currentOperation; }
102      private set {
103        if (value != currentOperation) {
104          currentOperation = value;
105          OnOperationChanged(value);
106        }
107      }
108    }
109
110    public virtual IAtomicOperation CurrentAtomicOperation {
111      get { return CurrentOperation as IAtomicOperation; }
112    }
113
114    public virtual IExecutionContext CurrentExecutionContext {
115      get { return CurrentOperation as IExecutionContext; }
116    }
117
118
119    [Storable]
120    private Dictionary<IAtomicOperation, IAtomicOperation> operatorParents;
121
122    public virtual bool CanContinue {
123      get { return CurrentOperation != null || ExecutionStack.Count > 0; }
124    }
125
126    public virtual bool IsAtBreakpoint {
127      get { return CurrentAtomicOperation != null && CurrentAtomicOperation.Operator != null && CurrentAtomicOperation.Operator.Breakpoint; }
128    }
129
130    #endregion
131
132    #region Events
133
134    public event EventHandler<OperationChangedEventArgs> CurrentOperationChanged;
135    protected virtual void OnOperationChanged(IOperation newOperation) {
136      EventHandler<OperationChangedEventArgs> handler = CurrentOperationChanged;
137      if (handler != null) {
138        handler(this, new OperationChangedEventArgs(newOperation));
139      }
140    }
141
142    #endregion
143
144    #region Std Methods
145    public sealed override void Prepare() {
146      base.Prepare();
147      ExecutionStack.Clear();
148      CurrentOperation = null;
149      OperatorTrace.Clear();
150      operatorParents.Clear();
151      OnPrepared();
152    }
153    public void Prepare(IOperation initialOperation) {
154      base.Prepare();
155      ExecutionStack.Clear();
156      if (initialOperation != null)
157        ExecutionStack.Add(initialOperation);
158      CurrentOperation = null;
159      OperatorTrace.Clear();
160      operatorParents.Clear();
161      OnPrepared();
162    }
163    protected override void OnPrepared() {
164      Log.LogMessage("Engine prepared");
165      base.OnPrepared();
166    }
167
168    public virtual void Step(bool skipStackOperations) {
169      OnStarted();
170      lastUpdateTime = DateTime.Now;
171      timer.Start();
172      ProcessNextOperation();
173      while (skipStackOperations && !(CurrentOperation is IAtomicOperation) && CanContinue)
174        ProcessNextOperation();
175      timer.Stop();
176      ExecutionTime += DateTime.Now - lastUpdateTime;
177      OnPaused();
178    }
179
180    public override void Start() {
181      base.Start();
182      ThreadPool.QueueUserWorkItem(new WaitCallback(Run), null);
183    }
184
185    protected override void OnStarted() {
186      Log.LogMessage("Engine started");
187      base.OnStarted();
188    }
189
190    public override void Pause() {
191      base.Pause();
192      pausePending = true;
193      if (currentOperator != null) currentOperator.Abort();
194    }
195
196    protected override void OnPaused() {
197      Log.LogMessage("Engine paused");
198      base.OnPaused();
199    }
200
201    public override void Stop() {
202      CurrentOperation = null;
203      base.Stop();
204      stopPending = true;
205      if (currentOperator != null) currentOperator.Abort();
206      if (ExecutionState == ExecutionState.Paused) OnStopped();
207    }
208
209    protected override void OnStopped() {
210      Log.LogMessage("Engine stopped");
211      base.OnStopped();
212    }
213
214    protected override void OnExceptionOccurred(Exception exception) {
215      Log.LogException(exception);
216      base.OnExceptionOccurred(exception);
217    }
218
219    private void Run(object state) {
220      OnStarted();
221      pausePending = stopPending = false;
222
223      lastUpdateTime = DateTime.Now;
224      timer.Start();
225      if (!pausePending && !stopPending && CanContinue)
226        ProcessNextOperation();
227      while (!pausePending && !stopPending && CanContinue && !IsAtBreakpoint)
228        ProcessNextOperation();
229      timer.Stop();
230      ExecutionTime += DateTime.Now - lastUpdateTime;
231
232      if (IsAtBreakpoint)
233        Log.LogMessage(string.Format("Breaking before: {0}", CurrentAtomicOperation.Operator.Name));
234      if (pausePending || IsAtBreakpoint)
235        OnPaused();
236      else
237        OnStopped();
238    }
239
240    private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) {
241      DateTime now = DateTime.Now;
242      ExecutionTime += now - lastUpdateTime;
243      lastUpdateTime = now;
244    }
245    #endregion
246
247    #region Methods
248
249
250
251    /// <summary>
252    /// Deals with the next operation, if it is an <see cref="AtomicOperation"/> it is executed,
253    /// if it is a <see cref="CompositeOperation"/> its single operations are pushed on the execution stack.
254    /// </summary>
255    /// <remarks>If an error occurs during the execution the operation is aborted and the operation
256    /// is pushed on the stack again.<br/>
257    /// If the execution was successful <see cref="EngineBase.OnOperationExecuted"/> is called.</remarks>
258    protected virtual void ProcessNextOperation() {
259      try {
260        IAtomicOperation atomicOperation = CurrentOperation as IAtomicOperation;
261        OperationCollection operations = CurrentOperation as OperationCollection;
262        if (atomicOperation != null && operations != null)
263          throw new InvalidOperationException("Current operation is both atomic and an operation collection");
264
265        if (atomicOperation != null) {
266          Log.LogMessage(string.Format("Performing atomic operation {0}", Name(atomicOperation)));
267          PerformAtomicOperation(atomicOperation);
268        } else if (operations != null) {
269          Log.LogMessage("Expanding operation collection");
270          ExecutionStack.AddRange(operations.Reverse());
271          CurrentOperation = null;
272        } else if (ExecutionStack.Count > 0) {
273          Log.LogMessage("Popping execution stack");
274          CurrentOperation = ExecutionStack.Last();
275          ExecutionStack.RemoveAt(ExecutionStack.Count - 1);
276        } else {
277          Log.LogMessage("Nothing to do");
278        }
279        GenerateOperationTrace();
280      } catch (Exception x) {
281        OnExceptionOccurred(x);
282      }
283    }
284
285    private void GenerateOperationTrace() {
286      var operation = CurrentOperation as IAtomicOperation;
287      if (operation != null) {
288        List<IOperator> trace = new List<IOperator>();
289        while (operation != null) {
290          trace.Add(operation.Operator);
291          IAtomicOperation parent = null;
292          operatorParents.TryGetValue(operation, out parent);
293          operation = parent;
294        }
295        trace.Reverse();
296        OperatorTrace.ReplaceAll(trace);
297      }
298    }
299
300    protected virtual void PerformAtomicOperation(IAtomicOperation operation) {
301      if (operation != null) {
302        try {
303          currentOperator = operation.Operator;
304          IOperation successor = operation.Operator.Execute((IExecutionContext)operation);
305          if (successor != null) {
306            AssignParents(operation, successor);
307            ExecutionStack.Add(successor);
308          }
309          currentOperator = null;
310          CurrentOperation = null;
311        } catch (Exception ex) {
312          OnExceptionOccurred(new OperatorExecutionException(operation.Operator, ex));
313          Pause();
314        }
315      }
316    }
317
318    private void AssignParents(IAtomicOperation parent, IOperation successor) {
319      OperationCollection operations = successor as OperationCollection;
320      if (operations != null)
321        foreach (var op in operations)
322          AssignParents(parent, op);
323      IAtomicOperation atomicOperation = successor as IAtomicOperation;
324      if (atomicOperation != null && atomicOperation.Operator != null && !operatorParents.ContainsKey(atomicOperation))
325        operatorParents[atomicOperation] = parent;
326    }
327
328    protected virtual string Name(IAtomicOperation operation) {
329      return string.IsNullOrEmpty(operation.Operator.Name) ? operation.Operator.ItemName : operation.Operator.Name;
330    }
331
332    #endregion
333  }
334}
Note: See TracBrowser for help on using the repository browser.