Skip to content

Commit

Permalink
[Truffle] Hash load balance and resize.
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisseaton committed May 11, 2015
1 parent 855c25f commit 7c29362
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,7 @@ public Object setPackedArray(VirtualFrame frame, RubyHash hash, RubyString key,
private final ConditionProfile foundProfile = ConditionProfile.createBinaryProfile();
private final ConditionProfile bucketCollisionProfile = ConditionProfile.createBinaryProfile();
private final ConditionProfile appendingProfile = ConditionProfile.createBinaryProfile();
private final ConditionProfile resizeProfile = ConditionProfile.createBinaryProfile();

@Specialization(guards = {"isBucketsStorage(hash)", "!isRubyString(key)"})
public Object setBuckets(VirtualFrame frame, RubyHash hash, Object key, Object value) {
Expand All @@ -346,10 +347,12 @@ public Object setBuckets(VirtualFrame frame, RubyHash hash, Object key, Object v
final Entry entry = result.getEntry();

if (foundProfile.profile(entry == null)) {
final Entry[] entries = (Entry[]) hash.getStore();

final Entry newEntry = new Entry(result.getHashed(), key, value);

if (bucketCollisionProfile.profile(result.getPreviousEntry() == null)) {
((Entry[]) hash.getStore())[result.getIndex()] = newEntry;
entries[result.getIndex()] = newEntry;
} else {
result.getPreviousEntry().setNextInLookup(newEntry);
}
Expand All @@ -365,7 +368,15 @@ public Object setBuckets(VirtualFrame frame, RubyHash hash, Object key, Object v

hash.setLastInSequence(newEntry);

hash.setSize(hash.getSize() + 1);
final int newSize = hash.getSize() + 1;

hash.setSize(newSize);

// TODO CS 11-May-15 could store the next size for resize instead of doing a float operation each time

if (resizeProfile.profile(newSize / (double) entries.length > BucketsStrategy.MAX_LOAD_BALANCE)) {
BucketsStrategy.resize(hash);
}
} else {
entry.setKeyValue(result.getHashed(), key, value);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,15 @@
*/
package org.jruby.truffle.runtime.hash;

import com.oracle.truffle.api.CompilerDirectives;
import org.jruby.truffle.runtime.core.RubyHash;

import java.util.Arrays;

public abstract class BucketsStrategy {

public static final double MAX_LOAD_BALANCE = 0.75;

public static final int SIGN_BIT_MASK = ~(1 << 31);

private static final int[] CAPACITIES = Arrays.copyOf(org.jruby.RubyHash.MRI_PRIMES, org.jruby.RubyHash.MRI_PRIMES.length - 1);
Expand Down Expand Up @@ -68,4 +71,36 @@ public static void addNewEntry(RubyHash hash, int hashed, Object key, Object val
assert HashOperations.verifyStore(hash);
}

@CompilerDirectives.TruffleBoundary
public static void resize(RubyHash hash) {
HashOperations.verifyStore(hash);

final int bucketsCount = capacityGreaterThan(hash.getSize()) * 2;
final Entry[] newEntries = new Entry[bucketsCount];

Entry entry = hash.getFirstInSequence();

while (entry != null) {
final int bucketIndex = getBucketIndex(entry.getHashed(), bucketsCount);
Entry previousInLookup = newEntries[bucketIndex];

if (previousInLookup == null) {
newEntries[bucketIndex] = entry;
} else {
while (previousInLookup.getNextInLookup() != null) {
previousInLookup = previousInLookup.getNextInLookup();
}

previousInLookup.setNextInLookup(entry);
}

entry.setNextInLookup(null);
entry = entry.getNextInSequence();
}

hash.setStore(newEntries, hash.getSize(), hash.getFirstInSequence(), hash.getLastInSequence());

HashOperations.verifyStore(hash);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
*/
package org.jruby.truffle.runtime.hash;

import com.oracle.truffle.api.CompilerDirectives;
import org.jruby.truffle.runtime.core.RubyHash;
import org.jruby.util.cli.Options;

Expand Down Expand Up @@ -77,6 +78,7 @@ public static void removeEntry(Object[] store, int n) {
}
}

@CompilerDirectives.TruffleBoundary
public static void promoteToBuckets(RubyHash hash, Object[] store, int size) {
final Entry[] buckets = new Entry[BucketsStrategy.capacityGreaterThan(size)];

Expand Down

0 comments on commit 7c29362

Please sign in to comment.