Free cookie consent management tool by TermsFeed Policy Generator

source: branches/PersistenceReintegration/HeuristicLab.Algorithms.Benchmarks/3.3/BenchmarkAlgorithm.cs @ 16003

Last change on this file since 16003 was 15018, checked in by gkronber, 8 years ago

#2520 introduced StorableConstructorFlag type for StorableConstructors

File size: 19.0 KB
RevLine 
[6934]1#region License Information
2/* HeuristicLab
[14185]3 * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
[6934]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.Drawing;
25using System.Linq;
26using System.Threading;
27using System.Threading.Tasks;
28using HeuristicLab.Collections;
29using HeuristicLab.Common;
30using HeuristicLab.Core;
31using HeuristicLab.Data;
32using HeuristicLab.Optimization;
[6948]33using HeuristicLab.Parameters;
[14927]34using HeuristicLab.Persistence;
[6948]35using HeuristicLab.PluginInfrastructure;
[6934]36
37namespace HeuristicLab.Algorithms.Benchmarks {
[7246]38  [Item("Benchmark Algorithm", "An algorithm to execute performance benchmarks (Linpack, Dhrystone, Whetstone, etc.).")]
[12504]39  [Creatable(CreatableAttribute.Categories.TestingAndAnalysis, Priority = 130)]
[14927]40  [StorableType("ba854a73-3342-471c-a7f9-314435879f90")]
[7246]41  public sealed class BenchmarkAlgorithm : IAlgorithm {
42    private CancellationTokenSource cancellationTokenSource;
[6934]43
[7248]44    public string ItemName {
45      get { return ItemAttribute.GetName(this.GetType()); }
46    }
47    public string ItemDescription {
48      get { return ItemAttribute.GetDescription(this.GetType()); }
49    }
50    public Version ItemVersion {
51      get { return ItemAttribute.GetVersion(this.GetType()); }
52    }
53    public static Image StaticItemImage {
54      get { return HeuristicLab.Common.Resources.VSImageLibrary.Event; }
55    }
56    public Image ItemImage {
57      get {
58        if (ExecutionState == ExecutionState.Prepared) return HeuristicLab.Common.Resources.VSImageLibrary.ExecutablePrepared;
59        else if (ExecutionState == ExecutionState.Started) return HeuristicLab.Common.Resources.VSImageLibrary.ExecutableStarted;
60        else if (ExecutionState == ExecutionState.Paused) return HeuristicLab.Common.Resources.VSImageLibrary.ExecutablePaused;
61        else if (ExecutionState == ExecutionState.Stopped) return HeuristicLab.Common.Resources.VSImageLibrary.ExecutableStopped;
62        else return ItemAttribute.GetImage(this.GetType());
63      }
64    }
65
[6948]66    [Storable]
[6934]67    private DateTime lastUpdateTime;
68
69    [Storable]
[7246]70    private IBenchmark benchmark;
71    public IBenchmark Benchmark {
72      get { return benchmark; }
[6948]73      set {
74        if (value == null) throw new ArgumentNullException();
[7246]75        benchmark = value;
[6948]76      }
77    }
78
79    [Storable]
[6934]80    private ExecutionState executionState;
81    public ExecutionState ExecutionState {
82      get { return executionState; }
83      private set {
84        if (executionState != value) {
85          executionState = value;
86          OnExecutionStateChanged();
87          OnItemImageChanged();
88        }
89      }
90    }
91
92    [Storable]
93    private TimeSpan executionTime;
94    public TimeSpan ExecutionTime {
95      get { return executionTime; }
[7246]96      private set {
[6934]97        executionTime = value;
98        OnExecutionTimeChanged();
99      }
100    }
101
102    [Storable]
103    private bool storeAlgorithmInEachRun;
104    public bool StoreAlgorithmInEachRun {
105      get { return storeAlgorithmInEachRun; }
106      set {
107        if (storeAlgorithmInEachRun != value) {
108          storeAlgorithmInEachRun = value;
109          OnStoreAlgorithmInEachRunChanged();
110        }
111      }
112    }
113
114    [Storable]
[7246]115    private int runsCounter;
[6934]116
117    [Storable]
118    private RunCollection runs = new RunCollection();
119    public RunCollection Runs {
120      get { return runs; }
[7246]121      private set {
[6934]122        if (value == null) throw new ArgumentNullException();
123        if (runs != value) {
124          if (runs != null) DeregisterRunsEvents();
125          runs = value;
126          if (runs != null) RegisterRunsEvents();
127        }
128      }
129    }
130
131    [Storable]
132    private ResultCollection results;
133    public ResultCollection Results {
134      get { return results; }
135    }
136
[7246]137    public Type ProblemType {
[7248]138      get {
139        // BenchmarkAlgorithm does not have a problem, so return a type which is no problem for sure
140        return typeof(BenchmarkAlgorithm);
141      }
[7246]142    }
143
[6934]144    public IProblem Problem {
[7248]145      get { return null; }
146      set { throw new NotImplementedException("BenchmarkAlgorithm does not have a problem."); }
[6934]147    }
148
149    [Storable]
[7246]150    private string name;
[6934]151    public string Name {
152      get { return name; }
153      set {
154        if (!CanChangeName) throw new NotSupportedException("Name cannot be changed.");
155        if (!(name.Equals(value) || (value == null) && (name == string.Empty))) {
156          CancelEventArgs<string> e = value == null ? new CancelEventArgs<string>(string.Empty) : new CancelEventArgs<string>(value);
157          OnNameChanging(e);
158          if (!e.Cancel) {
159            name = value == null ? string.Empty : value;
160            OnNameChanged();
[8962]161            runs.OptimizerName = name;
[6934]162          }
163        }
164      }
165    }
166    public bool CanChangeName {
[7248]167      get { return true; }
[6934]168    }
169
170    [Storable]
[7246]171    private string description;
[6934]172    public string Description {
173      get { return description; }
174      set {
175        if (!CanChangeDescription) throw new NotSupportedException("Description cannot be changed.");
176        if (!(description.Equals(value) || (value == null) && (description == string.Empty))) {
177          description = value == null ? string.Empty : value;
178          OnDescriptionChanged();
179        }
180      }
181    }
182    public bool CanChangeDescription {
[7248]183      get { return true; }
[6934]184    }
185
186    [Storable]
187    private ParameterCollection parameters = new ParameterCollection();
188    public IKeyedItemCollection<string, IParameter> Parameters {
189      get { return parameters; }
190    }
191    private ReadOnlyKeyedItemCollection<string, IParameter> readOnlyParameters;
192    IKeyedItemCollection<string, IParameter> IParameterizedItem.Parameters {
193      get {
194        if (readOnlyParameters == null) readOnlyParameters = parameters.AsReadOnly();
195        return readOnlyParameters;
196      }
197    }
198
199    public IEnumerable<IOptimizer> NestedOptimizers {
200      get { return Enumerable.Empty<IOptimizer>(); }
201    }
202
[6948]203    #region Parameter Properties
[8121]204    public IConstrainedValueParameter<IBenchmark> BenchmarkParameter {
205      get { return (IConstrainedValueParameter<IBenchmark>)Parameters["Benchmark"]; }
[6948]206    }
207    private ValueParameter<IntValue> ChunkSizeParameter {
208      get { return (ValueParameter<IntValue>)Parameters["ChunkSize"]; }
209    }
210    private ValueParameter<DoubleValue> TimeLimitParameter {
211      get { return (ValueParameter<DoubleValue>)Parameters["TimeLimit"]; }
212    }
213    #endregion
214
[6934]215    #region Constructors
[7002]216    [StorableConstructor]
[15018]217    private BenchmarkAlgorithm(StorableConstructorFlag deserializing) { }
[7248]218    private BenchmarkAlgorithm(BenchmarkAlgorithm original, Cloner cloner) {
219      if (original.ExecutionState == ExecutionState.Started) throw new InvalidOperationException(string.Format("Clone not allowed in execution state \"{0}\".", ExecutionState));
220      cloner.RegisterClonedObject(original, this);
221      name = original.name;
222      description = original.description;
223      parameters = cloner.Clone(original.parameters);
224      readOnlyParameters = null;
225      executionState = original.executionState;
226      executionTime = original.executionTime;
227      storeAlgorithmInEachRun = original.storeAlgorithmInEachRun;
228      runsCounter = original.runsCounter;
229      Runs = cloner.Clone(original.runs);
230      results = cloner.Clone(original.results);
231    }
[7246]232    public BenchmarkAlgorithm() {
[6934]233      name = ItemName;
234      description = ItemDescription;
235      parameters = new ParameterCollection();
236      readOnlyParameters = null;
237      executionState = ExecutionState.Stopped;
238      executionTime = TimeSpan.Zero;
239      storeAlgorithmInEachRun = false;
240      runsCounter = 0;
[8962]241      Runs = new RunCollection() { OptimizerName = name };
[6934]242      results = new ResultCollection();
[6948]243      CreateParameters();
244      DiscoverBenchmarks();
[6934]245      Prepare();
246    }
247    #endregion
248
[6948]249    private void CreateParameters() {
[7248]250      Parameters.Add(new ValueParameter<IntValue>("ChunkSize", "The size in MB of the chunk data array that is generated.", new IntValue(0)));
251      Parameters.Add(new ValueParameter<DoubleValue>("TimeLimit", "The time limit in minutes for a benchmark run (zero means a fixed number of iterations).", new DoubleValue(0)));
[6948]252    }
253    private void DiscoverBenchmarks() {
254      var benchmarks = from t in ApplicationManager.Manager.GetTypes(typeof(IBenchmark))
255                       select t;
256      ItemSet<IBenchmark> values = new ItemSet<IBenchmark>();
257      foreach (var benchmark in benchmarks) {
258        IBenchmark b = (IBenchmark)Activator.CreateInstance(benchmark);
259        values.Add(b);
260      }
[7246]261      string paramName = "Benchmark";
[6948]262      if (!Parameters.ContainsKey(paramName)) {
263        if (values.Count > 0) {
[7248]264          Parameters.Add(new ConstrainedValueParameter<IBenchmark>(paramName, "The benchmark which should be executed.", values, values.First(a => a is IBenchmark)));
[6948]265        } else {
[7248]266          Parameters.Add(new ConstrainedValueParameter<IBenchmark>(paramName, "The benchmark which should be executed.", values));
[6948]267        }
268      }
269    }
270
[7248]271    public IDeepCloneable Clone(Cloner cloner) {
272      return new BenchmarkAlgorithm(this, cloner);
[6934]273    }
[7248]274    public object Clone() {
275      return Clone(new Cloner());
276    }
[6934]277
[7248]278    public override string ToString() {
279      return Name;
280    }
281
[7246]282    public void Prepare() {
[6934]283      if ((ExecutionState != ExecutionState.Prepared) && (ExecutionState != ExecutionState.Paused) && (ExecutionState != ExecutionState.Stopped))
284        throw new InvalidOperationException(string.Format("Prepare not allowed in execution state \"{0}\".", ExecutionState));
285      results.Clear();
286      OnPrepared();
287    }
288    public void Prepare(bool clearRuns) {
289      if ((ExecutionState != ExecutionState.Prepared) && (ExecutionState != ExecutionState.Paused) && (ExecutionState != ExecutionState.Stopped))
290        throw new InvalidOperationException(string.Format("Prepare not allowed in execution state \"{0}\".", ExecutionState));
291      if (clearRuns) runs.Clear();
292      Prepare();
293    }
[7246]294    public void Pause() {
[6934]295      if (ExecutionState != ExecutionState.Started)
296        throw new InvalidOperationException(string.Format("Pause not allowed in execution state \"{0}\".", ExecutionState));
297    }
[7246]298    public void Stop() {
[6934]299      if ((ExecutionState != ExecutionState.Started) && (ExecutionState != ExecutionState.Paused))
300        throw new InvalidOperationException(string.Format("Stop not allowed in execution state \"{0}\".", ExecutionState));
[6948]301      cancellationTokenSource.Cancel();
[6934]302    }
[7246]303    public void Start() {
[6948]304      cancellationTokenSource = new CancellationTokenSource();
[6934]305      OnStarted();
306      Task task = Task.Factory.StartNew(Run, cancellationTokenSource.Token, cancellationTokenSource.Token);
307      task.ContinueWith(t => {
308        try {
309          t.Wait();
[14927]310        } catch (AggregateException ex) {
[6934]311          try {
312            ex.Flatten().Handle(x => x is OperationCanceledException);
[14927]313          } catch (AggregateException remaining) {
[6934]314            if (remaining.InnerExceptions.Count == 1) OnExceptionOccurred(remaining.InnerExceptions[0]);
315            else OnExceptionOccurred(remaining);
316          }
317        }
[6948]318
[6934]319        cancellationTokenSource.Dispose();
320        cancellationTokenSource = null;
321        OnStopped();
322      });
323    }
324
[7246]325    private void Run(object state) {
[6934]326      CancellationToken cancellationToken = (CancellationToken)state;
[9343]327      lastUpdateTime = DateTime.UtcNow;
[6934]328      System.Timers.Timer timer = new System.Timers.Timer(250);
329      timer.AutoReset = true;
330      timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
331      timer.Start();
332      try {
[7246]333        Benchmark = (IBenchmark)BenchmarkParameter.ActualValue;
[6948]334        int chunkSize = ((IntValue)ChunkSizeParameter.ActualValue).Value;
335        if (chunkSize > 0) {
[7248]336          Benchmark.ChunkData = CreateChunkData(chunkSize);
[6987]337        } else if (chunkSize < 0) {
338          throw new ArgumentException("ChunkSize must not be negativ.");
[6948]339        }
[6987]340        TimeSpan timelimit = TimeSpan.FromMinutes(((DoubleValue)TimeLimitParameter.ActualValue).Value);
341        if (timelimit.TotalMilliseconds < 0) {
342          throw new ArgumentException("TimeLimit must not be negativ. ");
343        }
[7246]344        Benchmark.TimeLimit = timelimit;
345        Benchmark.Run(cancellationToken, results);
[14927]346      } catch (OperationCanceledException) {
347      } finally {
[6934]348        timer.Elapsed -= new System.Timers.ElapsedEventHandler(timer_Elapsed);
349        timer.Stop();
[9343]350        ExecutionTime += DateTime.UtcNow - lastUpdateTime;
[6934]351      }
352    }
353
354    private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) {
355      System.Timers.Timer timer = (System.Timers.Timer)sender;
356      timer.Enabled = false;
[9343]357      DateTime now = DateTime.UtcNow;
[6934]358      ExecutionTime += now - lastUpdateTime;
359      lastUpdateTime = now;
360      timer.Enabled = true;
361    }
362
[7246]363    public void CollectResultValues(IDictionary<string, IItem> values) {
[6934]364      values.Add("Execution Time", new TimeSpanValue(ExecutionTime));
365      CollectResultsRecursively("", Results, values);
366    }
367    private void CollectResultsRecursively(string path, ResultCollection results, IDictionary<string, IItem> values) {
368      foreach (IResult result in results) {
369        values.Add(path + result.Name, result.Value);
370        ResultCollection childCollection = result.Value as ResultCollection;
371        if (childCollection != null) {
372          CollectResultsRecursively(path + result.Name + ".", childCollection, values);
373        }
374      }
375    }
[7246]376    public void CollectParameterValues(IDictionary<string, IItem> values) {
[6934]377      foreach (IValueParameter param in parameters.OfType<IValueParameter>()) {
378        if (param.GetsCollected && param.Value != null) values.Add(param.Name, param.Value);
379        if (param.Value is IParameterizedItem) {
380          Dictionary<string, IItem> children = new Dictionary<string, IItem>();
381          ((IParameterizedItem)param.Value).CollectParameterValues(children);
382          foreach (string key in children.Keys)
383            values.Add(param.Name + "." + key, children[key]);
384        }
385      }
386    }
387
[7248]388    private byte[][] CreateChunkData(int megaBytes) {
[6948]389      if (megaBytes <= 0) {
390        throw new ArgumentException("MegaBytes must be greater than zero", "megaBytes");
391      }
[7248]392      Random random = new Random();
[6948]393      byte[][] chunk = new byte[megaBytes][];
394      for (int i = 0; i < chunk.Length; i++) {
395        chunk[i] = new byte[1024 * 1024];
396        random.NextBytes(chunk[i]);
397      }
398      return chunk;
399    }
400
[6934]401    #region Events
402    public event EventHandler ExecutionStateChanged;
[7246]403    private void OnExecutionStateChanged() {
[6934]404      EventHandler handler = ExecutionStateChanged;
405      if (handler != null) handler(this, EventArgs.Empty);
406    }
407    public event EventHandler ExecutionTimeChanged;
[7246]408    private void OnExecutionTimeChanged() {
[6934]409      EventHandler handler = ExecutionTimeChanged;
410      if (handler != null) handler(this, EventArgs.Empty);
411    }
[7248]412    public event EventHandler ProblemChanged { add { } remove { } }
[6934]413    public event EventHandler StoreAlgorithmInEachRunChanged;
[7246]414    private void OnStoreAlgorithmInEachRunChanged() {
[6934]415      EventHandler handler = StoreAlgorithmInEachRunChanged;
416      if (handler != null) handler(this, EventArgs.Empty);
417    }
418    public event EventHandler Prepared;
[7246]419    private void OnPrepared() {
[6934]420      ExecutionState = ExecutionState.Prepared;
421      ExecutionTime = TimeSpan.Zero;
422      foreach (IStatefulItem statefulObject in this.GetObjectGraphObjects().OfType<IStatefulItem>()) {
423        statefulObject.InitializeState();
424      }
425      EventHandler handler = Prepared;
426      if (handler != null) handler(this, EventArgs.Empty);
427    }
428    public event EventHandler Started;
[7246]429    private void OnStarted() {
[6934]430      ExecutionState = ExecutionState.Started;
431      EventHandler handler = Started;
432      if (handler != null) handler(this, EventArgs.Empty);
433    }
434    public event EventHandler Paused;
[7246]435    private void OnPaused() {
[6934]436      ExecutionState = ExecutionState.Paused;
437      EventHandler handler = Paused;
438      if (handler != null) handler(this, EventArgs.Empty);
439    }
440    public event EventHandler Stopped;
[7246]441    private void OnStopped() {
[6934]442      ExecutionState = ExecutionState.Stopped;
443      foreach (IStatefulItem statefulObject in this.GetObjectGraphObjects().OfType<IStatefulItem>()) {
444        statefulObject.ClearState();
445      }
446      runsCounter++;
447      runs.Add(new Run(string.Format("{0} Run {1}", Name, runsCounter), this));
448      EventHandler handler = Stopped;
449      if (handler != null) handler(this, EventArgs.Empty);
450    }
451    public event EventHandler<EventArgs<Exception>> ExceptionOccurred;
[7246]452    private void OnExceptionOccurred(Exception exception) {
[6934]453      EventHandler<EventArgs<Exception>> handler = ExceptionOccurred;
454      if (handler != null) handler(this, new EventArgs<Exception>(exception));
455    }
456
457    public event EventHandler<CancelEventArgs<string>> NameChanging;
[7246]458    private void OnNameChanging(CancelEventArgs<string> e) {
[6934]459      var handler = NameChanging;
460      if (handler != null) handler(this, e);
461    }
462
463    public event EventHandler NameChanged;
[7246]464    private void OnNameChanged() {
[6934]465      var handler = NameChanged;
466      if (handler != null) handler(this, EventArgs.Empty);
467      OnToStringChanged();
468    }
469
470    public event EventHandler DescriptionChanged;
[7246]471    private void OnDescriptionChanged() {
[6934]472      var handler = DescriptionChanged;
473      if (handler != null) handler(this, EventArgs.Empty);
474    }
475
476    public event EventHandler ItemImageChanged;
[7246]477    private void OnItemImageChanged() {
[6934]478      EventHandler handler = ItemImageChanged;
479      if (handler != null) handler(this, EventArgs.Empty);
480    }
481    public event EventHandler ToStringChanged;
[7246]482    private void OnToStringChanged() {
[6934]483      EventHandler handler = ToStringChanged;
484      if (handler != null) handler(this, EventArgs.Empty);
485    }
486
[7246]487    private void DeregisterRunsEvents() {
[6934]488      runs.CollectionReset -= new CollectionItemsChangedEventHandler<IRun>(Runs_CollectionReset);
489    }
[7246]490    private void RegisterRunsEvents() {
[6934]491      runs.CollectionReset += new CollectionItemsChangedEventHandler<IRun>(Runs_CollectionReset);
492    }
[7246]493    private void Runs_CollectionReset(object sender, CollectionItemsChangedEventArgs<IRun> e) {
[6934]494      runsCounter = runs.Count;
495    }
496    #endregion
497  }
498}
Note: See TracBrowser for help on using the repository browser.