Ignore:
Timestamp:
11/20/10 14:13:32 (9 years ago)
Author:
epitzer
Message:

Refactoring and modularization of DebugEngine (#47)

File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/HeuristicLab.DebugEngine/DebugEngine.cs

    r4827 r4871  
    2121
    2222using System;
     23using System.Linq;
    2324using System.Collections.Generic;
    2425using HeuristicLab.Common;
    2526using HeuristicLab.Core;
    2627using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
     28using HeuristicLab.Collections;
     29using System.Threading;
    2730
    2831namespace HeuristicLab.DebugEngine {
     
    3033  [StorableClass]
    3134  [Item("Debug Engine", "Engine for debugging algorithms.")]
    32   public class DebugEngine : Engine {
    33     private IOperator currentOperator;
    34 
     35  public class DebugEngine : Executable, IEngine {
     36
     37
     38    #region Construction and Cloning
     39   
    3540    [StorableConstructor]
    36     protected DebugEngine(bool deserializing) : base(deserializing) { }
    37     protected DebugEngine(DebugEngine original, Cloner cloner) : base(original, cloner) { }
     41    protected DebugEngine(bool deserializing) : base(deserializing) {
     42      pausePending = stopPending = false;
     43      timer = new System.Timers.Timer(100);
     44      timer.AutoReset = true;
     45      timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
     46    }
     47    protected DebugEngine(DebugEngine original, Cloner cloner) : 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      pausePending = original.pausePending;
     52      stopPending = original.stopPending;
     53      timer = new System.Timers.Timer(100);
     54      timer.AutoReset = true;
     55      timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
     56      this.currentOperation = cloner.Clone(original.currentOperation);
     57      this.currentOperator = cloner.Clone(original.currentOperator);
     58    }
    3859    public DebugEngine()
    3960      : base() {
    40     }
    41 
    42     public new Stack<IOperation> ExecutionStack {
    43       get { return base.ExecutionStack; }
    44     }
    45 
    46     public IAtomicOperation CurrentOperation { get; private set; }
     61      Log = new Log();
     62      ExecutionStack = new ExecutionStack();
     63      pausePending = stopPending = false;
     64      timer = new System.Timers.Timer(100);
     65      timer.AutoReset = true;
     66      timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
     67    }
    4768
    4869    public override IDeepCloneable Clone(Cloner cloner) {
    4970      return new DebugEngine(this, cloner);
     71    }
     72
     73    #endregion
     74
     75    #region Fields and Properties
     76
     77    [Storable]
     78    public ILog Log { get; protected set; }
     79
     80    [Storable]
     81    public ExecutionStack ExecutionStack { get; protected set; }
     82
     83    private bool pausePending, stopPending;
     84    private DateTime lastUpdateTime;
     85    private System.Timers.Timer timer;
     86     
     87    [Storable]
     88    private IOperator currentOperator;
     89
     90    [Storable]
     91    private bool ignoreNextBreakpoint;
     92
     93    [Storable]
     94    private IOperation currentOperation;
     95    public virtual IOperation CurrentOperation {
     96      get { return currentOperation; }
     97      private set {
     98        if (value == currentOperation)
     99          return;
     100        currentOperation = value;
     101        OnOperationChanged(value);
     102      }
     103    }
     104
     105    public virtual IAtomicOperation CurrentAtomicOperation {
     106      get { return CurrentOperation as IAtomicOperation; }
     107    }
     108
     109    public virtual IExecutionContext CurrentExecutionContext {
     110      get { return CurrentOperation as IExecutionContext;  }
     111    }
     112
     113    #endregion
     114
     115    #region Events
     116
     117    public event EventHandler<OperationChangedEventArgs> CurrentOperationChanged;
     118
     119    protected virtual void OnOperationChanged(IOperation newOperation) {
     120      EventHandler<OperationChangedEventArgs> handler = CurrentOperationChanged;
     121      if (handler != null) {
     122        handler(this, new OperationChangedEventArgs(newOperation));
     123      }
     124    }
     125
     126    #endregion
     127
     128    #region Std Methods
     129    public sealed override void Prepare() {
     130      base.Prepare();
     131      ExecutionStack.Clear();
     132      ignoreNextBreakpoint = false;
     133      CurrentOperation = null;
     134      OnPrepared();
     135    }
     136    public void Prepare(IOperation initialOperation) {
     137      base.Prepare();
     138      ExecutionStack.Clear();
     139      if (initialOperation != null)
     140        ExecutionStack.Add(initialOperation);
     141      ignoreNextBreakpoint = false;
     142      CurrentOperation = null;
     143      OnPrepared();
     144    }
     145    protected override void OnPrepared() {
     146      Log.LogMessage("Engine prepared");
     147      base.OnPrepared();
     148    }
     149
     150    public virtual void Step() {
     151      OnStarted();
     152      lastUpdateTime = DateTime.Now;
     153      ignoreNextBreakpoint = true;
     154      timer.Start();
     155      ProcessNextOperation();     
     156      timer.Stop();
     157      ExecutionTime += DateTime.Now - lastUpdateTime;
     158      ignoreNextBreakpoint = false;
     159      OnPaused();
     160    }
     161
     162    public override void Start() {
     163      base.Start();
     164      CurrentOperation = null;
     165      ThreadPool.QueueUserWorkItem(new WaitCallback(Run), null);
     166    }
     167   
     168    protected override void OnStarted() {
     169      Log.LogMessage("Engine started");
     170      base.OnStarted();
     171    }
     172
     173    public override void Pause() {
     174      base.Pause();
     175      pausePending = true;
     176      if (currentOperator != null) currentOperator.Abort();
     177    }
     178
     179    protected override void OnPaused() {
     180      Log.LogMessage("Engine paused");
     181      base.OnPaused();
     182    }
     183
     184    public override void Stop() {
     185      CurrentOperation = null;
     186      base.Stop();
     187      stopPending = true;
     188      if (currentOperator != null) currentOperator.Abort();
     189      ignoreNextBreakpoint = false;
     190      if (ExecutionState == ExecutionState.Paused) OnStopped();
     191    }
     192   
     193    protected override void OnStopped() {
     194      Log.LogMessage("Engine stopped");
     195      base.OnStopped();
     196    }
     197
     198    protected override void OnExceptionOccurred(Exception exception) {
     199      Log.LogException(exception);
     200      base.OnExceptionOccurred(exception);
     201    }
     202
     203    private void Run(object state) {
     204      OnStarted();
     205      pausePending = stopPending = false;
     206
     207      lastUpdateTime = DateTime.Now;
     208      timer.Start();
     209      while (!pausePending && !stopPending && CanContinue) {
     210        ProcessNextOperation();
     211      }
     212      timer.Stop();
     213      ExecutionTime += DateTime.Now - lastUpdateTime;
     214
     215      if (pausePending) OnPaused();
     216      else OnStopped();
     217    }
     218
     219    private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) {
     220      DateTime now = DateTime.Now;
     221      ExecutionTime += now - lastUpdateTime;
     222      lastUpdateTime = now;
     223    }
     224    #endregion
     225
     226    #region Methods
     227
     228    public virtual bool CanContinue {
     229      get { return CurrentOperation != null || ExecutionStack.Count > 0; }
    50230    }
    51231
     
    57237    /// is pushed on the stack again.<br/>
    58238    /// If the execution was successful <see cref="EngineBase.OnOperationExecuted"/> is called.</remarks>
    59     protected override void ProcessNextOperation() {
    60       currentOperator = null;
    61       IOperation next = ExecutionStack.Pop();
    62       OperationCollection coll = next as OperationCollection;
    63       while (coll != null) {
    64         Log.LogMessage("Expanding OperationCollection");
    65         for (int i = coll.Count - 1; i >= 0; i--) {
    66           ExecutionStack.Push(coll[i]);
     239    protected virtual void ProcessNextOperation() {
     240      try {
     241        IAtomicOperation atomicOperation = CurrentOperation as IAtomicOperation;
     242        OperationCollection operations = CurrentOperation as OperationCollection;
     243        if (atomicOperation != null && operations != null)
     244          throw new InvalidOperationException("Current operation is both atomic and an operation collection");
     245
     246        if (atomicOperation != null) {
     247          Log.LogMessage(string.Format("Performing atomic operation {0}", Name(atomicOperation)));
     248          PerformAtomicOperation(atomicOperation);
     249        } else if (operations != null) {
     250          Log.LogMessage("Expanding operation collection");
     251          ExpandOperationCollection(operations);
     252        } else if (ExecutionStack.Count > 0) {
     253          Log.LogMessage("Poping execution stack");
     254          CurrentOperation = ExecutionStack.Last();
     255          ExecutionStack.RemoveAt(ExecutionStack.Count - 1);
     256        } else {
     257          Log.LogMessage("Nothing to do");
    67258        }
    68         next = ExecutionStack.Count > 0 ? ExecutionStack.Pop() : null;
    69         coll = next as OperationCollection;
    70       }
    71       IAtomicOperation operation = next as IAtomicOperation;
     259      } catch (Exception x) {
     260        OnExceptionOccurred(x);
     261      }
     262    }
     263
     264    protected virtual void PerformAtomicOperation(IAtomicOperation operation) {
    72265      if (operation != null) {
    73         Log.LogMessage("Preparing IAtomicOperation");
     266        if (operation.Operator.Breakpoint) {
     267          if (ignoreNextBreakpoint) {
     268            ignoreNextBreakpoint = false;
     269          } else {
     270            ignoreNextBreakpoint = true;
     271            Log.LogMessage(string.Format("Breaking before: {0}", Name(operation)));
     272            Pause();
     273            return;
     274          }
     275        }
    74276        try {
    75277          currentOperator = operation.Operator;
    76           CurrentOperation = operation;
    77           if (operation.Operator.Breakpoint) {
    78             Log.LogMessage(string.Format("Breakpoint: Before {0}", operation.Operator.Name != string.Empty ? operation.Operator.Name : operation.Operator.ItemName));
    79             Pause();
     278          IOperation successor = operation.Operator.Execute((IExecutionContext)operation);
     279          CurrentOperation = null;
     280          currentOperator = null;
     281          if (successor != null) {
     282            ExecutionStack.Add(successor);
    80283          }
    81           Log.LogMessage("Executing IAtomicOperation");
    82           ExecutionStack.Push(operation.Operator.Execute((IExecutionContext)operation));
    83284        } catch (Exception ex) {
    84285          OnExceptionOccurred(new OperatorExecutionException(operation.Operator, ex));
    85286          Pause();
    86287        }
    87       } else {
    88         Log.LogMessage("Nothing to do");
    89         CurrentOperation = null;
    90       }
    91     }
    92 
    93     public override void Pause() {
    94       base.Pause();
    95       if (currentOperator != null) currentOperator.Abort();
    96     }
    97     public override void Stop() {
    98       base.Stop();
    99       if (currentOperator != null) currentOperator.Abort();
    100     }
    101 
    102     public virtual void Step() {
    103       OnStarted();
    104       var lastUpdateTime = DateTime.Now;
    105       if (ExecutionStack.Count > 0) {
    106         while (ExecutionStack.Count > 0 && ExecutionStack.Peek() == null)
    107           ExecutionStack.Pop();
    108         if (ExecutionStack.Count > 0)
    109           ProcessNextOperation();
    110       }
    111       ExecutionTime += DateTime.Now - lastUpdateTime;
    112       OnPaused();
    113     }
     288      }
     289    }
     290
     291    protected virtual void ExpandOperationCollection(OperationCollection operations) {
     292      ExecutionStack.AddRange(operations.Reverse());
     293      CurrentOperation = null;
     294    }
     295
     296    protected virtual string Name(IAtomicOperation operation) {
     297      return string.IsNullOrEmpty(operation.Operator.Name) ? operation.Operator.ItemName : operation.Operator.Name;
     298    }
     299
     300    #endregion
    114301  }
    115302}
Note: See TracChangeset for help on using the changeset viewer.