From c264a7e52a54941b2cab22f647a396c2c5389a3e Mon Sep 17 00:00:00 2001 From: stepan <stepan.sindelar@oracle.com> Date: Thu, 14 Jul 2016 15:48:02 +0200 Subject: [PATCH] Add tracemem builtin Adds memory tracing in semi-flexible way. Vector implementations report copy event to MemoryTracer, which forwards these to the registered listener. The gnur Makefile has to be changed so that our gnur build also supports memory tracing and we can use tracemem in tests. --- .../gnur/Makefile.gnur | 2 +- .../r/nodes/builtin/base/BasePackage.java | 1 + .../r/nodes/builtin/base/TraceFunctions.java | 38 ++++++++++ .../r/nodes/builtin/base/UpdateDimNames.java | 2 +- .../r/nodes/builtin/base/UpdateNames.java | 2 +- .../truffle/r/runtime/data/MemoryTracer.java | 72 +++++++++++++++++++ .../truffle/r/runtime/data/RComplex.java | 4 +- .../r/runtime/data/RComplexVector.java | 2 +- .../truffle/r/runtime/data/RDouble.java | 4 +- .../truffle/r/runtime/data/RDoubleVector.java | 2 +- .../truffle/r/runtime/data/RIntVector.java | 2 +- .../truffle/r/runtime/data/RInteger.java | 4 +- .../oracle/truffle/r/runtime/data/RList.java | 2 +- .../truffle/r/runtime/data/RLogical.java | 4 +- .../r/runtime/data/RLogicalVector.java | 2 +- .../oracle/truffle/r/runtime/data/RRaw.java | 4 +- .../truffle/r/runtime/data/RRawVector.java | 2 +- .../truffle/r/runtime/data/RScalarVector.java | 16 +++-- .../truffle/r/runtime/data/RSequence.java | 4 +- .../truffle/r/runtime/data/RString.java | 4 +- .../truffle/r/runtime/data/RStringVector.java | 2 +- .../truffle/r/runtime/data/RVector.java | 48 +++++++++++-- .../data/closures/RToVectorClosure.java | 13 +++- .../r/runtime/data/model/RAbstractVector.java | 5 +- .../instrument/InstrumentationState.java | 28 ++++++-- .../truffle/r/test/ExpectedTestOutput.test | 4 ++ .../r/test/builtins/TestBuiltin_tracemem.java | 38 ++++++++++ 27 files changed, 274 insertions(+), 37 deletions(-) create mode 100644 com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/MemoryTracer.java create mode 100644 com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_tracemem.java diff --git a/com.oracle.truffle.r.native/gnur/Makefile.gnur b/com.oracle.truffle.r.native/gnur/Makefile.gnur index 76eb523030..238eb6c3e5 100644 --- a/com.oracle.truffle.r.native/gnur/Makefile.gnur +++ b/com.oracle.truffle.r.native/gnur/Makefile.gnur @@ -116,7 +116,7 @@ endif $(GNUR_HOME)/Makefile: ed $(GNUR_HOME)/src/extra/xz/Makefile.in < patchXzMakefile - (cd $(GNUR_HOME); ./configure --with-x=no --without-recommended-packages $(GNUR_CONFIG_FLAGS) > gnur_configure.log 2>&1) + (cd $(GNUR_HOME); ./configure --with-x=no --without-recommended-packages --enable-memory-profiling $(GNUR_CONFIG_FLAGS) > gnur_configure.log 2>&1) build: $(GNUR_HOME)/bin/R diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java index 407c046347..aa0b4bacc2 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java @@ -580,6 +580,7 @@ public class BasePackage extends RBuiltinPackage { add(TraceFunctions.PrimTrace.class, TraceFunctionsFactory.PrimTraceNodeGen::create); add(TraceFunctions.PrimUnTrace.class, TraceFunctionsFactory.PrimUnTraceNodeGen::create); add(TraceFunctions.TraceOnOff.class, TraceFunctionsFactory.TraceOnOffNodeGen::create); + add(TraceFunctions.Tracemem.class, TraceFunctionsFactory.TracememNodeGen::create); add(Transpose.class, TransposeNodeGen::create); add(TrigExpFunctions.Acos.class, TrigExpFunctionsFactory.AcosNodeGen::create); add(TrigExpFunctions.Acosh.class, TrigExpFunctionsFactory.AcoshNodeGen::create); diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/TraceFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/TraceFunctions.java index 341a599ab3..c32d2e369e 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/TraceFunctions.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/TraceFunctions.java @@ -22,6 +22,9 @@ */ package com.oracle.truffle.r.nodes.builtin.base; +import java.io.IOException; +import java.util.HashSet; + import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.dsl.Specialization; @@ -35,10 +38,13 @@ import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.RVisibility; +import com.oracle.truffle.r.runtime.conn.StdConnections; import com.oracle.truffle.r.runtime.context.RContext; +import com.oracle.truffle.r.runtime.data.MemoryTracer; import com.oracle.truffle.r.runtime.data.RFunction; import com.oracle.truffle.r.runtime.data.RNull; import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector; +import com.oracle.truffle.r.runtime.data.model.RAbstractVector; public class TraceFunctions { @@ -111,4 +117,36 @@ public class TraceFunctions { return RRuntime.asLogical(RContext.getInstance().stateInstrumentation.getTracingState()); } } + + @RBuiltin(name = "tracemem", kind = RBuiltinKind.PRIMITIVE, parameterNames = "x") + public abstract static class Tracemem extends RBuiltinNode { + + static { + MemoryTracer.setListener(new TracememListener()); + } + + @Specialization + protected String execute(Object x) { + getTracedObjects().add(x); + MemoryTracer.reportEvents(); + return String.format("<0x%x>", x.hashCode()); + } + + private static HashSet<Object> getTracedObjects() { + return RContext.getInstance().getInstrumentationState().getTracemem().getTracedObjects(); + } + + private static final class TracememListener implements MemoryTracer.Listener { + public void reportCopying(RAbstractVector src, RAbstractVector dest) { + if (getTracedObjects().contains(src)) { + String msg = String.format("tracemem[0x%x -> 0x%x]", src.hashCode(), dest.hashCode()); + try { + StdConnections.getStdout().writeString(msg, true); + } catch (IOException ex) { + throw RError.error(RError.NO_CALLER, RError.Message.GENERIC, ex.getMessage()); + } + } + } + } + } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateDimNames.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateDimNames.java index d91d4a8fbb..8c67c523f2 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateDimNames.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateDimNames.java @@ -163,7 +163,7 @@ public abstract class UpdateDimNames extends RBuiltinNode { RList resDimNames = newDimNames; if (newDimNamesLength < dimensions.length) { // resize the array and fill the missing entries with NULL-s - resDimNames = resDimNames.copyResized(dimensions.length, true); + resDimNames = (RList) resDimNames.copyResized(dimensions.length, true); resDimNames.setAttributes(newDimNames); for (int i = newDimNamesLength; i < dimensions.length; i++) { resDimNames.updateDataAt(i, RNull.instance, null); diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateNames.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateNames.java index d192337e37..317ce79c47 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateNames.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateNames.java @@ -72,7 +72,7 @@ public abstract class UpdateNames extends RBuiltinNode { } RAbstractContainer result = (RAbstractContainer) container.getNonShared(); if (stringVector.getLength() < result.getLength()) { - stringVector = stringVector.copyResized(result.getLength(), true); + stringVector = (RStringVector) stringVector.copyResized(result.getLength(), true); } else if (stringVector.getLength() > result.getLength()) { throw RError.error(this, Message.NAMES_LONGER, stringVector.getLength(), result.getLength()); } else if (stringVector == container) { diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/MemoryTracer.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/MemoryTracer.java new file mode 100644 index 0000000000..e8f271a92d --- /dev/null +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/MemoryTracer.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.truffle.r.runtime.data; + +import com.oracle.truffle.api.Assumption; +import com.oracle.truffle.api.Truffle; +import com.oracle.truffle.r.runtime.data.model.RAbstractVector; + +/** + * Helper for tracing memory related events. All implementors of {@link RAbstractVector} are + * expected to report to {@link MemoryTracer} and othes can listen to them through {@link Listener} + * interface. Use method {@link #reportEvents()} to start the tracing. + */ +public final class MemoryTracer { + private static Listener listener; + private static final Assumption noMemoryTracingAssumption = Truffle.getRuntime().createAssumption(); + + private MemoryTracer() { + // only static methods + } + + /** + * Sets the listener of memory tracing events. For the time being there can only be one + * listener. This can be extended to an array should we need more listeners. + */ + public static void setListener(Listener newListener) { + listener = newListener; + } + + /** + * After calling this method memory related events will be reported to the listener. This + * invalidates global assumption and should be used with caution. + */ + public static void reportEvents() { + noMemoryTracingAssumption.invalidate(); + } + + /** + * Reports copy event to the listener. If there are no traced objects, this should turn into + * no-op. + */ + public static void reportCopying(RAbstractVector source, RAbstractVector dest) { + if (!noMemoryTracingAssumption.isValid() && listener != null) { + listener.reportCopying(source, dest); + } + } + + public interface Listener { + void reportCopying(RAbstractVector source, RAbstractVector dest); + } +} diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RComplex.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RComplex.java index a3d7858c77..1bfe70252d 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RComplex.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RComplex.java @@ -67,7 +67,9 @@ public final class RComplex extends RScalarVector implements RAbstractComplexVec @Override public RComplexVector materialize() { - return RDataFactory.createComplexVectorFromScalar(this); + RComplexVector result = RDataFactory.createComplexVectorFromScalar(this); + MemoryTracer.reportCopying(this, result); + return result; } @Override diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RComplexVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RComplexVector.java index 530b0796a9..e94bd445cc 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RComplexVector.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RComplexVector.java @@ -198,7 +198,7 @@ public final class RComplexVector extends RVector implements RAbstractComplexVec } @Override - public RComplexVector copyResized(int size, boolean fillNA) { + protected RComplexVector internalCopyResized(int size, boolean fillNA) { boolean isComplete = isComplete() && ((data.length >= size) || !fillNA); return RDataFactory.createComplexVector(copyResizedData(size, fillNA), isComplete); } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDouble.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDouble.java index b31722d76e..096356c36a 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDouble.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDouble.java @@ -89,7 +89,9 @@ public final class RDouble extends RScalarVector implements RAbstractDoubleVecto @Override public RDoubleVector materialize() { - return RDataFactory.createDoubleVectorFromScalar(getValue()); + RDoubleVector result = RDataFactory.createDoubleVectorFromScalar(getValue()); + MemoryTracer.reportCopying(this, result); + return result; } @Override diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDoubleVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDoubleVector.java index a3be269758..c542875fa7 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDoubleVector.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDoubleVector.java @@ -211,7 +211,7 @@ public final class RDoubleVector extends RVector implements RAbstractDoubleVecto } @Override - public RDoubleVector copyResized(int size, boolean fillNA) { + protected RDoubleVector internalCopyResized(int size, boolean fillNA) { boolean isComplete = isComplete() && ((data.length >= size) || !fillNA); return RDataFactory.createDoubleVector(copyResizedData(size, fillNA), isComplete); } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RIntVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RIntVector.java index 6a672cdbac..74e182b9ce 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RIntVector.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RIntVector.java @@ -208,7 +208,7 @@ public final class RIntVector extends RVector implements RAbstractIntVector { } @Override - public RIntVector copyResized(int size, boolean fillNA) { + protected RIntVector internalCopyResized(int size, boolean fillNA) { boolean isComplete = isComplete() && ((data.length >= size) || !fillNA); return RDataFactory.createIntVector(copyResizedData(size, fillNA), isComplete); } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RInteger.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RInteger.java index 0df0f556e1..075d9ee511 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RInteger.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RInteger.java @@ -87,7 +87,9 @@ public final class RInteger extends RScalarVector implements RAbstractIntVector @Override public RIntVector materialize() { - return RDataFactory.createIntVectorFromScalar(value); + RIntVector result = RDataFactory.createIntVectorFromScalar(value); + MemoryTracer.reportCopying(this, result); + return result; } @Override diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RList.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RList.java index cb0496f25d..c97e5a73d8 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RList.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RList.java @@ -72,7 +72,7 @@ public final class RList extends RListBase { } @Override - public RList copyResized(int size, boolean fillNA) { + protected RList internalCopyResized(int size, boolean fillNA) { return RDataFactory.createList(copyResizedData(size, fillNA)); } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLogical.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLogical.java index 65f0ad784f..05d0e6d1b1 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLogical.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLogical.java @@ -93,7 +93,9 @@ public final class RLogical extends RScalarVector implements RAbstractLogicalVec @Override public RLogicalVector materialize() { - return RDataFactory.createLogicalVectorFromScalar(value); + RLogicalVector result = RDataFactory.createLogicalVectorFromScalar(value); + MemoryTracer.reportCopying(this, result); + return result; } @Override diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLogicalVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLogicalVector.java index 4d30688419..a492093eb7 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLogicalVector.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLogicalVector.java @@ -169,7 +169,7 @@ public final class RLogicalVector extends RVector implements RAbstractLogicalVec } @Override - public RLogicalVector copyResized(int size, boolean fillNA) { + protected RLogicalVector internalCopyResized(int size, boolean fillNA) { boolean isComplete = isComplete() && ((data.length >= size) || !fillNA); return RDataFactory.createLogicalVector(copyResizedData(size, fillNA), isComplete); } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RRaw.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RRaw.java index bb93e20a57..d843cacfb9 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RRaw.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RRaw.java @@ -64,7 +64,9 @@ public final class RRaw extends RScalarVector implements RAbstractRawVector { @Override public RRawVector materialize() { - return RDataFactory.createRawVector(new byte[]{value}); + RRawVector result = RDataFactory.createRawVector(new byte[]{value}); + MemoryTracer.reportCopying(this, result); + return result; } @Override diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RRawVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RRawVector.java index fdadc7cd66..01ef62b132 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RRawVector.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RRawVector.java @@ -187,7 +187,7 @@ public final class RRawVector extends RVector implements RAbstractRawVector { } @Override - public RRawVector copyResized(int size, boolean fillNA) { + protected RRawVector internalCopyResized(int size, boolean fillNA) { return RDataFactory.createRawVector(copyResizedData(size, fillNA)); } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RScalarVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RScalarVector.java index 6d7ddced92..6e4a7ca5d9 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RScalarVector.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RScalarVector.java @@ -142,22 +142,30 @@ public abstract class RScalarVector extends RScalar implements RAbstractVector { @Override public RVector copyResized(int size, boolean fillNA) { - return materialize().copyResized(size, fillNA); + RVector result = materialize().copyResized(size, fillNA); + MemoryTracer.reportCopying(this, result); + return result; } @Override public RAbstractVector copyWithNewDimensions(int[] newDimensions) { - return materialize().copyWithNewDimensions(newDimensions); + RAbstractVector result = materialize().copyWithNewDimensions(newDimensions); + MemoryTracer.reportCopying(this, result); + return result; } @Override public RVector copyResizedWithDimensions(int[] newDimensions, boolean fillNA) { - return materialize().copyResizedWithDimensions(newDimensions, fillNA); + RVector result = materialize().copyResizedWithDimensions(newDimensions, fillNA); + MemoryTracer.reportCopying(this, result); + return result; } @Override public RAbstractVector copyDropAttributes() { - return materialize().copyDropAttributes(); + RVector result = materialize().copyDropAttributes(); + MemoryTracer.reportCopying(this, result); + return result; } @Override diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RSequence.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RSequence.java index df3204230a..3dcc48a783 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RSequence.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RSequence.java @@ -80,7 +80,9 @@ public abstract class RSequence implements RAbstractVector { } public final RVector createVector() { - return internalCreateVector(); + RVector result = internalCreateVector(); + MemoryTracer.reportCopying(this, result); + return result; } protected abstract RVector internalCreateVector(); diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RString.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RString.java index 03edef949b..764f4c4b4b 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RString.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RString.java @@ -73,7 +73,9 @@ public final class RString extends RScalarVector implements RAbstractStringVecto @Override public RStringVector materialize() { - return RDataFactory.createStringVector(new String[]{getValue()}, isComplete()); + RStringVector result = RDataFactory.createStringVector(new String[]{getValue()}, isComplete()); + MemoryTracer.reportCopying(this, result); + return result; } @Override diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RStringVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RStringVector.java index 85a263b13b..53f6667432 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RStringVector.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RStringVector.java @@ -190,7 +190,7 @@ public final class RStringVector extends RVector implements RAbstractStringVecto } @Override - public RStringVector copyResized(int size, boolean fillNA) { + protected RStringVector internalCopyResized(int size, boolean fillNA) { boolean isComplete = isComplete() && ((data.length >= size) || !fillNA); return RDataFactory.createStringVector(copyResizedData(size, fillNA ? RRuntime.STRING_NA : null), isComplete); } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RVector.java index 2c7e3e7153..159addc3e2 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RVector.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RVector.java @@ -410,7 +410,7 @@ public abstract class RVector extends RSharingAttributeStorage implements RShare RList resDimNames = newDimNames; if (newDimNamesLength < dimensions.length) { // resize the array and fill the missing entries with NULL-s - resDimNames = resDimNames.copyResized(dimensions.length, true); + resDimNames = (RList) resDimNames.copyResized(dimensions.length, true); resDimNames.setAttributes(newDimNames); for (int i = newDimNamesLength; i < dimensions.length; i++) { resDimNames.updateDataAt(i, RNull.instance, null); @@ -547,9 +547,11 @@ public abstract class RVector extends RSharingAttributeStorage implements RShare } } + // public interface *copy* methods are final and delegate to *internalCopyAndReport* methods + @Override public final RVector copy() { - RVector result = internalCopy(); + RVector result = internalCopyAndReport(); setAttributes(result); incCopyCount(); result.setTypedValueInfo(getTypedValueInfo()); @@ -558,21 +560,55 @@ public abstract class RVector extends RSharingAttributeStorage implements RShare @Override public final RVector copyDropAttributes() { - return internalCopy(); + RVector result = internalCopyAndReport(); + return result; } @Override - public RVector deepCopy() { - RVector result = internalDeepCopy(); + public final RVector deepCopy() { + RVector result = internalDeepCopyAndReport(); setAttributes(result); return result; } + @Override + public final RVector copyResized(int size, boolean fillNA) { + return internalCopyResizedAndReport(size, fillNA); + } + + // *internalCopyAndReport* methods do just the copy and report it to MemoryTracer. These should + // be used if additional logic in public interface *copy* method is not desired. + + protected final RVector internalCopyAndReport() { + RVector result = internalCopy(); + MemoryTracer.reportCopying(this, result); + return result; + } + + protected final RVector internalDeepCopyAndReport() { + RVector result = internalDeepCopy(); + MemoryTracer.reportCopying(this, result); + return result; + } + + protected final RVector internalCopyResizedAndReport(int size, boolean fillNA) { + RVector result = internalCopyResized(size, fillNA); + MemoryTracer.reportCopying(this, result); + return result; + } + + // *internalCopy* methods should only be overridden, but never invoked from anywhere but + // *internalCopyAndReport* + + protected abstract RVector internalCopyResized(int size, boolean fillNA); + // to be overridden by recursive structures protected RVector internalDeepCopy() { return internalCopy(); } + protected abstract RVector internalCopy(); + @Override public RVector copyResizedWithDimensions(int[] newDimensions, boolean fillNA) { // TODO support for higher dimensions @@ -588,8 +624,6 @@ public abstract class RVector extends RSharingAttributeStorage implements RShare protected abstract String getDataAtAsString(int index); - protected abstract RVector internalCopy(); - protected abstract boolean internalVerify(); /** diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RToVectorClosure.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RToVectorClosure.java index a0a74fcdcb..0fe0baccfc 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RToVectorClosure.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RToVectorClosure.java @@ -22,6 +22,7 @@ */ package com.oracle.truffle.r.runtime.data.closures; +import com.oracle.truffle.r.runtime.data.MemoryTracer; import com.oracle.truffle.r.runtime.data.RAttributeProfiles; import com.oracle.truffle.r.runtime.data.RAttributes; import com.oracle.truffle.r.runtime.data.RList; @@ -127,12 +128,16 @@ abstract class RToVectorClosure implements RAbstractVector { @Override public final RAbstractVector copy() { - return vector.copy(); + RAbstractVector result = vector.copy(); + MemoryTracer.reportCopying(this, result); + return result; } @Override public final RVector copyResized(int size, boolean fillNA) { - return vector.copyResized(size, fillNA); + RVector result = vector.copyResized(size, fillNA); + MemoryTracer.reportCopying(this, result); + return result; } @Override @@ -146,7 +151,9 @@ abstract class RToVectorClosure implements RAbstractVector { @Override public final RAbstractVector copyDropAttributes() { - return vector.copyDropAttributes(); + RAbstractVector result = vector.copyDropAttributes(); + MemoryTracer.reportCopying(this, result); + return result; } @Override diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractVector.java index b0f2d25be4..a2ae57288b 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractVector.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractVector.java @@ -24,8 +24,12 @@ package com.oracle.truffle.r.runtime.data.model; import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.r.runtime.RType; +import com.oracle.truffle.r.runtime.data.MemoryTracer; import com.oracle.truffle.r.runtime.data.RVector; +/** + * When implementing, make sure to invoke related {@link MemoryTracer} methods. + */ public interface RAbstractVector extends RAbstractContainer { /** @@ -76,5 +80,4 @@ public interface RAbstractVector extends RAbstractContainer { void setComplete(boolean complete); void setNA(Object store, int index); - } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/instrument/InstrumentationState.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/instrument/InstrumentationState.java index 87b3341dae..2dc42bdcf7 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/instrument/InstrumentationState.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/instrument/InstrumentationState.java @@ -23,6 +23,7 @@ package com.oracle.truffle.r.runtime.instrument; import java.io.PrintWriter; +import java.util.HashSet; import java.util.WeakHashMap; import com.oracle.truffle.api.instrumentation.EventBinding; @@ -58,21 +59,33 @@ public final class InstrumentationState implements RContext.ContextState { private final RprofState rprofState; + private final TracememContext tracememContext; + + /** + * State used by the {@code tracemem} built-in. + */ + public static final class TracememContext { + private HashSet<Object> tracedObjects; + + public HashSet<Object> getTracedObjects() { + if (tracedObjects == null) { + tracedObjects = new HashSet<>(); + } + return tracedObjects; + } + } + /** * State used by {@code Rprof}. * */ - public static class RprofState { + public static final class RprofState { private PrintWriter out; private Thread profileThread; private ExecutionEventListener statementListener; private long intervalInMillis; private boolean lineProfiling; - public static RprofState newContext(@SuppressWarnings("unused") RContext context) { - return new RprofState(); - } - public void initialize(PrintWriter outA, Thread profileThreadA, ExecutionEventListener statementListenerA, long intervalInMillisA, boolean lineProfilingA) { this.out = outA; @@ -107,6 +120,7 @@ public final class InstrumentationState implements RContext.ContextState { private InstrumentationState(Instrumenter instrumenter) { this.instrumenter = instrumenter; this.rprofState = new RprofState(); + this.tracememContext = new TracememContext(); } public void putTraceBinding(SourceSection ss, EventBinding<?> binding) { @@ -158,6 +172,10 @@ public final class InstrumentationState implements RContext.ContextState { return rprofState; } + public TracememContext getTracemem() { + return tracememContext; + } + public static InstrumentationState newContext(@SuppressWarnings("unused") RContext context, Instrumenter instrumenter) { return new InstrumentationState(instrumenter); } diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test index 478ac346fb..3a285e9485 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test @@ -48821,6 +48821,10 @@ character(0) #argv <- structure(list(x = c('na', NA, 'banana')), .Names = 'x');do.call('toupper', argv) [1] "NA" NA "BANANA" +##com.oracle.truffle.r.test.builtins.TestBuiltin_tracemem.basicTests +#v <- c(1,10); addr<-tracemem(v); f<-function(x) x[[1]]<-42; out<-capture.output(f(v)); addr<-sub('>','',sub('<','',addr)); grep(paste0('tracemem[', addr), out, fixed=TRUE) +[1] 1 + ##com.oracle.truffle.r.test.builtins.TestBuiltin_trigamma.testtrigamma1 #argv <- list(structure(c(9.16602362697115, 1.16602362697115, 3.16602362697115, 6.16602362697115, 6.16602362697115, 2.16602362697115, 8.16602362697115, 1.16602362697115, 7.16602362697115, 19.1660236269712, 2.16602362697115), .Names = c('1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11')));trigamma(argv[[1]]); 1 2 3 4 5 6 7 diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_tracemem.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_tracemem.java new file mode 100644 index 0000000000..ecf20b6ec0 --- /dev/null +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_tracemem.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.truffle.r.test.builtins; + +import org.junit.Test; + +import com.oracle.truffle.r.test.TestBase; + +public class TestBuiltin_tracemem extends TestBase { + @Test + public void basicTests() { + // tracemem returns the hash in form of "<0x0fa0abcd>", we get rid of the "<" and ">" to + // match it against the output that is produced by copying 'v', which should be in the form + // of "tracemem[0x0fa0abcd->someotherhash]". + assertEval("v <- c(1,10); addr<-tracemem(v); f<-function(x) x[[1]]<-42; out<-capture.output(f(v)); addr<-sub('>','',sub('<','',addr)); grep(paste0('tracemem[', addr), out, fixed=TRUE)"); + } +} -- GitLab