diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/Rprof.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/Rprof.java index ac7b085011344fd31ae0976a6ef408bea7c916fd..d03f663b1151eaae9a39bdecede4f62e9996a80e 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/Rprof.java +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/Rprof.java @@ -50,9 +50,9 @@ import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.RSource; import com.oracle.truffle.r.runtime.Utils; import com.oracle.truffle.r.runtime.context.RContext; -import com.oracle.truffle.r.runtime.context.RprofState; import com.oracle.truffle.r.runtime.data.RNull; import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector; +import com.oracle.truffle.r.runtime.instrument.InstrumentationState.RprofState; import com.oracle.truffle.r.runtime.nodes.RSyntaxNode; public abstract class Rprof extends RExternalBuiltinNode.Arg8 { @@ -64,7 +64,7 @@ public abstract class Rprof extends RExternalBuiltinNode.Arg8 { if (!RContext.getInstance().isInitial()) { throw RError.error(this, RError.Message.GENERIC, "profiling not supported in created contexts"); } - RprofState profState = RContext.getInstance().stateRprof; + RprofState profState = RContext.getInstance().stateInstrumentation.getRprof(); String filename = filenameVec.getDataAt(0); if (filename.length() == 0) { // disable @@ -100,7 +100,7 @@ public abstract class Rprof extends RExternalBuiltinNode.Arg8 { } private static void endProfiling() { - RprofState profState = RContext.getInstance().stateRprof; + RprofState profState = RContext.getInstance().stateInstrumentation.getRprof(); ProfileThread profileThread = (ProfileThread) profState.profileThread(); profileThread.running = false; HashMap<String, Integer> fileMap = null; 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 042b3d0cca597784dde0e0c3c4030d1a64fe0d79..d0e3a8c0b290f4475b190a19221974a6ec1ebd32 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 @@ -44,14 +44,12 @@ import com.oracle.truffle.r.nodes.builtin.base.foreign.DotC; import com.oracle.truffle.r.nodes.builtin.base.foreign.DotCNodeGen; import com.oracle.truffle.r.nodes.builtin.base.foreign.ForeignFunctions; import com.oracle.truffle.r.nodes.builtin.base.foreign.ForeignFunctionsFactory; -import com.oracle.truffle.r.nodes.builtin.fastr.FastRCallCounting; -import com.oracle.truffle.r.nodes.builtin.fastr.FastRCallCountingFactory; import com.oracle.truffle.r.nodes.builtin.fastr.FastRContext; import com.oracle.truffle.r.nodes.builtin.fastr.FastRContextFactory; import com.oracle.truffle.r.nodes.builtin.fastr.FastRDebug; import com.oracle.truffle.r.nodes.builtin.fastr.FastRDebugNodeGen; -import com.oracle.truffle.r.nodes.builtin.fastr.FastRFunctionTimer; -import com.oracle.truffle.r.nodes.builtin.fastr.FastRFunctionTimerFactory; +import com.oracle.truffle.r.nodes.builtin.fastr.FastRFunctionProfiler; +import com.oracle.truffle.r.nodes.builtin.fastr.FastRFunctionProfilerFactory; import com.oracle.truffle.r.nodes.builtin.fastr.FastRIdentity; import com.oracle.truffle.r.nodes.builtin.fastr.FastRIdentityNodeGen; import com.oracle.truffle.r.nodes.builtin.fastr.FastRInspect; @@ -277,8 +275,6 @@ public class BasePackage extends RBuiltinPackage { add(WithVisible.class, WithVisibleNodeGen::create); add(Exists.class, ExistsNodeGen::create); add(Expression.class, ExpressionNodeGen::create); - add(FastRCallCounting.CreateCallCounter.class, FastRCallCountingFactory.CreateCallCounterNodeGen::create); - add(FastRCallCounting.GetCallCounter.class, FastRCallCountingFactory.GetCallCounterNodeGen::create); add(FastRContext.CloseChannel.class, FastRContextFactory.CloseChannelNodeGen::create); add(FastRContext.Create.class, FastRContextFactory.CreateNodeGen::create); add(FastRContext.CreateChannel.class, FastRContextFactory.CreateChannelNodeGen::create); @@ -293,8 +289,10 @@ public class BasePackage extends RBuiltinPackage { add(FastRContext.Join.class, FastRContextFactory.JoinNodeGen::create); add(FastrDqrls.class, FastrDqrlsNodeGen::create); add(FastRDebug.class, FastRDebugNodeGen::create); - add(FastRFunctionTimer.CreateFunctionTimer.class, FastRFunctionTimerFactory.CreateFunctionTimerNodeGen::create); - add(FastRFunctionTimer.GetFunctionTimer.class, FastRFunctionTimerFactory.GetFunctionTimerNodeGen::create); + add(FastRFunctionProfiler.Create.class, FastRFunctionProfilerFactory.CreateNodeGen::create); + add(FastRFunctionProfiler.Get.class, FastRFunctionProfilerFactory.GetNodeGen::create); + add(FastRFunctionProfiler.Reset.class, FastRFunctionProfilerFactory.ResetNodeGen::create); + add(FastRFunctionProfiler.Clear.class, FastRFunctionProfilerFactory.ClearNodeGen::create); add(FastRIdentity.class, FastRIdentityNodeGen::create); add(FastRInspect.class, FastRInspectNodeGen::create); add(FastRInterop.Eval.class, FastRInteropFactory.EvalNodeGen::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 45ded5c9169373e32d0615ac29f2fa4c9e7c9df0..341a599ab3100966d00a8cae5e0d361e6d1cf630 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 @@ -97,10 +97,10 @@ public class TraceFunctions { @Specialization @TruffleBoundary protected byte traceOnOff(byte state) { - boolean prevState = RContext.getInstance().stateTraceHandling.getTracingState(); + boolean prevState = RContext.getInstance().stateInstrumentation.getTracingState(); boolean newState = RRuntime.fromLogical(state); if (newState != prevState) { - RContext.getInstance().stateTraceHandling.setTracingState(newState); + RContext.getInstance().stateInstrumentation.setTracingState(newState); } return RRuntime.asLogical(prevState); } @@ -108,7 +108,7 @@ public class TraceFunctions { @Specialization @TruffleBoundary protected byte traceOnOff(@SuppressWarnings("unused") RNull state) { - return RRuntime.asLogical(RContext.getInstance().stateTraceHandling.getTracingState()); + return RRuntime.asLogical(RContext.getInstance().stateInstrumentation.getTracingState()); } } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRCallCounting.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRCallCounting.java deleted file mode 100644 index 4039faa429afd3aafb46e1409bba4c31c8469d4f..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRCallCounting.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2014, 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.nodes.builtin.fastr; - -import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; -import com.oracle.truffle.api.dsl.Fallback; -import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; -import com.oracle.truffle.r.nodes.instrumentation.REntryCounters; -import com.oracle.truffle.r.runtime.RBuiltin; -import com.oracle.truffle.r.runtime.RBuiltinKind; -import com.oracle.truffle.r.runtime.RError; -import com.oracle.truffle.r.runtime.RVisibility; -import com.oracle.truffle.r.runtime.data.RFunction; -import com.oracle.truffle.r.runtime.data.RNull; - -public class FastRCallCounting { - - @RBuiltin(name = ".fastr.createcc", visibility = RVisibility.OFF, kind = RBuiltinKind.PRIMITIVE, parameterNames = {"func"}) - public abstract static class CreateCallCounter extends RBuiltinNode { - @Specialization - @TruffleBoundary - protected RNull createCallCounter(RFunction function) { - if (!function.isBuiltin()) { - REntryCounters.FunctionListener.installCounter(function); - } - return RNull.instance; - } - - @SuppressWarnings("unused") - @Fallback - protected Object fallback(Object a1) { - throw RError.error(this, RError.Message.INVALID_ARGUMENT, "func"); - } - } - - @RBuiltin(name = ".fastr.getcc", visibility = RVisibility.OFF, kind = RBuiltinKind.PRIMITIVE, parameterNames = {"func"}) - public abstract static class GetCallCounter extends RBuiltinNode { - @Specialization - @TruffleBoundary - protected Object getCallCount(RFunction function) { - if (!function.isBuiltin()) { - int entryCount = REntryCounters.FunctionListener.findCounter(function).getEnterCount(); - if (entryCount < 0) { - throw RError.error(this, RError.Message.GENERIC, "no associated counter"); - } else { - return entryCount; - } - } - return RNull.instance; - } - - @SuppressWarnings("unused") - @Fallback - protected Object fallback(Object a1) { - throw RError.error(this, RError.Message.INVALID_ARGUMENT, "func"); - } - } -} diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRFunctionProfiler.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRFunctionProfiler.java new file mode 100644 index 0000000000000000000000000000000000000000..977de8fc70a5c51aefd9b21f23c0ab68316a6c81 --- /dev/null +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRFunctionProfiler.java @@ -0,0 +1,257 @@ +/* + * Copyright (c) 2014, 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.nodes.builtin.fastr; + +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue; + +import java.util.ArrayList; + +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.missingValue; +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.doubleValue; +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.instanceOf; +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.integerValue; + +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.r.nodes.builtin.CastBuilder; +import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; +import com.oracle.truffle.r.nodes.instrumentation.RFunctionProfiler; +import com.oracle.truffle.r.runtime.RBuiltin; +import com.oracle.truffle.r.runtime.RBuiltinKind; +import com.oracle.truffle.r.runtime.RError; +import com.oracle.truffle.r.runtime.RInternalError; +import com.oracle.truffle.r.runtime.RRuntime; +import com.oracle.truffle.r.runtime.RVisibility; +import com.oracle.truffle.r.runtime.data.RDataFactory; +import com.oracle.truffle.r.runtime.data.RDoubleVector; +import com.oracle.truffle.r.runtime.data.RFunction; +import com.oracle.truffle.r.runtime.data.RList; +import com.oracle.truffle.r.runtime.data.RMissing; +import com.oracle.truffle.r.runtime.data.RNull; +import com.oracle.truffle.r.runtime.data.RStringVector; +import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector; +import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector; +import com.oracle.truffle.tools.Profiler; + +public class FastRFunctionProfiler { + + @RBuiltin(name = ".fastr.profiler.create", visibility = RVisibility.OFF, kind = RBuiltinKind.PRIMITIVE, parameterNames = {"func", "mode"}) + public abstract static class Create extends RBuiltinNode { + private static final int COUNTING = 1; + private static final int TIMING = 2; + + @Override + public Object[] getDefaultParameterValues() { + return new Object[]{RMissing.instance, "counting"}; + } + + @Override + protected void createCasts(CastBuilder casts) { + casts.arg("func").mustBe(instanceOf(RFunction.class).or(missingValue())); + + casts.arg("mode").mustBe(stringValue()).asStringVector(); + } + + private int checkMode(RAbstractStringVector modeVec) { + int result = 0; + for (int i = 0; i < modeVec.getLength(); i++) { + String mode = modeVec.getDataAt(i); + switch (mode) { + case "counting": + result |= COUNTING; + break; + case "timing": + result |= TIMING; + break; + default: + throw RError.error(this, RError.Message.GENERIC, "invalid 'mode', one of 'count, timning' expected"); + } + } + return result; + } + + @Specialization + @TruffleBoundary + protected RNull createFunctionProfiler(RFunction function, RAbstractStringVector modeVec) { + int mode = checkMode(modeVec); + if (!function.isBuiltin()) { + RFunctionProfiler.installTimer(function, (mode & COUNTING) != 0, (mode & TIMING) != 0); + } else { + throw RError.error(this, RError.Message.GENERIC, "cannot profile builtin functions"); + } + return RNull.instance; + } + + @Specialization + @TruffleBoundary + protected RNull createFunctionProfiler(@SuppressWarnings("unused") RMissing value, RAbstractStringVector modeVec) { + int mode = checkMode(modeVec); + RFunctionProfiler.installTimer(null, (mode & COUNTING) != 0, (mode & TIMING) != 0); + return RNull.instance; + } + + } + + @RBuiltin(name = ".fastr.profiler.get", kind = RBuiltinKind.PRIMITIVE, parameterNames = {"func", "threshold", "scale"}) + public abstract static class Get extends RBuiltinNode { + + private static final RStringVector COLNAMES = RDataFactory.createStringVector(new String[]{"Invocations", "TotalTime", "SelfTime"}, RDataFactory.COMPLETE_VECTOR); + private static final RStringVector ROWNAMES = RDataFactory.createStringVector(new String[]{"Combined", "Interpreted", "Compiled"}, RDataFactory.COMPLETE_VECTOR); + private static final int NCOLS = 3; + private static final int NROWS = 3; + + @Override + protected void createCasts(CastBuilder casts) { + casts.arg("func").mustBe(instanceOf(RFunction.class).or(missingValue())); + + casts.arg("threshold").mustBe(integerValue().or(doubleValue())).asDoubleVector(); + + casts.arg("scale").mustBe(stringValue()).asStringVector(); + } + + @Override + public Object[] getDefaultParameterValues() { + return new Object[]{RMissing.instance, 0.0, "nanos"}; + } + + private void checkScale(String s) throws RError { + if (!(s.equals("nanos") || s.equals("millis") || s.equals("micros") || s.equals("secs"))) { + throw RError.error(this, RError.Message.GENERIC, "invalid scale: one of 'nanos, micros, millis, secs' expected"); + } + } + + @Specialization + @TruffleBoundary + protected Object get(@SuppressWarnings("unused") RMissing value, RAbstractDoubleVector thresholdVec, RAbstractStringVector scaleVec) { + String scale = scaleVec.getDataAt(0); + checkScale(scale); + double threshold = thresholdVec.getDataAt(0); + Profiler.Counter[] counters = RFunctionProfiler.getCounters(); + if (counters == null) { + throw RError.error(this, RError.Message.GENERIC, "profiling not enabled"); + } + ArrayList<RDoubleVector> dataList = new ArrayList<>(); + ArrayList<String> nameList = new ArrayList<>(); + for (int i = 0; i < counters.length; i++) { + Profiler.Counter counter = counters[i]; + if (threshold > 0.0) { + long time = counter.getTotalTime(Profiler.Counter.TimeKind.INTERPRETED_AND_COMPILED); + if (time <= threshold) { + continue; + } + } + dataList.add(getFunctionMatrix(counter, scale)); + nameList.add(counter.getName()); + } + Object[] data = new Object[dataList.size()]; + String[] names = new String[nameList.size()]; + return RDataFactory.createList(dataList.toArray(data), RDataFactory.createStringVector(nameList.toArray(names), RDataFactory.COMPLETE_VECTOR)); + } + + @Specialization + @TruffleBoundary + protected Object get(RFunction function, @SuppressWarnings("unused") RAbstractDoubleVector threshold, RAbstractStringVector scaleVec) { + String scale = scaleVec.getDataAt(0); + checkScale(scale); + if (!function.isBuiltin()) { + Profiler.Counter counter = RFunctionProfiler.getCounter(function); + if (counter == null) { + throw RError.error(this, RError.Message.GENERIC, "profiling not enabled"); + } else { + return getFunctionMatrix(counter, scale); + } + } else { + throw RError.error(this, RError.Message.GENERIC, "cannot profile builtin functions"); + } + } + + private static RDoubleVector getFunctionMatrix(Profiler.Counter counter, String scale) { + double[] data = new double[NROWS * NCOLS]; + boolean isTiming = RFunctionProfiler.isTiming(); + boolean complete = isTiming ? RDataFactory.COMPLETE_VECTOR : RDataFactory.INCOMPLETE_VECTOR; + for (int r = 0; r < NROWS; r++) { + Profiler.Counter.TimeKind timeKind = Profiler.Counter.TimeKind.values()[r]; + for (int c = 0; c < NCOLS; c++) { + int index = c * NROWS + r; + double value = 0.0; + switch (c) { + case 0: + value = counter.getInvocations(timeKind); + break; + case 1: + value = isTiming ? counter.getTotalTime(timeKind) : RRuntime.DOUBLE_NA; + break; + case 2: + value = isTiming ? counter.getSelfTime(timeKind) : RRuntime.DOUBLE_NA; + } + data[index] = c == 0 ? value : scaledTime(scale, value); + } + } + RDoubleVector result = RDataFactory.createDoubleVector(data, complete, new int[]{3, 3}); + Object[] dimNamesData = new Object[2]; + dimNamesData[0] = ROWNAMES; + dimNamesData[1] = COLNAMES; + RList dimNames = RDataFactory.createList(dimNamesData); + result.setDimNames(dimNames); + return result; + } + + private static double scaledTime(String scale, double time) { + if (RRuntime.isNA(time)) { + return time; + } + switch (scale) { + case "nanos": + return time; + case "micros": + return time / 1000.0; + case "millis": + return time / 1000000.0; + case "secs": + return time / 1000000000.0; + default: + throw RInternalError.shouldNotReachHere(); + } + } + } + + @RBuiltin(name = ".fastr.profiler.reset", kind = RBuiltinKind.PRIMITIVE, parameterNames = {}, visibility = RVisibility.OFF) + public abstract static class Reset extends RBuiltinNode { + @Specialization + @TruffleBoundary + protected Object reset() { + RFunctionProfiler.reset(); + return RNull.instance; + } + } + + @RBuiltin(name = ".fastr.profiler.clear", kind = RBuiltinKind.PRIMITIVE, parameterNames = {}, visibility = RVisibility.OFF) + public abstract static class Clear extends RBuiltinNode { + @Specialization + @TruffleBoundary + protected Object clear() { + RFunctionProfiler.clear(); + return RNull.instance; + } + } +} diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRFunctionTimer.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRFunctionTimer.java deleted file mode 100644 index 1a967545babb8328c37243b0ba4d3f4370188406..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRFunctionTimer.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (c) 2014, 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.nodes.builtin.fastr; - -import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; -import com.oracle.truffle.api.dsl.Fallback; -import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; -import com.oracle.truffle.r.nodes.instrumentation.RNodeTimer; -import com.oracle.truffle.r.runtime.RBuiltin; -import com.oracle.truffle.r.runtime.RBuiltinKind; -import com.oracle.truffle.r.runtime.RError; -import com.oracle.truffle.r.runtime.RVisibility; -import com.oracle.truffle.r.runtime.data.RDataFactory; -import com.oracle.truffle.r.runtime.data.RFunction; -import com.oracle.truffle.r.runtime.data.RMissing; -import com.oracle.truffle.r.runtime.data.RNull; -import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector; - -public class FastRFunctionTimer { - - @RBuiltin(name = ".fastr.createtimer", visibility = RVisibility.OFF, kind = RBuiltinKind.PRIMITIVE, parameterNames = {"func"}) - public abstract static class CreateFunctionTimer extends RBuiltinNode { - @Specialization - @TruffleBoundary - protected RNull createFunctionTimer(RFunction function) { - if (!function.isBuiltin()) { - RNodeTimer.StatementListener.installTimer(function); - } - return RNull.instance; - } - - @SuppressWarnings("unused") - @Fallback - protected Object fallback(Object a1) { - throw RError.error(this, RError.Message.INVALID_ARGUMENT, "func"); - } - } - - @RBuiltin(name = ".fastr.gettimer", kind = RBuiltinKind.PRIMITIVE, parameterNames = {"func", "scale"}) - public abstract static class GetFunctionTimer extends RBuiltinNode { - @Override - public Object[] getDefaultParameterValues() { - return new Object[]{RMissing.instance, "nanos"}; - } - - @Specialization - @TruffleBoundary - protected Object getFunctionTimer(RFunction function, RAbstractStringVector scale) { - if (!function.isBuiltin()) { - long timeInfo = RNodeTimer.StatementListener.findTimer(function); - if (timeInfo < 0) { - throw RError.error(this, RError.Message.GENERIC, "no associated timer"); - } else { - double timeVal = timeInfo; - switch (scale.getDataAt(0)) { - case "nanos": - break; - case "micros": - timeVal = timeVal / 1000.0; - break; - case "millis": - timeVal = timeVal / 1000000.0; - break; - case "secs": - timeVal = timeVal / 1000000000.0; - break; - default: - throw RError.error(this, RError.Message.GENERIC, "invalid scale: one of 'nanos, micros, millis, secs' expected"); - } - return RDataFactory.createDoubleVectorFromScalar(timeVal); - } - } - return RNull.instance; - } - - @SuppressWarnings("unused") - @Fallback - protected Object fallback(Object a1, Object a2) { - throw RError.error(this, RError.Message.INVALID_ARGUMENT, "func"); - } - } -} diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/helpers/DebugHandling.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/helpers/DebugHandling.java index 0e04ac5e551ba5ac58f805bea5dae3e864e09e79..76c6e1167e48c003fdb5ee32c9fb597514912321 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/helpers/DebugHandling.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/helpers/DebugHandling.java @@ -24,7 +24,6 @@ package com.oracle.truffle.r.nodes.builtin.helpers; import java.io.IOException; import java.util.ArrayList; -import java.util.WeakHashMap; import com.oracle.truffle.api.Assumption; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; @@ -44,7 +43,6 @@ import com.oracle.truffle.r.nodes.control.AbstractLoopNode; import com.oracle.truffle.r.nodes.function.FunctionDefinitionNode; import com.oracle.truffle.r.nodes.instrumentation.RInstrumentation; import com.oracle.truffle.r.nodes.instrumentation.RSyntaxTags; -import com.oracle.truffle.r.runtime.FunctionUID; import com.oracle.truffle.r.runtime.RArguments; import com.oracle.truffle.r.runtime.RDeparse; import com.oracle.truffle.r.runtime.RError; @@ -102,11 +100,6 @@ import com.oracle.truffle.r.runtime.nodes.RSyntaxNodeVisitor; */ public class DebugHandling { - /** - * Records all functions that have debug listeners installed. - */ - private static final WeakHashMap<FunctionUID, FunctionStatementsEventListener> listenerMap = new WeakHashMap<>(); - /** * This flag is used to (temporarily) disable all debugging across calls that are used * internally in the implementation. @@ -117,8 +110,7 @@ public class DebugHandling { * Attach the DebugHandling instrument to the FunctionStatementsNode and all syntactic nodes. */ public static boolean enableDebug(RFunction func, Object text, Object condition, boolean once) { - FunctionDefinitionNode fdn = (FunctionDefinitionNode) func.getRootNode(); - FunctionStatementsEventListener fbr = listenerMap.get(fdn.getUID()); + FunctionStatementsEventListener fbr = getFunctionStatementsEventListener(func); if (fbr == null) { attachDebugHandler(func, text, condition, once); } else { @@ -128,7 +120,7 @@ public class DebugHandling { } public static boolean undebug(RFunction func) { - FunctionStatementsEventListener fbr = listenerMap.get(((FunctionDefinitionNode) func.getRootNode()).getUID()); + FunctionStatementsEventListener fbr = getFunctionStatementsEventListener(func); if (fbr == null) { return false; } else { @@ -138,10 +130,18 @@ public class DebugHandling { } public static boolean isDebugged(RFunction func) { - FunctionStatementsEventListener fser = listenerMap.get(((FunctionDefinitionNode) func.getRootNode()).getUID()); + FunctionStatementsEventListener fser = getFunctionStatementsEventListener(func); return fser != null && !fser.disabled(); } + private static FunctionStatementsEventListener getFunctionStatementsEventListener(RFunction func) { + return (FunctionStatementsEventListener) RContext.getInstance().stateInstrumentation.getDebugListener(RInstrumentation.getSourceSection(func)); + } + + private static FunctionStatementsEventListener getFunctionStatementsEventListener(FunctionDefinitionNode fdn) { + return (FunctionStatementsEventListener) RContext.getInstance().stateInstrumentation.getDebugListener(fdn.getSourceSection()); + } + /** * Disables/enables debugging globally. Intended to be used for short period, typically while * executing functions used internally by the implementation. @@ -186,7 +186,7 @@ public class DebugHandling { } private static void ensureSingleStep(FunctionDefinitionNode fdn) { - FunctionStatementsEventListener fser = listenerMap.get(fdn.getUID()); + FunctionStatementsEventListener fser = getFunctionStatementsEventListener(fdn); if (fser == null) { // attach a "once" listener fser = attachDebugHandler(fdn, null, null, true); @@ -262,7 +262,7 @@ public class DebugHandling { * will everything get invalidated? */ stepIntoInstrument = RInstrumentation.getInstrumenter().attachListener(SourceSectionFilter.newBuilder().tagIs(StandardTags.RootTag.class).build(), - new StepIntoInstrumentListener(listenerMap.get(functionDefinitionNode.getUID()))); + new StepIntoInstrumentListener(getFunctionStatementsEventListener(functionDefinitionNode))); } break; case BrowserInteractNode.CONTINUE: @@ -275,7 +275,7 @@ public class DebugHandling { AbstractLoopNode loopNode = inLoop(node); if (loopNode != null) { // Have to disable just the body of the loop - FunctionStatementsEventListener fser = listenerMap.get(functionDefinitionNode.getUID()); + FunctionStatementsEventListener fser = getFunctionStatementsEventListener(functionDefinitionNode); fser.setFinishing(loopNode); } else { doContinue(); @@ -285,7 +285,7 @@ public class DebugHandling { } private void doContinue() { - FunctionStatementsEventListener fser = listenerMap.get(functionDefinitionNode.getUID()); + FunctionStatementsEventListener fser = getFunctionStatementsEventListener(functionDefinitionNode); fser.setContinuing(); } @@ -323,7 +323,7 @@ public class DebugHandling { FunctionStatementsEventListener(FunctionDefinitionNode functionDefinitionNode, Object text, Object condition, boolean once) { super(functionDefinitionNode, text, condition); - listenerMap.put(functionDefinitionNode.getUID(), this); + RContext.getInstance().stateInstrumentation.putDebugListener(functionDefinitionNode.getSourceSection(), this); statementListener = new StatementEventListener(functionDefinitionNode, text, condition); this.once = once; } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/helpers/TraceHandling.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/helpers/TraceHandling.java index 1418ab39e90504bb45fd8867c7bec30ed9562d02..798fd225d0eb4101e79b8ed1b90b3722c0577653 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/helpers/TraceHandling.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/helpers/TraceHandling.java @@ -33,7 +33,6 @@ import com.oracle.truffle.api.instrumentation.ExecutionEventListener; import com.oracle.truffle.api.instrumentation.SourceSectionFilter; import com.oracle.truffle.api.instrumentation.StandardTags; import com.oracle.truffle.api.utilities.CyclicAssumption; -import com.oracle.truffle.r.nodes.function.FunctionDefinitionNode; import com.oracle.truffle.r.nodes.instrumentation.RInstrumentation; import com.oracle.truffle.r.runtime.FastROptions; import com.oracle.truffle.r.runtime.RArguments; @@ -52,9 +51,8 @@ import com.oracle.truffle.r.runtime.data.RMissing; public class TraceHandling { public static void enableTrace(RFunction func) { - FunctionDefinitionNode fdn = (FunctionDefinitionNode) func.getRootNode(); @SuppressWarnings("unchecked") - EventBinding<TraceEventListener> binding = (EventBinding<TraceEventListener>) RContext.getInstance().stateTraceHandling.get(fdn.getUID()); + EventBinding<TraceEventListener> binding = (EventBinding<TraceEventListener>) RContext.getInstance().stateInstrumentation.getTraceBinding(RInstrumentation.getSourceSection(func)); if (binding != null) { // only one binding.dispose(); @@ -63,17 +61,16 @@ public class TraceHandling { } public static void disableTrace(RFunction func) { - FunctionDefinitionNode fdn = (FunctionDefinitionNode) func.getRootNode(); @SuppressWarnings("unchecked") - EventBinding<TraceEventListener> binding = (EventBinding<TraceEventListener>) RContext.getInstance().stateTraceHandling.get(fdn.getUID()); + EventBinding<TraceEventListener> binding = (EventBinding<TraceEventListener>) RContext.getInstance().stateInstrumentation.getTraceBinding(RInstrumentation.getSourceSection(func)); if (binding != null) { binding.dispose(); - RContext.getInstance().stateTraceHandling.put(RInstrumentation.getFunctionDefinitionNode(func).getUID(), null); + RContext.getInstance().stateInstrumentation.putTraceBinding(RInstrumentation.getSourceSection(func), null); } } public static void setTracingState(boolean state) { - Object[] listeners = RContext.getInstance().stateTraceHandling.getListeners(); + EventBinding<?>[] listeners = RContext.getInstance().stateInstrumentation.getTraceBindings(); for (int i = 0; i < listeners.length; i++) { @SuppressWarnings("unchecked") EventBinding<TraceEventListener> binding = (EventBinding<TraceEventListener>) listeners[i]; @@ -97,9 +94,8 @@ public class TraceHandling { } public static boolean enableStatementTrace(RFunction func, RLanguage tracer, @SuppressWarnings("unused") Object exit, Object at, boolean print) { - FunctionDefinitionNode fdn = (FunctionDefinitionNode) func.getRootNode(); @SuppressWarnings("unchecked") - EventBinding<TraceEventListener> binding = (EventBinding<TraceEventListener>) RContext.getInstance().stateTraceHandling.get(fdn.getUID()); + EventBinding<TraceEventListener> binding = (EventBinding<TraceEventListener>) RContext.getInstance().stateInstrumentation.getTraceBinding(RInstrumentation.getSourceSection(func)); if (binding != null) { // only one allowed binding.dispose(); @@ -109,7 +105,7 @@ public class TraceHandling { TracerFunctionEntryEventListener listener = new TracerFunctionEntryEventListener(tracer, print); binding = RInstrumentation.getInstrumenter().attachListener(RInstrumentation.createFunctionStartFilter(func).build(), listener); setOutputHandler(); - RContext.getInstance().stateTraceHandling.put(RInstrumentation.getFunctionDefinitionNode(func).getUID(), binding); + RContext.getInstance().stateInstrumentation.putTraceBinding(RInstrumentation.getSourceSection(func), binding); } return false; } @@ -118,7 +114,7 @@ public class TraceHandling { PrimitiveFunctionEntryEventListener fser = new PrimitiveFunctionEntryEventListener(); EventBinding<TraceEventListener> binding = RInstrumentation.getInstrumenter().attachListener(RInstrumentation.createFunctionStartFilter(func).build(), fser); setOutputHandler(); - RContext.getInstance().stateTraceHandling.put(RInstrumentation.getFunctionDefinitionNode(func).getUID(), binding); + RContext.getInstance().stateInstrumentation.putTraceBinding(RInstrumentation.getSourceSection(func), binding); } private abstract static class TraceEventListener implements ExecutionEventListener { diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ALONGFunctionUIDFactory.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ALONGFunctionUIDFactory.java deleted file mode 100644 index f508505dfa5eb8ec196ebf574896c10b90ef6340..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ALONGFunctionUIDFactory.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2015, 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.nodes.function; - -import java.util.concurrent.atomic.AtomicLong; - -import com.oracle.truffle.r.runtime.FunctionUID; -import com.oracle.truffle.r.runtime.instrument.FunctionUIDFactory; - -public class ALONGFunctionUIDFactory extends FunctionUIDFactory { - - private static final AtomicLong ID = new AtomicLong(); - - private static final class ALongFunctionUID implements FunctionUID { - - private final long uuid; - - private ALongFunctionUID(long uuid) { - this.uuid = uuid; - } - - @Override - public int compareTo(FunctionUID o) { - ALongFunctionUID oa = (ALongFunctionUID) o; - if (uuid == oa.uuid) { - return 0; - } else if (uuid < oa.uuid) { - return -1; - } else { - return 1; - } - } - - @Override - public String toString() { - return Long.toString(uuid); - } - } - - @Override - public FunctionUID createUID() { - return new ALongFunctionUID(ID.incrementAndGet()); - } -} diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionDefinitionNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionDefinitionNode.java index 4433a0eae310957e59d41789a6ff8864618845ea..9e3d611808fd439720b539a5e27f79e9e7889082 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionDefinitionNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionDefinitionNode.java @@ -47,10 +47,8 @@ import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode; import com.oracle.truffle.r.nodes.builtin.RBuiltinFactory; import com.oracle.truffle.r.nodes.control.BreakException; import com.oracle.truffle.r.nodes.control.NextException; -import com.oracle.truffle.r.nodes.instrumentation.RInstrumentation; import com.oracle.truffle.r.runtime.ArgumentsSignature; import com.oracle.truffle.r.runtime.BrowserQuitException; -import com.oracle.truffle.r.runtime.FunctionUID; import com.oracle.truffle.r.runtime.RArguments; import com.oracle.truffle.r.runtime.RArguments.DispatchArgs; import com.oracle.truffle.r.runtime.RArguments.S3Args; @@ -63,21 +61,19 @@ import com.oracle.truffle.r.runtime.RSerialize; import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.ReturnException; import com.oracle.truffle.r.runtime.Utils.DebugExitException; -import com.oracle.truffle.r.runtime.WithFunctionUID; import com.oracle.truffle.r.runtime.context.RContext; import com.oracle.truffle.r.runtime.data.RBuiltinDescriptor; import com.oracle.truffle.r.runtime.data.RNull; import com.oracle.truffle.r.runtime.env.REnvironment; import com.oracle.truffle.r.runtime.env.frame.FrameSlotChangeMonitor; import com.oracle.truffle.r.runtime.env.frame.RFrameSlot; -import com.oracle.truffle.r.runtime.instrument.FunctionUIDFactory; import com.oracle.truffle.r.runtime.nodes.RCodeBuilder; import com.oracle.truffle.r.runtime.nodes.RNode; import com.oracle.truffle.r.runtime.nodes.RSyntaxElement; import com.oracle.truffle.r.runtime.nodes.RSyntaxFunction; import com.oracle.truffle.r.runtime.nodes.RSyntaxNode; -public final class FunctionDefinitionNode extends RRootNode implements RSyntaxNode, WithFunctionUID, RSyntaxFunction { +public final class FunctionDefinitionNode extends RRootNode implements RSyntaxNode, RSyntaxFunction { @Child private RNode body; // typed as RNode to avoid custom instrument wrapper /** @@ -92,7 +88,6 @@ public final class FunctionDefinitionNode extends RRootNode implements RSyntaxNo * loaded from packages, where at the point of definition any assignee variable is unknown. */ private String name; - private FunctionUID uuid; private boolean instrumented = false; private SourceSection sourceSectionR; private final SourceSection[] argSourceSections; @@ -133,11 +128,11 @@ public final class FunctionDefinitionNode extends RRootNode implements RSyntaxNo public static FunctionDefinitionNode create(SourceSection src, FrameDescriptor frameDesc, SourceSection[] argSourceSections, SaveArgumentsNode saveArguments, RSyntaxNode body, FormalArguments formals, String name, PostProcessArgumentsNode argPostProcess) { - return new FunctionDefinitionNode(src, frameDesc, argSourceSections, saveArguments, body, formals, name, argPostProcess, FunctionUIDFactory.get().createUID()); + return new FunctionDefinitionNode(src, frameDesc, argSourceSections, saveArguments, body, formals, name, argPostProcess); } private FunctionDefinitionNode(SourceSection src, FrameDescriptor frameDesc, SourceSection[] argSourceSections, RNode saveArguments, RSyntaxNode body, FormalArguments formals, - String name, PostProcessArgumentsNode argPostProcess, FunctionUID uuid) { + String name, PostProcessArgumentsNode argPostProcess) { super(null, formals, frameDesc, RASTBuilder.createFunctionFastPath(body, formals.getSignature())); this.argSourceSections = argSourceSections; assert FrameSlotChangeMonitor.isValidFrameDescriptor(frameDesc); @@ -147,11 +142,9 @@ public final class FunctionDefinitionNode extends RRootNode implements RSyntaxNo this.body = body.asRNode(); this.name = name; this.onExitSlot = FrameSlotNode.createInitialized(frameDesc, RFrameSlot.OnExit, false); - this.uuid = uuid; this.needsSplitting = needsAnyBuiltinSplitting(); this.containsDispatch = containsAnyDispatch(body); this.argPostProcess = argPostProcess; - RInstrumentation.registerFunctionDefinition(this); } @Override @@ -165,7 +158,6 @@ public final class FunctionDefinitionNode extends RRootNode implements RSyntaxNo args.add(RCodeBuilder.argument(source, getFormalArguments().getSignature().getName(i), value == null ? null : builder.process(value.asRSyntaxNode()))); } RootCallTarget callTarget = RContext.getASTBuilder().rootFunction(getSourceSection(), args, builder.process(getBody()), name); - ((FunctionDefinitionNode) callTarget.getRootNode()).uuid = uuid; return callTarget; } @@ -235,11 +227,6 @@ public final class FunctionDefinitionNode extends RRootNode implements RSyntaxNo return needsSplitting; } - @Override - public FunctionUID getUID() { - return uuid; - } - public RSyntaxNode getBody() { return body.asRSyntaxNode(); } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/UUIDFunctionUIDFactory.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/UUIDFunctionUIDFactory.java deleted file mode 100644 index 3d3a4163f8cb8fb63f8b708b50f4f2cd93d20b84..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/UUIDFunctionUIDFactory.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2014, 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.nodes.function; - -import java.util.UUID; - -import com.oracle.truffle.r.runtime.FunctionUID; -import com.oracle.truffle.r.runtime.instrument.FunctionUIDFactory; - -public class UUIDFunctionUIDFactory extends FunctionUIDFactory { - - private static final class UUIDFunctionUID implements FunctionUID { - - private final UUID uuid; - - private UUIDFunctionUID(UUID uuid) { - this.uuid = uuid; - } - - @Override - public int compareTo(FunctionUID o) { - return uuid.compareTo(((UUIDFunctionUID) o).uuid); - } - - @Override - public String toString() { - return uuid.toString(); - } - } - - @Override - public FunctionUID createUID() { - return new UUIDFunctionUID(UUID.randomUUID()); - } -} diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/instrumentation/REntryCounters.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/instrumentation/REntryCounters.java deleted file mode 100644 index 33343ce29eb227fb13acccd8deb64c2440d0f20c..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/instrumentation/REntryCounters.java +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Copyright (c) 2014, 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.nodes.instrumentation; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; - -import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.api.instrumentation.EventContext; -import com.oracle.truffle.api.instrumentation.ExecutionEventListener; -import com.oracle.truffle.api.instrumentation.SourceSectionFilter; -import com.oracle.truffle.api.instrumentation.StandardTags; -import com.oracle.truffle.api.source.SourceSection; -import com.oracle.truffle.r.nodes.function.FunctionDefinitionNode; -import com.oracle.truffle.r.nodes.instrumentation.RInstrumentation.FunctionIdentification; -import com.oracle.truffle.r.runtime.FunctionUID; -import com.oracle.truffle.r.runtime.RPerfStats; -import com.oracle.truffle.r.runtime.data.RFunction; - -/** - * Basic support for adding entry/exit counters to nodes. The {@link SourceSection} attribute is is - * used to retrieve the counter associated with a node. - * - */ -public class REntryCounters { - public static final class Counter { - private final Object ident; - private int enterCount; - private int exitCount; - - Counter(Object ident) { - this.ident = ident; - } - - public int getEnterCount() { - return enterCount; - } - - public int getExitCount() { - return exitCount; - } - - public Object getIdent() { - return ident; - } - } - - /** - * Listener that is independent of the kind of node and specific instance being counted. - */ - private abstract static class BasicListener implements ExecutionEventListener { - - private HashMap<SourceSection, Counter> counterMap = new HashMap<>(); - - private Counter getCounter(EventContext context) { - SourceSection ss = context.getInstrumentedSourceSection(); - Counter counter = counterMap.get(ss); - if (counter == null) { - Object obj = counterCreated(context); - counter = new Counter(obj); - counterMap.put(ss, counter); - } - return counter; - } - - protected Counter getCounter(SourceSection sourceSection) { - Counter counter = counterMap.get(sourceSection); - assert counter != null; - return counter; - } - - protected Map<SourceSection, Counter> getCounterMap() { - return counterMap; - } - - @Override - public void onEnter(EventContext context, VirtualFrame frame) { - getCounter(context).enterCount++; - } - - @Override - public void onReturnValue(EventContext context, VirtualFrame frame, Object result) { - getCounter(context).exitCount++; - } - - @Override - public void onReturnExceptional(EventContext context, VirtualFrame frame, Throwable exception) { - getCounter(context).exitCount++; - } - - protected abstract Object counterCreated(EventContext context); - } - - /** - * A counter that is specialized for function entry, tagged with the {@link FunctionUID}. - */ - public static class FunctionListener extends BasicListener { - private static final FunctionListener singleton = new FunctionListener(); - - static void installCounters() { - if (enabled()) { - SourceSectionFilter.Builder builder = SourceSectionFilter.newBuilder(); - builder.tagIs(StandardTags.RootTag.class); - SourceSectionFilter filter = builder.build(); - RInstrumentation.getInstrumenter().attachListener(filter, singleton); - } - } - - public static void installCounter(RFunction func) { - RInstrumentation.getInstrumenter().attachListener(RInstrumentation.createFunctionStartFilter(func).build(), singleton); - } - - public static Counter findCounter(RFunction func) { - FunctionDefinitionNode fdn = (FunctionDefinitionNode) func.getRootNode(); - return singleton.getCounter(fdn.getBody().getSourceSection()); - } - - @Override - protected FunctionUID counterCreated(EventContext context) { - FunctionDefinitionNode fdn = (FunctionDefinitionNode) context.getInstrumentedNode().getRootNode(); - return fdn.getUID(); - } - - static { - RPerfStats.register(new PerfHandler()); - } - - static boolean enabled() { - return RPerfStats.enabled(PerfHandler.NAME); - } - - private static class PerfHandler implements RPerfStats.Handler { - private static class FunctionCount implements Comparable<FunctionCount> { - int count; - String name; - - FunctionCount(int count, String name) { - this.count = count; - this.name = name; - } - - @Override - public int compareTo(FunctionCount o) { - if (count < o.count) { - return 1; - } else if (count > o.count) { - return -1; - } else { - return name.compareTo(o.name); - } - } - } - - static final String NAME = "functioncounts"; - - @Override - public void initialize(String optionText) { - } - - @Override - public String getName() { - return NAME; - } - - /** - * R's anonymous function definitions don't help with reporting. We make an attempt to - * locate a function name in the global/package environments. - */ - @Override - public void report() { - RPerfStats.out().println("R Function Entry Counts"); - ArrayList<FunctionCount> results = new ArrayList<>(); - for (Map.Entry<SourceSection, Counter> entry : FunctionListener.singleton.getCounterMap().entrySet()) { - Counter counter = entry.getValue(); - FunctionIdentification fdi = RInstrumentation.getFunctionIdentification((FunctionUID) counter.getIdent()); - int count = counter.getEnterCount(); - if (count > 0) { - results.add(new FunctionCount(count, fdi.name)); - } - } - FunctionCount[] sortedCounts = new FunctionCount[results.size()]; - results.toArray(sortedCounts); - Arrays.sort(sortedCounts); - for (FunctionCount functionCount : sortedCounts) { - RPerfStats.out().printf("%6d: %s%n", functionCount.count, functionCount.name); - } - } - } - } -} diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/instrumentation/RFunctionProfiler.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/instrumentation/RFunctionProfiler.java new file mode 100644 index 0000000000000000000000000000000000000000..7689451ea34d03a7b9860deb0c67742a3272badd --- /dev/null +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/instrumentation/RFunctionProfiler.java @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2014, 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.nodes.instrumentation; + +import java.util.Arrays; +import java.util.Map; + +import com.oracle.truffle.api.source.Source; +import com.oracle.truffle.api.source.SourceSection; +import com.oracle.truffle.api.vm.PolyglotEngine; +import com.oracle.truffle.r.runtime.RPerfStats; +import com.oracle.truffle.r.runtime.RSource; +import com.oracle.truffle.r.runtime.Utils; +import com.oracle.truffle.r.runtime.context.RContext; +import com.oracle.truffle.r.runtime.data.RFunction; +import com.oracle.truffle.tools.Profiler; +import com.oracle.truffle.tools.Profiler.Counter; +import com.oracle.truffle.tools.Profiler.Counter.TimeKind; + +/** + * Interface to the Truffle {@link Profiler}. + */ +public class RFunctionProfiler { + static { + RPerfStats.register(new PerfHandler()); + } + + static boolean enabled() { + return RPerfStats.enabled(PerfHandler.NAME); + } + + /** + * This is called on startup to support {@link RPerfStats}. + */ + static void installTimers(RContext context) { + if (enabled()) { + enableTiming(context, true, true); + } + } + + private static Profiler getProfiler(RContext context) { + PolyglotEngine vm = context.getVM(); + Profiler profiler = Profiler.find(vm); + return profiler; + } + + private static Profiler getProfiler() { + PolyglotEngine vm = RContext.getInstance().getVM(); + Profiler profiler = Profiler.find(vm); + return profiler; + } + + private static void enableTiming(RContext context, @SuppressWarnings("unused") boolean counting, boolean timing) { + Profiler profiler = getProfiler(context); + context.getInstrumentationState().setProfiler(profiler); + profiler.setTiming(timing); + profiler.setCollecting(true); + } + + /** + * (Interactively) installs a timer for a specific function. Currently the {@link Profiler} does + * not support profiling limited to specific functions so this effectively enables everything. + * If {@code func} is {@code null} profile all functions. In principle profiling can be + * restricted to entry counting and timing but currently counting is always on. + * + */ + public static void installTimer(@SuppressWarnings("unused") RFunction func, boolean counting, boolean timing) { + enableTiming(RContext.getInstance(), counting, timing); + } + + public static Counter getCounter(RFunction func) { + Profiler profiler = getProfiler(); + if (profiler.isCollecting()) { + String funcName = func.getTarget().getRootNode().getName(); + Map<SourceSection, Counter> counters = profiler.getCounters(); + for (Counter counter : counters.values()) { + if (counter.getName().equals(funcName)) { + return counter; + } + } + } + return null; + } + + public static void reset() { + Profiler profiler = getProfiler(); + profiler.clearData(); + profiler.setCollecting(false); + } + + public static void clear() { + Profiler profiler = getProfiler(); + profiler.clearData(); + } + + public static Counter[] getCounters() { + Profiler profiler = getProfiler(); + if (profiler.isCollecting()) { + Map<SourceSection, Counter> counters = profiler.getCounters(); + Counter[] result = new Counter[counters.size()]; + counters.values().toArray(result); + return result; + } else { + return null; + } + } + + public static boolean isTiming() { + Profiler profiler = getProfiler(); + return profiler.isTiming(); + } + + private static class PerfHandler implements RPerfStats.Handler { + static final String NAME = "timer"; + @SuppressWarnings("unused") private boolean stmts; + private int threshold; + + @Override + public void initialize(String optionText) { + if (optionText.length() > 0) { + String[] subOptions = optionText.split(":"); + for (String subOption : subOptions) { + if (subOption.equals("stmts")) { + Utils.warn("statement timing is not implemented"); + stmts = true; + } else if (subOption.startsWith("threshold")) { + threshold = Integer.parseInt(subOption.substring(subOption.indexOf('=') + 1)) * 1000; + } + } + } + } + + @Override + public String getName() { + return NAME; + } + + private static class SortableCounter implements Comparable<SortableCounter> { + private Counter counter; + + SortableCounter(Counter counter) { + this.counter = counter; + } + + @Override + public int compareTo(SortableCounter other) { + long myTime = counter.getSelfTime(TimeKind.INTERPRETED_AND_COMPILED); + long otherTime = other.counter.getSelfTime(TimeKind.INTERPRETED_AND_COMPILED); + return myTime < otherTime ? 1 : (myTime > otherTime ? -1 : 0); + } + + } + + /** + * Report the statement timing information at the end of the run. The report is per function + * Functions that consumed less time than requested threshold (default 0) are not included + * in the report. The report is sorted by cumulative time. + */ + @Override + public void report() { + Profiler profiler = RContext.getInstance().getInstrumentationState().getProfiler(); + // profiler.printHistograms(RPerfStats.out()); + Map<SourceSection, Counter> counters = profiler.getCounters(); + long totalTime = 0; + SortableCounter[] sortedCounters = new SortableCounter[counters.size()]; + int i = 0; + for (Counter counter : counters.values()) { + totalTime += counter.getSelfTime(TimeKind.INTERPRETED_AND_COMPILED); + sortedCounters[i++] = new SortableCounter(counter); + } + Arrays.sort(sortedCounters); + for (SortableCounter scounter : sortedCounters) { + long time = scounter.counter.getSelfTime(TimeKind.INTERPRETED_AND_COMPILED); + if (time > 0 && time > threshold) { + SourceSection ss = scounter.counter.getSourceSection(); + Source source = ss.getSource(); + RPerfStats.out().println("=========="); + double thisPercent = percent(time, totalTime); + RPerfStats.out().printf("%d ms (%.2f%%): %s, %s%n", time, thisPercent, scounter.counter.getName(), RSource.getOrigin(source)); + } + } + System.console(); + } + + private static double percent(long a, long b) { + return ((double) a * 100) / b; + } + + } +} diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/instrumentation/RInstrumentation.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/instrumentation/RInstrumentation.java index 5bc62fc2332bc6d699e4e6a7cefe1f854990346d..c51da1dd105e9f7cda7fddaa74322a28564fa41c 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/instrumentation/RInstrumentation.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/instrumentation/RInstrumentation.java @@ -22,142 +22,38 @@ */ package com.oracle.truffle.r.nodes.instrumentation; -import java.util.HashMap; -import java.util.Map; - import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.instrumentation.Instrumenter; import com.oracle.truffle.api.instrumentation.SourceSectionFilter; import com.oracle.truffle.api.instrumentation.StandardTags; -import com.oracle.truffle.api.nodes.RootNode; -import com.oracle.truffle.api.source.Source; import com.oracle.truffle.api.source.SourceSection; import com.oracle.truffle.r.nodes.function.FunctionDefinitionNode; import com.oracle.truffle.r.runtime.FastROptions; -import com.oracle.truffle.r.runtime.FunctionUID; -import com.oracle.truffle.r.runtime.RPerfStats; -import com.oracle.truffle.r.runtime.RSource; import com.oracle.truffle.r.runtime.context.RContext; import com.oracle.truffle.r.runtime.data.RFunction; -import com.oracle.truffle.r.runtime.data.RPromise; -import com.oracle.truffle.r.runtime.data.RStringVector; -import com.oracle.truffle.r.runtime.env.REnvironment; /** * Handles the initialization of the (NEW) instrumentation system which sets up various instruments - * depending on command line options. + * depending on command line options and provides utility methods for instrumentation-based tools. * */ public class RInstrumentation { - /** - * Collects together all the relevant data for a function, keyed by the {@link FunctionUID}, - * which is unique, for {@link RPerfStats} use. - */ - private static Map<FunctionUID, FunctionData> functionMap; - - /** - * Created lazily as needed. - */ - static class FunctionIdentification { - public final Source source; - public final String name; - public final String origin; - public final FunctionDefinitionNode node; - - FunctionIdentification(Source source, String name, String origin, FunctionDefinitionNode node) { - this.source = source; - this.name = name; - this.origin = origin; - this.node = node; - } - } - - /** - * Created for every {@link FunctionDefinitionNode}. maybe could be lazier. - */ - private static class FunctionData { - private final FunctionUID uid; - private final FunctionDefinitionNode fdn; - private FunctionIdentification ident; - - FunctionData(FunctionUID uid, FunctionDefinitionNode fdn) { - this.uid = uid; - this.fdn = fdn; - } - - private FunctionIdentification getIdentification() { - if (ident == null) { - SourceSection ss = fdn.getSourceSection(); - /* - * The default for "name" is the description associated with "fdn". If the function - * was parsed from text this will be the variable name the function value was - * assigned to, or the first 40 characters of the definition if anonymous. - */ - String idName = fdn.toString(); - Source idSource = null; - String idOrigin = null; - if (ss.getSource() != null) { - idSource = ss.getSource(); - String sourceName = idSource.getName(); - idOrigin = sourceName; - String packageName = RSource.getPackageName(idSource); - if (packageName != null) { - // try to find the name in the package environments - String functionName = findFunctionName(uid, packageName); - if (functionName != null) { - idName = functionName; - } - } else { - idOrigin = sourceName; - } - } else { - // One of the RSyntaxNode "unavailable"s. - idOrigin = idName; - idSource = RSource.fromTextInternal(idName, RSource.Internal.NO_SOURCE); - } - ident = new FunctionIdentification(idSource, idName, idOrigin, fdn); - } - return ident; - - } - } - /** * The function names that were requested to be used in implicit {@code debug(f)} calls, when * those functions are defined. Global to all contexts. */ @CompilationFinal private static String[] debugFunctionNames; - /** - * Called back from {@link FunctionDefinitionNode} so that we can record the {@link FunctionUID} - * and use {@code fdn} as the canonical {@link FunctionDefinitionNode}. - * - * @param fdn - */ - public static void registerFunctionDefinition(FunctionDefinitionNode fdn) { - // For PerfStats we need to record the info on fdn for the report - if (functionMap != null) { - FunctionUID uid = fdn.getUID(); - FunctionData fd = functionMap.get(uid); - if (fd != null) { - // duplicate - return; - } - assert fd == null; - functionMap.put(uid, new FunctionData(uid, fdn)); - } - } - - static FunctionIdentification getFunctionIdentification(FunctionUID uid) { - return functionMap.get(uid).getIdentification(); - } - public static FunctionDefinitionNode getFunctionDefinitionNode(RFunction func) { assert !func.isBuiltin(); return (FunctionDefinitionNode) func.getRootNode(); } + public static SourceSection getSourceSection(RFunction func) { + return getFunctionDefinitionNode(func).getSourceSection(); + } + /** * Create a filter that matches all the statement nodes in {@code func}. */ @@ -183,7 +79,6 @@ public class RInstrumentation { builder.sourceIs(fdns.getSource()); builder.rootSourceSectionEquals(fdns); return builder; - } /** @@ -201,15 +96,13 @@ public class RInstrumentation { * Activate the instrumentation system for {@code context}. Currently this simply checks for the * global (command-line) options for tracing and timing. They are applied to every context. */ - public static void activate(@SuppressWarnings("unused") RContext context) { + public static void activate(RContext context) { String rdebugValue = FastROptions.Rdebug.getStringValue(); if (rdebugValue != null) { debugFunctionNames = rdebugValue.split(","); } - if (REntryCounters.FunctionListener.enabled() || RNodeTimer.StatementListener.enabled()) { - functionMap = new HashMap<>(); - REntryCounters.FunctionListener.installCounters(); - RNodeTimer.StatementListener.installTimers(); + if (RFunctionProfiler.enabled()) { + RFunctionProfiler.installTimers(context); } // Check for function tracing RContext.getRRuntimeASTAccess().traceAllFunctions(); @@ -230,66 +123,4 @@ public class RInstrumentation { } } - private static Map<FunctionUID, String> functionNameMap; - - /** - * Attempts to locate a name for an (assumed) builtin or global function. Returns {@code null} - * if not found. - */ - private static String findFunctionName(FunctionUID uid, String packageName) { - if (functionNameMap == null) { - functionNameMap = new HashMap<>(); - } - String name = functionNameMap.get(uid); - if (name == null) { - name = findFunctionInPackage(uid, packageName); - } - return name; - } - - /** - * Try to find the function identified by uid in the given package. N.B. If we have the uid, the - * promise identifying the lazily loaded function must have been evaluated! So there is no need - * to evaluate any promises. N.B. For packages, we must use the namespace env as that contains - * public and private functions. - */ - private static String findFunctionInPackage(FunctionUID uid, String packageName) { - if (packageName == null) { - return findFunctionInEnv(uid, REnvironment.globalEnv()); - } - REnvironment env = REnvironment.lookupOnSearchPath(packageName); - env = env.getPackageNamespaceEnv(); - return findFunctionInEnv(uid, env); - } - - private static String findFunctionInEnv(FunctionUID uid, REnvironment env) { - // This is rather inefficient, but it doesn't matter - RStringVector names = env.ls(true, null, false); - for (int i = 0; i < names.getLength(); i++) { - String name = names.getDataAt(i); - Object val = env.get(name); - if (val instanceof RPromise) { - RPromise prVal = (RPromise) val; - if (prVal.isEvaluated()) { - val = prVal.getValue(); - } else { - continue; - } - } - if (val instanceof RFunction) { - RFunction func = (RFunction) val; - RootNode rootNode = func.getRootNode(); - if (rootNode instanceof FunctionDefinitionNode) { - FunctionDefinitionNode fdn = (FunctionDefinitionNode) rootNode; - if (fdn.getUID().equals(uid)) { - functionNameMap.put(fdn.getUID(), name); - return name; - } - } - } - } - // Most likely a nested function, which is ok - // because they are not lazy and so have names from the parser. - return null; - } } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/instrumentation/RNodeTimer.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/instrumentation/RNodeTimer.java deleted file mode 100644 index 84c3cb1927b446d10a3702acd33193a63d837293..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/instrumentation/RNodeTimer.java +++ /dev/null @@ -1,352 +0,0 @@ -/* - * Copyright (c) 2015, 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.nodes.instrumentation; - -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import java.util.TreeMap; - -import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.api.instrumentation.EventContext; -import com.oracle.truffle.api.instrumentation.ExecutionEventListener; -import com.oracle.truffle.api.instrumentation.SourceSectionFilter; -import com.oracle.truffle.api.instrumentation.StandardTags; -import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.api.source.SourceSection; -import com.oracle.truffle.r.nodes.control.BlockNode; -import com.oracle.truffle.r.nodes.function.FunctionDefinitionNode; -import com.oracle.truffle.r.nodes.instrumentation.RInstrumentation.FunctionIdentification; -import com.oracle.truffle.r.runtime.FunctionUID; -import com.oracle.truffle.r.runtime.RPerfStats; -import com.oracle.truffle.r.runtime.data.RFunction; -import com.oracle.truffle.r.runtime.nodes.RNode; -import com.oracle.truffle.r.runtime.nodes.RSyntaxNode; -import com.oracle.truffle.r.runtime.nodes.RSyntaxNodeVisitor; - -/** - * Basic support for adding as timer to a node. Currently limited to "statement" timing. - * - * The instrument records the cumulative time spent executing this node during the process execution - * using {@link System#nanoTime()}. - * - */ -public class RNodeTimer { - - public static final class TimeInfo { - private final Object ident; - protected long enterTime; - protected long cumulativeTime; - - TimeInfo(Object ident) { - this.ident = ident; - } - - public long getTime() { - return cumulativeTime; - } - - public Object getIdent() { - return ident; - } - } - - private abstract static class BasicListener implements ExecutionEventListener { - private HashMap<SourceSection, TimeInfo> timeInfoMap = new HashMap<>(); - - private TimeInfo getTimeInfo(EventContext context) { - SourceSection ss = context.getInstrumentedSourceSection(); - TimeInfo timeInfo = timeInfoMap.get(ss); - if (timeInfo == null) { - Object obj = timeInfoCreated(context); - timeInfo = new TimeInfo(obj); - timeInfoMap.put(ss, timeInfo); - } - return timeInfo; - } - - protected TimeInfo getTimeInfo(SourceSection sourceSection) { - TimeInfo timeInfo = timeInfoMap.get(sourceSection); - assert timeInfo != null; - return timeInfo; - } - - protected Map<SourceSection, TimeInfo> getTimeInfoMap() { - return timeInfoMap; - } - - @Override - public void onEnter(EventContext context, VirtualFrame frame) { - getTimeInfo(context).enterTime = System.nanoTime(); - } - - @Override - public void onReturnValue(EventContext context, VirtualFrame frame, Object result) { - TimeInfo timeInfo = getTimeInfo(context); - timeInfo.cumulativeTime += System.nanoTime() - timeInfo.enterTime; - } - - @Override - public void onReturnExceptional(EventContext context, VirtualFrame frame, Throwable exception) { - onReturnValue(context, frame, exception); - } - - protected abstract Object timeInfoCreated(EventContext context); - - } - - public static class StatementListener extends BasicListener { - private static final StatementListener singleton = new StatementListener(); - - public static long findTimer(RFunction func) { - FunctionDefinitionNode fdn = (FunctionDefinitionNode) func.getRootNode(); - FunctionUID uid = fdn.getUID(); - long cumTime = 0; - for (Map.Entry<SourceSection, TimeInfo> entry : StatementListener.singleton.getTimeInfoMap().entrySet()) { - TimeInfo timeInfo = entry.getValue(); - Node node = (Node) timeInfo.getIdent(); - FunctionDefinitionNode entryFdn = (FunctionDefinitionNode) node.getRootNode(); - FunctionUID entryUid = entryFdn.getUID(); - if (entryUid.equals(uid)) { - // statement in "func" - cumTime += timeInfo.cumulativeTime; - } - } - return cumTime; - } - - static void installTimers() { - if (enabled()) { - SourceSectionFilter.Builder builder = SourceSectionFilter.newBuilder(); - builder.tagIs(StandardTags.StatementTag.class); - SourceSectionFilter filter = builder.build(); - RInstrumentation.getInstrumenter().attachListener(filter, singleton); - } - } - - public static void installTimer(RFunction func) { - RInstrumentation.getInstrumenter().attachListener(RInstrumentation.createFunctionStatementFilter(func).build(), singleton); - } - - @Override - protected Node timeInfoCreated(EventContext context) { - return context.getInstrumentedNode(); - } - - // PerfStats support - - static { - RPerfStats.register(new PerfHandler()); - } - - static boolean enabled() { - return RPerfStats.enabled(PerfHandler.NAME); - } - - private static class TimingData implements Comparable<TimingData> { - long time; - FunctionUID functionUID; - - TimingData(FunctionUID functionUID) { - this.functionUID = functionUID; - } - - void addTime(long t) { - this.time += t; - } - - @Override - public int compareTo(TimingData o) { - if (time < o.time) { - return 1; - } else if (time > o.time) { - return -1; - } else { - return 0; - } - } - } - - private static class PerfHandler implements RPerfStats.Handler { - static final String NAME = "timing"; - private boolean stmts; - private int threshold; - - @Override - public void initialize(String optionText) { - if (optionText.length() > 0) { - String[] subOptions = optionText.split(":"); - for (String subOption : subOptions) { - if (subOption.equals("stmts")) { - stmts = true; - } else if (subOption.startsWith("threshold")) { - threshold = Integer.parseInt(subOption.substring(subOption.indexOf('=') + 1)) * 1000; - } - } - } - } - - @Override - public String getName() { - return NAME; - } - - /** - * Report the statement timing information at the end of the run. The report is per - * function {@link FunctionUID}, which uniquely defines a function in the face of call - * target splitting. Functions that consumed less time than requested threshold (default - * 0) are not included in the report. The report is sorted by cumulative time. - */ - @Override - public void report() { - Map<FunctionUID, TimingData> functionMap = new TreeMap<>(); - - for (Map.Entry<SourceSection, TimeInfo> entry : StatementListener.singleton.getTimeInfoMap().entrySet()) { - TimeInfo timeInfo = entry.getValue(); - Node node = (Node) timeInfo.getIdent(); - if (node.getRootNode() instanceof FunctionDefinitionNode) { - FunctionDefinitionNode fdn = (FunctionDefinitionNode) node.getRootNode(); - FunctionUID uid = fdn.getUID(); - TimingData timingData = functionMap.get(uid); - if (timingData == null) { - timingData = new TimingData(uid); - functionMap.put(uid, timingData); - } - timingData.addTime(millis(entry.getValue().cumulativeTime)); - } - } - - Collection<TimingData> values = functionMap.values(); - TimingData[] sortedData = new TimingData[values.size()]; - values.toArray(sortedData); - Arrays.sort(sortedData); - long totalTime = 0; - for (TimingData t : sortedData) { - totalTime += t.time; - } - - RPerfStats.out().printf("Total (user) time %d ms%n", totalTime); - for (TimingData t : sortedData) { - if (t.time > 0) { - if (t.time > threshold) { - FunctionIdentification fdi = RInstrumentation.getFunctionIdentification(t.functionUID); - RPerfStats.out().println("=========="); - RPerfStats.out().printf("%d ms (%.2f%%): %s, %s%n", t.time, percent(t.time, totalTime), fdi.name, fdi.origin); - if (stmts) { - SourceSection ss = fdi.node.getSourceSection(); - if (ss == null) { - // wrapper - ss = fdi.node.getBody().getSourceSection(); - if (ss == null) { - RPerfStats.out().println("no source available"); - } - } else { - long[] time = createLineTimes(fdi); - int startLine = ss.getStartLine(); - int lastLine = ss.getEndLine(); - for (int i = startLine; i <= lastLine; i++) { - RPerfStats.out().printf("%8dms: %s%n", time[i], fdi.source.getCode(i)); - } - - } - } - } - } - } - } - } - - private static double percent(long a, long b) { - return ((double) a * 100) / b; - } - - private abstract static class StatementVisitor implements RSyntaxNodeVisitor { - @SuppressWarnings("unused") protected final FunctionUID uid; - - StatementVisitor(FunctionUID uid) { - this.uid = uid; - } - - @Override - public boolean visit(RSyntaxNode node, int depth) { - if (node instanceof BlockNode) { - BlockNode sequenceNode = (BlockNode) node; - RNode[] block = sequenceNode.getSequence(); - for (int i = 0; i < block.length; i++) { - RSyntaxNode n = block[i].unwrap().asRSyntaxNode(); - if (!callback(n)) { - return false; - } - } - } - return true; - } - - protected abstract boolean callback(RSyntaxNode node); - - } - - private static class LineTimesNodeVisitor extends StatementVisitor { - private final long[] times; - - LineTimesNodeVisitor(FunctionUID uid, long[] time) { - super(uid); - this.times = time; - } - - @Override - protected boolean callback(RSyntaxNode node) { - SourceSection ss = node.getSourceSection(); - TimeInfo timeInfo = singleton.getTimeInfoMap().get(ss); - if (timeInfo != null) { - assert ss.getStartLine() != 0; - long stmtTime = millis(timeInfo.cumulativeTime); - times[0] += stmtTime; - times[ss.getStartLine()] += stmtTime; - } else { - /* - * This happens because default arguments are not visited during the AST probe - * walk. - */ - } - return true; - } - } - - private static long millis(long nanos) { - return nanos / 1000000; - } - - private static long[] createLineTimes(FunctionIdentification fdi) { - /* - * Although only those lines occupied by the function will actually have entries in the - * array, addressing is easier if we allocate an array that is as long as the entire - * source. Since there is never a line 0, we use that to compute the total. - */ - final long[] times = new long[fdi.source.getLineCount() + 1]; - RSyntaxNode.accept(fdi.node.getBody().asNode(), 0, new LineTimesNodeVisitor(fdi.node.getUID(), times), false); - return times; - } - } -} diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/FunctionUID.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/FunctionUID.java deleted file mode 100644 index 891850463405f5fc2871f9096fba8e106ca7d068..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/FunctionUID.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2014, 2015, 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; - -/** - * An abstract UID for a {@code FunctionDefinitionNode}, used by instrumentation code. There may be - * many clones of a {@code FunctionDefinitionNode}, but they all share the same UID. - */ -public interface FunctionUID extends Comparable<FunctionUID> { - -} diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/WithFunctionUID.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/WithFunctionUID.java deleted file mode 100644 index b4399e5d19bbc3055b63b0c7afd7e62e2ef296d5..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/WithFunctionUID.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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; - -public interface WithFunctionUID { - - FunctionUID getUID(); -} diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java index 3ba538ba94eb59c674b36efe0154bf3a92fad094..a616a7eddf1da34c0843fb6318d39cf6d4af7756 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java @@ -41,7 +41,6 @@ import com.oracle.truffle.api.interop.TruffleObject; import com.oracle.truffle.api.nodes.InvalidAssumptionException; import com.oracle.truffle.api.source.Source; import com.oracle.truffle.api.vm.PolyglotEngine; -import com.oracle.truffle.tools.Profiler; import com.oracle.truffle.r.runtime.FastROptions; import com.oracle.truffle.r.runtime.LazyDBCache; import com.oracle.truffle.r.runtime.PrimitiveMethodsInfo; @@ -72,7 +71,7 @@ import com.oracle.truffle.r.runtime.data.RList; import com.oracle.truffle.r.runtime.data.RStringVector; import com.oracle.truffle.r.runtime.env.REnvironment; import com.oracle.truffle.r.runtime.ffi.RFFIContextStateFactory; -import com.oracle.truffle.r.runtime.instrument.TraceState; +import com.oracle.truffle.r.runtime.instrument.InstrumentationState; import com.oracle.truffle.r.runtime.nodes.RCodeBuilder; import com.oracle.truffle.r.runtime.nodes.RSyntaxNode; import com.oracle.truffle.r.runtime.rng.RRNG; @@ -253,30 +252,6 @@ public final class RContext extends ExecutionContext implements TruffleObject { } } - /** - * Captures all state regarding instrumentation. - */ - public static class InstrumentationState { - private final Instrumenter instrumenter; - private Profiler profiler; - - InstrumentationState(Instrumenter instrumenter) { - this.instrumenter = instrumenter; - } - - public void setProfiler(Profiler profiler) { - this.profiler = profiler; - } - - public Profiler getProfiler() { - return profiler; - } - - public Instrumenter getInstrumenter() { - return instrumenter; - } - } - private final ContextInfo info; private final Engine engine; @@ -365,7 +340,6 @@ public final class RContext extends ExecutionContext implements TruffleObject { @CompilationFinal private static RContext singleContext; private final Env env; - private final InstrumentationState instrumentationState; private final HashMap<String, TruffleObject> exportedSymbols = new HashMap<>(); private final boolean initial; /** @@ -389,13 +363,12 @@ public final class RContext extends ExecutionContext implements TruffleObject { public final ContextState stateRFFI; public final RSerialize.ContextStateImpl stateRSerialize; public final LazyDBCache.ContextStateImpl stateLazyDBCache; - public final TraceState.ContextStateImpl stateTraceHandling; + public final InstrumentationState stateInstrumentation; public final ContextStateImpl stateInternalCode; - public final RprofState stateRprof; private ContextState[] contextStates() { return new ContextState[]{stateREnvVars, stateRProfile, stateROptions, stateREnvironment, stateRErrorHandling, stateRConnection, stateStdConnections, stateRNG, stateRFFI, stateRSerialize, - stateLazyDBCache, stateTraceHandling, stateRprof}; + stateLazyDBCache, stateInstrumentation}; } private RContext(Env env, Instrumenter instrumenter, boolean isInitial) { @@ -422,7 +395,6 @@ public final class RContext extends ExecutionContext implements TruffleObject { } this.env = env; - this.instrumentationState = new InstrumentationState(instrumenter); if (info.getConsoleHandler() == null) { throw Utils.fail("no console handler set"); } @@ -460,9 +432,8 @@ public final class RContext extends ExecutionContext implements TruffleObject { stateRFFI = RFFIContextStateFactory.newContext(this); stateRSerialize = RSerialize.ContextStateImpl.newContext(this); stateLazyDBCache = LazyDBCache.ContextStateImpl.newContext(this); - stateTraceHandling = TraceState.newContext(this); + stateInstrumentation = InstrumentationState.newContext(this, instrumenter); stateInternalCode = ContextStateImpl.newContext(this); - stateRprof = RprofState.newContext(this); engine.activate(stateREnvironment); if (info.getKind() == ContextKind.SHARE_PARENT_RW) { @@ -517,7 +488,7 @@ public final class RContext extends ExecutionContext implements TruffleObject { } public InstrumentationState getInstrumentationState() { - return instrumentationState; + return stateInstrumentation; } public ContextKind getKind() { diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RprofState.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RprofState.java deleted file mode 100644 index 9124e8f4d054e8bea9ed52ee91c5cd9e2981eb1c..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RprofState.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2016, 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.context; - -import java.io.PrintWriter; - -import com.oracle.truffle.api.instrumentation.ExecutionEventListener; - -public class RprofState implements RContext.ContextState { - 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; - this.profileThread = profileThreadA; - this.statementListener = statementListenerA; - this.intervalInMillis = intervalInMillisA; - this.lineProfiling = lineProfilingA; - } - - public boolean lineProfiling() { - return lineProfiling; - } - - public PrintWriter out() { - return out; - } - - public long intervalInMillis() { - return intervalInMillis; - } - - public ExecutionEventListener statementListener() { - return statementListener; - } - - public Thread profileThread() { - return profileThread; - } - -} diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/instrument/FunctionUIDFactory.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/instrument/FunctionUIDFactory.java deleted file mode 100644 index c0c02637a774dc0db47a9fe08c0b00bcdd7ecdef..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/instrument/FunctionUIDFactory.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2014, 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.instrument; - -import com.oracle.truffle.r.runtime.FunctionUID; -import com.oracle.truffle.r.runtime.Utils; - -public abstract class FunctionUIDFactory { - private static final String FACTORY_CLASS_PROPERTY = "fastr.fuid.factory.class"; - private static final String PACKAGE_PREFIX = "com.oracle.truffle.r.nodes.function."; - private static final String SUFFIX = "FunctionUIDFactory"; - private static final String DEFAULT_FACTORY = "along"; - private static final String DEFAULT_FACTORY_CLASS = mapSimpleName(DEFAULT_FACTORY); - - private static String mapSimpleName(String simpleName) { - return PACKAGE_PREFIX + simpleName.toUpperCase() + SUFFIX; - } - - private static FunctionUIDFactory instance; - - static { - String prop = System.getProperty(FACTORY_CLASS_PROPERTY); - if (prop != null) { - if (!prop.contains(".")) { - // simple name - prop = mapSimpleName(prop); - } - } else { - prop = DEFAULT_FACTORY_CLASS; - } - try { - instance = (FunctionUIDFactory) Class.forName(prop).newInstance(); - } catch (Exception ex) { - Utils.fail("Failed to instantiate class: " + prop + ": " + ex); - } - } - - public static FunctionUIDFactory get() { - return instance; - } - - public abstract FunctionUID createUID(); -} 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 new file mode 100644 index 0000000000000000000000000000000000000000..8ffa8a307cc34835a1cbf2c5719e38131bbbc0e3 --- /dev/null +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/instrument/InstrumentationState.java @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2013, 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.instrument; + +import java.io.PrintWriter; +import java.util.WeakHashMap; + +import com.oracle.truffle.api.instrumentation.EventBinding; +import com.oracle.truffle.api.instrumentation.ExecutionEventListener; +import com.oracle.truffle.api.instrumentation.Instrumenter; +import com.oracle.truffle.api.source.SourceSection; +import com.oracle.truffle.r.runtime.context.RContext; +import com.oracle.truffle.tools.Profiler; + +/** + * The tracingState is a global variable in R, so we store it (and the associated listener objects) + * in the {@link RContext}. We also store related {@code debug} state, as that is also context + * specific. + * + */ +public class InstrumentationState implements RContext.ContextState { + + /** + * Records all functions that have trace listeners installed. + */ + private final WeakHashMap<SourceSection, EventBinding<?>> traceBindingMap = new WeakHashMap<>(); + + private boolean tracingState = true; + + /** + * Records all functions that have debug listeners installed. + */ + private final WeakHashMap<SourceSection, ExecutionEventListener> debugListenerMap = new WeakHashMap<>(); + + private final Instrumenter instrumenter; + + private Profiler profiler; + + private final RprofState rprofState; + + /** + * State used by {@code Rprof}. + * + */ + public static 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; + this.profileThread = profileThreadA; + this.statementListener = statementListenerA; + this.intervalInMillis = intervalInMillisA; + this.lineProfiling = lineProfilingA; + } + + public boolean lineProfiling() { + return lineProfiling; + } + + public PrintWriter out() { + return out; + } + + public long intervalInMillis() { + return intervalInMillis; + } + + public ExecutionEventListener statementListener() { + return statementListener; + } + + public Thread profileThread() { + return profileThread; + } + + } + + private InstrumentationState(Instrumenter instrumenter) { + this.instrumenter = instrumenter; + this.rprofState = new RprofState(); + } + + public void putTraceBinding(SourceSection ss, EventBinding<?> binding) { + traceBindingMap.put(ss, binding); + } + + public EventBinding<?> getTraceBinding(SourceSection ss) { + return traceBindingMap.get(ss); + } + + public void putDebugListener(SourceSection ss, ExecutionEventListener listener) { + debugListenerMap.put(ss, listener); + } + + public EventBinding<?>[] getTraceBindings() { + EventBinding<?>[] result = new EventBinding<?>[traceBindingMap.size()]; + traceBindingMap.values().toArray(result); + return result; + + } + + public ExecutionEventListener getDebugListener(SourceSection ss) { + return debugListenerMap.get(ss); + } + + public boolean setTracingState(boolean state) { + boolean prev = tracingState; + tracingState = state; + return prev; + } + + public boolean getTracingState() { + return tracingState; + } + + public void setProfiler(Profiler profiler) { + this.profiler = profiler; + } + + public Profiler getProfiler() { + return profiler; + } + + public Instrumenter getInstrumenter() { + return instrumenter; + } + + public RprofState getRprof() { + return rprofState; + } + + public static InstrumentationState newContext(@SuppressWarnings("unused") RContext context, Instrumenter instrumenter) { + return new InstrumentationState(instrumenter); + } +} diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/instrument/TraceState.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/instrument/TraceState.java deleted file mode 100644 index 4bbf3d547340fd38c04948b4f776cc6fdd9a626e..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/instrument/TraceState.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2013, 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.instrument; - -import java.util.WeakHashMap; - -import com.oracle.truffle.r.runtime.FunctionUID; -import com.oracle.truffle.r.runtime.context.RContext; - -/** - * The tracingState is a global variable in R, so we store it (and the associated listener objects) - * in the {@link RContext}. To finesse the temporary existence of two instrumentation frameworks the - * receiver is typed as {@link Object}. - * - */ -public class TraceState { - public static class ContextStateImpl implements RContext.ContextState { - - /** - * Records all functions that have trace listeners installed. - */ - private final WeakHashMap<FunctionUID, Object> listenerMap = new WeakHashMap<>(); - private boolean tracingState = true; - - public void put(FunctionUID functionUID, Object listener) { - listenerMap.put(functionUID, listener); - } - - public Object get(FunctionUID functionUID) { - return listenerMap.get(functionUID); - } - - public boolean setTracingState(boolean state) { - boolean prev = tracingState; - tracingState = state; - return prev; - } - - public boolean getTracingState() { - return tracingState; - } - - public Object[] getListeners() { - Object[] result = new Object[listenerMap.size()]; - listenerMap.values().toArray(result); - return result; - } - } - - public static ContextStateImpl newContext(@SuppressWarnings("unused") RContext context) { - return new ContextStateImpl(); - } -}