Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 5051 was 5002, checked in by epitzer, 13 years ago

unseal views, rename OperatorTrace.Generate to Regenerate, and remove questionable virtual from property with private setter (#47)

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