Skip to content

Commit 206c750

Browse files
lberkicopybara-github
authored andcommitted
Implement memory dumping using command line flag.
This is somewhat more user-friendly. RELNOTES: None. PiperOrigin-RevId: 622773348 Change-Id: Ibd939f69797c1b86863b3b9bbb027aa1d1595cf3
1 parent 0c8bc9d commit 206c750

File tree

2 files changed

+85
-109
lines changed

2 files changed

+85
-109
lines changed

src/main/java/com/google/devtools/build/lib/runtime/commands/DumpCommand.java

Lines changed: 83 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818

1919
import com.google.common.collect.ImmutableList;
2020
import com.google.common.collect.ImmutableMap;
21-
import com.google.devtools.build.lib.analysis.config.CoreOptionConverters.LabelConverter;
2221
import com.google.devtools.build.lib.cmdline.Label;
2322
import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
2423
import com.google.devtools.build.lib.cmdline.PackageIdentifier;
@@ -57,12 +56,14 @@
5756
import com.google.devtools.build.skyframe.NodeEntry;
5857
import com.google.devtools.build.skyframe.QueryableGraph.Reason;
5958
import com.google.devtools.build.skyframe.SkyKey;
59+
import com.google.devtools.common.options.Converter;
6060
import com.google.devtools.common.options.EnumConverter;
6161
import com.google.devtools.common.options.Option;
6262
import com.google.devtools.common.options.OptionDocumentationCategory;
6363
import com.google.devtools.common.options.OptionEffectTag;
6464
import com.google.devtools.common.options.OptionsBase;
6565
import com.google.devtools.common.options.OptionsParser;
66+
import com.google.devtools.common.options.OptionsParsingException;
6667
import com.google.devtools.common.options.OptionsParsingResult;
6768
import java.io.IOException;
6869
import java.io.PrintStream;
@@ -72,6 +73,7 @@
7273
import java.util.Comparator;
7374
import java.util.HashMap;
7475
import java.util.List;
76+
import java.util.Locale;
7577
import java.util.Map;
7678
import java.util.Optional;
7779
import javax.annotation.Nullable;
@@ -90,24 +92,16 @@
9092
shortDescription = "Dumps the internal state of the %{product} server process.",
9193
binaryStdOut = true)
9294
public class DumpCommand implements BlazeCommand {
93-
9495
/** How to dump Skyframe memory. */
95-
public enum MemoryCollectionMode {
96-
NONE, // Memory dumping disabled
97-
SHALLOW, // Dump the objects owned by a single SkyValue
98-
DEEP, // Dump objects reachable from a single SkyValue
99-
}
100-
101-
/** Converter for {@link MemoryCollectionMode}. */
102-
public static final class MemoryCollectionModeConverter
103-
extends EnumConverter<MemoryCollectionMode> {
104-
public MemoryCollectionModeConverter() {
105-
super(MemoryCollectionMode.class, "memory collection mode");
106-
}
96+
private enum MemoryCollectionMode {
97+
/** Dump the objects owned by a single SkyValue */
98+
SHALLOW,
99+
/** Dump objects reachable from a single SkyValue */
100+
DEEP,
107101
}
108102

109103
/** How to display Skyframe memory use. */
110-
public enum MemoryDisplayMode {
104+
private enum MemoryDisplayMode {
111105
/** Just a summary line */
112106
SUMMARY,
113107
/** Object count by class */
@@ -116,10 +110,52 @@ public enum MemoryDisplayMode {
116110
BYTES,
117111
}
118112

113+
/** Whose memory use we should measure. */
114+
private enum MemorySubjectType {
115+
/** Starlark module */
116+
STARLARK_MODULE,
117+
/* Build package */
118+
PACKAGE,
119+
/* Configured target */
120+
CONFIGURED_TARGET,
121+
}
122+
123+
private record MemoryMode(
124+
MemoryCollectionMode collectionMode,
125+
MemoryDisplayMode displayMode,
126+
MemorySubjectType type,
127+
String subject) {}
128+
119129
/** Converter for {@link MemoryCollectionMode}. */
120-
public static final class MemoryDisplayModeConverter extends EnumConverter<MemoryDisplayMode> {
121-
public MemoryDisplayModeConverter() {
122-
super(MemoryDisplayMode.class, "memory display mode");
130+
public static final class MemoryModeConverter extends Converter.Contextless<MemoryMode> {
131+
@Override
132+
public String getTypeDescription() {
133+
return "memory mode";
134+
}
135+
136+
@Override
137+
public MemoryMode convert(String input) throws OptionsParsingException {
138+
// The SkyKey designator is frequently a Label, which usually contains a colon so we must not
139+
// split the argument into an unlimited number of elements
140+
String[] items = input.split(":", 4);
141+
if (items.length != 4) {
142+
throw new OptionsParsingException("Invalid memory");
143+
}
144+
145+
MemoryCollectionMode collectionMode;
146+
MemoryDisplayMode displayMode;
147+
MemorySubjectType subjectType;
148+
149+
try {
150+
collectionMode = MemoryCollectionMode.valueOf(items[0].toUpperCase(Locale.ROOT));
151+
displayMode = MemoryDisplayMode.valueOf(items[1].toUpperCase(Locale.ROOT));
152+
subjectType = MemorySubjectType.valueOf(items[2].toUpperCase(Locale.ROOT));
153+
} catch (IllegalArgumentException e) {
154+
throw new OptionsParsingException(
155+
"Invalid collection mode, display mode or subject type", e);
156+
}
157+
158+
return new MemoryMode(collectionMode, displayMode, subjectType, items[3]);
123159
}
124160
}
125161

@@ -199,55 +235,12 @@ public static class DumpOptions extends OptionsBase {
199235

200236
@Option(
201237
name = "memory",
202-
defaultValue = "none",
203-
converter = MemoryCollectionModeConverter.class,
204-
documentationCategory = OptionDocumentationCategory.OUTPUT_SELECTION,
205-
effectTags = {OptionEffectTag.BAZEL_MONITORING},
206-
help = "Dump the memory use of the given Skyframe node.")
207-
public MemoryCollectionMode memoryCollectionMode;
208-
209-
@Option(
210-
name = "memory_display",
211-
defaultValue = "summary",
212-
converter = MemoryDisplayModeConverter.class,
213-
documentationCategory = OptionDocumentationCategory.OUTPUT_SELECTION,
214-
effectTags = {OptionEffectTag.BAZEL_MONITORING},
215-
help = "The way to display the memory collected by --memory.")
216-
public MemoryDisplayMode memoryDisplayMode;
217-
218-
@Option(
219-
name = "memory_starlark_module",
220238
defaultValue = "null",
221-
converter = LabelConverter.class,
239+
converter = MemoryModeConverter.class,
222240
documentationCategory = OptionDocumentationCategory.OUTPUT_SELECTION,
223241
effectTags = {OptionEffectTag.BAZEL_MONITORING},
224-
help = "The Starlark module whose memory use should be dumped.")
225-
public Label memoryStarlarkModule;
226-
227-
@Option(
228-
name = "memory_package",
229-
defaultValue = "null",
230-
documentationCategory = OptionDocumentationCategory.OUTPUT_SELECTION,
231-
effectTags = {OptionEffectTag.BAZEL_MONITORING},
232-
help = "The package whose memory use should be dumped.")
233-
public String memoryPackage;
234-
235-
@Option(
236-
name = "memory_configured_target",
237-
defaultValue = "null",
238-
converter = LabelConverter.class,
239-
documentationCategory = OptionDocumentationCategory.OUTPUT_SELECTION,
240-
effectTags = {OptionEffectTag.BAZEL_MONITORING},
241-
help = "The label of the configured target whose memory use should be dumped.")
242-
public Label memoryConfiguredTarget;
243-
244-
@Option(
245-
name = "memory_configkey",
246-
defaultValue = "null",
247-
documentationCategory = OptionDocumentationCategory.OUTPUT_SELECTION,
248-
effectTags = {OptionEffectTag.BAZEL_MONITORING},
249-
help = "The configuration key of the configured target whose memory use should be dumped.")
250-
public String memoryConfigKey;
242+
help = "Dump the memory use of the given Skyframe node.")
243+
public MemoryMode memory;
251244
}
252245

253246
/**
@@ -288,7 +281,7 @@ public BlazeCommandResult exec(CommandEnvironment env, OptionsParsingResult opti
288281
|| dumpOptions.dumpRules
289282
|| dumpOptions.starlarkMemory != null
290283
|| dumpOptions.dumpSkyframe != SkyframeDumpOption.OFF
291-
|| dumpOptions.memoryCollectionMode != MemoryCollectionMode.NONE;
284+
|| dumpOptions.memory != null;
292285
if (!anyOutput) {
293286
Collection<Class<? extends OptionsBase>> optionList = new ArrayList<>();
294287
optionList.add(DumpOptions.class);
@@ -344,7 +337,7 @@ public BlazeCommandResult exec(CommandEnvironment env, OptionsParsingResult opti
344337
}
345338
}
346339

347-
if (dumpOptions.memoryCollectionMode != MemoryCollectionMode.NONE) {
340+
if (dumpOptions.memory != null) {
348341
failure = dumpSkyframeMemory(env, dumpOptions, out);
349342
}
350343

@@ -533,47 +526,31 @@ private static BuildConfigurationKey getConfigurationKey(CommandEnvironment env,
533526
}
534527

535528
@Nullable
536-
private static SkyKey getMemoryDumpSkyKey(CommandEnvironment env, DumpOptions dumpOptions) {
537-
Reporter reporter = env.getReporter();
538-
539-
List<SkyKey> result = new ArrayList<>();
540-
541-
if (dumpOptions.memoryStarlarkModule != null) {
542-
result.add(BzlLoadValue.keyForBuild(dumpOptions.memoryStarlarkModule));
543-
}
544-
545-
if (dumpOptions.memoryPackage != null) {
546-
PackageIdentifier identifier;
547-
try {
548-
identifier = PackageIdentifier.parse(dumpOptions.memoryPackage);
549-
} catch (LabelSyntaxException e) {
550-
reporter.error(null, "Cannot parse package identifier: " + e.getMessage());
551-
return null;
552-
}
553-
554-
result.add(identifier);
555-
}
556-
557-
if (dumpOptions.memoryConfiguredTarget != null) {
558-
BuildConfigurationKey configurationKey =
559-
getConfigurationKey(env, dumpOptions.memoryConfigKey);
560-
if (configurationKey == null) {
561-
return null;
562-
}
563-
564-
result.add(
565-
ConfiguredTargetKey.builder()
529+
private static SkyKey getMemoryDumpSkyKey(CommandEnvironment env, MemoryMode memoryMode) {
530+
try {
531+
switch (memoryMode.type()) {
532+
case PACKAGE -> {
533+
return PackageIdentifier.parse(memoryMode.subject);
534+
}
535+
case STARLARK_MODULE -> {
536+
return BzlLoadValue.keyForBuild(Label.parseCanonical(memoryMode.subject));
537+
}
538+
case CONFIGURED_TARGET -> {
539+
String[] labelAndConfig = memoryMode.subject.split("@", 2);
540+
BuildConfigurationKey configurationKey =
541+
getConfigurationKey(env, labelAndConfig.length == 2 ? labelAndConfig[1] : null);
542+
return ConfiguredTargetKey.builder()
566543
.setConfigurationKey(configurationKey)
567-
.setLabel(dumpOptions.memoryConfiguredTarget)
568-
.build());
569-
}
570-
571-
if (result.size() != 1) {
572-
reporter.error(null, "You must specify exactly one Skyframe node to dump.");
544+
.setLabel(Label.parseCanonical(labelAndConfig[0]))
545+
.build();
546+
}
547+
}
548+
} catch (LabelSyntaxException e) {
549+
env.getReporter().error(null, "Cannot parse label: " + e.getMessage());
573550
return null;
574551
}
575552

576-
return result.get(0);
553+
throw new IllegalStateException();
577554
}
578555

579556
private static void dumpRamByClass(Map<String, Long> memory, PrintStream out) {
@@ -633,7 +610,7 @@ private static Stats dumpRamReachable(
633610
private static Optional<BlazeCommandResult> dumpSkyframeMemory(
634611
CommandEnvironment env, DumpOptions dumpOptions, PrintStream out)
635612
throws InterruptedException {
636-
SkyKey skyKey = getMemoryDumpSkyKey(env, dumpOptions);
613+
SkyKey skyKey = getMemoryDumpSkyKey(env, dumpOptions.memory);
637614
if (skyKey == null) {
638615
return Optional.of(
639616
createFailureResult("Cannot dump Skyframe memory", Code.SKYFRAME_MEMORY_DUMP_FAILED));
@@ -657,13 +634,12 @@ private static Optional<BlazeCommandResult> dumpSkyframeMemory(
657634

658635
ConcurrentIdentitySet seen = getBuiltinsSet(env, fieldCache);
659636
Stats stats =
660-
switch (dumpOptions.memoryCollectionMode) {
637+
switch (dumpOptions.memory.collectionMode) {
661638
case DEEP -> dumpRamReachable(nodeEntry, fieldCache, memoryAccountant, seen);
662639
case SHALLOW -> dumpRamShallow(graph, nodeEntry, fieldCache, memoryAccountant, seen);
663-
case NONE -> throw new IllegalStateException();
664640
};
665641

666-
switch (dumpOptions.memoryDisplayMode) {
642+
switch (dumpOptions.memory.displayMode) {
667643
case SUMMARY ->
668644
out.printf(
669645
"%d objects, %d bytes retained\n", stats.getObjectCount(), stats.getMemoryUse());

src/test/shell/integration/dump_test.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ sh_library(name='a')
6969
EOF
7070

7171
bazel query //a:all >& $TEST_log || fail "query failed"
72-
bazel dump --memory=deep --memory_package=//a --memory_display=summary >& $TEST_log \
72+
bazel dump --memory=deep:summary:package://a >& $TEST_log \
7373
|| failed "dump failed"
7474
expect_log "objects,.*bytes retained"
7575
}
@@ -90,7 +90,7 @@ b = {}
9090
EOF
9191

9292
bazel query //a:all >& $TEST_log || fail "query failed"
93-
bazel dump --memory=shallow --memory_starlark_module=//a:a.bzl --memory_display=count >& $TEST_log \
93+
bazel dump --memory=shallow:count:starlark_module://a:a.bzl >& $TEST_log \
9494
|| failed "dump failed"
9595
expect_log "^net.starlark.java.eval.Module: 1" # Only a.bzl, not b.bzl
9696
}

0 commit comments

Comments
 (0)