Free cookie consent management tool by TermsFeed Policy Generator

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

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

Move parent tracing to operator trace class (#47)

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