Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Query] Adds public backend metrics property to Diagnostics #4001

Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
f440f1b
initial commit
Maya-Painter Jul 21, 2023
b287e27
some pr comments, WIP
Maya-Painter Jul 21, 2023
82b9871
Refactor
Maya-Painter Jul 24, 2023
1770560
more
Maya-Painter Jul 24, 2023
6fa6e2a
Public constructors and modify accumulators
Maya-Painter Jul 26, 2023
451763b
accumulator updates and undo test changes
Maya-Painter Jul 27, 2023
d4f6c07
add test
Maya-Painter Jul 27, 2023
de863d9
PR comments
Maya-Painter Jul 27, 2023
b1a7823
bug fix
Maya-Painter Jul 27, 2023
b96203a
ToString() refactor
Maya-Painter Jul 28, 2023
f84e698
contract updates
Maya-Painter Jul 28, 2023
e2137d2
test updates
Maya-Painter Jul 28, 2023
e3f1876
Merge branch 'master' into users/mayapainter/querymetrics
Maya-Painter Jul 28, 2023
4c5152d
small fixes
Maya-Painter Jul 28, 2023
f18b585
text fix
Maya-Painter Jul 28, 2023
b25f872
Update accumulators
Maya-Painter Jul 31, 2023
7f8aa59
fix
Maya-Painter Aug 1, 2023
0ebb267
Merge branch 'master' into users/mayapainter/querymetrics
Maya-Painter Aug 1, 2023
f9af873
PR comments
Maya-Painter Aug 1, 2023
d320017
small fix
Maya-Painter Aug 1, 2023
edc5aab
Rename BE -> ServerSide
Maya-Painter Aug 2, 2023
b64d837
more renaming
Maya-Painter Aug 2, 2023
8d71294
Update API and tests
Maya-Painter Aug 2, 2023
95f8efb
separate public and internal classes
Maya-Painter Aug 3, 2023
4f9dd80
API update
Maya-Painter Aug 3, 2023
a1a3915
change namespace
Maya-Painter Aug 4, 2023
eccf865
Pr comments
Maya-Painter Aug 4, 2023
120bccf
public constructors and bug fix
Maya-Painter Aug 7, 2023
94f5612
API updates
Maya-Painter Aug 8, 2023
065d323
renaming and test updates
Maya-Painter Aug 11, 2023
99679c0
PR comments
Maya-Painter Aug 11, 2023
41af90a
more PR comments
Maya-Painter Aug 11, 2023
ba80d30
Merge branch 'master' into users/mayapainter/querymetrics
Maya-Painter Aug 11, 2023
b31e382
PR comments, test additions
Maya-Painter Aug 14, 2023
e6825c3
API updates and more tests
Maya-Painter Aug 14, 2023
2bb36c8
tests and pkrangeid update
Maya-Painter Aug 15, 2023
466be56
PR comments
Maya-Painter Aug 15, 2023
6abd122
more PR comments
Maya-Painter Aug 16, 2023
0b4fcba
smol test fix
Maya-Painter Aug 16, 2023
eca1292
PR comments - renaming properties and constructor rehash
Maya-Painter Aug 16, 2023
c273463
Merge branch 'master' into users/mayapainter/querymetrics
Maya-Painter Aug 16, 2023
f19bafc
contract update
Maya-Painter Aug 16, 2023
e08aff7
seal classes and private fields.
Maya-Painter Aug 23, 2023
2f0cf75
update indexHitRatio calc
Maya-Painter Aug 23, 2023
4a0b17f
mocking refactor to abstract classes
Maya-Painter Aug 25, 2023
6ecdd0c
Merge branch 'master' into users/mayapainter/querymetrics
Maya-Painter Aug 25, 2023
e30b8bc
contract updates
Maya-Painter Sep 5, 2023
3d9fc86
Merge branch 'master' into users/mayapainter/querymetrics
Maya-Painter Sep 5, 2023
806a160
PR comments - Update documentation
Maya-Painter Sep 8, 2023
255b10d
Merge branch 'master' into users/mayapainter/querymetrics
Maya-Painter Sep 8, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions Microsoft.Azure.Cosmos/src/Diagnostics/CosmosDiagnostics.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ namespace Microsoft.Azure.Cosmos
{
using System;
using System.Collections.Generic;
using Microsoft.Azure.Cosmos.Query.Core.Metrics;

/// <summary>
/// Contains the cosmos diagnostic information for the current request to Azure Cosmos DB service.
Expand Down Expand Up @@ -43,6 +44,16 @@ public virtual int GetFailedRequestCount()
throw new NotImplementedException($"{nameof(CosmosDiagnostics)}.{nameof(GetFailedRequestCount)}");
}

