From 4b2ce8c590af98b08d001a3b94a22d14d87884fe Mon Sep 17 00:00:00 2001 From: Hubert Plociniczak Date: Fri, 5 May 2023 13:11:08 +0200 Subject: [PATCH] Limit the number of reported warnings Artifically limiting the number of reported warnings to 100. Also added benchmarks with random ints to investigate perf issues when dealing with warnings (future task). Closes #6283. --- .../semantic/WarningBenchmarks.java | 88 +++++++++++++++---- .../runtime/error/WithWarnings.java | 25 +++++- test/Tests/src/Semantic/Warnings_Spec.enso | 9 ++ 3 files changed, 103 insertions(+), 19 deletions(-) diff --git a/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/WarningBenchmarks.java b/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/WarningBenchmarks.java index 58e42fb2d6d1c..fe7fe74ef81b5 100644 --- a/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/WarningBenchmarks.java +++ b/engine/runtime/src/bench/java/org/enso/interpreter/bench/benchmarks/semantic/WarningBenchmarks.java @@ -18,7 +18,11 @@ import org.openjdk.jmh.infra.BenchmarkParams; import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import java.util.Objects; +import java.util.Random; import java.util.concurrent.TimeUnit; @BenchmarkMode(Mode.AverageTime) @@ -28,27 +32,50 @@ @OutputTimeUnit(TimeUnit.MILLISECONDS) @State(Scope.Benchmark) public class WarningBenchmarks extends TestBase { - private static final int INPUT_VEC_SIZE = 10000; + private static final int INPUT_VEC_SIZE = 10_000; + private static final int INPUT_DIFF_VEC_SIZE = 10_000; private Context ctx; private Value vecSumBench; private Value createVec; + private Value mapVecWithWarnings; private Value noWarningsVec; private Value sameWarningVec; + private Value randomVec; + private Value randomElemsWithWarningsVec; + private Value constElem; + private Value constElemWithWarning; - private Value elem; + private String benchmarkName; - private Value elemWithWarning; + private int randomVectorSum = 0; - private String benchmarkName; + private record GeneratedVector(StringBuilder repr, int sum) {} + + private GeneratedVector generateRandomVector(Random random, String vectorName, long vectorSize, int maxRange) { + List primitiveValues = new ArrayList<>(); + random.ints(vectorSize, 0, maxRange).forEach(primitiveValues::add); + Collections.shuffle(primitiveValues); + var sb = new StringBuilder(); + sb.append(vectorName).append(" = ["); + var sum = 0; + for (Integer intValue : primitiveValues) { + sb.append(intValue).append(","); + sum += Math.abs(intValue); + } + sb.setCharAt(sb.length() - 1, ']'); + sb.append('\n'); + return new GeneratedVector(sb, sum); + } @Setup public void initializeBench(BenchmarkParams params) throws IOException { ctx = createDefaultContext(); + var random = new Random(42); benchmarkName = SrcUtil.findName(params); - var code = """ + var code = new StringBuilder(""" from Standard.Base import all vec_sum_bench : Vector Integer -> Integer @@ -61,18 +88,34 @@ public void initializeBench(BenchmarkParams params) throws IOException { elem = 42 - elem_with_warning = + elem_const_with_warning = x = 42 Warning.attach "Foo!" x - """; - var src = SrcUtil.source(benchmarkName, code); + + elem_with_warning v = + Warning.attach "Foo!" v + + map_vector_with_warnings vec = + vec.map (e-> elem_with_warning e) + """); + + // generate random vector + var randomIntVectorName = "vector_with_random_values"; + var vectorWithRandomValues = generateRandomVector(random, randomIntVectorName, INPUT_DIFF_VEC_SIZE, 3_000); + code.append(vectorWithRandomValues.repr()); + randomVectorSum = vectorWithRandomValues.sum(); + + var src = SrcUtil.source(benchmarkName, code.toString()); Value module = ctx.eval(src); vecSumBench = Objects.requireNonNull(module.invokeMember(MethodNames.Module.EVAL_EXPRESSION, "vec_sum_bench")); createVec = Objects.requireNonNull(module.invokeMember(MethodNames.Module.EVAL_EXPRESSION, "create_vec")); - elem = Objects.requireNonNull(module.invokeMember(MethodNames.Module.EVAL_EXPRESSION, "elem")); - elemWithWarning = Objects.requireNonNull(module.invokeMember(MethodNames.Module.EVAL_EXPRESSION, "elem_with_warning")); - noWarningsVec = createVec.execute(INPUT_VEC_SIZE, elem); - sameWarningVec = createVec.execute(INPUT_VEC_SIZE, elemWithWarning); + mapVecWithWarnings = Objects.requireNonNull(module.invokeMember(MethodNames.Module.EVAL_EXPRESSION, "map_vector_with_warnings")); + constElem = Objects.requireNonNull(module.invokeMember(MethodNames.Module.EVAL_EXPRESSION, "elem")); + constElemWithWarning = Objects.requireNonNull(module.invokeMember(MethodNames.Module.EVAL_EXPRESSION, "elem_const_with_warning")); + noWarningsVec = createVec.execute(INPUT_VEC_SIZE, constElem); + sameWarningVec = createVec.execute(INPUT_VEC_SIZE, constElemWithWarning); + randomVec = Objects.requireNonNull(module.invokeMember(MethodNames.Module.EVAL_EXPRESSION, randomIntVectorName)); + randomElemsWithWarningsVec = mapVecWithWarnings.execute(randomVec); } @TearDown @@ -83,17 +126,30 @@ public void cleanup() { @Benchmark public void noWarningsVecSum() { Value res = vecSumBench.execute(noWarningsVec); - checkResult(res); + checkResult(res, INPUT_VEC_SIZE*42); } @Benchmark public void sameWarningVecSum() { Value res = vecSumBench.execute(sameWarningVec); - checkResult(res); + checkResult(res, INPUT_VEC_SIZE*42); + } + + @Benchmark + public void randomElementsVecSum() { + Value res = vecSumBench.execute(randomVec); + checkResult(res, randomVectorSum); } - private static void checkResult(Value res) { - if (res.asInt() != INPUT_VEC_SIZE*42) { + @Benchmark + public void diiffWarningRandomElementsVecSum() { + Value res = vecSumBench.execute(randomElemsWithWarningsVec); + checkResult(res, randomVectorSum); + } + + + private static void checkResult(Value res, int expected) { + if (res.asInt() != expected) { throw new AssertionError("Expected result: " + INPUT_VEC_SIZE*42 + ", got: " + res.asInt()); } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/error/WithWarnings.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/error/WithWarnings.java index d80981d4058a4..e9642de285fcd 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/error/WithWarnings.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/error/WithWarnings.java @@ -21,6 +21,9 @@ @ExportLibrary(WarningsLibrary.class) @ExportLibrary(ReflectionLibrary.class) public final class WithWarnings implements TruffleObject { + + private static final int MAX_WARNINGS_LIMIT = 100; + private final EconomicSet warnings; private final Object value; @@ -160,15 +163,31 @@ public int hashCode(Object o) { @CompilerDirectives.TruffleBoundary private EconomicSet createSetFromArray(Warning[] entries) { EconomicSet set = EconomicSet.create(new WarningEquivalence()); - set.addAll(Arrays.stream(entries).iterator()); + for (int i=0; i= MAX_WARNINGS_LIMIT) { + return set; + } + set.add(entries[i]); + } + return set; } @CompilerDirectives.TruffleBoundary private EconomicSet cloneSetAndAppend(EconomicSet initial, Warning[] entries) { EconomicSet set = EconomicSet.create(new WarningEquivalence()); - set.addAll(initial.iterator()); - set.addAll(Arrays.stream(entries).iterator()); + for (Warning warning: initial) { + if (set.size() >= MAX_WARNINGS_LIMIT) { + return set; + } + set.add(warning); + } + for (int i=0; i= MAX_WARNINGS_LIMIT) { + return set; + } + set.add(entries[i]); + } return set; } diff --git a/test/Tests/src/Semantic/Warnings_Spec.enso b/test/Tests/src/Semantic/Warnings_Spec.enso index 2d399139c5b67..72445725ee100 100644 --- a/test/Tests/src/Semantic/Warnings_Spec.enso +++ b/test/Tests/src/Semantic/Warnings_Spec.enso @@ -408,4 +408,13 @@ spec = Test.group "Dataflow Warnings" <| result_4 = f a 1 + f a 2 + f a 3 Warning.get_all result_4 . map (x-> x.value.to_text) . should_equal ["Baz!", "Baz!", "Baz!"] + Test.specify "should only report the first 100 unique warnings" <| + vec = (0.up_to 500).map(e -> Warning.attach "Foo!" e) + vec_plus_1 = vec.map(e -> e+1) + Warning.get_all vec_plus_1 . length . should_equal 100 + + warn = Warning.attach "Boo!" 42 + vec_2 = (0.up_to 500).map(e -> if (e < 30) then Warning.attach "Foo!" e else (warn + e)) + Warning.get_all vec_2 . length . should_equal 31 + main = Test_Suite.run_main spec