Free cookie consent management tool by TermsFeed Policy Generator

Changeset 6183 for trunk/sources


Ignore:
Timestamp:
05/11/11 15:36:30 (13 years ago)
Author:
epitzer
Message:

Prepare for parallel external evaluation (#1516)
~ move cache to problem for better visibility
+ configurable persistence of cache Content
+ proper synchronization for parallel access to cache

Location:
trunk/sources
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/sources/HeuristicLab.Problems.ExternalEvaluation.Views/3.3/EvaluationCacheView.cs

    r6169 r6183  
    2222      Content.SizeChanged -= new System.EventHandler(Content_StatusChanged);
    2323      Content.HitsChanged -= new System.EventHandler(Content_StatusChanged);
     24      Content.ActiveEvalutionsChanged -= new EventHandler(Content_StatusChanged);
    2425      base.DeregisterContentEvents();
    2526    }
     
    2930      Content.SizeChanged += new System.EventHandler(Content_StatusChanged);
    3031      Content.HitsChanged += new System.EventHandler(Content_StatusChanged);
     32      Content.ActiveEvalutionsChanged += new EventHandler(Content_StatusChanged);
    3133    }
    3234
     
    3638        Invoke(new EventHandler(Content_StatusChanged), sender, e);
    3739      else
    38         hits_sizeTextBox.Text = string.Format("{0}/{1}", Content.Hits, Content.Size);
     40        hits_sizeTextBox.Text = string.Format("{0}/{1} ({2} active)", Content.Hits, Content.Size, Content.ActiveEvaluations);
    3941    }
    4042
  • trunk/sources/HeuristicLab.Problems.ExternalEvaluation/3.3/CachedExternalEvaluator.cs

    r6172 r6183  
    2121
    2222
     23using System.Threading;
    2324using HeuristicLab.Common;
    2425using HeuristicLab.Core;
     
    3334
    3435    #region Parameters
    35     public OptionalValueParameter<EvaluationCache> CacheParameter {
    36       get { return (OptionalValueParameter<EvaluationCache>)Parameters["Cache"]; }
     36    public ValueLookupParameter<EvaluationCache> CacheParameter {
     37      get { return (ValueLookupParameter<EvaluationCache>)Parameters["Cache"]; }
    3738    }
    3839    #endregion
    3940
    4041    #region Parameter Values
    41     public EvaluationCache Cache {
    42       get { return CacheParameter.Value; }
    43       set { CacheParameter.Value = value; }
    44     }
    4542    protected DoubleValue Quality {
    4643      get { return QualityParameter.ActualValue; }
     
    4946    protected IEvaluationServiceClient Client {
    5047      get { return ClientParameter.ActualValue; }
     48    }
     49    protected EvaluationCache Cache {
     50      get { return CacheParameter.ActualValue; }
     51      set { CacheParameter.ActualValue = value; }
    5152    }
    5253    #endregion
     
    6162    public CachedExternalEvaluator()
    6263      : base() {
    63       Parameters.Add(new OptionalValueParameter<EvaluationCache>("Cache", "Cache of previously evaluated solutions"));
     64      Parameters.Add(new ValueLookupParameter<EvaluationCache>("Cache", "Cache of previously evaluated solutions"));
    6465    }
    6566    #endregion
    6667
    6768    public override IOperation Apply() {
    68       if (Cache == null) Cache = new EvaluationCache();
     69      if (Cache == null)
     70        return base.Apply();
     71
    6972      if (Quality == null) Quality = new DoubleValue(0);
    70 
    7173      Quality.Value = Cache.GetValue(BuildSolutionMessage(), m => Client.Evaluate(m).Quality);
    72 
    7374      if (Successor != null)
    7475        return ExecutionContext.CreateOperation(Successor);
  • trunk/sources/HeuristicLab.Problems.ExternalEvaluation/3.3/EvaluationCache.cs

    r6169 r6183  
    2626using System.Collections.Generic;
    2727using System.Linq;
     28using System.Threading;
    2829using HeuristicLab.Common;
    2930using HeuristicLab.Common.Resources;
     
    7374    private LinkedList<CacheEntry> list;
    7475    private Dictionary<CacheEntry, LinkedListNode<CacheEntry>> index;
     76    private static HashSet<string> activeEvaluations = new HashSet<string>();
     77    private static object cacheLock = new object();
     78    private static object evaluationLock = new object();
     79    private static AutoResetEvent evaluationDone = new AutoResetEvent(false);
    7580    #endregion
    7681
     
    8085    }
    8186    public int Size {
    82       get { return index.Count; }
     87      get {
     88        lock (cacheLock) {
     89          return index.Count;
     90        }
     91      }
     92    }
     93    public int ActiveEvaluations {
     94      get {
     95        lock (evaluationLock) {
     96          return activeEvaluations.Count;
     97        }
     98      }
    8399    }
    84100    [Storable]
     
    89105    public event EventHandler SizeChanged;
    90106    public event EventHandler HitsChanged;
     107    public event EventHandler ActiveEvalutionsChanged;
    91108
    92109    protected virtual void OnSizeChanged() {
     
    100117        handler(this, EventArgs.Empty);
    101118    }
     119    protected virtual void OnActiveEvalutionsChanged() {
     120      EventHandler handler = ActiveEvalutionsChanged;
     121      if (handler != null)
     122        handler(this, EventArgs.Empty);
     123    }
    102124    #endregion
    103125
     
    105127    public FixedValueParameter<IntValue> CapacityParameter {
    106128      get { return (FixedValueParameter<IntValue>)Parameters["Capacity"]; }
     129    }
     130    public FixedValueParameter<BoolValue> PersistentCacheParameter {
     131      get { return (FixedValueParameter<BoolValue>)Parameters["PersistentCache"]; }
    107132    }
    108133    #endregion
     
    113138      set { CapacityParameter.Value.Value = value; }
    114139    }
     140    public bool IsPersistent {
     141      get { return PersistentCacheParameter.Value.Value; }
     142    }
    115143    #endregion
    116144
     
    119147    private IEnumerable<KeyValuePair<string, double>> Cache_Persistence {
    120148      get {
     149        if (IsPersistent) {
     150          return GetCacheValues();
     151        } else {
     152          return Enumerable.Empty<KeyValuePair<string, double>>();
     153        }
     154      }
     155      set {
     156        SetCacheValues(value);
     157      }
     158    }
     159    [StorableHook(HookType.AfterDeserialization)]
     160    private void AfterDeserialization() {
     161      RegisterEvents();
     162    }
     163    #endregion
     164
     165    #region Construction & Cloning
     166    [StorableConstructor]
     167    protected EvaluationCache(bool deserializing) : base(deserializing) { }
     168    protected EvaluationCache(EvaluationCache original, Cloner cloner)
     169      : base(original, cloner) {
     170      SetCacheValues(original.GetCacheValues());
     171      RegisterEvents();
     172    }
     173    public EvaluationCache() {
     174      list = new LinkedList<CacheEntry>();
     175      index = new Dictionary<CacheEntry, LinkedListNode<CacheEntry>>();
     176      Parameters.Add(new FixedValueParameter<IntValue>("Capacity", "Maximum number of cache entries.", new IntValue(10000)));
     177      Parameters.Add(new FixedValueParameter<BoolValue>("PersistentCache", "Save cache when serializing object graph?", new BoolValue(false)));
     178      RegisterEvents();
     179    }
     180    public override IDeepCloneable Clone(Cloner cloner) {
     181      return new EvaluationCache(this, cloner);
     182    }
     183    #endregion
     184
     185    #region Event Handling
     186    private void RegisterEvents() {
     187      CapacityParameter.Value.ValueChanged += new EventHandler(Value_ValueChanged);
     188    }
     189
     190    void Value_ValueChanged(object sender, EventArgs e) {
     191      if (Capacity < 0)
     192        throw new ArgumentOutOfRangeException("Cache capacity cannot be less than zero");
     193      Trim();
     194    }
     195    #endregion
     196
     197    #region Methods
     198    public void Reset() {
     199      lock (cacheLock) {
     200        list = new LinkedList<CacheEntry>();
     201        index = new Dictionary<CacheEntry, LinkedListNode<CacheEntry>>();
     202        Hits = 0;
     203      }
     204      OnSizeChanged();
     205      OnHitsChanged();
     206    }
     207
     208    public double GetValue(SolutionMessage message, Evaluator evaluate) {
     209      CacheEntry entry = new CacheEntry(message.ToString());
     210      LinkedListNode<CacheEntry> node;
     211      bool lockTaken = false;
     212      try {
     213        Monitor.Enter(cacheLock, ref lockTaken);
     214        if (index.TryGetValue(entry, out node)) {
     215          list.Remove(node);
     216          list.AddLast(node);
     217          Hits++;
     218          lockTaken = false;
     219          Monitor.Exit(cacheLock);
     220          OnHitsChanged();
     221          return node.Value.Value;
     222        } else {
     223          lockTaken = false;
     224          Monitor.Exit(cacheLock);
     225          return Evaluate(message, evaluate, entry);
     226        }
     227      } finally {
     228        if (lockTaken)
     229          Monitor.Exit(cacheLock);
     230      }
     231    }
     232
     233    private double Evaluate(SolutionMessage message, Evaluator evaluate, CacheEntry entry) {
     234      bool lockTaken = false;
     235      try {
     236        Monitor.Enter(evaluationLock, ref lockTaken);
     237        if (activeEvaluations.Contains(entry.Key)) {
     238          while (activeEvaluations.Contains(entry.Key)) {
     239            lockTaken = false;
     240            Monitor.Exit(evaluationLock);
     241            evaluationDone.WaitOne();
     242            Monitor.Enter(evaluationLock, ref lockTaken);
     243          }
     244          lock (cacheLock) {
     245            return index[entry].Value.Value;
     246          }
     247        } else {
     248          activeEvaluations.Add(entry.Key);
     249          lockTaken = false;
     250          Monitor.Exit(evaluationLock);
     251          OnActiveEvalutionsChanged();
     252          entry.Value = evaluate(message);
     253          lock (cacheLock) {
     254            index[entry] = list.AddLast(entry);
     255          }
     256          lock (evaluationLock) {
     257            activeEvaluations.Remove(entry.Key);
     258            evaluationDone.Set();
     259          }
     260          OnActiveEvalutionsChanged();
     261          Trim();
     262          return entry.Value;
     263        }
     264      } finally {
     265        if (lockTaken)
     266          Monitor.Exit(evaluationLock);
     267      }
     268    }
     269
     270    private void Trim() {
     271      lock (cacheLock) {
     272        while (list.Count > Capacity) {
     273          LinkedListNode<CacheEntry> item = list.First;
     274          list.Remove(item);
     275          index.Remove(item.Value);
     276        }
     277      }
     278      OnSizeChanged();
     279    }
     280    private IEnumerable<KeyValuePair<string, double>> GetCacheValues() {
     281      lock (cacheLock) {
    121282        return index.ToDictionary(kvp => kvp.Key.Key, kvp => kvp.Key.Value);
    122283      }
    123       set {
     284    }
     285    private void SetCacheValues(IEnumerable<KeyValuePair<string, double>> value) {
     286      lock (cacheLock) {
    124287        list = new LinkedList<CacheEntry>();
    125288        index = new Dictionary<CacheEntry, LinkedListNode<CacheEntry>>();
     
    131294      }
    132295    }
    133     [StorableHook(HookType.AfterDeserialization)]
    134     private void AfterDeserialization() {
    135       RegisterEvents();
    136     }
    137     #endregion
    138 
    139     #region Construction & Cloning
    140     [StorableConstructor]
    141     protected EvaluationCache(bool deserializing) : base(deserializing) { }
    142     protected EvaluationCache(EvaluationCache original, Cloner cloner)
    143       : base(original, cloner) {
    144       Cache_Persistence = original.Cache_Persistence;
    145       RegisterEvents();
    146     }
    147     public EvaluationCache() {
    148       list = new LinkedList<CacheEntry>();
    149       index = new Dictionary<CacheEntry, LinkedListNode<CacheEntry>>();
    150       Parameters.Add(new FixedValueParameter<IntValue>("Capacity", "Maximum number of cache entries.", new IntValue(10000)));
    151       RegisterEvents();
    152     }
    153     public override IDeepCloneable Clone(Cloner cloner) {
    154       return new EvaluationCache(this, cloner);
    155     }
    156     #endregion
    157 
    158     #region Event Handling
    159     private void RegisterEvents() {
    160       CapacityParameter.Value.ValueChanged += new EventHandler(Value_ValueChanged);
    161     }
    162 
    163     void Value_ValueChanged(object sender, EventArgs e) {
    164       if (Capacity < 0)
    165         throw new ArgumentOutOfRangeException("Cache capacity cannot be less than zero");
    166       Trim();
    167     }
    168     #endregion
    169 
    170     #region Methods
    171     public void Reset() {
    172       list = new LinkedList<CacheEntry>();
    173       index = new Dictionary<CacheEntry, LinkedListNode<CacheEntry>>();
    174       Hits = 0;
    175       OnSizeChanged();
    176       OnHitsChanged();
    177     }
    178 
    179     public double GetValue(SolutionMessage message, Evaluator evaluate) {
    180       CacheEntry entry = new CacheEntry(message.ToString());
    181       LinkedListNode<CacheEntry> node;
    182       if (index.TryGetValue(entry, out node)) {
    183         list.Remove(node);
    184         list.AddLast(node);
    185         Hits++;
    186         OnHitsChanged();
    187         return node.Value.Value;
    188       } else {
    189         entry.Value = evaluate(message);
    190         index[entry] = list.AddLast(entry);
    191         Trim();
    192         return entry.Value;
    193       }
    194     }
    195 
    196     private void Trim() {
    197       while (list.Count > Capacity) {
    198         LinkedListNode<CacheEntry> item = list.First;
    199         list.Remove(item);
    200         index.Remove(item.Value);
    201       }
    202       OnSizeChanged();
    203     }
    204296    #endregion
    205297
  • trunk/sources/HeuristicLab.Problems.ExternalEvaluation/3.3/ExternalEvaluationProblem.cs

    r5809 r6183  
    8686      get { return (ValueParameter<ItemList<IOperator>>)Parameters["Operators"]; }
    8787    }
     88    public OptionalValueParameter<EvaluationCache> CacheParameter {
     89      get { return (OptionalValueParameter<EvaluationCache>)Parameters["Cache"]; }
     90    }
    8891    #endregion
    8992
     
    148151      Parameters.Add(new OptionalValueParameter<IScope>("BestKnownSolution", "The best known solution for this external evaluation problem."));
    149152      Parameters.Add(new ValueParameter<ItemList<IOperator>>("Operators", "The operators that are passed to the algorithm.", new ItemList<IOperator>()));
     153      Parameters.Add(new OptionalValueParameter<EvaluationCache>("Cache", "Cache of previously evaluated solutions."));
    150154
    151155      InitializeOperators();
Note: See TracChangeset for help on using the changeset viewer.