Free cookie consent management tool by TermsFeed Policy Generator

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

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

Add operator trace view (#47)

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