/// <nodoc/> public EvaluationResult EvalWrapper(Node node, Context context, ModuleLiteral env, EvaluationStackFrame args, Func <EvaluationResult> continuation) { Contract.Requires(node != null); Contract.Requires(context != null); Contract.Requires(args != null); Contract.Requires(continuation != null); // We want to profile apply expression nodes only var applyExpression = node as ApplyExpression; if (applyExpression != null) { // We record that this functor needs its evaluated value by adding it to the dictionary with a null value if it is not there yet m_functorsPendingEvaluation.TryAdd(applyExpression.Functor, null); // Register start time and then call the continuation var startTime = m_stopwatch.ElapsedMilliseconds; var applyResult = continuation(); var endTime = m_stopwatch.ElapsedMilliseconds; // After running the continuation, the functor value should not be pending anymore. So we retrieve its id and location Contract.Assert(m_functorsPendingEvaluation.ContainsKey(applyExpression.Functor) && m_functorsPendingEvaluation[applyExpression.Functor] != null); GetFunctorIdNameAndLocation(context, m_functorsPendingEvaluation[applyExpression.Functor], out int functorId, out string functorName, out string functorLocation); // We cannot really remove the entry here since there might be other parallel evaluations that depend on it // TODO: we could try something out if memory turns out to be a problem. var entry = new ProfiledFunctionCall( callsiteInvocation: node.ToDisplayString(context), callsiteLocation: node.Location.ToLocationData(env.Path), durationInclusive: endTime - startTime, qualifier: env.Qualifier.QualifierId.ToDisplayString(context), functionId: functorId, functionName: functorName, functionLocation: functorLocation); m_profilerEntries.Enqueue(entry); return(applyResult); } // In this case we don't profile the evaluation call, but we check if this happens to be the functor for which we need its value for a parent evaluation var result = continuation(); if (m_functorsPendingEvaluation.TryGetValue(node, out object existingResult) && existingResult == null) { m_functorsPendingEvaluation[node] = result.Value; } return(result); }
private string GetLine(ProfiledFunctionCall entry) { var result = string.Format( CultureInfo.InvariantCulture, "{0}\t{1}\t{2}\t{3}\t{4}\t{5}\t{6}", entry.CallsiteInvocation, entry.DurationInclusive, entry.CallsiteLocation.ToString(m_pathTable), entry.Qualifier, entry.FunctionId, entry.FunctionName, entry.FunctionLocation); return(result); }