/// <summary> /// Evaluates an LLDB expression. It decides which expression evaluation method to use /// (e.g. LLDB, lldb-eval, path expression, etc.) depending on the Stadia SDK settings and /// the input |expression|. It doesn't support format specifiers, only expressions that /// can be directly evaluated in the LLDB environment. /// </summary> /// <param name="expression">The expression to be evaluated.</param> /// <param name="variable">The evaluation context.</param> /// <param name="natvisScope">The Natvis tokens to be resolved before evaluation.</param> /// <param name="displayName">The display name given to the result. If null the underlying /// debugger's context specific name is used.</param> /// <returns>The expression result.</returns> async Task <IVariableInformation> EvaluateLldbExpressionAsync(VsExpression expression, IVariableInformation variable, NatvisScope natvisScope, string displayName) { ExpressionEvaluationStrategy strategy = _extensionOptions.ExpressionEvaluationStrategy; var stepsRecorder = new ExpressionEvaluationRecorder.StepsRecorder(_timeSource); long startTimestampUs = _timeSource.GetTimestampUs(); IVariableInformation variableInformation = await EvaluateLldbExpressionWithMetricsAsync( expression, variable, natvisScope, displayName, strategy, stepsRecorder); // Evaluating a context variable will just return the reference to it. Because of // deferred evaluation of display values, some values could be incorrectly displayed // (in the case a context variable was changed in between two expression evaluations). // In order to prevent this, we create a copy of result if the expression was simply // a context variable. if (natvisScope.IsContextVariable(expression.Value)) { variableInformation = variableInformation.Clone(expression.FormatSpecifier); } long endTimestampUs = _timeSource.GetTimestampUs(); _expressionEvaluationRecorder.Record(strategy, ExpressionEvaluationContext.VALUE, stepsRecorder, startTimestampUs, endTimestampUs, variable.Id); return(variableInformation); }
async Task <RemoteValue> CreateValueFromExpressionAsync(string expression) { var stepsRecorder = new ExpressionEvaluationRecorder.StepsRecorder(_timeSource); long startTimestampUs = _timeSource.GetTimestampUs(); RemoteValue remoteValue = await CreateValueFromExpressionWithMetricsAsync(expression, stepsRecorder); long endTimestampUs = _timeSource.GetTimestampUs(); _expressionEvaluationRecorder.Record(_expressionEvaluationStrategy, _expressionEvaluationContext, stepsRecorder, startTimestampUs, endTimestampUs); return(remoteValue); }
public void RecordSingleEventWithTwoStepsTest() { const ExpressionEvaluationStrategy strategySource = ExpressionEvaluationStrategy.LLDB; const ExpressionEvaluationContext contextSource = ExpressionEvaluationContext.FRAME; var stepsRecorder = new ExpressionEvaluationRecorder.StepsRecorder(_timeSource); using (Step step = stepsRecorder.NewStep(ExpressionEvaluationEngine.LLDB_VARIABLE_PATH)) { step.Finalize(LLDBErrorCode.ERROR); } using (Step step = stepsRecorder.NewStep(ExpressionEvaluationEngine.LLDB)) { step.Finalize(LLDBErrorCode.OK); } const long startTimestampUs = 750; const long endTimestampUs = 21562; _expressionEvaluationRecorder.Record(strategySource, contextSource, stepsRecorder, startTimestampUs, endTimestampUs); // Get a copy of the batch summary sent to batchEventAggregator so we can verify // that it matches the one being sent to metrics. ExpressionEvaluationBatchSummary batchSummary = null; _batchEventAggregator.BatchSummaryReady += (_, newSummary) => batchSummary = newSummary; _timer.Increment(_minimumBatchSeparationMilliseconds); _eventScheduler.Increment(_minimumBatchSeparationMilliseconds); const ExpressionEvaluation.Types.Strategy strategyExpected = ExpressionEvaluation.Types.Strategy.Lldb; const ExpressionEvaluation.Types.Context contextExpected = ExpressionEvaluation.Types .Context.Frame; Assert.AreEqual(1, batchSummary.Proto.ExpressionEvaluations.Count); ExpressionEvaluation received = batchSummary.Proto.ExpressionEvaluations[0]; Assert.Multiple(() => { Assert.AreEqual(strategyExpected, received.Strategy); Assert.AreEqual(contextExpected, received.Context); Assert.NotNull(received.EvaluationSteps); Assert.AreEqual(2, received.EvaluationSteps.Count); Assert.AreEqual(startTimestampUs, received.StartTimestampMicroseconds); Assert.AreEqual(endTimestampUs, received.EndTimestampMicroseconds); Assert.Null(received.NatvisValueId); }); const ExpressionEvaluationStep.Types.Engine firstStepEngineExpected = ExpressionEvaluationStep.Types.Engine.LldbVariablePath; const ExpressionEvaluationStep.Types.EngineResult firstStepEngineResultExpected = ExpressionEvaluationStep.Types.EngineResult.LldbError; const ExpressionEvaluationStep.Types.Engine secondStepEngineExpected = ExpressionEvaluationStep.Types.Engine.Lldb; const ExpressionEvaluationStep.Types.EngineResult secondStepEngineResultExpected = ExpressionEvaluationStep.Types.EngineResult.LldbOk; ExpressionEvaluationStep firstStep = received.EvaluationSteps[0]; ExpressionEvaluationStep secondStep = received.EvaluationSteps[1]; Assert.Multiple(() => { Assert.AreEqual(firstStepEngineExpected, firstStep.Engine); Assert.AreEqual(firstStepEngineResultExpected, firstStep.Result); Assert.AreEqual(1, firstStep.DurationMicroseconds); Assert.AreEqual(secondStepEngineExpected, secondStep.Engine); Assert.AreEqual(secondStepEngineResultExpected, secondStep.Result); Assert.AreEqual(1, secondStep.DurationMicroseconds); }); _metrics.Received(1) .RecordEvent(DeveloperEventType.Types.Type.VsiDebugExpressionEvaluationBatch, new DeveloperLogEvent { DebugExpressionEvaluationBatch = batchSummary.Proto, StatusCode = DeveloperEventStatus.Types.Code.Success }); }