/// <summary>
/// This represents the accumulated backend query metrics for the request.
/// </summary>
/// <returns>The accumulated backend metrics for the request.</returns>
public virtual BackendMetrics GetQueryMetrics()
{
// Default implementation avoids breaking change for users upgrading.
throw new NotImplementedException($"{nameof(CosmosDiagnostics)}.{nameof(GetQueryMetrics)}");
}

/// <summary>
/// Gets the string field <see cref="CosmosDiagnostics"/> instance in the Azure CosmosDB database service.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ namespace Microsoft.Azure.Cosmos.Diagnostics
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Azure.Cosmos.Json;
using Microsoft.Azure.Cosmos.Query.Core.Metrics;
using Microsoft.Azure.Cosmos.Tracing;
using Microsoft.Azure.Cosmos.Tracing.TraceData;
using static Microsoft.Azure.Cosmos.Tracing.TraceData.ClientSideRequestStatisticsTraceDatum;
Expand Down Expand Up @@ -49,6 +49,14 @@ public override TimeSpan GetClientElapsedTime()
return this.Value?.Summary?.RegionsContacted;
}

public override BackendMetrics GetQueryMetrics()
{
BackendMetricsAccumulator accumulator = new BackendMetricsAccumulator();
BackendMetricsAccumulator.WalkTraceTreeForQueryMetrics(this.Value, accumulator);
return BackendMetricsAccumulator.ToBackendMetrics(accumulator);

}

internal bool IsGoneExceptionHit()
{
return this.WalkTraceTreeForGoneException(this.Value);
Expand All @@ -61,9 +69,9 @@ private bool WalkTraceTreeForGoneException(ITrace currentTrace)
return false;
}

