diff options
Diffstat (limited to 'src/test/java/com/google/devtools')
5 files changed, 251 insertions, 14 deletions
diff --git a/src/test/java/com/google/devtools/build/lib/BUILD b/src/test/java/com/google/devtools/build/lib/BUILD index bbca953c6c..e16db89f2e 100644 --- a/src/test/java/com/google/devtools/build/lib/BUILD +++ b/src/test/java/com/google/devtools/build/lib/BUILD @@ -45,6 +45,7 @@ filegroup( "//src/test/java/com/google/devtools/build/lib/buildeventstream/transports:srcs", "//src/test/java/com/google/devtools/build/lib/buildtool:srcs", "//src/test/java/com/google/devtools/build/lib/profiler/callcounts:srcs", + "//src/test/java/com/google/devtools/build/lib/profiler/memory:srcs", "//src/test/java/com/google/devtools/build/lib/rules/android:srcs", "//src/test/java/com/google/devtools/build/lib/rules/apple:srcs", "//src/test/java/com/google/devtools/build/lib/rules/config:srcs", diff --git a/src/test/java/com/google/devtools/build/lib/packages/RuleClassTest.java b/src/test/java/com/google/devtools/build/lib/packages/RuleClassTest.java index 6fad20690e..dd2c54cb04 100644 --- a/src/test/java/com/google/devtools/build/lib/packages/RuleClassTest.java +++ b/src/test/java/com/google/devtools/build/lib/packages/RuleClassTest.java @@ -862,6 +862,7 @@ public class RuleClassTest extends PackageLoadingTestCase { : ruleDefinitionEnvironment.getTransitiveContentHashCode(); return new RuleClass( name, + name, /*isSkylark=*/ skylarkExecutable, skylarkExecutable, /*skylarkTestable=*/ false, diff --git a/src/test/java/com/google/devtools/build/lib/profiler/memory/AllocationTrackerTest.java b/src/test/java/com/google/devtools/build/lib/profiler/memory/AllocationTrackerTest.java new file mode 100644 index 0000000000..9f35a7057c --- /dev/null +++ b/src/test/java/com/google/devtools/build/lib/profiler/memory/AllocationTrackerTest.java @@ -0,0 +1,210 @@ +// Copyright 2017 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package com.google.devtools.build.lib.profiler.memory; + +import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import com.google.devtools.build.lib.events.Location; +import com.google.devtools.build.lib.events.Location.LineAndColumn; +import com.google.devtools.build.lib.packages.RuleClass; +import com.google.devtools.build.lib.packages.RuleFunction; +import com.google.devtools.build.lib.profiler.memory.AllocationTracker.RuleBytes; +import com.google.devtools.build.lib.syntax.ASTNode; +import com.google.devtools.build.lib.syntax.BaseFunction; +import com.google.devtools.build.lib.syntax.Callstack; +import com.google.devtools.build.lib.syntax.SyntaxTreeVisitor; +import com.google.devtools.build.lib.vfs.PathFragment; +import com.google.perftools.profiles.ProfileProto.Function; +import com.google.perftools.profiles.ProfileProto.Profile; +import com.google.perftools.profiles.ProfileProto.Sample; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Tests for {@link AllocationTracker}. */ +@RunWith(JUnit4.class) +public class AllocationTrackerTest { + + private AllocationTracker allocationTracker; + + static class TestNode extends ASTNode { + TestNode(String file, int line) { + setLocation(location(file, line)); + } + + @Override + public void prettyPrint(Appendable buffer, int indentLevel) throws IOException {} + + @Override + public void accept(SyntaxTreeVisitor visitor) {} + } + + static class TestFunction extends BaseFunction { + TestFunction(String file, String name, int line) { + super(name); + this.location = location(file, line); + } + } + + static class TestRuleFunction extends TestFunction implements RuleFunction { + + private final RuleClass ruleClass; + + TestRuleFunction(String file, String name, int line) { + super(file, name, line); + this.ruleClass = mock(RuleClass.class); + when(ruleClass.getName()).thenReturn(name); + when(ruleClass.getKey()).thenReturn(name); + } + + @Override + public RuleClass getRuleClass() { + return ruleClass; + } + } + + @Before + public void setup() { + Callstack.setEnabled(true); + CurrentRuleTracker.setEnabled(true); + allocationTracker = new AllocationTracker(1, 0); + } + + @After + public void tearDown() { + Callstack.resetStateForTest(); + CurrentRuleTracker.setEnabled(false); + } + + @Test + public void testSimpleMemoryProfile() { + Object allocation = new Object(); + Callstack.push(new TestFunction("fileA", "fn", 120)); + Callstack.push(new TestNode("fileA", 10)); + allocationTracker.sampleAllocation(1, "", allocation, 12); + Callstack.pop(); + Callstack.pop(); + + Map<String, RuleBytes> rules = new HashMap<>(); + Map<String, RuleBytes> aspects = new HashMap<>(); + allocationTracker.getRuleMemoryConsumption(rules, aspects); + assertThat(rules).isEmpty(); + assertThat(aspects).isEmpty(); + + Profile profile = allocationTracker.buildMemoryProfile(); + assertThat(profile.getSampleList()).hasSize(1); + assertThat(sampleToCallstack(profile, profile.getSample(0))).containsExactly("fileA:fn:10"); + } + + @Test + public void testLongerCallstack() { + Object allocation = new Object(); + Callstack.push(new TestFunction("fileB", "fnB", 120)); + Callstack.push(new TestNode("fileB", 10)); + Callstack.push(new TestNode("fileB", 12)); + Callstack.push(new TestNode("fileB", 14)); + Callstack.push(new TestNode("fileB", 18)); + Callstack.push(new TestFunction("fileA", "fnA", 120)); + Callstack.push(new TestNode("fileA", 10)); + allocationTracker.sampleAllocation(1, "", allocation, 12); + for (int i = 0; i < 7; ++i) { + Callstack.pop(); + } + + Profile profile = allocationTracker.buildMemoryProfile(); + assertThat(profile.getSampleList()).hasSize(1); + assertThat(sampleToCallstack(profile, profile.getSample(0))) + .containsExactly("fileB:fnB:18", "fileA:fnA:10"); + } + + @Test + public void testConfiguredTargetsMemoryAllocation() { + RuleClass ruleClass = mock(RuleClass.class); + when(ruleClass.getName()).thenReturn("rule"); + when(ruleClass.getKey()).thenReturn("rule"); + CurrentRuleTracker.beginConfiguredTarget(ruleClass); + Object ruleAllocation0 = new Object(); + Object ruleAllocation1 = new Object(); + allocationTracker.sampleAllocation(1, "", ruleAllocation0, 10); + allocationTracker.sampleAllocation(1, "", ruleAllocation1, 20); + CurrentRuleTracker.endConfiguredTarget(); + + CurrentRuleTracker.beginConfiguredAspect(() -> "aspect"); + Object aspectAllocation = new Object(); + allocationTracker.sampleAllocation(1, "", aspectAllocation, 12); + CurrentRuleTracker.endConfiguredAspect(); + + Map<String, RuleBytes> rules = new HashMap<>(); + Map<String, RuleBytes> aspects = new HashMap<>(); + allocationTracker.getRuleMemoryConsumption(rules, aspects); + assertThat(rules).containsExactly("rule", new RuleBytes("rule").addBytes(30L)); + assertThat(aspects).containsExactly("aspect", new RuleBytes("aspect").addBytes(12L)); + + Profile profile = allocationTracker.buildMemoryProfile(); + assertThat(profile.getSampleList()).isEmpty(); // No callstacks + } + + @Test + public void testLoadingPhaseRuleAllocations() { + Object allocation = new Object(); + Callstack.push(new TestFunction("fileB", "fnB", 120)); + Callstack.push(new TestNode("fileB", 18)); + Callstack.push(new TestFunction("fileA", "fnA", 120)); + Callstack.push(new TestNode("fileA", 10)); + Callstack.push(new TestRuleFunction("<native>", "proto_library", -1)); + allocationTracker.sampleAllocation(1, "", allocation, 128); + for (int i = 0; i < 5; ++i) { + Callstack.pop(); + } + + Map<String, RuleBytes> rules = new HashMap<>(); + Map<String, RuleBytes> aspects = new HashMap<>(); + allocationTracker.getRuleMemoryConsumption(rules, aspects); + assertThat(rules) + .containsExactly("proto_library", new RuleBytes("proto_library").addBytes(128L)); + } + + /** Formats a callstack as (file):(method name):(line) */ + private List<String> sampleToCallstack(Profile profile, Sample sample) { + List<String> result = new ArrayList<>(); + for (long locationId : sample.getLocationIdList()) { + com.google.perftools.profiles.ProfileProto.Location location = + profile.getLocation((int) locationId - 1); + assertThat(location.getLineList()).hasSize(1); + long functionId = location.getLine(0).getFunctionId(); + long line = location.getLine(0).getLine(); + Function function = profile.getFunction((int) functionId - 1); + long fileId = function.getFilename(); + long methodId = function.getName(); + String file = profile.getStringTable((int) fileId); + String method = profile.getStringTable((int) methodId); + result.add(String.format("%s:%s:%d", file, method, line)); + } + return result; + } + + private static Location location(String path, int line) { + return Location.fromPathAndStartColumn( + PathFragment.create(path), 0, 0, new LineAndColumn(line, 0)); + } +} diff --git a/src/test/java/com/google/devtools/build/lib/profiler/memory/BUILD b/src/test/java/com/google/devtools/build/lib/profiler/memory/BUILD new file mode 100644 index 0000000000..3bfc630795 --- /dev/null +++ b/src/test/java/com/google/devtools/build/lib/profiler/memory/BUILD @@ -0,0 +1,25 @@ +licenses(["notice"]) # Apache 2.0 + +filegroup( + name = "srcs", + srcs = glob(["**"]), + visibility = ["//src/test/java/com/google/devtools/build/lib:__pkg__"], +) + +java_test( + name = "AllocationTrackerTest", + srcs = ["AllocationTrackerTest.java"], + deps = [ + "//src/main/java/com/google/devtools/build/lib:events", + "//src/main/java/com/google/devtools/build/lib:packages", + "//src/main/java/com/google/devtools/build/lib:syntax", + "//src/main/java/com/google/devtools/build/lib/profiler/memory:allocationtracker", + "//src/main/java/com/google/devtools/build/lib/profiler/memory:current_rule_tracker", + "//src/main/java/com/google/devtools/build/lib/vfs", + "//third_party:guava", + "//third_party:junit4", + "//third_party:mockito", + "//third_party:truth", + "//third_party/pprof:profile_java_proto", + ], +) diff --git a/src/test/java/com/google/devtools/build/lib/skylark/SkylarkRuleClassFunctionsTest.java b/src/test/java/com/google/devtools/build/lib/skylark/SkylarkRuleClassFunctionsTest.java index 855162d3a9..bbf3c5b09c 100644 --- a/src/test/java/com/google/devtools/build/lib/skylark/SkylarkRuleClassFunctionsTest.java +++ b/src/test/java/com/google/devtools/build/lib/skylark/SkylarkRuleClassFunctionsTest.java @@ -25,7 +25,7 @@ import com.google.common.collect.Iterables; import com.google.devtools.build.lib.analysis.skylark.SkylarkAttr; import com.google.devtools.build.lib.analysis.skylark.SkylarkAttr.Descriptor; import com.google.devtools.build.lib.analysis.skylark.SkylarkFileType; -import com.google.devtools.build.lib.analysis.skylark.SkylarkRuleClassFunctions.RuleFunction; +import com.google.devtools.build.lib.analysis.skylark.SkylarkRuleClassFunctions.SkylarkRuleFunction; import com.google.devtools.build.lib.analysis.skylark.SkylarkRuleContext; import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.packages.AdvertisedProviderSet; @@ -141,7 +141,7 @@ public class SkylarkRuleClassFunctionsTest extends SkylarkTestCase { } private RuleClass getRuleClass(String name) throws Exception { - return ((RuleFunction) lookup(name)).getRuleClass(); + return ((SkylarkRuleFunction) lookup(name)).getRuleClass(); } private void registerDummyUserDefinedFunction() throws Exception { @@ -605,7 +605,7 @@ public class SkylarkRuleClassFunctionsTest extends SkylarkTestCase { @Test public void testRuleImplementation() throws Exception { evalAndExport("def impl(ctx): return None", "rule1 = rule(impl)"); - RuleClass c = ((RuleFunction) lookup("rule1")).getRuleClass(); + RuleClass c = ((SkylarkRuleFunction) lookup("rule1")).getRuleClass(); assertThat(c.getConfiguredTargetFunction().getName()).isEqualTo("impl"); } @@ -628,7 +628,7 @@ public class SkylarkRuleClassFunctionsTest extends SkylarkTestCase { @Test public void testRuleAddAttribute() throws Exception { evalAndExport("def impl(ctx): return None", "r1 = rule(impl, attrs={'a1': attr.string()})"); - RuleClass c = ((RuleFunction) lookup("r1")).getRuleClass(); + RuleClass c = ((SkylarkRuleFunction) lookup("r1")).getRuleClass(); assertThat(c.hasAttr("a1", Type.STRING)).isTrue(); } @@ -659,8 +659,8 @@ public class SkylarkRuleClassFunctionsTest extends SkylarkTestCase { "x = d", "y = d", "z = d"); - String dName = ((RuleFunction) lookup("d")).getRuleClass().getName(); - String fooName = ((RuleFunction) lookup("foo")).getRuleClass().getName(); + String dName = ((SkylarkRuleFunction) lookup("d")).getRuleClass().getName(); + String fooName = ((SkylarkRuleFunction) lookup("foo")).getRuleClass().getName(); assertThat(dName).isEqualTo("d"); assertThat(fooName).isEqualTo("d"); } @@ -668,7 +668,7 @@ public class SkylarkRuleClassFunctionsTest extends SkylarkTestCase { @Test public void testOutputToGenfiles() throws Exception { evalAndExport("def impl(ctx): pass", "r1 = rule(impl, output_to_genfiles=True)"); - RuleClass c = ((RuleFunction) lookup("r1")).getRuleClass(); + RuleClass c = ((SkylarkRuleFunction) lookup("r1")).getRuleClass(); assertThat(c.hasBinaryOutput()).isFalse(); } @@ -681,7 +681,7 @@ public class SkylarkRuleClassFunctionsTest extends SkylarkTestCase { " 'a1': attr.label_list(allow_files=True),", " 'a2': attr.int()", "})"); - RuleClass c = ((RuleFunction) lookup("r1")).getRuleClass(); + RuleClass c = ((SkylarkRuleFunction) lookup("r1")).getRuleClass(); assertThat(c.hasAttr("a1", BuildType.LABEL_LIST)).isTrue(); assertThat(c.hasAttr("a2", Type.INTEGER)).isTrue(); } @@ -690,7 +690,7 @@ public class SkylarkRuleClassFunctionsTest extends SkylarkTestCase { evalAndExport( "def impl(ctx): return None", "r1 = rule(impl, attrs = {'a1': attr.string(mandatory=True)})"); - RuleClass c = ((RuleFunction) lookup("r1")).getRuleClass(); + RuleClass c = ((SkylarkRuleFunction) lookup("r1")).getRuleClass(); assertThat(c.getAttributeByName("a1").isMandatory()).isTrue(); } @@ -699,7 +699,7 @@ public class SkylarkRuleClassFunctionsTest extends SkylarkTestCase { evalAndExport( "def impl(ctx): return None", "r1 = rule(impl, outputs = {'a': 'a.txt'})"); - RuleClass c = ((RuleFunction) lookup("r1")).getRuleClass(); + RuleClass c = ((SkylarkRuleFunction) lookup("r1")).getRuleClass(); ImplicitOutputsFunction function = c.getDefaultImplicitOutputsFunction(); assertThat(function.getImplicitOutputs(null)).containsExactly("a.txt"); } @@ -775,7 +775,7 @@ public class SkylarkRuleClassFunctionsTest extends SkylarkTestCase { "def impl(ctx): return None\n" + "r1 = rule(impl, attrs = {'a1': " + "attr.label(default = Label('//foo:foo'), allow_files=True)})"); - RuleClass c = ((RuleFunction) lookup("r1")).getRuleClass(); + RuleClass c = ((SkylarkRuleFunction) lookup("r1")).getRuleClass(); Attribute a = c.getAttributeByName("a1"); assertThat(a.getDefaultValueForTesting()).isInstanceOf(Label.class); assertThat(a.getDefaultValueForTesting().toString()).isEqualTo("//foo:foo"); @@ -786,7 +786,7 @@ public class SkylarkRuleClassFunctionsTest extends SkylarkTestCase { evalAndExport( "def impl(ctx): return None", "r1 = rule(impl, attrs = {'a1': attr.int(default = 40+2)})"); - RuleClass c = ((RuleFunction) lookup("r1")).getRuleClass(); + RuleClass c = ((SkylarkRuleFunction) lookup("r1")).getRuleClass(); Attribute a = c.getAttributeByName("a1"); assertThat(a.getDefaultValueForTesting()).isEqualTo(42); } @@ -801,7 +801,7 @@ public class SkylarkRuleClassFunctionsTest extends SkylarkTestCase { @Test public void testRuleInheritsBaseRuleAttributes() throws Exception { evalAndExport("def impl(ctx): return None", "r1 = rule(impl)"); - RuleClass c = ((RuleFunction) lookup("r1")).getRuleClass(); + RuleClass c = ((SkylarkRuleFunction) lookup("r1")).getRuleClass(); assertThat(c.hasAttr("tags", Type.STRING_LIST)).isTrue(); assertThat(c.hasAttr("visibility", BuildType.NODEP_LABEL_LIST)).isTrue(); assertThat(c.hasAttr("deprecation", Type.STRING)).isTrue(); @@ -1590,7 +1590,7 @@ public class SkylarkRuleClassFunctionsTest extends SkylarkTestCase { scratch.file("test/BUILD", "toolchain_type(name = 'my_toolchain_type')"); evalAndExport( "def impl(ctx): return None", "r1 = rule(impl, toolchains=['//test:my_toolchain_type'])"); - RuleClass c = ((RuleFunction) lookup("r1")).getRuleClass(); + RuleClass c = ((SkylarkRuleFunction) lookup("r1")).getRuleClass(); assertThat(c.getRequiredToolchains()).containsExactly(makeLabel("//test:my_toolchain_type")); } |