Free cookie consent management tool by TermsFeed Policy Generator

source: branches/WebJobManager/HeuristicLab.Algorithms.Benchmarks/3.3/BenchmarkAlgorithm.cs @ 15834

Last change on this file since 15834 was 13656, checked in by ascheibe, 9 years ago

#2582 created branch for Hive Web Job Manager

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