diff --git a/docs/language-server/protocol-language-server.md b/docs/language-server/protocol-language-server.md index eab6aa926dca..3b80db029557 100644 --- a/docs/language-server/protocol-language-server.md +++ b/docs/language-server/protocol-language-server.md @@ -24,6 +24,7 @@ transport formats, please look [here](./protocol-architecture). - [`StackItem`](#stackitem) - [`MethodPointer`](#methodpointer) - [`ExpressionValueUpdate`](#expressionvalueupdate) + - [`ProfilingInfo`](#profilinginfo) - [`VisualisationConfiguration`](#visualisationconfiguration) - [`SuggestionEntryArgument`](#suggestionentryargument) - [`SuggestionEntry`](#suggestionentry) @@ -65,8 +66,8 @@ transport formats, please look [here](./protocol-architecture). - [`executionContext/canModify`](#executioncontextcanmodify) - [`executionContext/receivesUpdates`](#executioncontextreceivesupdates) - [`search/receivesSuggestionsDatabaseUpdates`](#searchreceivessuggestionsdatabaseupdates) - - [Enables](#enables-4) - - [Disables](#disables-4) + - [Enables](#enables) + - [Disables](#disables) - [File Management Operations](#file-management-operations) - [`file/write`](#filewrite) - [`file/read`](#fileread) @@ -125,21 +126,21 @@ transport formats, please look [here](./protocol-architecture). - [`search/suggestionsDatabaseUpdate`](#searchsuggestionsdatabaseupdate) - [`search/completion`](#searchcompletion) - [`search/import`](#searchimport) -- [Input/Output Operations](#input-output-operations) - - [`io/redirectStandardOutput`](#ioredirectstdardoutput) - - [`io/suppressStandardOutput`](#iosuppressstdardoutput) +- [Input/Output Operations](#inputoutput-operations) + - [`io/redirectStandardOutput`](#ioredirectstandardoutput) + - [`io/suppressStandardOutput`](#iosuppressstandardoutput) - [`io/standardOutputAppended`](#iostandardoutputappended) - [`io/redirectStandardError`](#ioredirectstandarderror) - [`io/suppressStandardError`](#iosuppressstandarderror) - [`io/standardErrorAppended`](#iostandarderrorappended) - [`io/feedStandardInput`](#iofeedstandardinput) - [`io/waitingForStandardInput`](#iowaitingforstandardinput) -- [Errors](#errors-57) +- [Errors](#errors) - [`AccessDeniedError`](#accessdeniederror) - [`FileSystemError`](#filesystemerror) - [`ContentRootNotFoundError`](#contentrootnotfounderror) - [`FileNotFound`](#filenotfound) - - [`FileExists`](#fileexists) + - [`FileExists`](#fileexists-1) - [`OperationTimeoutError`](#operationtimeouterror) - [`NotDirectory`](#notdirectory) - [`StackItemNotFoundError`](#stackitemnotfounderror) @@ -160,6 +161,7 @@ transport formats, please look [here](./protocol-architecture). - [`SuggestionsDatabaseError`](#suggestionsdatabaseerror) - [`ProjectNotFoundError`](#projectnotfounderror) - [`ModuleNameNotResolvedError`](#modulenamenotresolvederror) + - [`SuggestionNotFoundError`](#suggestionnotfounderror) @@ -229,6 +231,8 @@ interface MethodPointer { ### `ExpressionValueUpdate` +Metadata on an updated expression. + ```typescript interface ExpressionValueUpdate { /** The id of updated expression */ @@ -239,6 +243,33 @@ interface ExpressionValueUpdate { /** The updated pointer to the method call */ methodPointer?: SuggestionId; + + /** Profiling information for the expression */ + profilingInfo: ProfilingInfo[]; + + /** Whether the expression value came from the cache or not */ + fromCache: bool; +} +``` + +Currently, the `profilingInfo` array is guaranteed to contain at least the +`ExecutionTime` information. + +### `ProfilingInfo` + +Profiling information on an executed expression. It is implemented as a union as +additional types of information will be added in the future. + +```typescript +type ProfilingInfo = ExecutionTime; +``` + +Where: + +```typescript +interface ExecutionTime { + /** The time elapsed during the expression's evaluation, in nanoseconds */ + nanoTime: Number; } ``` diff --git a/engine/language-server/src/main/scala/org/enso/languageserver/runtime/ContextEventsListener.scala b/engine/language-server/src/main/scala/org/enso/languageserver/runtime/ContextEventsListener.scala index 48c407fee87d..ecafc1e14379 100644 --- a/engine/language-server/src/main/scala/org/enso/languageserver/runtime/ContextEventsListener.scala +++ b/engine/language-server/src/main/scala/org/enso/languageserver/runtime/ContextEventsListener.scala @@ -137,7 +137,12 @@ final class ContextEventsListener( log.error(s"Unable to find suggestion for $pointer") None } - } + }, + update.profilingInfo.map { + case Api.ProfilingInfo.ExecutionTime(t) => + ProfilingInfo.ExecutionTime(t) + }, + update.fromCache ) } val payload = diff --git a/engine/language-server/src/main/scala/org/enso/languageserver/runtime/ExpressionValueUpdate.scala b/engine/language-server/src/main/scala/org/enso/languageserver/runtime/ExpressionValueUpdate.scala index 334673c5768d..41180a66f424 100644 --- a/engine/language-server/src/main/scala/org/enso/languageserver/runtime/ExpressionValueUpdate.scala +++ b/engine/language-server/src/main/scala/org/enso/languageserver/runtime/ExpressionValueUpdate.scala @@ -7,9 +7,13 @@ import org.enso.languageserver.runtime.ExecutionApi.ExpressionId * @param expressionId the id of updated expression * @param `type` the updated type of expression * @param methodPointer the suggestion id of the updated method pointer + * @param profilingInfo profiling information about the expression + * @param fromCache whether or not the expression's value came from the cache */ case class ExpressionValueUpdate( expressionId: ExpressionId, `type`: Option[String], - methodPointer: Option[Long] + methodPointer: Option[Long], + profilingInfo: Vector[ProfilingInfo], + fromCache: Boolean ) diff --git a/engine/language-server/src/main/scala/org/enso/languageserver/runtime/ProfilingInfo.scala b/engine/language-server/src/main/scala/org/enso/languageserver/runtime/ProfilingInfo.scala new file mode 100644 index 000000000000..0685ced8e861 --- /dev/null +++ b/engine/language-server/src/main/scala/org/enso/languageserver/runtime/ProfilingInfo.scala @@ -0,0 +1,15 @@ +package org.enso.languageserver.runtime + +/** A trait to unify various types of profiling information about an executed + * expression. + */ +sealed trait ProfilingInfo +object ProfilingInfo { + + /** The time spent executing the expression. + * + * @param nanoTime the time elapsed while executing the expression in + * nanoseconds + */ + case class ExecutionTime(nanoTime: Long) extends ProfilingInfo +} diff --git a/engine/language-server/src/test/scala/org/enso/languageserver/runtime/ContextEventsListenerSpec.scala b/engine/language-server/src/test/scala/org/enso/languageserver/runtime/ContextEventsListenerSpec.scala index 9bbce0c21458..f768ce6e9f6c 100644 --- a/engine/language-server/src/test/scala/org/enso/languageserver/runtime/ContextEventsListenerSpec.scala +++ b/engine/language-server/src/test/scala/org/enso/languageserver/runtime/ContextEventsListenerSpec.scala @@ -90,9 +90,11 @@ class ContextEventsListenerSpec Api.MethodPointer( Suggestions.method.module, Suggestions.method.selfType, - Suggestions.method.name + Suggestions.method.name, ) - ) + ), + Vector(), + false ) ) ) @@ -106,7 +108,9 @@ class ContextEventsListenerSpec ExpressionValueUpdate( Suggestions.method.externalId.get, Some(Suggestions.method.returnType), - Some(suggestionIds(1).get) + Some(suggestionIds(1).get), + Vector(), + false ) ) ) @@ -134,7 +138,9 @@ class ContextEventsListenerSpec Api.ExpressionValueUpdate( Suggestions.method.externalId.get, None, - None + None, + Vector(), + false ) ) ) @@ -145,7 +151,9 @@ class ContextEventsListenerSpec Api.ExpressionValueUpdate( Suggestions.local.externalId.get, None, - None + None, + Vector(), + false ) ) ) @@ -161,12 +169,16 @@ class ContextEventsListenerSpec ExpressionValueUpdate( Suggestions.method.externalId.get, None, - None + None, + Vector(), + false ), ExpressionValueUpdate( Suggestions.local.externalId.get, None, - None + None, + Vector(), + false ) ) ) diff --git a/engine/polyglot-api/src/main/scala/org/enso/polyglot/runtime/Runtime.scala b/engine/polyglot-api/src/main/scala/org/enso/polyglot/runtime/Runtime.scala index e68163f36932..bef4d81380ef 100644 --- a/engine/polyglot-api/src/main/scala/org/enso/polyglot/runtime/Runtime.scala +++ b/engine/polyglot-api/src/main/scala/org/enso/polyglot/runtime/Runtime.scala @@ -3,7 +3,6 @@ package org.enso.polyglot.runtime import java.io.File import java.nio.ByteBuffer import java.util.UUID - import com.fasterxml.jackson.annotation.{JsonSubTypes, JsonTypeInfo} import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.dataformat.cbor.CBORFactory @@ -192,6 +191,7 @@ object Runtime { ) ) sealed trait Api + sealed trait ApiEnvelope extends Api sealed trait ApiRequest extends Api sealed trait ApiResponse extends Api sealed trait ApiNotification extends ApiResponse @@ -231,7 +231,6 @@ object Runtime { ) ) sealed trait StackItem - object StackItem { /** A call performed at the top of the stack, to initialize the context. @@ -252,13 +251,41 @@ object Runtime { * @param expressionId expression id. * @param expressionType the type of expression. * @param methodCall the pointer to a method definition. + * @param profilingInfo profiling information about the execution of this + * expression + * @param fromCache whether or not the value for this expression came from + * the cache */ case class ExpressionValueUpdate( expressionId: ExpressionId, expressionType: Option[String], - methodCall: Option[MethodPointer] + methodCall: Option[MethodPointer], + profilingInfo: Vector[ProfilingInfo], + fromCache: Boolean ) + /** An object representing profiling information about an executed + * expression. + */ + @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type") + @JsonSubTypes( + Array( + new JsonSubTypes.Type( + value = classOf[ProfilingInfo.ExecutionTime], + name = "executionTime" + ) + ) + ) + sealed trait ProfilingInfo + object ProfilingInfo { + + /** A representation of the time elapsed during execution. + * + * @param nanoTime the time elapsed during execution in nanoseconds + */ + case class ExecutionTime(nanoTime: Long) extends ProfilingInfo + } + /** An object representing invalidated expressions selector. */ @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type") @@ -275,7 +302,6 @@ object Runtime { ) ) sealed trait InvalidatedExpressions - object InvalidatedExpressions { /** An object representing invalidation of all expressions. @@ -468,7 +494,6 @@ object Runtime { ) sealed trait DiagnosticType object DiagnosticType { - case class Error() extends DiagnosticType case class Warning() extends DiagnosticType } @@ -638,6 +663,7 @@ object Runtime { * @param payload the request payload. */ case class Request(requestId: Option[RequestId], payload: ApiRequest) + extends ApiEnvelope object Request { @@ -665,6 +691,7 @@ object Runtime { * @param payload response */ case class Response(correlationId: Option[RequestId], payload: ApiResponse) + extends ApiEnvelope object Response { diff --git a/engine/runtime/src/main/java/org/enso/interpreter/Language.java b/engine/runtime/src/main/java/org/enso/interpreter/Language.java index da7cdb5de41f..f561e848e56f 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/Language.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/Language.java @@ -45,6 +45,8 @@ IdentifiedTag.class }) public final class Language extends TruffleLanguage { + private IdExecutionInstrument idExecutionInstrument; + /** * Creates a new Enso context. * @@ -58,9 +60,8 @@ protected Context createContext(Env env) { Context context = new Context(this, getLanguageHome(), env); InstrumentInfo idValueListenerInstrument = env.getInstruments().get(IdExecutionInstrument.INSTRUMENT_ID); - IdExecutionInstrument idExecutionInstrumentService = - env.lookup(idValueListenerInstrument, IdExecutionInstrument.class); - env.registerService(new ExecutionService(context, idExecutionInstrumentService)); + idExecutionInstrument = env.lookup(idValueListenerInstrument, IdExecutionInstrument.class); + env.registerService(new ExecutionService(context, idExecutionInstrument)); return context; } @@ -114,4 +115,9 @@ protected OptionDescriptors getOptionDescriptors() { protected Iterable findTopScopes(Context context) { return Collections.singleton(context.getTopScope().getScope()); } + + /** @return a reference to the execution instrument */ + public IdExecutionInstrument getIdExecutionInstrument() { + return idExecutionInstrument; + } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/instrument/IdExecutionInstrument.java b/engine/runtime/src/main/java/org/enso/interpreter/instrument/IdExecutionInstrument.java index beffac1bd272..971f4382535d 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/instrument/IdExecutionInstrument.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/instrument/IdExecutionInstrument.java @@ -10,6 +10,10 @@ import com.oracle.truffle.api.interop.InteropLibrary; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.RootNode; +import java.util.Arrays; +import org.enso.interpreter.instrument.execution.Timer; +import org.enso.interpreter.instrument.profiling.ExecutionTime; +import org.enso.interpreter.instrument.profiling.ProfilingInfo; import org.enso.interpreter.node.EnsoRootNode; import org.enso.interpreter.node.ExpressionNode; import org.enso.interpreter.node.MethodRootNode; @@ -32,6 +36,7 @@ public class IdExecutionInstrument extends TruffleInstrument { public static final String INSTRUMENT_ID = "id-value-extractor"; + private Timer timer; private Env env; /** @@ -42,9 +47,18 @@ public class IdExecutionInstrument extends TruffleInstrument { @Override protected void onCreate(Env env) { env.registerService(this); + this.timer = new Timer.Nanosecond(); this.env = env; } + /** Override the default nanosecond timer with the specified {@code timer}. + * + * @param timer the timer to override with + */ + public void overrideTimer(Timer timer) { + this.timer = timer; + } + /** A class for notifications about functions being called in the course of execution. */ public static class ExpressionCall { private final UUID expressionId; @@ -80,6 +94,8 @@ public static class ExpressionValue { private final String cachedType; private final FunctionCallInfo callInfo; private final FunctionCallInfo cachedCallInfo; + private final ProfilingInfo[] profilingInfo; + private final boolean wasCached; /** * Creates a new instance of this class. @@ -89,6 +105,9 @@ public static class ExpressionValue { * @param type the type of the returned value. * @param cachedType the cached type of the value. * @param callInfo the function call data. + * @param cachedCallInfo the cached call data. + * @param profilingInfo the profiling information associated with this node + * @param wasCached whether or not the value was obtained from the cache */ public ExpressionValue( UUID expressionId, @@ -96,17 +115,22 @@ public ExpressionValue( String type, String cachedType, FunctionCallInfo callInfo, - FunctionCallInfo cachedCallInfo) { + FunctionCallInfo cachedCallInfo, + ProfilingInfo[] profilingInfo, + boolean wasCached) { this.expressionId = expressionId; this.value = value; this.type = type; this.cachedType = cachedType; this.callInfo = callInfo; this.cachedCallInfo = cachedCallInfo; + this.profilingInfo = profilingInfo; + this.wasCached = wasCached; } @Override public String toString() { + String profilingInfo = Arrays.toString(this.profilingInfo); return "ExpressionValue{" + "expressionId=" + expressionId @@ -122,6 +146,10 @@ public String toString() { + callInfo + ", cachedCallInfo=" + cachedCallInfo + + ", profilingInfo=" + + profilingInfo + + ", wasCached=" + + wasCached + '}'; } @@ -154,6 +182,16 @@ public FunctionCallInfo getCallInfo() { public FunctionCallInfo getCachedCallInfo() { return cachedCallInfo; } + + /** @return the profiling information associated with this expression */ + public ProfilingInfo[] getProfilingInfo() { + return profilingInfo; + } + + /** @return whether or not the expression result was obtained from the cache */ + public boolean wasCached() { + return wasCached; + } } /** Information about the function call. */ @@ -237,6 +275,8 @@ private static class IdExecutionEventListener implements ExecutionEventListener private final MethodCallsCache callsCache; private final UUID nextExecutionItem; private final Map calls = new HashMap<>(); + private final Timer timer; + private long nanoTimeElapsed = 0; /** * Creates a new listener. @@ -249,16 +289,18 @@ private static class IdExecutionEventListener implements ExecutionEventListener * @param onComputedCallback the consumer of the computed value events. * @param onCachedCallback the consumer of the cached value events. * @param onExceptionalCallback the consumer of the exceptional events. + * @param timer the timer for timing execution */ public IdExecutionEventListener( CallTarget entryCallTarget, RuntimeCache cache, MethodCallsCache methodCallsCache, - UUID nextExecutionItem, + UUID nextExecutionItem, // The expression ID Consumer functionCallCallback, Consumer onComputedCallback, Consumer onCachedCallback, - Consumer onExceptionalCallback) { + Consumer onExceptionalCallback, + Timer timer) { this.entryCallTarget = entryCallTarget; this.cache = cache; this.callsCache = methodCallsCache; @@ -267,6 +309,7 @@ public IdExecutionEventListener( this.onComputedCallback = onComputedCallback; this.onCachedCallback = onCachedCallback; this.onExceptionalCallback = onExceptionalCallback; + this.timer = timer; } @Override @@ -289,6 +332,9 @@ public void onEnter(EventContext context, VirtualFrame frame) { nodeId = ((FunctionCallInstrumentationNode) node).getId(); } + // Add a flag to say it was cached. + // An array of `ProfilingInfo` in the value update. + Object result = cache.get(nodeId); // When executing the call stack we need to capture the FunctionCall of the next (top) stack // item in the `functionCallCallback`. We allow to execute the cached `stackTop` value to be @@ -301,9 +347,13 @@ public void onEnter(EventContext context, VirtualFrame frame) { cache.getType(nodeId), Types.getName(result), calls.get(nodeId), - cache.getCall(nodeId))); + cache.getCall(nodeId), + new ProfilingInfo[] {ExecutionTime.empty()}, + true)); throw context.createUnwind(result); } + + nanoTimeElapsed = timer.getTime(); } /** @@ -316,6 +366,7 @@ public void onEnter(EventContext context, VirtualFrame frame) { */ @Override public void onReturnValue(EventContext context, VirtualFrame frame, Object result) { + nanoTimeElapsed = timer.getTime() - nanoTimeElapsed; if (!isTopFrame(entryCallTarget)) { return; } @@ -341,8 +392,10 @@ public void onReturnValue(EventContext context, VirtualFrame frame, Object resul String cachedType = cache.putType(nodeId, resultType); FunctionCallInfo call = calls.get(nodeId); FunctionCallInfo cachedCall = cache.putCall(nodeId, call); + var profilingInfo = new ProfilingInfo[] {new ExecutionTime(nanoTimeElapsed)}; onComputedCallback.accept( - new ExpressionValue(nodeId, result, resultType, cachedType, call, cachedCall)); + new ExpressionValue( + nodeId, result, resultType, cachedType, call, cachedCall, profilingInfo, false)); } } @@ -439,6 +492,7 @@ public EventBinding bind( functionCallCallback, onComputedCallback, onCachedCallback, - onExceptionalCallback)); + onExceptionalCallback, + timer)); } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/instrument/profiling/ExecutionTime.java b/engine/runtime/src/main/java/org/enso/interpreter/instrument/profiling/ExecutionTime.java new file mode 100644 index 000000000000..15cd71a1b475 --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/instrument/profiling/ExecutionTime.java @@ -0,0 +1,25 @@ +package org.enso.interpreter.instrument.profiling; + +/** Information on the execution time of an introspected expression. */ +public class ExecutionTime implements ProfilingInfo { + private final long nanoTimeElapsed; + + public ExecutionTime(long nanoTimeElapsed) { + this.nanoTimeElapsed = nanoTimeElapsed; + } + + /** @return the time elapsed while executing the expression */ + public long getNanoTimeElapsed() { + return nanoTimeElapsed; + } + + @Override + public String toString() { + return "ExecutionTime{nanoTimeElapsed=" + nanoTimeElapsed + "}"; + } + + /** @return an execution time representing that no time has passed */ + public static ExecutionTime empty() { + return new ExecutionTime(0); + } +} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/instrument/profiling/ProfilingInfo.java b/engine/runtime/src/main/java/org/enso/interpreter/instrument/profiling/ProfilingInfo.java new file mode 100644 index 000000000000..7b05e35d6739 --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/instrument/profiling/ProfilingInfo.java @@ -0,0 +1,4 @@ +package org.enso.interpreter.instrument.profiling; + +/** An interface describing various kinds of profiling information that the runtime can provide. */ +public interface ProfilingInfo {} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/Context.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/Context.java index 272985d96512..d565ed3e90c9 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/Context.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/Context.java @@ -327,4 +327,6 @@ public ResourceManager getResourceManager() { public boolean isCachingDisabled() { return isCachingDisabled; } + + } diff --git a/engine/runtime/src/main/scala/org/enso/interpreter/instrument/execution/Timer.scala b/engine/runtime/src/main/scala/org/enso/interpreter/instrument/execution/Timer.scala new file mode 100644 index 000000000000..49fd983457b1 --- /dev/null +++ b/engine/runtime/src/main/scala/org/enso/interpreter/instrument/execution/Timer.scala @@ -0,0 +1,13 @@ +package org.enso.interpreter.instrument.execution + +/** A very simple timer. */ +trait Timer { + def getTime(): Long; +} +object Timer { + + /** A nanosecond precision timer. */ + class Nanosecond extends Timer { + override def getTime(): Long = System.nanoTime() + } +} diff --git a/engine/runtime/src/main/scala/org/enso/interpreter/instrument/job/ProgramExecutionSupport.scala b/engine/runtime/src/main/scala/org/enso/interpreter/instrument/job/ProgramExecutionSupport.scala index c51e7934c802..7b7f66b78b9d 100644 --- a/engine/runtime/src/main/scala/org/enso/interpreter/instrument/job/ProgramExecutionSupport.scala +++ b/engine/runtime/src/main/scala/org/enso/interpreter/instrument/job/ProgramExecutionSupport.scala @@ -1,10 +1,5 @@ package org.enso.interpreter.instrument.job -import java.io.File -import java.util.{Objects, UUID} -import java.util.function.Consumer -import java.util.logging.Level - import cats.implicits._ import com.oracle.truffle.api.source.SourceSection import com.oracle.truffle.api.{ @@ -22,6 +17,7 @@ import org.enso.interpreter.instrument.job.ProgramExecutionSupport.{ ExecutionItem, LocalCallFrame } +import org.enso.interpreter.instrument.profiling.ExecutionTime import org.enso.interpreter.instrument.{ InstrumentFrame, MethodCallsCache, @@ -41,8 +37,12 @@ import org.enso.polyglot.runtime.Runtime.Api import org.enso.polyglot.runtime.Runtime.Api.ContextId import org.enso.text.editing.model -import scala.jdk.OptionConverters._ +import java.io.File +import java.util.function.Consumer +import java.util.logging.Level +import java.util.{Objects, UUID} import scala.jdk.CollectionConverters._ +import scala.jdk.OptionConverters._ /** Provides support for executing Enso code. Adds convenient methods to * run Enso programs in a Truffle context. @@ -119,7 +119,9 @@ trait ProgramExecutionSupport { expressionType, expressionType, expressionCall, - expressionCall + expressionCall, + Array(ExecutionTime.empty()), + true ) ) } @@ -372,7 +374,11 @@ trait ProgramExecutionSupport { Api.ExpressionValueUpdate( value.getExpressionId, Option(value.getType), - methodPointer + methodPointer, + value.getProfilingInfo.map { case e: ExecutionTime => + Api.ProfilingInfo.ExecutionTime(e.getNanoTimeElapsed) + }.toVector, + value.wasCached() ) ) ) diff --git a/engine/runtime/src/test/scala/org/enso/interpreter/test/ValueEquality.scala b/engine/runtime/src/test/scala/org/enso/interpreter/test/ValueEquality.scala index c57fbba1b68d..c4405feb2c6b 100644 --- a/engine/runtime/src/test/scala/org/enso/interpreter/test/ValueEquality.scala +++ b/engine/runtime/src/test/scala/org/enso/interpreter/test/ValueEquality.scala @@ -9,6 +9,7 @@ trait ValueEquality { case _: Long => a.isNumber && a.fitsInLong && a.asLong == b case _: Int => a.isNumber && a.fitsInInt && a.asInt == b case _: String => a.isString && a.asString == b + case _: Value => a == b case _ => false } } diff --git a/engine/runtime/src/test/scala/org/enso/interpreter/test/instrument/RuntimeServerTest.scala b/engine/runtime/src/test/scala/org/enso/interpreter/test/instrument/RuntimeServerTest.scala index a2efd6a5d9c9..04e47871a629 100644 --- a/engine/runtime/src/test/scala/org/enso/interpreter/test/instrument/RuntimeServerTest.scala +++ b/engine/runtime/src/test/scala/org/enso/interpreter/test/instrument/RuntimeServerTest.scala @@ -1,32 +1,43 @@ package org.enso.interpreter.test.instrument -import java.io.{ByteArrayOutputStream, File} -import java.nio.ByteBuffer -import java.nio.file.Files -import java.util.UUID -import java.util.concurrent.{LinkedBlockingQueue, TimeUnit} - +import org.enso.interpreter.instrument.execution.Timer import org.enso.interpreter.runtime.`type`.Constants +import org.enso.interpreter.runtime.{Context => EnsoContext} import org.enso.interpreter.test.Metadata import org.enso.pkg.{Package, PackageManager} import org.enso.polyglot._ import org.enso.polyglot.data.Tree import org.enso.polyglot.runtime.Runtime.Api -import org.enso.text.{ContentVersion, Sha3_224VersionCalculator} +import org.enso.polyglot.runtime.Runtime.Api.ProfilingInfo import org.enso.text.editing.model import org.enso.text.editing.model.TextEdit +import org.enso.text.{ContentVersion, Sha3_224VersionCalculator} import org.graalvm.polyglot.Context import org.graalvm.polyglot.io.MessageEndpoint import org.scalatest.BeforeAndAfterEach import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers +import java.io.{ByteArrayOutputStream, File} +import java.nio.ByteBuffer +import java.nio.file.Files +import java.util.UUID +import java.util.concurrent.{LinkedBlockingQueue, TimeUnit} + @scala.annotation.nowarn("msg=multiarg infix syntax") class RuntimeServerTest extends AnyFlatSpec with Matchers with BeforeAndAfterEach { + // === Test Timer =========================================================== + + class TestTimer extends Timer { + override def getTime(): Long = 0 + } + + // === Test Utilities ======================================================= + var context: TestContext = _ class TestContext(packageName: String) { @@ -70,6 +81,15 @@ class RuntimeServerTest ) executionContext.context.initialize(LanguageInfo.ID) + val languageContext = executionContext.context + .getBindings(LanguageInfo.ID) + .invokeMember(MethodNames.TopScope.LEAK_CONTEXT) + .asHostObject[EnsoContext] + val info = + languageContext.getEnvironment.getPublicLanguages.get(LanguageInfo.ID) + languageContext.getLanguage.getIdExecutionInstrument + .overrideTimer(new TestTimer) + def writeMain(contents: String): File = Files.write(pkg.mainFile.toPath, contents.getBytes).toFile @@ -104,6 +124,8 @@ class RuntimeServerTest def executionComplete(contextId: UUID): Api.Response = Api.Response(Api.ExecutionComplete(contextId)) + // === The Tests ========================================================== + object Main { val metadata = new Metadata @@ -142,7 +164,9 @@ class RuntimeServerTest Api.ExpressionValueUpdate( Main.idMainX, Some(Constants.INTEGER), - None + None, + Vector(ProfilingInfo.ExecutionTime(0)), + false ) ) ) @@ -162,7 +186,9 @@ class RuntimeServerTest Constants.NUMBER, "foo" ) - ) + ), + Vector(ProfilingInfo.ExecutionTime(0)), + false ) ) ) @@ -176,7 +202,9 @@ class RuntimeServerTest Api.ExpressionValueUpdate( Main.idMainZ, Some(Constants.INTEGER), - None + None, + Vector(ProfilingInfo.ExecutionTime(0)), + false ) ) ) @@ -190,7 +218,9 @@ class RuntimeServerTest Api.ExpressionValueUpdate( Main.idFooY, Some(Constants.INTEGER), - None + None, + Vector(ProfilingInfo.ExecutionTime(0)), + false ) ) ) @@ -204,7 +234,9 @@ class RuntimeServerTest Api.ExpressionValueUpdate( Main.idFooZ, Some(Constants.INTEGER), - None + None, + Vector(ProfilingInfo.ExecutionTime(0)), + false ) ) ) @@ -248,7 +280,9 @@ class RuntimeServerTest Api.ExpressionValueUpdate( idMainY, Some(Constants.INTEGER), - Some(Api.MethodPointer("Test.Main", "Test.Main", "foo")) + Some(Api.MethodPointer("Test.Main", "Test.Main", "foo")), + Vector(ProfilingInfo.ExecutionTime(0)), + false ) ) ) @@ -262,7 +296,9 @@ class RuntimeServerTest Api.ExpressionValueUpdate( idMainZ, Some(Constants.INTEGER), - Some(Api.MethodPointer("Test.Main", "Test.Main", "bar")) + Some(Api.MethodPointer("Test.Main", "Test.Main", "bar")), + Vector(ProfilingInfo.ExecutionTime(0)), + false ) ) ) @@ -379,7 +415,9 @@ class RuntimeServerTest Some(Constants.INTEGER), Some( Api.MethodPointer("Test.Main", Constants.NUMBER, "foo") - ) + ), + Vector(ProfilingInfo.ExecutionTime(0)), + true ) ) ) @@ -488,7 +526,9 @@ class RuntimeServerTest Some(Constants.INTEGER), Some( Api.MethodPointer("Test.Main", "Test.Main.Quux", "foo") - ) + ), + Vector(ProfilingInfo.ExecutionTime(0)), + false ) ) ) @@ -502,7 +542,9 @@ class RuntimeServerTest Some(Constants.INTEGER), Some( Api.MethodPointer("Test.Main", "Test.Main", "bar") - ) + ), + Vector(ProfilingInfo.ExecutionTime(0)), + false ) ) ) @@ -514,7 +556,9 @@ class RuntimeServerTest Api.ExpressionValueUpdate( idMainM, Some("Test.A.A"), - None + None, + Vector(ProfilingInfo.ExecutionTime(0)), + false ) ) ) @@ -528,7 +572,9 @@ class RuntimeServerTest Some(Constants.INTEGER), Some( Api.MethodPointer("Test.A", "Test.A.A", "foo") - ) + ), + Vector(ProfilingInfo.ExecutionTime(0)), + false ) ) ) @@ -542,7 +588,9 @@ class RuntimeServerTest Some(Constants.INTEGER), Some( Api.MethodPointer("Test.A", "Test.A", "bar") - ) + ), + Vector(ProfilingInfo.ExecutionTime(0)), + false ) ) ) @@ -554,7 +602,9 @@ class RuntimeServerTest Api.ExpressionValueUpdate( idMainF, Some(Constants.INTEGER), - None + None, + Vector(ProfilingInfo.ExecutionTime(0)), + false ) ) ) @@ -566,7 +616,9 @@ class RuntimeServerTest Api.ExpressionValueUpdate( idMain, Some(Constants.NOTHING), - None + None, + Vector(ProfilingInfo.ExecutionTime(0)), + false ) ) ) @@ -632,7 +684,9 @@ class RuntimeServerTest Api.ExpressionValueUpdate( idMainFoo, Some(Constants.INTEGER), - Some(Api.MethodPointer(moduleName, "Test.Main", "foo")) + Some(Api.MethodPointer(moduleName, "Test.Main", "foo")), + Vector(ProfilingInfo.ExecutionTime(0)), + false ) ) ) @@ -641,8 +695,13 @@ class RuntimeServerTest Api.ExpressionValuesComputed( contextId, Vector( - Api - .ExpressionValueUpdate(idMain, Some(Constants.INTEGER), None) + Api.ExpressionValueUpdate( + idMain, + Some(Constants.INTEGER), + None, + Vector(ProfilingInfo.ExecutionTime(0)), + false + ) ) ) ), @@ -664,7 +723,8 @@ class RuntimeServerTest .Argument("this", "Test.Main", false, false, None), Suggestion .Argument("a", Constants.ANY, false, false, None), - Suggestion.Argument("b", Constants.ANY, false, false, None) + Suggestion + .Argument("b", Constants.ANY, false, false, None) ), "Test.Main", Constants.ANY, @@ -756,7 +816,9 @@ class RuntimeServerTest Api.ExpressionValueUpdate( idMainFoo, Some(Constants.INTEGER), - Some(Api.MethodPointer(moduleName, "Test.Main", "foo")) + Some(Api.MethodPointer(moduleName, "Test.Main", "foo")), + Vector(ProfilingInfo.ExecutionTime(0)), + false ) ) ) @@ -768,7 +830,9 @@ class RuntimeServerTest Api.ExpressionValueUpdate( idMain, Some(Constants.NOTHING), - None + None, + Vector(ProfilingInfo.ExecutionTime(0)), + false ) ) ) @@ -791,7 +855,8 @@ class RuntimeServerTest .Argument("this", "Test.Main", false, false, None), Suggestion .Argument("a", Constants.ANY, false, false, None), - Suggestion.Argument("b", Constants.ANY, false, false, None) + Suggestion + .Argument("b", Constants.ANY, false, false, None) ), "Test.Main", Constants.ANY, @@ -883,7 +948,9 @@ class RuntimeServerTest Api.ExpressionValueUpdate( idMainBar, Some(Constants.INTEGER), - Some(Api.MethodPointer(moduleName, "Test.Main", "bar")) + Some(Api.MethodPointer(moduleName, "Test.Main", "bar")), + Vector(ProfilingInfo.ExecutionTime(0)), + false ) ) ) @@ -895,7 +962,9 @@ class RuntimeServerTest Api.ExpressionValueUpdate( idMain, Some(Constants.NOTHING), - None + None, + Vector(ProfilingInfo.ExecutionTime(0)), + false ) ) ) @@ -1009,7 +1078,9 @@ class RuntimeServerTest Api.ExpressionValueUpdate( idMainBar, Some(Constants.INTEGER), - Some(Api.MethodPointer(moduleName, "Test.Main", "bar")) + Some(Api.MethodPointer(moduleName, "Test.Main", "bar")), + Vector(ProfilingInfo.ExecutionTime(0)), + false ) ) ) @@ -1021,7 +1092,9 @@ class RuntimeServerTest Api.ExpressionValueUpdate( idMain, Some(Constants.NOTHING), - None + None, + Vector(ProfilingInfo.ExecutionTime(0)), + false ) ) ) @@ -1135,7 +1208,9 @@ class RuntimeServerTest Api.ExpressionValueUpdate( idMainFoo, Some(Constants.INTEGER), - Some(Api.MethodPointer(moduleName, "Test.Main", "foo")) + Some(Api.MethodPointer(moduleName, "Test.Main", "foo")), + Vector(ProfilingInfo.ExecutionTime(0)), + false ) ) ) @@ -1144,8 +1219,13 @@ class RuntimeServerTest Api.ExpressionValuesComputed( contextId, Vector( - Api - .ExpressionValueUpdate(idMain, Some(Constants.INTEGER), None) + Api.ExpressionValueUpdate( + idMain, + Some(Constants.INTEGER), + None, + Vector(ProfilingInfo.ExecutionTime(0)), + false + ) ) ) ), @@ -1167,7 +1247,8 @@ class RuntimeServerTest .Argument("this", "Test.Main", false, false, None), Suggestion .Argument("a", Constants.ANY, false, false, None), - Suggestion.Argument("b", Constants.ANY, false, false, None) + Suggestion + .Argument("b", Constants.ANY, false, false, None) ), "Test.Main", Constants.ANY, @@ -1216,7 +1297,9 @@ class RuntimeServerTest Api.ExpressionValueUpdate( idMain, Some(Constants.INTEGER), - None + None, + Vector(ProfilingInfo.ExecutionTime(0)), + false ) ) ) @@ -1349,7 +1432,8 @@ class RuntimeServerTest false, None ), - Suggestion.Argument("x", Constants.ANY, false, false, None) + Suggestion + .Argument("x", Constants.ANY, false, false, None) ), Constants.NUMBER, Constants.ANY, @@ -1425,7 +1509,9 @@ class RuntimeServerTest Some(Constants.INTEGER), Some( Api.MethodPointer("Test.Main", Constants.NUMBER, "foo") - ) + ), + Vector(ProfilingInfo.ExecutionTime(0)), + true ) ) ) @@ -1495,7 +1581,9 @@ class RuntimeServerTest Api.ExpressionValueUpdate( idResult, Some(Constants.INTEGER), - None + None, + Vector(ProfilingInfo.ExecutionTime(0)), + false ) ) ) @@ -1507,7 +1595,9 @@ class RuntimeServerTest Api.ExpressionValueUpdate( idPrintln, Some(Constants.NOTHING), - None + None, + Vector(ProfilingInfo.ExecutionTime(0)), + false ) ) ) @@ -1519,7 +1609,9 @@ class RuntimeServerTest Api.ExpressionValueUpdate( idMain, Some(Constants.NOTHING), - None + None, + Vector(ProfilingInfo.ExecutionTime(0)), + false ) ) ) @@ -1593,8 +1685,13 @@ class RuntimeServerTest Api.ExpressionValuesComputed( contextId, Vector( - Api - .ExpressionValueUpdate(idResult, Some(Constants.TEXT), None) + Api.ExpressionValueUpdate( + idResult, + Some(Constants.TEXT), + None, + Vector(ProfilingInfo.ExecutionTime(0)), + false + ) ) ) ), @@ -1667,7 +1764,9 @@ class RuntimeServerTest Api.ExpressionValueUpdate( idMainA, Some(Constants.INTEGER), - None + None, + Vector(ProfilingInfo.ExecutionTime(0)), + false ) ) ) @@ -1679,7 +1778,9 @@ class RuntimeServerTest Api.ExpressionValueUpdate( idMainP, Some(Constants.NOTHING), - None + None, + Vector(ProfilingInfo.ExecutionTime(0)), + false ) ) ) @@ -1691,7 +1792,9 @@ class RuntimeServerTest Api.ExpressionValueUpdate( idMain, Some(Constants.NOTHING), - None + None, + Vector(ProfilingInfo.ExecutionTime(0)), + false ) ) ) @@ -1806,7 +1909,8 @@ class RuntimeServerTest false, None ), - Suggestion.Argument("y", Constants.ANY, false, false, None) + Suggestion + .Argument("y", Constants.ANY, false, false, None) ), Constants.NUMBER, Constants.ANY, @@ -1846,7 +1950,9 @@ class RuntimeServerTest Api.ExpressionValueUpdate( idMainA, Some(Constants.INTEGER), - Some(Api.MethodPointer(moduleName, Constants.NUMBER, "x")) + Some(Api.MethodPointer(moduleName, Constants.NUMBER, "x")), + Vector(ProfilingInfo.ExecutionTime(0)), + false ) ) ) @@ -1894,7 +2000,9 @@ class RuntimeServerTest Api.ExpressionValueUpdate( idMainA, Some(Constants.INTEGER), - Some(Api.MethodPointer(moduleName, "Test.Main", "pie")) + Some(Api.MethodPointer(moduleName, "Test.Main", "pie")), + Vector(ProfilingInfo.ExecutionTime(0)), + false ) ) ) @@ -1925,7 +2033,9 @@ class RuntimeServerTest Api.ExpressionValueUpdate( idMainA, Some(Constants.INTEGER), - Some(Api.MethodPointer(moduleName, "Test.Main", "uwu")) + Some(Api.MethodPointer(moduleName, "Test.Main", "uwu")), + Vector(ProfilingInfo.ExecutionTime(0)), + false ) ) ) @@ -1956,7 +2066,9 @@ class RuntimeServerTest Api.ExpressionValueUpdate( idMainA, Some(Constants.TEXT), - Some(Api.MethodPointer(moduleName, "Test.Main", "hie")) + Some(Api.MethodPointer(moduleName, "Test.Main", "hie")), + Vector(ProfilingInfo.ExecutionTime(0)), + false ) ) ) @@ -1984,7 +2096,13 @@ class RuntimeServerTest Api.ExpressionValuesComputed( contextId, Vector( - Api.ExpressionValueUpdate(idMainA, Some(Constants.TEXT), None) + Api.ExpressionValueUpdate( + idMainA, + Some(Constants.TEXT), + None, + Vector(ProfilingInfo.ExecutionTime(0)), + false + ) ) ) ), @@ -2054,7 +2172,9 @@ class RuntimeServerTest Api.ExpressionValueUpdate( idMain, Some(Constants.NOTHING), - None + None, + Vector(ProfilingInfo.ExecutionTime(0)), + false ) ) ) @@ -2072,7 +2192,9 @@ class RuntimeServerTest Constants.NUMBER, "overloaded" ) - ) + ), + Vector(ProfilingInfo.ExecutionTime(0)), + false ) ) ) @@ -2087,7 +2209,9 @@ class RuntimeServerTest Some( Api .MethodPointer(moduleName, Constants.TEXT, "overloaded") - ) + ), + Vector(ProfilingInfo.ExecutionTime(0)), + false ) ) ) @@ -2105,7 +2229,9 @@ class RuntimeServerTest Constants.NUMBER, "overloaded" ) - ) + ), + Vector(ProfilingInfo.ExecutionTime(0)), + false ) ) ) @@ -2241,7 +2367,9 @@ class RuntimeServerTest Constants.NUMBER, "overloaded" ) - ) + ), + Vector(ProfilingInfo.ExecutionTime(0)), + fromCache = true ) ) ) @@ -2259,7 +2387,9 @@ class RuntimeServerTest Constants.TEXT, "overloaded" ) - ) + ), + Vector(ProfilingInfo.ExecutionTime(0)), + fromCache = false ) ) ) @@ -2277,7 +2407,9 @@ class RuntimeServerTest Constants.NUMBER, "overloaded" ) - ) + ), + Vector(ProfilingInfo.ExecutionTime(0)), + fromCache = false ) ) ) @@ -2317,7 +2449,9 @@ class RuntimeServerTest Constants.NUMBER, "overloaded" ) - ) + ), + Vector(ProfilingInfo.ExecutionTime(0)), + true ) ) ) @@ -2332,7 +2466,9 @@ class RuntimeServerTest Some( Api .MethodPointer(moduleName, Constants.TEXT, "overloaded") - ) + ), + Vector(ProfilingInfo.ExecutionTime(0)), + false ) ) ) @@ -2350,7 +2486,9 @@ class RuntimeServerTest Constants.NUMBER, "overloaded" ) - ) + ), + Vector(ProfilingInfo.ExecutionTime(0)), + false ) ) ) @@ -2390,7 +2528,9 @@ class RuntimeServerTest Constants.NUMBER, "overloaded" ) - ) + ), + Vector(ProfilingInfo.ExecutionTime(0)), + true ) ) ) @@ -2405,7 +2545,9 @@ class RuntimeServerTest Some( Api .MethodPointer(moduleName, Constants.TEXT, "overloaded") - ) + ), + Vector(ProfilingInfo.ExecutionTime(0)), + false ) ) ) @@ -2423,7 +2565,9 @@ class RuntimeServerTest Constants.NUMBER, "overloaded" ) - ) + ), + Vector(ProfilingInfo.ExecutionTime(0)), + false ) ) ) @@ -2521,7 +2665,9 @@ class RuntimeServerTest ) ) ) - context.receive shouldEqual Some(context.executionComplete(contextId)) + context.receive shouldEqual Some( + context.executionComplete(contextId) + ) context.consumeOut shouldEqual List("I'm a modified!") // Close the file @@ -2579,7 +2725,13 @@ class RuntimeServerTest Api.ExpressionValuesComputed( contextId, Vector( - Api.ExpressionValueUpdate(idMain, Some(Constants.INTEGER), None) + Api.ExpressionValueUpdate( + idMain, + Some(Constants.INTEGER), + None, + Vector(ProfilingInfo.ExecutionTime(0)), + false + ) ) ) ), @@ -2629,7 +2781,9 @@ class RuntimeServerTest ) ) ) - context.receive shouldEqual Some(context.executionComplete(contextId)) + context.receive shouldEqual Some( + context.executionComplete(contextId) + ) } it should "send suggestion notifications when file is executed" in { @@ -2641,7 +2795,15 @@ class RuntimeServerTest Api.Response( Api.ExpressionValuesComputed( contextId, - Vector(Api.ExpressionValueUpdate(idMain, Some(Constants.INTEGER), None)) + Vector( + Api.ExpressionValueUpdate( + idMain, + Some(Constants.INTEGER), + None, + Vector(ProfilingInfo.ExecutionTime(0)), + false + ) + ) ) ) val version = contentsVersion(context.Main.code) @@ -2767,7 +2929,8 @@ class RuntimeServerTest Seq( Suggestion .Argument("this", Constants.NUMBER, false, false, None), - Suggestion.Argument("x", Constants.ANY, false, false, None) + Suggestion + .Argument("x", Constants.ANY, false, false, None) ), Constants.NUMBER, Constants.ANY, @@ -2841,7 +3004,9 @@ class RuntimeServerTest Api.ExpressionValueUpdate( context.Main.idMainY, Some(Constants.INTEGER), - Some(Api.MethodPointer("Test.Main", Constants.NUMBER, "foo")) + Some(Api.MethodPointer("Test.Main", Constants.NUMBER, "foo")), + Vector(ProfilingInfo.ExecutionTime(0)), + true ) ) ) @@ -4122,7 +4287,9 @@ class RuntimeServerTest Api.ExpressionValueUpdate( idMain, Some(Constants.INTEGER), - None + None, + Vector(ProfilingInfo.ExecutionTime(0)), + false ) ) ) @@ -4149,7 +4316,8 @@ class RuntimeServerTest false, None ), - Suggestion.Argument("x", Constants.ANY, false, false, None) + Suggestion + .Argument("x", Constants.ANY, false, false, None) ), "Test.Visualisation", Constants.ANY, @@ -4173,7 +4341,8 @@ class RuntimeServerTest false, None ), - Suggestion.Argument("x", Constants.ANY, false, false, None) + Suggestion + .Argument("x", Constants.ANY, false, false, None) ), "Test.Visualisation", Constants.ANY, @@ -4322,7 +4491,8 @@ class RuntimeServerTest false, None ), - Suggestion.Argument("x", Constants.ANY, false, false, None) + Suggestion + .Argument("x", Constants.ANY, false, false, None) ), "Test.Visualisation", Constants.ANY, @@ -4346,7 +4516,8 @@ class RuntimeServerTest false, None ), - Suggestion.Argument("x", Constants.ANY, false, false, None) + Suggestion + .Argument("x", Constants.ANY, false, false, None) ), "Test.Visualisation", Constants.ANY, @@ -4513,7 +4684,8 @@ class RuntimeServerTest false, None ), - Suggestion.Argument("x", Constants.ANY, false, false, None) + Suggestion + .Argument("x", Constants.ANY, false, false, None) ), "Test.Visualisation", Constants.ANY, @@ -4537,7 +4709,8 @@ class RuntimeServerTest false, None ), - Suggestion.Argument("x", Constants.ANY, false, false, None) + Suggestion + .Argument("x", Constants.ANY, false, false, None) ), "Test.Visualisation", Constants.ANY, @@ -4637,7 +4810,8 @@ class RuntimeServerTest Seq( Suggestion .Argument("this", Constants.NUMBER, false, false, None), - Suggestion.Argument("x", Constants.ANY, false, false, None) + Suggestion + .Argument("x", Constants.ANY, false, false, None) ), Constants.NUMBER, Constants.ANY, @@ -5027,7 +5201,7 @@ class RuntimeServerTest // open file context.send( - Api.Request(Api.OpenFileNotification(mainFile, contents, true)) + Api.Request(Api.OpenFileNotification(mainFile, contents, isIndexed = true)) ) context.receiveNone shouldEqual None @@ -5088,7 +5262,9 @@ class RuntimeServerTest Api.ExpressionValueUpdate( context.Main.idMainY, Some(Constants.INTEGER), - Some(Api.MethodPointer("Foo.Main", Constants.NUMBER, "foo")) + Some(Api.MethodPointer("Foo.Main", Constants.NUMBER, "foo")), + Vector(ProfilingInfo.ExecutionTime(0)), + false ) ) )