foreach (object datums in currentTrace.Data.Values)
foreach (object datum in currentTrace.Data.Values)
{
if (datums is ClientSideRequestStatisticsTraceDatum clientSideRequestStatisticsTraceDatum)
if (datum is ClientSideRequestStatisticsTraceDatum clientSideRequestStatisticsTraceDatum)
{
foreach (StoreResponseStatistics responseStatistics in clientSideRequestStatisticsTraceDatum.StoreResponseStatisticsList)
{
Expand Down
125 changes: 29 additions & 96 deletions Microsoft.Azure.Cosmos/src/Query/Core/Metrics/BackendMetrics.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,12 @@ namespace Microsoft.Azure.Cosmos.Query.Core.Metrics
/// <summary>
/// Metrics received for queries from the backend.
/// </summary>
#if INTERNAL
#pragma warning disable SA1600
#pragma warning disable CS1591
public
#else
internal
#endif
sealed class BackendMetrics
public sealed class BackendMetrics
Maya-Painter marked this conversation as resolved.
Show resolved Hide resolved
{
/// <summary>
/// QueryMetrics that with all members having default (but not null) members.
/// </summary>
public static readonly BackendMetrics Empty = new BackendMetrics(
internal static readonly BackendMetrics Empty = new BackendMetrics(
retrievedDocumentCount: default,
retrievedDocumentSize: default,
outputDocumentCount: default,
Expand All @@ -36,6 +29,21 @@ sealed class BackendMetrics
runtimeExecutionTimes: RuntimeExecutionTimes.Empty,
documentWriteTime: default);

/// <summary>
/// Initializes a new instance of the <see cref="BackendMetrics"/> class.
/// </summary>
/// <param name="retrievedDocumentCount"></param>
/// <param name="retrievedDocumentSize"></param>
/// <param name="outputDocumentCount"></param>
/// <param name="outputDocumentSize"></param>
/// <param name="indexHitRatio"></param>
/// <param name="totalQueryExecutionTime"></param>
/// <param name="queryPreparationTimes"></param>
/// <param name="indexLookupTime"></param>
/// <param name="documentLoadTime"></param>
/// <param name="vmExecutionTime"></param>
/// <param name="runtimeExecutionTimes"></param>
/// <param name="documentWriteTime"></param>
public BackendMetrics(
long retrievedDocumentCount,
long retrievedDocumentSize,
Expand Down Expand Up @@ -124,114 +132,39 @@ public BackendMetrics(
/// </summary>
public TimeSpan VMExecutionTime { get; }

public override string ToString()
/// <summary>
/// String representation of BackendMetric.
/// </summary>
/// <returns>BackendMetric text</returns>
public override string ToString() //todo move this logic elsewhere?
{
return $"totalExecutionTimeInMs={this.TotalTime.TotalMilliseconds};queryCompileTimeInMs={this.QueryPreparationTimes.QueryCompilationTime.TotalMilliseconds};queryLogicalPlanBuildTimeInMs={this.QueryPreparationTimes.LogicalPlanBuildTime.TotalMilliseconds};queryPhysicalPlanBuildTimeInMs={this.QueryPreparationTimes.PhysicalPlanBuildTime.TotalMilliseconds};queryOptimizationTimeInMs={this.QueryPreparationTimes.QueryOptimizationTime.TotalMilliseconds};indexLookupTimeInMs={this.IndexLookupTime.TotalMilliseconds};documentLoadTimeInMs={this.DocumentLoadTime.TotalMilliseconds};systemFunctionExecuteTimeInMs={this.RuntimeExecutionTimes.SystemFunctionExecutionTime.TotalMilliseconds};userFunctionExecuteTimeInMs={this.RuntimeExecutionTimes.UserDefinedFunctionExecutionTime.TotalMilliseconds};retrievedDocumentCount={this.RetrievedDocumentCount};retrievedDocumentSize={this.RetrievedDocumentSize};outputDocumentCount={this.OutputDocumentCount};outputDocumentSize={this.OutputDocumentSize};writeOutputTimeInMs={this.DocumentWriteTime.TotalMilliseconds};indexUtilizationRatio={this.IndexHitRatio}";
}

public static BackendMetrics CreateFromIEnumerable(IEnumerable<BackendMetrics> backendMetricsEnumerable)
internal static BackendMetrics CreateFromIEnumerable(IEnumerable<BackendMetrics> backendMetricsEnumerable)
Maya-Painter marked this conversation as resolved.
Show resolved Hide resolved
{
BackendMetrics.Accumulator accumulator = default;
BackendMetricsAccumulator accumulator = default;
foreach (BackendMetrics backendMetrics in backendMetricsEnumerable)
{
accumulator = accumulator.Accumulate(backendMetrics);
accumulator.Accumulate(backendMetrics);
}

return BackendMetrics.Accumulator.ToBackendMetrics(accumulator);
return BackendMetricsAccumulator.ToBackendMetrics(accumulator);
}

public static bool TryParseFromDelimitedString(string delimitedString, out BackendMetrics backendMetrics)
internal static bool TryParseFromDelimitedString(string delimitedString, out BackendMetrics backendMetrics)
{
return BackendMetricsParser.TryParse(delimitedString, out backendMetrics);
}

public static BackendMetrics ParseFromDelimitedString(string delimitedString)
internal static BackendMetrics ParseFromDelimitedString(string delimitedString)
{
if (!BackendMetricsParser.TryParse(delimitedString, out BackendMetrics backendMetrics))
{
throw new FormatException();
}

return backendMetrics;
}

public ref struct Accumulator
{
public Accumulator(
TimeSpan totalTime,
long retrievedDocumentCount,
long retrievedDocumentSize,
long outputDocumentCount,
long outputDocumentSize,
double indexHitRatio,
QueryPreparationTimes.Accumulator queryPreparationTimesAccumulator,
TimeSpan indexLookupTime,
TimeSpan documentLoadTime,
RuntimeExecutionTimes.Accumulator runtimeExecutionTimesAccumulator,
TimeSpan documentWriteTime,
TimeSpan vmExecutionTime)
{
this.TotalTime = totalTime;
this.RetrievedDocumentCount = retrievedDocumentCount;
this.RetrievedDocumentSize = retrievedDocumentSize;
this.OutputDocumentCount = outputDocumentCount;
this.OutputDocumentSize = outputDocumentSize;
this.IndexHitRatio = indexHitRatio;
this.QueryPreparationTimesAccumulator = queryPreparationTimesAccumulator;
this.IndexLookupTime = indexLookupTime;
this.DocumentLoadTime = documentLoadTime;
this.RuntimeExecutionTimesAccumulator = runtimeExecutionTimesAccumulator;
this.DocumentWriteTime = documentWriteTime;
this.VMExecutionTime = vmExecutionTime;
}

public TimeSpan TotalTime { get; }
public long RetrievedDocumentCount { get; }
public long RetrievedDocumentSize { get; }
public long OutputDocumentCount { get; }
public long OutputDocumentSize { get; }
public double IndexHitRatio { get; }
public QueryPreparationTimes.Accumulator QueryPreparationTimesAccumulator { get; }
public TimeSpan IndexLookupTime { get; }
public TimeSpan DocumentLoadTime { get; }
public RuntimeExecutionTimes.Accumulator RuntimeExecutionTimesAccumulator { get; }
public TimeSpan DocumentWriteTime { get; }
public TimeSpan VMExecutionTime { get; }

public Accumulator Accumulate(BackendMetrics backendMetrics)
{
return new Accumulator(
totalTime: this.TotalTime + backendMetrics.TotalTime,
retrievedDocumentCount: this.RetrievedDocumentCount + backendMetrics.RetrievedDocumentCount,
retrievedDocumentSize: this.RetrievedDocumentSize + backendMetrics.RetrievedDocumentSize,
outputDocumentCount: this.OutputDocumentCount + backendMetrics.OutputDocumentCount,
outputDocumentSize: this.OutputDocumentSize + backendMetrics.OutputDocumentSize,
indexHitRatio: ((this.OutputDocumentCount * this.IndexHitRatio) + (backendMetrics.OutputDocumentCount * backendMetrics.IndexHitRatio)) / (this.RetrievedDocumentCount + backendMetrics.RetrievedDocumentCount),
queryPreparationTimesAccumulator: this.QueryPreparationTimesAccumulator.Accumulate(backendMetrics.QueryPreparationTimes),
indexLookupTime: this.IndexLookupTime + backendMetrics.IndexLookupTime,
documentLoadTime: this.DocumentLoadTime + backendMetrics.DocumentLoadTime,
runtimeExecutionTimesAccumulator: this.RuntimeExecutionTimesAccumulator.Accumulate(backendMetrics.RuntimeExecutionTimes),
documentWriteTime: this.DocumentWriteTime + backendMetrics.DocumentWriteTime,
vmExecutionTime: this.VMExecutionTime + backendMetrics.VMExecutionTime);

}

public static BackendMetrics ToBackendMetrics(BackendMetrics.Accumulator accumulator)
{
return new BackendMetrics(
retrievedDocumentCount: accumulator.RetrievedDocumentCount,
retrievedDocumentSize: accumulator.RetrievedDocumentSize,
outputDocumentCount: accumulator.OutputDocumentCount,
outputDocumentSize: accumulator.OutputDocumentSize,
indexHitRatio: accumulator.IndexHitRatio,
totalQueryExecutionTime: accumulator.TotalTime,
queryPreparationTimes: QueryPreparationTimes.Accumulator.ToQueryPreparationTimes(accumulator.QueryPreparationTimesAccumulator),
indexLookupTime: accumulator.IndexLookupTime,
documentLoadTime: accumulator.DocumentLoadTime,
vmExecutionTime: accumulator.VMExecutionTime,
runtimeExecutionTimes: RuntimeExecutionTimes.Accumulator.ToRuntimeExecutionTimes(accumulator.RuntimeExecutionTimesAccumulator),
documentWriteTime: accumulator.DocumentWriteTime);
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------

namespace Microsoft.Azure.Cosmos.Query.Core.Metrics
{
using System;
using Microsoft.Azure.Cosmos.Tracing;
using Microsoft.Azure.Cosmos.Tracing.TraceData;

internal ref struct BackendMetricsAccumulator
{
public BackendMetricsAccumulator(
TimeSpan totalTime,
long retrievedDocumentCount,
long retrievedDocumentSize,
long outputDocumentCount,
long outputDocumentSize,
double indexHitRatio,
QueryPreparationTimesAccumulator queryPreparationTimesAccumulator,
TimeSpan indexLookupTime,
TimeSpan documentLoadTime,
RuntimeExecutionTimesAccumulator runtimeExecutionTimesAccumulator,
TimeSpan documentWriteTime,
TimeSpan vmExecutionTime)
{
this.TotalTime = totalTime;
this.RetrievedDocumentCount = retrievedDocumentCount;
this.RetrievedDocumentSize = retrievedDocumentSize;
this.OutputDocumentCount = outputDocumentCount;
this.OutputDocumentSize = outputDocumentSize;
this.IndexHitRatio = indexHitRatio;
this.QueryPreparationTimesAccumulator = queryPreparationTimesAccumulator;
this.IndexLookupTime = indexLookupTime;
this.DocumentLoadTime = documentLoadTime;
this.RuntimeExecutionTimesAccumulator = runtimeExecutionTimesAccumulator;
this.DocumentWriteTime = documentWriteTime;
this.VMExecutionTime = vmExecutionTime;
}

public TimeSpan TotalTime { get; set; }
public long RetrievedDocumentCount { get; set; }
public long RetrievedDocumentSize { get; set; }
public long OutputDocumentCount { get; set; }
public long OutputDocumentSize { get; set; }
public double IndexHitRatio { get; set; }
public QueryPreparationTimesAccumulator QueryPreparationTimesAccumulator { get; set; }
public TimeSpan IndexLookupTime { get; set; }
public TimeSpan DocumentLoadTime { get; set; }
public RuntimeExecutionTimesAccumulator RuntimeExecutionTimesAccumulator { get; set; }
public TimeSpan DocumentWriteTime { get; set; }
public TimeSpan VMExecutionTime { get; set; }

public void Accumulate(BackendMetrics backendMetrics)
{
Maya-Painter marked this conversation as resolved.
Show resolved Hide resolved
this.TotalTime += backendMetrics.TotalTime;
this.RetrievedDocumentCount += backendMetrics.RetrievedDocumentCount;
this.RetrievedDocumentSize += backendMetrics.RetrievedDocumentSize;
this.OutputDocumentCount += backendMetrics.OutputDocumentCount;
this.OutputDocumentSize += backendMetrics.OutputDocumentSize;
this.IndexHitRatio = ((this.OutputDocumentCount * this.IndexHitRatio) + (backendMetrics.OutputDocumentCount * backendMetrics.IndexHitRatio)) / (this.RetrievedDocumentCount + backendMetrics.RetrievedDocumentCount);
this.QueryPreparationTimesAccumulator.Accumulate(backendMetrics.QueryPreparationTimes);
Maya-Painter marked this conversation as resolved.
Show resolved Hide resolved
this.IndexLookupTime += backendMetrics.IndexLookupTime;
this.DocumentLoadTime += backendMetrics.DocumentLoadTime;
this.RuntimeExecutionTimesAccumulator.Accumulate(backendMetrics.RuntimeExecutionTimes);
this.DocumentWriteTime += backendMetrics.DocumentWriteTime;
this.VMExecutionTime += backendMetrics.VMExecutionTime;
}

public static BackendMetrics ToBackendMetrics(BackendMetricsAccumulator accumulator)
{
return new BackendMetrics(
retrievedDocumentCount: accumulator.RetrievedDocumentCount,
retrievedDocumentSize: accumulator.RetrievedDocumentSize,
outputDocumentCount: accumulator.OutputDocumentCount,
outputDocumentSize: accumulator.OutputDocumentSize,
indexHitRatio: accumulator.IndexHitRatio,
totalQueryExecutionTime: accumulator.TotalTime,
queryPreparationTimes: QueryPreparationTimesAccumulator.ToQueryPreparationTimes(accumulator.QueryPreparationTimesAccumulator),
indexLookupTime: accumulator.IndexLookupTime,
documentLoadTime: accumulator.DocumentLoadTime,
vmExecutionTime: accumulator.VMExecutionTime,
runtimeExecutionTimes: RuntimeExecutionTimesAccumulator.ToRuntimeExecutionTimes(accumulator.RuntimeExecutionTimesAccumulator),
documentWriteTime: accumulator.DocumentWriteTime);
}

public static void WalkTraceTreeForQueryMetrics(ITrace currentTrace, BackendMetricsAccumulator accumulator)
{
if (currentTrace == null)
{
return;
}

foreach (object datum in currentTrace.Data.Values)
{
if (datum is QueryMetricsTraceDatum queryMetricsTraceDatum)
{
accumulator.Accumulate(queryMetricsTraceDatum.QueryMetrics.BackendMetrics);
Maya-Painter marked this conversation as resolved.
Show resolved Hide resolved
return;
}
}

foreach (ITrace childTrace in currentTrace.Children)
{
WalkTraceTreeForQueryMetrics(childTrace, accumulator);
}

return;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,42 +54,5 @@ public ClientSideMetrics(
/// Gets the Fetch Execution Ranges for this continuation of the query.
/// </summary>
public IEnumerable<FetchExecutionRange> FetchExecutionRanges { get; }

public ref struct Accumulator
{
public Accumulator(long retries, double requestCharge, IEnumerable<FetchExecutionRange> fetchExecutionRanges)
{
this.Retries = retries;
this.RequestCharge = requestCharge;
this.FetchExecutionRanges = fetchExecutionRanges;
}

public long Retries { get; }

public double RequestCharge { get; }

public IEnumerable<FetchExecutionRange> FetchExecutionRanges { get; }

public Accumulator Accumulate(ClientSideMetrics clientSideMetrics)
{
if (clientSideMetrics == null)
{
throw new ArgumentNullException(nameof(clientSideMetrics));
}

return new Accumulator(
retries: this.Retries + clientSideMetrics.Retries,
requestCharge: this.RequestCharge + clientSideMetrics.RequestCharge,
fetchExecutionRanges: (this.FetchExecutionRanges ?? Enumerable.Empty<FetchExecutionRange>()).Concat(clientSideMetrics.FetchExecutionRanges));
}

public static ClientSideMetrics ToClientSideMetrics(Accumulator accumulator)
{
return new ClientSideMetrics(
retries: accumulator.Retries,
requestCharge: accumulator.RequestCharge,
fetchExecutionRanges: accumulator.FetchExecutionRanges);
}
}
}
}
Loading
Loading