Skip to content

Commit fc86f15

Browse files
comiuscopybara-github
authored andcommitted
Optimise Starlark providers' memory layout
Only the memory layout of Starlark providers returned from the rules is optimised. It's optimised by converting mutable lists to immutable ones and direct references to other Starlark providers. Elements of the lists are not optimised. PiperOrigin-RevId: 510996467 Change-Id: I95a26399e1aa024ead8dabb74a4d57dd04e66979
1 parent 21ddc2a commit fc86f15

File tree

6 files changed

+79
-0
lines changed

6 files changed

+79
-0
lines changed

src/main/java/com/google/devtools/build/lib/analysis/starlark/StarlarkRuleConfiguredTargetUtil.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,9 @@ private static void addProviders(
333333
}
334334
}
335335
} else {
336+
if (info instanceof StarlarkInfo) {
337+
info = ((StarlarkInfo) info).unsafeOptimizeMemoryLayout();
338+
}
336339
Provider.Key providerKey = getProviderKey(info);
337340
// Single declared provider
338341
declaredProviders.put(providerKey, info);
@@ -341,6 +344,12 @@ private static void addProviders(
341344
// Sequence of declared providers
342345
for (Info provider :
343346
Sequence.cast(rawProviders, Info.class, "result of rule implementation function")) {
347+
if (provider instanceof StarlarkInfo) {
348+
// Provider instances are optimised recursively, without optimising elements of the list.
349+
// Tradeoff is that some object may be duplicated if they are reachable by more than one
350+
// path, but we don't expect that much in practice.
351+
provider = ((StarlarkInfo) provider).unsafeOptimizeMemoryLayout();
352+
}
344353
Provider.Key providerKey = getProviderKey(provider);
345354
if (declaredProviders.put(providerKey, provider) != null) {
346355
context.ruleError("Multiple conflicting returned providers with key " + providerKey);

src/main/java/com/google/devtools/build/lib/packages/StarlarkInfo.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,15 @@ public static StarlarkInfo create(
4646
@Nullable
4747
@Override
4848
public abstract Object getValue(String name);
49+
50+
/**
51+
* Returns an equivalent memory-optimized version of this provider instance (which might be the
52+
* same existing instance modified in-place).
53+
*
54+
* <p>The existing instance must not be accessed concurrently while calling this method.
55+
*
56+
* <p>The mutability of any values contained in this instance must already be frozen prior to
57+
* calling this method.
58+
*/
59+
public abstract StarlarkInfo unsafeOptimizeMemoryLayout();
4960
}

src/main/java/com/google/devtools/build/lib/packages/StarlarkInfoNoSchema.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import javax.annotation.Nullable;
2424
import net.starlark.java.eval.EvalException;
2525
import net.starlark.java.eval.Starlark;
26+
import net.starlark.java.eval.StarlarkList;
2627
import net.starlark.java.syntax.Location;
2728
import net.starlark.java.syntax.TokenKind;
2829

@@ -293,4 +294,18 @@ private static StarlarkInfo plus(StarlarkInfoNoSchema x, StarlarkInfoNoSchema y)
293294

294295
return new StarlarkInfoNoSchema(x.provider, ztable, Location.BUILTIN);
295296
}
297+
298+
@Override
299+
public StarlarkInfoNoSchema unsafeOptimizeMemoryLayout() {
300+
for (int i = table.length / 2; i < table.length; i++) {
301+
if (table[i] instanceof StarlarkList<?>) {
302+
// On duplicated lists, ImmutableStarlarkLists objects are duplicated, but not underlying
303+
// Object arrays
304+
table[i] = ((StarlarkList<?>) table[i]).unsafeOptimizeMemoryLayout();
305+
} else if (table[i] instanceof StarlarkInfo) {
306+
table[i] = ((StarlarkInfo) table[i]).unsafeOptimizeMemoryLayout();
307+
}
308+
}
309+
return this;
310+
}
296311
}

src/main/java/com/google/devtools/build/lib/packages/StarlarkInfoWithSchema.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import javax.annotation.Nullable;
2525
import net.starlark.java.eval.EvalException;
2626
import net.starlark.java.eval.Starlark;
27+
import net.starlark.java.eval.StarlarkList;
2728
import net.starlark.java.syntax.Location;
2829
import net.starlark.java.syntax.TokenKind;
2930

@@ -153,4 +154,19 @@ private static StarlarkInfoWithSchema plus(StarlarkInfoWithSchema x, StarlarkInf
153154
}
154155
return new StarlarkInfoWithSchema(x.provider, ztable, Location.BUILTIN);
155156
}
157+
158+
@Override
159+
public StarlarkInfoWithSchema unsafeOptimizeMemoryLayout() {
160+
int n = table.length;
161+
for (int i = 0; i < n; i++) {
162+
if (table[i] instanceof StarlarkList<?>) {
163+
// On duplicated lists, ImmutableStarlarkLists are duplicated, but not underlying Object
164+
// arrays
165+
table[i] = ((StarlarkList<?>) table[i]).unsafeOptimizeMemoryLayout();
166+
} else if (table[i] instanceof StarlarkInfo) {
167+
table[i] = ((StarlarkInfo) table[i]).unsafeOptimizeMemoryLayout();
168+
}
169+
}
170+
return this;
171+
}
156172
}

src/main/java/net/starlark/java/eval/MutableStarlarkList.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,4 +219,17 @@ public <T> T[] toArray(T[] a) {
219219
Object[] elems() {
220220
return elems;
221221
}
222+
223+
@Override
224+
public StarlarkList<E> unsafeOptimizeMemoryLayout() {
225+
Preconditions.checkState(mutability.isFrozen());
226+
// Canonicalize our Mutability, on the off-chance the old one may be freed.
227+
mutability = Mutability.IMMUTABLE;
228+
if (elems.length > size) {
229+
// shrink the Object array
230+
elems = Arrays.copyOf(elems, size);
231+
}
232+
// Give the caller an immutable specialization of StarlarkList.
233+
return wrap(mutability, elems);
234+
}
222235
}

src/main/java/net/starlark/java/eval/StarlarkList.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,4 +418,19 @@ public Object pop(Object i) throws EvalException {
418418
removeElementAt(index);
419419
return result;
420420
}
421+
422+
/**
423+
* Mutates this list in-place to reduce memory usage, and returns an optimized list (which might
424+
* be the same as this instance).
425+
*
426+
* <p>This operation is not protected by the mutability mechanism. It is the caller's
427+
* responsibility to ensure this list is not concurrently accessed during this method's execution.
428+
*
429+
* <p>The mutated list and the returned list are both equivalent to the original list.
430+
*
431+
* <p>The mutability must be frozen prior to calling this method.
432+
*/
433+
public StarlarkList<E> unsafeOptimizeMemoryLayout() {
434+
return this;
435+
}
421436
}

0 commit comments

Comments
 (0)