Free cookie consent management tool by TermsFeed Policy Generator

Opened 9 years ago

Last modified 9 years ago

#2381 closed defect

Object-graph traversal does not finish in some cases / algorithm does not stop — at Version 4

Reported by: gkronber Owned by:
Priority: high Milestone: HeuristicLab 3.3.12
Component: Common Version: 3.3.11
Keywords: Cc:

Description (last modified by gkronber)

I observed a problem in the object graph traversal on several occasions.

The problem becomes apparent when an algorithm seemingly does not stop at the end of a run. The underlying issue seems to be the object graph traversal which seemingly terminates after a while with an error (which is not handled or displayed).

No run is produced, the algorithm is not set to state stopped, no thread is running.

This is related to traversal of structs (see below).

Change History (4)

comment:1 Changed 9 years ago by gkronber

  • Description modified (diff)

comment:2 Changed 9 years ago by gkronber

Investigated this and found an interesting reason. The culprit was the way a hashcode is calculated for structs. The CLR default implementation can lead to a large number of collisions for the "objects"-HashSet in the object graph traversal which leads to very bad runtime performance.

http://stackoverflow.com/questions/5926776/how-does-native-implementation-of-valuetype-gethashcode-work/5927853#5927853

comment:3 Changed 9 years ago by gkronber

HL-Script to reproduce the problem:

using System;
using System.Linq;
using System.Collections.Generic;

using HeuristicLab.Core;
using HeuristicLab.Common;
using System.Diagnostics;

public class MyScript : HeuristicLab.Scripting.CSharpScriptBase {  
  public struct MyStruct {
    public int a;
    public int b;
    public string c;
    // default implementation of GetHashCode() for structs returns only the hash-code of field a
  }

  private MyStruct s;  
  private MyStruct[] sArr;
  
  public override void Main() {
    try {
      this.s = new MyStruct();
      this.sArr = new MyStruct[3000];
      
      // slow
      for(int i=0;i<sArr.Length;i++) {
        sArr[i].a = 1; // -> all elements have the same hash-code
        sArr[i].b = i;
        sArr[i].c = string.Empty;
      }
      var sw = new Stopwatch();
      sw.Start();
      var objects = HeuristicLab.Common.ObjectExtensions.GetObjectGraphObjects(sArr).ToArray();
      sw.Stop();
      Console.WriteLine("{0}", objects.Length);
      Console.WriteLine("{0}", sw.Elapsed);

      // fast 
      for(int i=0;i<sArr.Length;i++) {
        sArr[i].a = i; // -> all elements have a different hash-code
        sArr[i].b = 1;
        sArr[i].c = string.Empty;
      }
      sw.Reset();
      sw.Start();
      objects = HeuristicLab.Common.ObjectExtensions.GetObjectGraphObjects(sArr).ToArray();
      sw.Stop();
      Console.WriteLine("{0}", objects.Length);
      Console.WriteLine("{0}", sw.Elapsed);

      Console.WriteLine("Done");
    } catch(Exception e) {
      Console.WriteLine(e.Message);
    }
  }
}

comment:4 Changed 9 years ago by gkronber

  • Description modified (diff)
Note: See TracTickets for help on using tickets.