unordered_dense icon indicating copy to clipboard operation
unordered_dense copied to clipboard

Slow performance with Custom Type

Open DanWillans opened this issue 9 months ago • 0 comments

Hi,

I'm testing ankerl::unordered_dense::map against std::unordered_map for my custom type. When I profile std::unordered_map against ankerl::unordered_dense::map it's faster, am I using it incorrectly? As you can see in the code below for the std::hash specialisation I'm just returning the uint64_t because I can guarantee they're unique but in the custom_hash_unique_object_representation I'm instantiating wyhash.

If I just use a uint64_t ankerl is faster as the documentation and benchmarking shows.

Example code struct and hash for both std and ankerl.

  struct dan{
    uint64_t id;
    auto operator==(dan const& other) const -> bool {
        return id == other.id;
    }
  };

  namespace std {
  template<> struct hash<dan>
  {
    uint64_t operator()(const dan& id) const noexcept { return id.id; }
  };
  }// namespace std

  struct custom_hash_unique_object_representation {
      using is_avalanching = void;

      [[nodiscard]] auto operator()(dan const& f) const noexcept -> uint64_t {
          static_assert(std::has_unique_object_representations_v<dan>);
          return ankerl::unordered_dense::detail::wyhash::hash(&f, sizeof(f));
      }
  };

// Alternatively, doing the same as std::hash means very slow insertion into the map.
  struct custom_hash_unique_object_representation {
      [[nodiscard]] auto operator()(dan const& f) const noexcept -> uint64_t {
          return f.id;
      }
  };

Example code of usage

  constexpr int entity_count = 1000000;
  ankerl::unordered_dense::map<dan, uint64_t, custom_hash_unique_object_representation> ankerl_map;
  std::unordered_map<dan, uint64_t> std_map;

  for(uint64_t i = 0; i < entity_count; ++i){
    ankerl_map[dan{i}] = i;
    std_map[dan{i}] = i;
  }

  Timer timer_5("ankerl_map_find");
  timer_5.ResetStart();
  for(uint64_t i = 0; i < entity_count; ++i){
    auto& hey = ankerl_map[dan{i}];
    hey = 1;
  }
  timer_5.CaptureTimePoint();
  timer_5.PrintAverageTime();

  Timer timer_6("std_map_find");
  timer_6.ResetStart();
  for(uint64_t i = 0; i < entity_count; ++i){
    auto& hey = std_map[dan{i}];
    hey = 1;
  }
  timer_6.CaptureTimePoint();
  timer_6.PrintAverageTime();

DanWillans avatar May 09 '24 16:05 DanWillans