Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.DebugEngine/3.3/DebugEngine.cs @ 5163

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

(#47)

  • Disable detailed logging while not stepping for drastic reduction in log size
  • Optionally disable operator trace for much faster execution and persistence (disabled by default)
  • Initially enable stepping over stack operations
File size: 9.8 KB
RevLine 
[4747]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;
[4871]23using System.Linq;
[4903]24using System.Threading;
[4743]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.")]
[4871]33  public class DebugEngine : Executable, IEngine {
[4743]34
[4903]35    #region Construction and Cloning
[4871]36
[4743]37    [StorableConstructor]
[4903]38    protected DebugEngine(bool deserializing)
39      : base(deserializing) {
[4871]40      pausePending = stopPending = false;
[4946]41      InitializeTimer();
[4871]42    }
[4946]43
[4903]44    protected DebugEngine(DebugEngine original, Cloner cloner)
45      : base(original, cloner) {
[4871]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);
[4947]49      OperatorTrace = cloner.Clone(original.OperatorTrace);
[4871]50      pausePending = original.pausePending;
51      stopPending = original.stopPending;
[4946]52      InitializeTimer();
53      currentOperation = cloner.Clone(original.currentOperation);
54      currentOperator = cloner.Clone(original.currentOperator);
[4871]55    }
[4743]56    public DebugEngine()
57      : base() {
[4871]58      Log = new Log();
59      ExecutionStack = new ExecutionStack();
[4993]60      OperatorTrace = new OperatorTrace();
[4871]61      pausePending = stopPending = false;
[4946]62      InitializeTimer();
[4743]63    }
64
[4871]65    public override IDeepCloneable Clone(Cloner cloner) {
66      return new DebugEngine(this, cloner);
[4743]67    }
68
[4946]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
[4871]75    #endregion
[4743]76
[4871]77    #region Fields and Properties
78
79    [Storable]
[5001]80    public ILog Log { get; private set; }
[4871]81
82    [Storable]
[5001]83    public ExecutionStack ExecutionStack { get; private set; }
[4871]84
[4993]85    [Storable]
86    public OperatorTrace OperatorTrace { get; private set; }
87
[4871]88    private bool pausePending, stopPending;
89    private DateTime lastUpdateTime;
90    private System.Timers.Timer timer;
[4903]91
[4871]92    [Storable]
93    private IOperator currentOperator;
94
95    [Storable]
96    private IOperation currentOperation;
[5002]97    public IOperation CurrentOperation {
[4871]98      get { return currentOperation; }
99      private set {
[4946]100        if (value != currentOperation) {
101          currentOperation = value;
102          OnOperationChanged(value);
103        }
[4871]104      }
[4743]105    }
106
[4871]107    public virtual IAtomicOperation CurrentAtomicOperation {
108      get { return CurrentOperation as IAtomicOperation; }
109    }
110
111    public virtual IExecutionContext CurrentExecutionContext {
[4903]112      get { return CurrentOperation as IExecutionContext; }
[4871]113    }
114
[4947]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
[4871]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;
[4996]142      OperatorTrace.Reset();
[4871]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;
[4996]151      OperatorTrace.Reset();
[4871]152      OnPrepared();
153    }
154    protected override void OnPrepared() {
155      Log.LogMessage("Engine prepared");
156      base.OnPrepared();
157    }
158
[4909]159    public virtual void Step(bool skipStackOperations) {
[4871]160      OnStarted();
161      lastUpdateTime = DateTime.Now;
162      timer.Start();
[5117]163      ProcessNextOperation(true);
[4909]164      while (skipStackOperations && !(CurrentOperation is IAtomicOperation) && CanContinue)
[5117]165        ProcessNextOperation(true);
[4871]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    }
[4903]175
[4871]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    }
[4903]199
[4871]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();
[4947]216      if (!pausePending && !stopPending && CanContinue)
[5117]217        ProcessNextOperation(false);
[4947]218      while (!pausePending && !stopPending && CanContinue && !IsAtBreakpoint)
[5117]219        ProcessNextOperation(false);
[4871]220      timer.Stop();
221      ExecutionTime += DateTime.Now - lastUpdateTime;
222
[4947]223      if (IsAtBreakpoint)
224        Log.LogMessage(string.Format("Breaking before: {0}", CurrentAtomicOperation.Operator.Name));
225      if (pausePending || IsAtBreakpoint)
226        OnPaused();
227      else
228        OnStopped();
[4871]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
[4947]241
[4743]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>
[5117]249    protected virtual void ProcessNextOperation(bool logOperations) {
[4871]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) {
[5117]257          if (logOperations)
258            Log.LogMessage(string.Format("Performing atomic operation {0}", Utils.Name(atomicOperation)));
[4871]259          PerformAtomicOperation(atomicOperation);
260        } else if (operations != null) {
[5117]261          if (logOperations)
262            Log.LogMessage("Expanding operation collection");
[4946]263          ExecutionStack.AddRange(operations.Reverse());
264          CurrentOperation = null;
[4871]265        } else if (ExecutionStack.Count > 0) {
[5117]266          if (logOperations)
267            Log.LogMessage("Popping execution stack");
[4871]268          CurrentOperation = ExecutionStack.Last();
269          ExecutionStack.RemoveAt(ExecutionStack.Count - 1);
270        } else {
[5117]271          if (logOperations)
272            Log.LogMessage("Nothing to do");
[4743]273        }
[5002]274        OperatorTrace.Regenerate(CurrentAtomicOperation);
[4947]275      } catch (Exception x) {
[4871]276        OnExceptionOccurred(x);
[4743]277      }
[4871]278    }
279
280    protected virtual void PerformAtomicOperation(IAtomicOperation operation) {
[4743]281      if (operation != null) {
282        try {
283          currentOperator = operation.Operator;
[4871]284          IOperation successor = operation.Operator.Execute((IExecutionContext)operation);
285          if (successor != null) {
[4996]286            OperatorTrace.RegisterParenthood(operation, successor);
[4871]287            ExecutionStack.Add(successor);
[4743]288          }
[4904]289          currentOperator = null;
290          CurrentOperation = null;
[4947]291        } catch (Exception ex) {
[4743]292          OnExceptionOccurred(new OperatorExecutionException(operation.Operator, ex));
293          Pause();
294        }
295      }
296    }
297
[4871]298    #endregion
[4743]299  }
300}
Note: See TracBrowser for help on using the repository browser.