From 7fb976dd247bd318208fe45446c74c10b23a6a58 Mon Sep 17 00:00:00 2001 From: Kelvin Nilsen Date: Sun, 11 Sep 2022 15:31:20 +0000 Subject: [PATCH 1/3] Fix up errors in implementation of Arraylets --- .../corretto/benchmark/extremem/Arraylet.java | 322 ++++++++++------ .../benchmark/extremem/ArrayletOflong.java | 352 +++++++++++------- 2 files changed, 433 insertions(+), 241 deletions(-) diff --git a/Extremem/src/main/java/com/amazon/corretto/benchmark/extremem/Arraylet.java b/Extremem/src/main/java/com/amazon/corretto/benchmark/extremem/Arraylet.java index 50b28bb..114c393 100644 --- a/Extremem/src/main/java/com/amazon/corretto/benchmark/extremem/Arraylet.java +++ b/Extremem/src/main/java/com/amazon/corretto/benchmark/extremem/Arraylet.java @@ -12,165 +12,252 @@ */ class Arraylet extends ExtrememObject { - private final int length; // Number of elements in Arraylet - private final int max_length; // Max array length - private final int num_tiers; // How may levels in fan-out structure? - private final int top_entry_span; // Each element of root spans this many - private final Object[] root; // Root of fan-out structure - private int total_arrays; - private int total_array_elements; + // We use max_arraylet_length for the typical segment size and the typical index size. We only truncate the + // last array segment and the last indexing segment at each indexing level. + + private final int max_arraylet_length; + private final int length; // Number of elements in Arraylet + private final int num_segments; // Total number of array segments representing the elements of this Arraylet + private final int indexing_tiers; // How many levels of indexing arrays, which is at least 1 + + private final int[] index_entry_span; + private final Object[] root_index; // if max_arraylet_length > 0, points to root index + private final BaseType[] root_segment; // if max_arraylet_length == 0, points to contiguous array representaiton Arraylet(ExtrememThread t, LifeSpan ls, int max_length, int length) { super(t, ls); Polarity Grow = Polarity.Expand; + Polarity Shrink = Polarity.Shrink; MemoryLog memory = t.memoryLog(); + if ((max_length != 0) && (max_length < 4)) { + Exception x = new IllegalArgumentException(Integer.toString(max_length)); + Util.fatalException("Maximum arraylet size must be >= 4)", x); + } + this.max_arraylet_length = max_length; this.length = length; - if (max_length == 0) { - this.max_length = length; - this.num_tiers = 1; - this.total_arrays = 2; - this.total_array_elements = length + 1; - Object[] array = new Object[length]; - root = new Object[1]; - root[0] = array; - this.top_entry_span = length; - } else { - this.max_length = max_length; - this.total_arrays = 0; - this.total_array_elements = 0; - int num_tiers = 1; - // At bottom tier of fan-out structure, each entry spans this - // many ArrayLet elements. - int span_of_entry = max_length; - while (span_of_entry * max_length < length) { - num_tiers++; - span_of_entry *= max_length; - } - this.num_tiers = num_tiers; - this.top_entry_span = span_of_entry; - - int[] counts = new int[num_tiers]; - Object[][] arrays = new Object[num_tiers][]; - - memory.accumulate(LifeSpan.Ephemeral, MemoryFlavor.ArrayObject, Grow, 2); - memory.accumulate(LifeSpan.Ephemeral, MemoryFlavor.ArrayRSB, - Grow, num_tiers * Util.SizeOfInt); - memory.accumulate(LifeSpan.Ephemeral, MemoryFlavor.ArrayReference, - Grow, num_tiers); - - for (int i = 0; i < num_tiers; i++) { - arrays[i] = new Object[max_length]; - this.total_arrays++; - this.total_array_elements += max_length; - if (i > 0) { - arrays[i-1][0] = arrays[i]; - counts[i-1] = 1; - } - } - this.root = arrays[0]; - int num_leaf_arrays = (length + max_length - 1) / max_length; - for (int i = 0; i < num_leaf_arrays; i++) { - Object[] element_array = new Object[max_length]; - this.total_arrays++; - this.total_array_elements += max_length; - adjustForNewLeaf(counts, arrays); - arrays[num_tiers-1][counts[num_tiers-1]-1] = element_array; + if (max_arraylet_length != 0) { + // At bottom indexing tier, each index element represents max_arraylet_length number of array elements + // At second indexing tier, each index element represents max_arraylet_length * max_arraylet_length + // At level N (with bottom equal to zero), each index element represents max_arraylet_length * max_arraylet_length ^ N + int index_levels = 1; + int potential_span = max_arraylet_length * max_arraylet_length; + while (potential_span < length) { + index_levels++; + potential_span *= max_arraylet_length; } + indexing_tiers = index_levels; + num_segments = (length + max_arraylet_length - 1) / max_arraylet_length; + index_entry_span = new int[indexing_tiers]; - MemoryLog garbage = t.garbageLog(); - garbage.accumulate(LifeSpan.Ephemeral, - MemoryFlavor.ArrayObject, Grow, 2); - garbage.accumulate(LifeSpan.Ephemeral, MemoryFlavor.ArrayRSB, - Grow, num_tiers * Util.SizeOfInt); - garbage.accumulate(LifeSpan.Ephemeral, MemoryFlavor.ArrayReference, - Grow, num_tiers); - } - // Account for 6 ints: length, max_length, num_tiers, top_entry_span, - // total_arrays, total_array_elements - memory.accumulate(ls, MemoryFlavor.ObjectRSB, Grow, 6 * Util.SizeOfInt); - // Account for root - memory.accumulate(ls, MemoryFlavor.ObjectReference, Grow, 1); + // index_entry_span + memory.accumulate(ls, MemoryFlavor.ArrayObject, Grow, 1); + memory.accumulate(LifeSpan.Ephemeral, MemoryFlavor.ArrayRSB, Grow, indexing_tiers * Util.SizeOfInt); + int[] initialized_segments = new int[indexing_tiers]; + int[] initialized_indices = new int[indexing_tiers]; + int[] index_segment_span = new int[indexing_tiers]; + Object[][] initialization_index = new Object[indexing_tiers][]; - memory.accumulate(ls, MemoryFlavor.ArrayObject, Grow, total_arrays); - memory.accumulate(ls, MemoryFlavor.ArrayReference, - Grow, total_array_elements); - } + // initialization_index, initialized_segments, initialized_indices, index_segment_span + memory.accumulate(LifeSpan.Ephemeral, MemoryFlavor.ArrayObject, Grow, 4); - private final void adjustForNewLeaf(int[] counts, Object[][] arrays) { - int focus_level = num_tiers - 1; - if (counts[focus_level] < max_length) { - counts[focus_level]++; - } else { - while ((focus_level > 0) && (counts[focus_level] >= max_length)) { - arrays[focus_level] = new Object[max_length][]; - this.total_arrays++; - this.total_array_elements += max_length; - counts[focus_level] = 1; - if (focus_level < num_tiers - 1) - arrays[focus_level][0] = arrays[focus_level+1]; - focus_level--; + // initialization_index + memory.accumulate(LifeSpan.Ephemeral, MemoryFlavor.ArrayReference, Grow, indexing_tiers); + + // initialized_segments, initialized_indices, index_segment_span + memory.accumulate(LifeSpan.Ephemeral, MemoryFlavor.ArrayRSB, Grow, 3 * indexing_tiers * Util.SizeOfInt); + + index_entry_span[0] = max_arraylet_length; + index_segment_span[0] = max_arraylet_length * max_arraylet_length; + initialized_segments[0] = 0; + initialized_indices[0] = 0; + + for (int i = 1; i < indexing_tiers; i++) { + index_entry_span[i] = index_segment_span[i-1]; + index_segment_span[i] = index_entry_span[i] * max_arraylet_length; + initialized_segments[i] = 0; + initialized_indices[i] = 0; + initialization_index[i] = null; } - if (focus_level < num_tiers - 1) { - arrays[focus_level][counts[focus_level]] = arrays[focus_level+1]; - counts[focus_level]++; + + int total_segment_span = 0; + for (int i = 0; i < num_segments; i++) { + if (total_segment_span >= length) { + // Do I want an assertion failure here? + break; + } else { + Object[] new_segment; + if (total_segment_span + max_arraylet_length < length) { + new_segment = new Object[max_arraylet_length]; + total_segment_span += max_arraylet_length; + } else { + new_segment = new Object[length - total_segment_span]; + total_segment_span = length; + } + // new_segment + memory.accumulate(ls, MemoryFlavor.ArrayObject, Grow, 1); + memory.accumulate(ls, MemoryFlavor.ArrayReference, Grow, new_segment.length); + + if (initialized_indices[0] == 0) { + // Need to allocate the level-0 index segment + int unspanned = length - initialized_segments[0] * index_segment_span[0]; + if (unspanned >= index_segment_span[0]) { + initialization_index[0] = new Object[max_arraylet_length]; + } else { + int roundup = (unspanned + index_entry_span[0] - 1) / index_entry_span[0]; + initialization_index[0] = new Object[roundup]; + } + // new level-0 index segment + memory.accumulate(ls, MemoryFlavor.ArrayObject, Grow, 1); + memory.accumulate(LifeSpan.Ephemeral, MemoryFlavor.ArrayReference, Grow, initialization_index[0].length); + } + initialization_index[0][initialized_indices[0]] = new_segment; + initialized_indices[0] += 1; + if (initialized_indices[0] >= max_arraylet_length) { + initialized_segments[0] += 1; + initialized_indices[0] = 0; + } + + for (int update_tier = 1; update_tier < indexing_tiers; update_tier++) { + if (initialized_indices[update_tier - 1] != 1) { + // We only need to update parent indices if the lower level was just expanded + break; + } + if (initialized_indices[update_tier] == 0) { + // Need to allocate a new level-N index segment + int unspanned = length - initialized_segments[update_tier] * index_segment_span[update_tier]; + if (unspanned >= index_segment_span[update_tier]) { + initialization_index[update_tier] = new Object[max_arraylet_length]; + } else { + int roundup = (unspanned + index_entry_span[update_tier] - 1) / index_entry_span[update_tier]; + initialization_index[update_tier] = new Object[roundup]; + } + // new index segment at level update_tier + memory.accumulate(ls, MemoryFlavor.ArrayObject, Grow, 1); + memory.accumulate(LifeSpan.Ephemeral, MemoryFlavor.ArrayReference, Grow, initialization_index[update_tier].length); + } + initialization_index[update_tier][initialized_indices[update_tier]] = initialization_index[update_tier - 1]; + initialized_indices[update_tier] += 1; + if (initialized_indices[update_tier] >= max_arraylet_length) { + initialized_segments[update_tier] += 1; + initialized_indices[update_tier] = 0; + } + } + } } + + // initialization_index,initialized_segments, initialized_indices, index_segment_span + memory.accumulate(LifeSpan.Ephemeral, MemoryFlavor.ArrayObject, Shrink, 4); + + // initialization_index + memory.accumulate(LifeSpan.Ephemeral, MemoryFlavor.ArrayReference, Shrink, indexing_tiers); + + // initialized_segments, initialized_indices, index_segment_span + memory.accumulate(LifeSpan.Ephemeral, MemoryFlavor.ArrayRSB, Shrink, 3 * indexing_tiers * Util.SizeOfInt); + root_index = initialization_index[indexing_tiers - 1]; + root_segment = null; + } else { + num_segments = 1; + indexing_tiers = 0; + index_entry_span = null; + root_index = null; + root_segment = (BaseType[]) new Object[length]; + // new root_segment + memory.accumulate(ls, MemoryFlavor.ArrayObject, Grow, 1); + memory.accumulate(ls, MemoryFlavor.ArrayReference, Grow, length); } + + // Account for 4 ints: length, max_arraylet_length, num_segments, indexing_tiers + memory.accumulate(ls, MemoryFlavor.ObjectRSB, Grow, 4 * Util.SizeOfInt); + + // Account for root_index, root_segment, index_entry_span + memory.accumulate(ls, MemoryFlavor.ObjectReference, Grow, 3); } final BaseType get(int at) { if ((at < 0) || (at >= length)) { Exception x = new ArrayIndexOutOfBoundsException(at); Util.fatalException("Index out of bounds in Arraylet.get", x); + // Not reached } - Object[] fan_out_node = root; - int entry_span = top_entry_span; - for (int i = 1; i < num_tiers; i++) { - fan_out_node = (Object []) fan_out_node[at / entry_span]; - at %= entry_span; - entry_span /= max_length; + if (max_arraylet_length == 0) { + return root_segment[at]; + } else { + int tier = indexing_tiers - 1; + int index = at / index_entry_span[tier]; + int remainder = at % index_entry_span[tier]; + Object[] index_segment = root_index; + while (tier-- > 0) { + index_segment = (Object[]) index_segment[index]; + index = remainder / index_entry_span[tier]; + remainder = remainder % index_entry_span[tier]; + } + BaseType[] data_segment = (BaseType[]) index_segment[index]; + return data_segment[remainder]; } - BaseType[] elements = (BaseType []) fan_out_node[at / max_length]; - return elements[at % max_length]; } final void set(int at, BaseType value) { if ((at < 0) || (at >= length)) { Exception x = new ArrayIndexOutOfBoundsException(at); Util.fatalException("Index out of bounds in Arraylet.get", x); + } else if (max_arraylet_length == 0) { + root_segment[at] = value; + } else { + int tier = indexing_tiers - 1; + int index = at / index_entry_span[tier]; + int remainder = at % index_entry_span[tier]; + Object[] index_segment = root_index; + while (tier-- > 0) { + index_segment = (Object[]) index_segment[index]; + index = remainder / index_entry_span[tier]; + remainder = remainder % index_entry_span[tier]; + } + BaseType[] data_segment = (BaseType[]) index_segment[index]; + data_segment[remainder] = value; } - Object[] fan_out_node = root; - int entry_span = top_entry_span; - for (int i = 1; i < num_tiers; i++) { - fan_out_node = (Object []) fan_out_node[at / entry_span]; - at %= entry_span; - entry_span /= max_length; - } - BaseType[] elements = (BaseType[]) fan_out_node[at / max_length]; - elements[at % max_length] = value; } final int length() { return length; } + private void helpTallyMemory(MemoryLog log, LifeSpan ls, Polarity p, Object[] index_segment, int tier) { + log.accumulate(ls, MemoryFlavor.ArrayObject, p, 1); + log.accumulate(ls, MemoryFlavor.ArrayReference, p, index_segment.length); + + if (tier > 1) { + for (int i = 0; i < index_segment.length; i++) { + Object[] sub_index_segment = (Object[]) index_segment[i]; + helpTallyMemory(log, ls, p, sub_index_segment, tier-1); + } + } else { + log.accumulate(ls, MemoryFlavor.ArrayObject, p, index_segment.length);; + for (int i = 0; i < index_segment.length; i++) { + BaseType[] data_segment = (BaseType[]) index_segment[i]; + log.accumulate(ls, MemoryFlavor.ArrayReference, p, data_segment.length); + } + } + } + void tallyMemory(MemoryLog log, LifeSpan ls, Polarity p) { super.tallyMemory(log, ls, p); - // Account for 6 ints: length, max_length, num_tiers, top_entry_span, - // total_arrays, total_array_elements - log.accumulate(ls, MemoryFlavor.ObjectRSB, p, 6 * Util.SizeOfInt); - // Account for root - log.accumulate(ls, MemoryFlavor.ObjectReference, p, 1); + // Account for 4 ints: length, max_arraylet_length, num_segments, indexing_tiers + log.accumulate(ls, MemoryFlavor.ObjectRSB, p, 4 * Util.SizeOfInt); + // Account for root_index, root_segment, index_entry_span + log.accumulate(ls, MemoryFlavor.ObjectReference, p, 3); - log.accumulate(ls, MemoryFlavor.ArrayObject, p, this.total_arrays); - log.accumulate(ls, MemoryFlavor.ArrayReference, - p, this.total_array_elements); + if (max_arraylet_length == 0) { + log.accumulate(ls, MemoryFlavor.ArrayObject, p, 1); + log.accumulate(ls, MemoryFlavor.ArrayReference, p, length); + } else { + helpTallyMemory(log, ls, p, root_index, indexing_tiers); + } } public static void main(String args[]) { - Trace.debug("Testing Arraylet with max size 4"); // Instantiate but do not run the Bootstrap thread. Just need a // a placeholder for memory accounting. @@ -178,6 +265,7 @@ public static void main(String args[]) { Arraylet a; try { + Trace.debug("Testing Arraylet with max size 4"); a = new Arraylet(t, LifeSpan.Ephemeral, 4, 56); for (int i = 0; i < 56; i++) a.set(i, new Long(-10 * i)); @@ -192,6 +280,7 @@ public static void main(String args[]) { } try { + Trace.debug("Testing Arraylet with max size 7"); a = new Arraylet(t, LifeSpan.Ephemeral, 7, 61); for (int i = 0; i < 61; i++) a.set(i, new Long(-10 * i)); @@ -207,6 +296,7 @@ public static void main(String args[]) { } try { + Trace.debug("Testing Arraylet with max size 0"); a = new Arraylet(t, LifeSpan.Ephemeral, 0, 61); for (int i = 0; i < 61; i++) a.set(i, new Long(-10 * i)); diff --git a/Extremem/src/main/java/com/amazon/corretto/benchmark/extremem/ArrayletOflong.java b/Extremem/src/main/java/com/amazon/corretto/benchmark/extremem/ArrayletOflong.java index fb8beb4..76499d5 100644 --- a/Extremem/src/main/java/com/amazon/corretto/benchmark/extremem/ArrayletOflong.java +++ b/Extremem/src/main/java/com/amazon/corretto/benchmark/extremem/ArrayletOflong.java @@ -12,171 +12,253 @@ */ class ArrayletOflong extends ExtrememObject { - private final int length; // Number of elements in Arraylet - private final int max_length; // Max array length - private final int num_tiers; // How may levels in fan-out structure? - private final int top_entry_span; // Each element of root spans this many - private final Object[] root; // Root of fan-out structure - private int total_arrays; - private int total_array_ref_elements; - private int total_array_long_elements; + // We use max_arraylet_length for the typical segment size and the typical index size. We only truncate the + // last array segment and the last indexing segment at each indexing level. + + private final int max_arraylet_length; + private final int length; // Number of elements in Arraylet + private final int num_segments; // Total number of array segments representing the elements of this Arraylet + private final int indexing_tiers; // How many levels of indexing arrays, which is at least 1 + + private final int[] index_entry_span; + private final Object[] root_index; // if max_arraylet_length > 0, points to root index + private final long[] root_segment; // if max_arraylet_length == 0, points to contiguous array representaiton ArrayletOflong (ExtrememThread t, LifeSpan ls, int max_length, int length) { super(t, ls); Polarity Grow = Polarity.Expand; + Polarity Shrink = Polarity.Shrink; MemoryLog memory = t.memoryLog(); + if ((max_length != 0) && (max_length < 4)) { + Exception x = new IllegalArgumentException(Integer.toString(max_length)); + Util.fatalException("Maximum arraylet size must be >= 4)", x); + } + this.max_arraylet_length = max_length; this.length = length; - if (max_length == 0) { - this.max_length = length; - this.num_tiers = 1; - this.total_arrays = 2; - this.total_array_ref_elements = 1; - this.total_array_long_elements = length; - long[] array = new long[length]; - root = new Object[1]; - root[0] = array; - this.top_entry_span = length; - } else { - this.max_length = max_length; - this.total_arrays = 0; - this.total_array_ref_elements = 0; - this.total_array_long_elements = 0; - int num_tiers = 1; - // At bottom tier of fan-out structure, each entry spans this - // many ArrayLet elements. - int span_of_entry = max_length; - while (span_of_entry * max_length < length) { - num_tiers++; - span_of_entry *= max_length; + if (max_arraylet_length != 0) { + // At bottom indexing tier, each index element represents max_arraylet_length number of array elements + // At second indexing tier, each index element represents max_arraylet_length * max_arraylet_length + // At level N (with bottom equal to zero), each index element represents max_arraylet_length * max_arraylet_length ^ N + int index_levels = 1; + int potential_span = max_arraylet_length * max_arraylet_length; + while (potential_span < length) { + index_levels++; + potential_span *= max_arraylet_length; } - this.num_tiers = num_tiers; - this.top_entry_span = span_of_entry; - - int[] counts = new int[num_tiers]; - Object[][] arrays = new Object[num_tiers][]; - - memory.accumulate(LifeSpan.Ephemeral, MemoryFlavor.ArrayObject, Grow, 2); - memory.accumulate(LifeSpan.Ephemeral, MemoryFlavor.ArrayRSB, - Grow, num_tiers * Util.SizeOfInt); - memory.accumulate(LifeSpan.Ephemeral, MemoryFlavor.ArrayReference, - Grow, num_tiers); - - for (int i = 0; i < num_tiers; i++) { - arrays[i] = new Object[max_length]; - this.total_arrays++; - this.total_array_ref_elements += max_length; - if (i > 0) { - arrays[i-1][0] = arrays[i]; - counts[i-1] = 1; - } + indexing_tiers = index_levels; + num_segments = (length + max_arraylet_length - 1) / max_arraylet_length; + index_entry_span = new int[indexing_tiers]; + + // index_entry_span + memory.accumulate(ls, MemoryFlavor.ArrayObject, Grow, 1); + memory.accumulate(LifeSpan.Ephemeral, MemoryFlavor.ArrayRSB, Grow, indexing_tiers * Util.SizeOfInt); + + int[] initialized_segments = new int[indexing_tiers]; + int[] initialized_indices = new int[indexing_tiers]; + int[] index_segment_span = new int[indexing_tiers]; + Object[][] initialization_index = new Object[indexing_tiers][]; + + // initialization_index, initialized_segments, initialized_indices, index_segment_span + memory.accumulate(LifeSpan.Ephemeral, MemoryFlavor.ArrayObject, Grow, 4); + + // initialization_index + memory.accumulate(LifeSpan.Ephemeral, MemoryFlavor.ArrayReference, Grow, indexing_tiers); + + // initialized_segments, initialized_indices, index_segment_span + memory.accumulate(LifeSpan.Ephemeral, MemoryFlavor.ArrayRSB, Grow, 3 * indexing_tiers * Util.SizeOfInt); + + index_entry_span[0] = max_arraylet_length; + index_segment_span[0] = max_arraylet_length * max_arraylet_length; + initialized_segments[0] = 0; + initialized_indices[0] = 0; + + for (int i = 1; i < indexing_tiers; i++) { + index_entry_span[i] = index_segment_span[i-1]; + index_segment_span[i] = index_entry_span[i] * max_arraylet_length; + initialized_segments[i] = 0; + initialized_indices[i] = 0; + initialization_index[i] = null; } - this.root = arrays[0]; - int num_leaf_arrays = (length + max_length - 1) / max_length; - for (int i = 0; i < num_leaf_arrays; i++) { - long[] element_array = new long[max_length]; - this.total_arrays++; - this.total_array_long_elements += max_length; - adjustForNewLeaf(counts, arrays); - arrays[num_tiers-1][counts[num_tiers-1]-1] = (Object) element_array; + + int total_segment_span = 0; + for (int i = 0; i < num_segments; i++) { + if (total_segment_span >= length) { + // Do I want an assertion failure here? + break; + } else { + long[] new_segment; + if (total_segment_span + max_arraylet_length < length) { + new_segment = new long[max_arraylet_length]; + total_segment_span += max_arraylet_length; + } else { + new_segment = new long[length - total_segment_span]; + total_segment_span = length; + } + // new_segment + memory.accumulate(ls, MemoryFlavor.ArrayObject, Grow, 1); + memory.accumulate(ls, MemoryFlavor.ArrayRSB, Grow, new_segment.length * Util.SizeOfLong); + + if (initialized_indices[0] == 0) { + // Need to allocate the level-0 index segment + int unspanned = length - initialized_segments[0] * index_segment_span[0]; + if (unspanned >= index_segment_span[0]) { + initialization_index[0] = new Object[max_arraylet_length]; + } else { + int roundup = (unspanned + index_entry_span[0] - 1) / index_entry_span[0]; + initialization_index[0] = new Object[roundup]; + } + // new level-0 index segment + memory.accumulate(ls, MemoryFlavor.ArrayObject, Grow, 1); + memory.accumulate(LifeSpan.Ephemeral, MemoryFlavor.ArrayReference, Grow, initialization_index[0].length); + } + initialization_index[0][initialized_indices[0]] = new_segment; + initialized_indices[0] += 1; + if (initialized_indices[0] >= max_arraylet_length) { + initialized_segments[0] += 1; + initialized_indices[0] = 0; + } + + for (int update_tier = 1; update_tier < indexing_tiers; update_tier++) { + if (initialized_indices[update_tier - 1] != 1) { + // We only need to update parent indices if the lower level was just expanded + break; + } + if (initialized_indices[update_tier] == 0) { + // Need to allocate a new level-N index segment + int unspanned = length - initialized_segments[update_tier] * index_segment_span[update_tier]; + if (unspanned >= index_segment_span[update_tier]) { + initialization_index[update_tier] = new Object[max_arraylet_length]; + } else { + int roundup = (unspanned + index_entry_span[update_tier] - 1) / index_entry_span[update_tier]; + initialization_index[update_tier] = new Object[roundup]; + } + // new index segment at level update_tier + memory.accumulate(ls, MemoryFlavor.ArrayObject, Grow, 1); + memory.accumulate(LifeSpan.Ephemeral, MemoryFlavor.ArrayReference, Grow, initialization_index[update_tier].length); + } + initialization_index[update_tier][initialized_indices[update_tier]] = initialization_index[update_tier - 1]; + initialized_indices[update_tier] += 1; + if (initialized_indices[update_tier] >= max_arraylet_length) { + initialized_segments[update_tier] += 1; + initialized_indices[update_tier] = 0; + } + } + } } - MemoryLog garbage = t.garbageLog(); - garbage.accumulate(LifeSpan.Ephemeral, - MemoryFlavor.ArrayObject, Grow, 2); - garbage.accumulate(LifeSpan.Ephemeral, MemoryFlavor.ArrayRSB, - Grow, num_tiers * Util.SizeOfInt); - garbage.accumulate(LifeSpan.Ephemeral, MemoryFlavor.ArrayReference, - Grow, num_tiers); - } - // Account for 7 ints: length, max_length, num_tiers, top_entry_span, - // total_arrays, total_array_ref_elements, total_array_long_elements - memory.accumulate(ls, MemoryFlavor.ObjectRSB, Grow, 7 * Util.SizeOfInt); - // Account for root - memory.accumulate(ls, MemoryFlavor.ObjectReference, Grow, 1); - - - memory.accumulate(ls, MemoryFlavor.ArrayObject, Grow, total_arrays); - memory.accumulate(ls, MemoryFlavor.ArrayReference, - Grow, total_array_ref_elements); - memory.accumulate(ls, MemoryFlavor.ArrayRSB, Grow, - this.total_array_long_elements * Util.SizeOfLong); - } + // initialization_index,initialized_segments, initialized_indices, index_segment_span + memory.accumulate(LifeSpan.Ephemeral, MemoryFlavor.ArrayObject, Shrink, 4); - private final void adjustForNewLeaf(int[] counts, Object[][] arrays) { - int focus_level = num_tiers - 1; - if (counts[focus_level] < max_length) { - counts[focus_level]++; + // initialization_index + memory.accumulate(LifeSpan.Ephemeral, MemoryFlavor.ArrayReference, Shrink, indexing_tiers); + + // initialized_segments, initialized_indices, index_segment_span + memory.accumulate(LifeSpan.Ephemeral, MemoryFlavor.ArrayRSB, Shrink, 3 * indexing_tiers * Util.SizeOfInt); + root_index = initialization_index[indexing_tiers - 1]; + root_segment = null; } else { - while ((focus_level > 0) && (counts[focus_level] >= max_length)) { - arrays[focus_level] = new Object[max_length]; - this.total_arrays++; - this.total_array_ref_elements += max_length; - counts[focus_level] = 1; - if (focus_level < num_tiers - 1) - arrays[focus_level][0] = arrays[focus_level+1]; - focus_level--; - } - if (focus_level < num_tiers - 1) { - arrays[focus_level][counts[focus_level]] = arrays[focus_level+1]; - counts[focus_level]++; - } + num_segments = 1; + indexing_tiers = 0; + index_entry_span = null; + root_index = null; + root_segment = new long[length]; + // new root_segment + memory.accumulate(ls, MemoryFlavor.ArrayObject, Grow, 1); + memory.accumulate(ls, MemoryFlavor.ArrayRSB, Grow, length * Util.SizeOfLong); } + + // Account for 4 ints: length, max_arraylet_length, num_segments, indexing_tiers + memory.accumulate(ls, MemoryFlavor.ObjectRSB, Grow, 4 * Util.SizeOfInt); + + // Account for root_index, root_segment, index_entry_span + memory.accumulate(ls, MemoryFlavor.ObjectReference, Grow, 3); } + final long get(int at) { if ((at < 0) || (at >= length)) { Exception x = new ArrayIndexOutOfBoundsException(at); Util.fatalException("Index out of bounds in Arraylet.get", x); + // Not reached } - Object[] fan_out_node = root; - int entry_span = top_entry_span; - for (int i = 1; i < num_tiers; i++) { - fan_out_node = (Object []) fan_out_node[at / entry_span]; - at %= entry_span; - entry_span /= max_length; + if (max_arraylet_length == 0) { + return root_segment[at]; + } else { + int tier = indexing_tiers - 1; + int index = at / index_entry_span[tier]; + int remainder = at % index_entry_span[tier]; + Object[] index_segment = root_index; + while (tier-- > 0) { + index_segment = (Object[]) index_segment[index]; + index = remainder / index_entry_span[tier]; + remainder = remainder % index_entry_span[tier]; + } + long[] data_segment = (long[]) index_segment[index]; + return data_segment[remainder]; } - long[] elements = (long []) fan_out_node[at / max_length]; - return elements[at % max_length]; } + final void set(int at, long value) { if ((at < 0) || (at >= length)) { Exception x = new ArrayIndexOutOfBoundsException(at); Util.fatalException("Index out of bounds in Arraylet.get", x); + } else if (max_arraylet_length == 0) { + root_segment[at] = value; + } else { + int tier = indexing_tiers - 1; + int index = at / index_entry_span[tier]; + int remainder = at % index_entry_span[tier]; + Object[] index_segment = root_index; + while (tier-- > 0) { + index_segment = (Object[]) index_segment[index]; + index = remainder / index_entry_span[tier]; + remainder = remainder % index_entry_span[tier]; + } + long[] data_segment = (long[]) index_segment[index]; + data_segment[remainder] = value; } - Object[] fan_out_node = root; - int entry_span = top_entry_span; - for (int i = 1; i < num_tiers; i++) { - fan_out_node = (Object []) fan_out_node[at / entry_span]; - at %= entry_span; - entry_span /= max_length; - } - long[] elements = (long []) fan_out_node[at / max_length]; - elements[at % max_length] = value; } final int length() { return length; } + private void helpTallyMemory(MemoryLog log, LifeSpan ls, Polarity p, Object[] index_segment, int tier) { + log.accumulate(ls, MemoryFlavor.ArrayObject, p, 1); + log.accumulate(ls, MemoryFlavor.ArrayReference, p, index_segment.length); + + if (tier > 1) { + for (int i = 0; i < index_segment.length; i++) { + Object[] sub_index_segment = (Object[]) index_segment[i]; + helpTallyMemory(log, ls, p, sub_index_segment, tier-1); + } + } else { + log.accumulate(ls, MemoryFlavor.ArrayObject, p, index_segment.length);; + for (int i = 0; i < index_segment.length; i++) { + long[] data_segment = (long[]) index_segment[i]; + log.accumulate(ls, MemoryFlavor.ArrayRSB, p, data_segment.length * Util.SizeOfLong); + } + } + } + void tallyMemory(MemoryLog log, LifeSpan ls, Polarity p) { super.tallyMemory(log, ls, p); - // Account for 7 ints: length, max_length, num_tiers, top_entry_span, - // total_arrays, total_array_ref_elements, total_array_long_elements - log.accumulate(ls, MemoryFlavor.ObjectRSB, p, 7 * Util.SizeOfInt); - // Account for root - log.accumulate(ls, MemoryFlavor.ObjectReference, p, 1); + // Account for 4 ints: length, max_arraylet_length, num_segments, indexing_tiers + log.accumulate(ls, MemoryFlavor.ObjectRSB, p, 4 * Util.SizeOfInt); + // Account for root_index, root_segment, index_entry_span + log.accumulate(ls, MemoryFlavor.ObjectReference, p, 3); - log.accumulate(ls, MemoryFlavor.ArrayObject, p, this.total_arrays); - log.accumulate(ls, MemoryFlavor.ArrayReference, - p, this.total_array_ref_elements); - log.accumulate(ls, MemoryFlavor.ArrayRSB, - p, this.total_array_long_elements); + if (max_arraylet_length == 0) { + log.accumulate(ls, MemoryFlavor.ArrayObject, p, 1); + log.accumulate(ls, MemoryFlavor.ArrayRSB, p, length * Util.SizeOfLong); + } else { + helpTallyMemory(log, ls, p, root_index, indexing_tiers); + } } public static void main(String args[]) { - Trace.debug("Testing Arraylet with max size 4"); // Instantiate but do not run the Bootstrap thread. Just need a // a placeholder for memory accounting. @@ -184,6 +266,7 @@ public static void main(String args[]) { ArrayletOflong a; try { + Trace.debug("Testing Arraylet with max size 4"); a = new ArrayletOflong(t, LifeSpan.Ephemeral, 4, 56); for (int i = 0; i < 56; i++) a.set(i, -10 * i); @@ -199,6 +282,7 @@ public static void main(String args[]) { } try { + Trace.debug("Testing Arraylet with max size 7"); a = new ArrayletOflong(t, LifeSpan.Ephemeral, 7, 61); for (int i = 0; i < 61; i++) a.set(i, -10 * i); @@ -213,7 +297,25 @@ public static void main(String args[]) { Util.printException(x); } + + try { + Trace.debug("Testing Small Arraylet with max size 7"); + a = new ArrayletOflong(t, LifeSpan.Ephemeral, 7, 6); + for (int i = 0; i < 6; i++) + a.set(i, -10 * i); + for (int i = 5; i >= 0; i--) { + Long l = a.get(i); + String s1 = Integer.toString(i); + String s2 = Long.toString(l); + Trace.debug("Array element[", s1, "] holds ", s2); + } + } catch (Exception x) { + Trace.debug("caught exception during third batch"); + Util.printException(x); + } + try { + Trace.debug("Testing Arraylet with max size 0"); a = new ArrayletOflong(t, LifeSpan.Ephemeral, 0, 61); for (int i = 0; i < 61; i++) a.set(i, -10 * i); @@ -224,7 +326,7 @@ public static void main(String args[]) { Trace.debug("Array element[", s1, "] holds ", s2); } } catch (Exception x) { - Trace.debug("caught exception during third batch"); + Trace.debug("caught exception during fourth batch"); Util.printException(x); } } From 1df83cae1c0069b3cb480d9b4a3d22182ac306bb Mon Sep 17 00:00:00 2001 From: Kelvin Nilsen Date: Sun, 11 Sep 2022 23:15:01 +0000 Subject: [PATCH 2/3] Fixup overflow of int arithmetic and check for null data segments --- .../com/amazon/corretto/benchmark/extremem/Arraylet.java | 7 ++++--- .../amazon/corretto/benchmark/extremem/ArrayletOflong.java | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Extremem/src/main/java/com/amazon/corretto/benchmark/extremem/Arraylet.java b/Extremem/src/main/java/com/amazon/corretto/benchmark/extremem/Arraylet.java index 114c393..7eecfd8 100644 --- a/Extremem/src/main/java/com/amazon/corretto/benchmark/extremem/Arraylet.java +++ b/Extremem/src/main/java/com/amazon/corretto/benchmark/extremem/Arraylet.java @@ -14,7 +14,6 @@ class Arraylet extends ExtrememObject { // We use max_arraylet_length for the typical segment size and the typical index size. We only truncate the // last array segment and the last indexing segment at each indexing level. - private final int max_arraylet_length; private final int length; // Number of elements in Arraylet private final int num_segments; // Total number of array segments representing the elements of this Arraylet @@ -40,7 +39,7 @@ class Arraylet extends ExtrememObject { // At second indexing tier, each index element represents max_arraylet_length * max_arraylet_length // At level N (with bottom equal to zero), each index element represents max_arraylet_length * max_arraylet_length ^ N int index_levels = 1; - int potential_span = max_arraylet_length * max_arraylet_length; + long potential_span = max_arraylet_length * (long) max_arraylet_length; while (potential_span < length) { index_levels++; potential_span *= max_arraylet_length; @@ -235,7 +234,9 @@ private void helpTallyMemory(MemoryLog log, LifeSpan ls, Polarity p, Object[] in log.accumulate(ls, MemoryFlavor.ArrayObject, p, index_segment.length);; for (int i = 0; i < index_segment.length; i++) { BaseType[] data_segment = (BaseType[]) index_segment[i]; - log.accumulate(ls, MemoryFlavor.ArrayReference, p, data_segment.length); + if (data_segment != null) { + log.accumulate(ls, MemoryFlavor.ArrayReference, p, data_segment.length); + } } } } diff --git a/Extremem/src/main/java/com/amazon/corretto/benchmark/extremem/ArrayletOflong.java b/Extremem/src/main/java/com/amazon/corretto/benchmark/extremem/ArrayletOflong.java index 76499d5..ef26169 100644 --- a/Extremem/src/main/java/com/amazon/corretto/benchmark/extremem/ArrayletOflong.java +++ b/Extremem/src/main/java/com/amazon/corretto/benchmark/extremem/ArrayletOflong.java @@ -14,7 +14,6 @@ class ArrayletOflong extends ExtrememObject { // We use max_arraylet_length for the typical segment size and the typical index size. We only truncate the // last array segment and the last indexing segment at each indexing level. - private final int max_arraylet_length; private final int length; // Number of elements in Arraylet private final int num_segments; // Total number of array segments representing the elements of this Arraylet @@ -40,7 +39,7 @@ class ArrayletOflong extends ExtrememObject { // At second indexing tier, each index element represents max_arraylet_length * max_arraylet_length // At level N (with bottom equal to zero), each index element represents max_arraylet_length * max_arraylet_length ^ N int index_levels = 1; - int potential_span = max_arraylet_length * max_arraylet_length; + long potential_span = max_arraylet_length * (long) max_arraylet_length; while (potential_span < length) { index_levels++; potential_span *= max_arraylet_length; @@ -236,7 +235,9 @@ private void helpTallyMemory(MemoryLog log, LifeSpan ls, Polarity p, Object[] in log.accumulate(ls, MemoryFlavor.ArrayObject, p, index_segment.length);; for (int i = 0; i < index_segment.length; i++) { long[] data_segment = (long[]) index_segment[i]; - log.accumulate(ls, MemoryFlavor.ArrayRSB, p, data_segment.length * Util.SizeOfLong); + if (data_segment != null) { + log.accumulate(ls, MemoryFlavor.ArrayRSB, p, data_segment.length * Util.SizeOfLong); + } } } } From 880afc7394e937bdf63c2341065455dc81d518e4 Mon Sep 17 00:00:00 2001 From: Kelvin Nilsen Date: Wed, 16 Nov 2022 14:46:04 +0000 Subject: [PATCH 3/3] Fix report of PhasedUpdate interval in configuration dump --- .../com/amazon/corretto/benchmark/extremem/Configuration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Extremem/src/main/java/com/amazon/corretto/benchmark/extremem/Configuration.java b/Extremem/src/main/java/com/amazon/corretto/benchmark/extremem/Configuration.java index a509adc..7e9fb4c 100644 --- a/Extremem/src/main/java/com/amazon/corretto/benchmark/extremem/Configuration.java +++ b/Extremem/src/main/java/com/amazon/corretto/benchmark/extremem/Configuration.java @@ -1130,7 +1130,7 @@ void dump(ExtrememThread t) { Report.output(" Fine-grain locking of data base (FastAndFurious): ", FastAndFurious? "true": "false"); Report.output(" Rebuild data base in phases (PhasedUpdates): ", PhasedUpdates? "true": "false"); Report.output(); - s = PhasedUpdateInterval.toString(); + s = PhasedUpdateInterval.toString(t); l = s.length(); Util.ephemeralString(t, l); Report.output(" Time between data rebuild (PhasedUpdateInterval): ", s);