From b7b1064ab7e8bb0d90825c95125c5e1e2d74cb50 Mon Sep 17 00:00:00 2001 From: Maya-Painter <130110800+Maya-Painter@users.noreply.github.com> Date: Fri, 8 Sep 2023 12:39:48 -0700 Subject: [PATCH] [Query] Adds public backend metrics property to Diagnostics (#4001) * initial commit * some pr comments, WIP * Refactor * more * Public constructors and modify accumulators * accumulator updates and undo test changes * add test * PR comments * bug fix * ToString() refactor * contract updates * test updates * small fixes * text fix * Update accumulators * fix * PR comments * small fix * Rename BE -> ServerSide * more renaming * Update API and tests * separate public and internal classes * API update * change namespace * Pr comments * public constructors and bug fix * API updates * renaming and test updates * PR comments * more PR comments * PR comments, test additions * API updates and more tests * tests and pkrangeid update * PR comments * more PR comments * smol test fix * PR comments - renaming properties and constructor rehash * contract update * seal classes and private fields. * update indexHitRatio calc * mocking refactor to abstract classes * contract updates * PR comments - Update documentation --- .../src/Diagnostics/CosmosDiagnostics.cs | 13 + .../src/Diagnostics/CosmosTraceDiagnostics.cs | 24 +- .../src/Query/Core/Metrics/BackendMetrics.cs | 237 ------------------ .../Query/Core/Metrics/ClientSideMetrics.cs | 38 --- .../Metrics/ClientSideMetricsAccumulator.cs | 47 ++++ .../Core/Metrics/IndexUtilizationInfo.cs | 38 --- .../IndexUtilizationInfoAccumulator.cs | 51 ++++ .../src/Query/Core/Metrics/QueryMetrics.cs | 70 ++---- .../Core/Metrics/QueryMetricsAccumulator.cs | 48 ++++ .../Core/Metrics/QueryMetricsTextWriter.cs | 4 +- .../Query/Core/Metrics/QueryMetricsWriter.cs | 28 +-- .../Core/Metrics/QueryPreparationTimes.cs | 104 -------- .../QueryPreparationTimesAccumulator.cs | 51 ++++ .../Metrics/QueryPreparationTimesInternal.cs | 65 +++++ .../Core/Metrics/RuntimeExecutionTimes.cs | 91 ------- .../RuntimeExecutionTimesAccumulator.cs | 48 ++++ .../Metrics/RuntimeExecutionTimesInternal.cs | 56 +++++ .../Metrics/ServerSideCumulativeMetrics.cs | 23 ++ .../ServerSideCumulativeMetricsInternal.cs | 29 +++ .../Query/Core/Metrics/ServerSideMetrics.cs | 74 ++++++ .../Core/Metrics/ServerSideMetricsInternal.cs | 153 +++++++++++ .../ServerSideMetricsInternalAccumulator.cs | 146 +++++++++++ ...csParser.cs => ServerSideMetricsParser.cs} | 164 ++++++------ ...nizer.cs => ServerSideMetricsTokenizer.cs} | 4 +- .../Core/Metrics/ServerSideMetricsUtils.cs | 13 + .../Metrics/ServerSidePartitionedMetrics.cs | 27 ++ .../ServerSidePartitionedMetricsInternal.cs | 40 +++ .../CosmosItemTests.cs | 134 +++++++++- .../QueryStatisticsDatumVisitor.cs | 14 +- .../QueryTests.cs | 26 +- .../Query/Metrics/Performance.cs | 2 +- .../TraceWriterBaselineTests.TraceData.xml | 2 +- .../Contracts/DotNetSDKAPI.json | 193 ++++++++++++++ .../Query/Metrics/ClientSideMetricsTests.cs | 8 +- .../Metrics/IndexUtilizationInfoTests.cs | 9 +- .../Query/Metrics/QueryMetricsTests.cs | 16 +- ...ricsTests.cs => ServerSideMetricsTests.cs} | 68 ++--- .../Tracing/TraceWriterBaselineTests.cs | 4 +- 38 files changed, 1420 insertions(+), 742 deletions(-) delete mode 100644 Microsoft.Azure.Cosmos/src/Query/Core/Metrics/BackendMetrics.cs create mode 100644 Microsoft.Azure.Cosmos/src/Query/Core/Metrics/ClientSideMetricsAccumulator.cs create mode 100644 Microsoft.Azure.Cosmos/src/Query/Core/Metrics/IndexUtilizationInfoAccumulator.cs create mode 100644 Microsoft.Azure.Cosmos/src/Query/Core/Metrics/QueryMetricsAccumulator.cs delete mode 100644 Microsoft.Azure.Cosmos/src/Query/Core/Metrics/QueryPreparationTimes.cs create mode 100644 Microsoft.Azure.Cosmos/src/Query/Core/Metrics/QueryPreparationTimesAccumulator.cs create mode 100644 Microsoft.Azure.Cosmos/src/Query/Core/Metrics/QueryPreparationTimesInternal.cs delete mode 100644 Microsoft.Azure.Cosmos/src/Query/Core/Metrics/RuntimeExecutionTimes.cs create mode 100644 Microsoft.Azure.Cosmos/src/Query/Core/Metrics/RuntimeExecutionTimesAccumulator.cs create mode 100644 Microsoft.Azure.Cosmos/src/Query/Core/Metrics/RuntimeExecutionTimesInternal.cs create mode 100644 Microsoft.Azure.Cosmos/src/Query/Core/Metrics/ServerSideCumulativeMetrics.cs create mode 100644 Microsoft.Azure.Cosmos/src/Query/Core/Metrics/ServerSideCumulativeMetricsInternal.cs create mode 100644 Microsoft.Azure.Cosmos/src/Query/Core/Metrics/ServerSideMetrics.cs create mode 100644 Microsoft.Azure.Cosmos/src/Query/Core/Metrics/ServerSideMetricsInternal.cs create mode 100644 Microsoft.Azure.Cosmos/src/Query/Core/Metrics/ServerSideMetricsInternalAccumulator.cs rename Microsoft.Azure.Cosmos/src/Query/Core/Metrics/{BackendMetricsParser.cs => ServerSideMetricsParser.cs} (53%) rename Microsoft.Azure.Cosmos/src/Query/Core/Metrics/{BackendMetricsTokenizer.cs => ServerSideMetricsTokenizer.cs} (98%) create mode 100644 Microsoft.Azure.Cosmos/src/Query/Core/Metrics/ServerSideMetricsUtils.cs create mode 100644 Microsoft.Azure.Cosmos/src/Query/Core/Metrics/ServerSidePartitionedMetrics.cs create mode 100644 Microsoft.Azure.Cosmos/src/Query/Core/Metrics/ServerSidePartitionedMetricsInternal.cs rename Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Metrics/{BackendMetricsTests.cs => ServerSideMetricsTests.cs} (78%) diff --git a/Microsoft.Azure.Cosmos/src/Diagnostics/CosmosDiagnostics.cs b/Microsoft.Azure.Cosmos/src/Diagnostics/CosmosDiagnostics.cs index a82ef2ecc2..b88eaa8efe 100644 --- a/Microsoft.Azure.Cosmos/src/Diagnostics/CosmosDiagnostics.cs +++ b/Microsoft.Azure.Cosmos/src/Diagnostics/CosmosDiagnostics.cs @@ -43,6 +43,19 @@ public virtual int GetFailedRequestCount() throw new NotImplementedException($"{nameof(CosmosDiagnostics)}.{nameof(GetFailedRequestCount)}"); } + /// + /// This represents the backend query metrics for the request. + /// + /// + /// This is only applicable for query operations. For all other operations this will return null. + /// + /// The accumulated backend metrics for the request. + public virtual ServerSideCumulativeMetrics GetQueryMetrics() + { + // Default implementation avoids breaking change for users upgrading. + throw new NotImplementedException($"{nameof(CosmosDiagnostics)}.{nameof(GetQueryMetrics)}"); + } + /// /// Gets the string field instance in the Azure Cosmos DB database service. /// diff --git a/Microsoft.Azure.Cosmos/src/Diagnostics/CosmosTraceDiagnostics.cs b/Microsoft.Azure.Cosmos/src/Diagnostics/CosmosTraceDiagnostics.cs index 07e340f0ac..2d92a2cfb7 100644 --- a/Microsoft.Azure.Cosmos/src/Diagnostics/CosmosTraceDiagnostics.cs +++ b/Microsoft.Azure.Cosmos/src/Diagnostics/CosmosTraceDiagnostics.cs @@ -9,12 +9,15 @@ namespace Microsoft.Azure.Cosmos.Diagnostics 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; internal sealed class CosmosTraceDiagnostics : CosmosDiagnostics { + private readonly Lazy accumulatedMetrics; + public CosmosTraceDiagnostics(ITrace trace) { if (trace == null) @@ -30,6 +33,7 @@ public CosmosTraceDiagnostics(ITrace trace) } this.Value = rootTrace; + this.accumulatedMetrics = new Lazy(() => PopulateServerSideCumulativeMetrics(this.Value)); } public ITrace Value { get; } @@ -49,6 +53,11 @@ public override TimeSpan GetClientElapsedTime() return this.Value?.Summary?.RegionsContacted; } + public override ServerSideCumulativeMetrics GetQueryMetrics() + { + return this.accumulatedMetrics.Value; + } + internal bool IsGoneExceptionHit() { return this.WalkTraceTreeForGoneException(this.Value); @@ -61,9 +70,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) { @@ -99,6 +108,17 @@ private ReadOnlyMemory WriteTraceToJsonWriter(JsonSerializationFormat json return jsonTextWriter.GetResult(); } + private static ServerSideCumulativeMetrics PopulateServerSideCumulativeMetrics(ITrace trace) + { + ServerSideMetricsInternalAccumulator accumulator = new ServerSideMetricsInternalAccumulator(); + ServerSideMetricsInternalAccumulator.WalkTraceTreeForQueryMetrics(trace, accumulator); + + IReadOnlyList serverSideMetricsList = accumulator.GetPartitionedServerSideMetrics().Select(metrics => new ServerSidePartitionedMetricsInternal(metrics)).ToList(); + + ServerSideCumulativeMetrics accumulatedMetrics = new ServerSideCumulativeMetricsInternal(serverSideMetricsList); + return accumulatedMetrics.PartitionedMetrics.Count != 0 ? accumulatedMetrics : null; + } + public override DateTime? GetStartTimeUtc() { if (this.Value == null || this.Value.StartTime == null) diff --git a/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/BackendMetrics.cs b/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/BackendMetrics.cs deleted file mode 100644 index e958aee949..0000000000 --- a/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/BackendMetrics.cs +++ /dev/null @@ -1,237 +0,0 @@ -//------------------------------------------------------------ -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------ - -namespace Microsoft.Azure.Cosmos.Query.Core.Metrics -{ - using System; - using System.Collections.Generic; - - /// - /// Metrics received for queries from the backend. - /// -#if INTERNAL -#pragma warning disable SA1600 -#pragma warning disable CS1591 - public -#else - internal -#endif - sealed class BackendMetrics - { - /// - /// QueryMetrics that with all members having default (but not null) members. - /// - public static readonly BackendMetrics Empty = new BackendMetrics( - retrievedDocumentCount: default, - retrievedDocumentSize: default, - outputDocumentCount: default, - outputDocumentSize: default, - indexHitRatio: default, - totalQueryExecutionTime: default, - queryPreparationTimes: QueryPreparationTimes.Zero, - indexLookupTime: default, - documentLoadTime: default, - vmExecutionTime: default, - runtimeExecutionTimes: RuntimeExecutionTimes.Empty, - documentWriteTime: default); - - public BackendMetrics( - long retrievedDocumentCount, - long retrievedDocumentSize, - long outputDocumentCount, - long outputDocumentSize, - double indexHitRatio, - TimeSpan totalQueryExecutionTime, - QueryPreparationTimes queryPreparationTimes, - TimeSpan indexLookupTime, - TimeSpan documentLoadTime, - TimeSpan vmExecutionTime, - RuntimeExecutionTimes runtimeExecutionTimes, - TimeSpan documentWriteTime) - { - this.RetrievedDocumentCount = retrievedDocumentCount; - this.RetrievedDocumentSize = retrievedDocumentSize; - this.OutputDocumentCount = outputDocumentCount; - this.OutputDocumentSize = outputDocumentSize; - this.IndexHitRatio = indexHitRatio; - this.TotalTime = totalQueryExecutionTime; - this.QueryPreparationTimes = queryPreparationTimes ?? throw new ArgumentNullException($"{nameof(queryPreparationTimes)} can not be null."); - this.IndexLookupTime = indexLookupTime; - this.DocumentLoadTime = documentLoadTime; - this.VMExecutionTime = vmExecutionTime; - this.RuntimeExecutionTimes = runtimeExecutionTimes ?? throw new ArgumentNullException($"{nameof(runtimeExecutionTimes)} can not be null."); - this.DocumentWriteTime = documentWriteTime; - } - - /// - /// Gets the total query time in the Azure Cosmos database service. - /// - public TimeSpan TotalTime { get; } - - /// - /// Gets the number of documents retrieved during query in the Azure Cosmos database service. - /// - public long RetrievedDocumentCount { get; } - - /// - /// Gets the size of documents retrieved in bytes during query in the Azure Cosmos DB service. - /// - public long RetrievedDocumentSize { get; } - - /// - /// Gets the number of documents returned by query in the Azure Cosmos DB service. - /// - public long OutputDocumentCount { get; } - - /// - /// Gets the size of documents outputted in bytes during query in the Azure Cosmos database service. - /// - public long OutputDocumentSize { get; } - - /// - /// Gets the query QueryPreparationTimes in the Azure Cosmos database service. - /// - public QueryPreparationTimes QueryPreparationTimes { get; } - - /// - /// Gets the query index lookup time in the Azure Cosmos database service. - /// - public TimeSpan IndexLookupTime { get; } - - /// - /// Gets the document loading time during query in the Azure Cosmos database service. - /// - public TimeSpan DocumentLoadTime { get; } - - /// - /// Gets the query runtime execution times during query in the Azure Cosmos database service. - /// - public RuntimeExecutionTimes RuntimeExecutionTimes { get; } - - /// - /// Gets the output writing/serializing time during query in the Azure Cosmos database service. - /// - public TimeSpan DocumentWriteTime { get; } - - /// - /// Gets the index hit ratio by query in the Azure Cosmos database service. - /// - public double IndexHitRatio { get; } - - /// - /// Gets the VMExecution Time. - /// - public TimeSpan VMExecutionTime { get; } - - public override string ToString() - { - 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 backendMetricsEnumerable) - { - BackendMetrics.Accumulator accumulator = default; - foreach (BackendMetrics backendMetrics in backendMetricsEnumerable) - { - accumulator = accumulator.Accumulate(backendMetrics); - } - - return BackendMetrics.Accumulator.ToBackendMetrics(accumulator); - } - - public static bool TryParseFromDelimitedString(string delimitedString, out BackendMetrics backendMetrics) - { - return BackendMetricsParser.TryParse(delimitedString, out backendMetrics); - } - - public 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); - } - } - } -} diff --git a/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/ClientSideMetrics.cs b/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/ClientSideMetrics.cs index e69f4c5808..ff68271a69 100644 --- a/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/ClientSideMetrics.cs +++ b/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/ClientSideMetrics.cs @@ -5,7 +5,6 @@ namespace Microsoft.Azure.Cosmos.Query.Core.Metrics { using System; using System.Collections.Generic; - using System.Linq; /// /// Stores client side QueryMetrics. @@ -54,42 +53,5 @@ public ClientSideMetrics( /// Gets the Fetch Execution Ranges for this continuation of the query. /// public IEnumerable FetchExecutionRanges { get; } - - public ref struct Accumulator - { - public Accumulator(long retries, double requestCharge, IEnumerable fetchExecutionRanges) - { - this.Retries = retries; - this.RequestCharge = requestCharge; - this.FetchExecutionRanges = fetchExecutionRanges; - } - - public long Retries { get; } - - public double RequestCharge { get; } - - public IEnumerable 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()).Concat(clientSideMetrics.FetchExecutionRanges)); - } - - public static ClientSideMetrics ToClientSideMetrics(Accumulator accumulator) - { - return new ClientSideMetrics( - retries: accumulator.Retries, - requestCharge: accumulator.RequestCharge, - fetchExecutionRanges: accumulator.FetchExecutionRanges); - } - } } } diff --git a/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/ClientSideMetricsAccumulator.cs b/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/ClientSideMetricsAccumulator.cs new file mode 100644 index 0000000000..57816580b6 --- /dev/null +++ b/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/ClientSideMetricsAccumulator.cs @@ -0,0 +1,47 @@ +//------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------ +namespace Microsoft.Azure.Cosmos.Query.Core.Metrics +{ + using System; + using System.Collections.Generic; + + internal sealed class ClientSideMetricsAccumulator + { + private readonly List clientSideMetricsList; + + public ClientSideMetricsAccumulator() + { + this.clientSideMetricsList = new List(); + } + + public void Accumulate(ClientSideMetrics clientSideMetrics) + { + if (clientSideMetrics == null) + { + throw new ArgumentNullException(nameof(clientSideMetrics)); + } + + this.clientSideMetricsList.Add(clientSideMetrics); + } + + public ClientSideMetrics GetClientSideMetrics() + { + long retries = 0; + double requestCharge = 0; + List fetchExecutionRanges = new List(); + + foreach (ClientSideMetrics clientSideMetrics in this.clientSideMetricsList) + { + retries += clientSideMetrics.Retries; + requestCharge += clientSideMetrics.RequestCharge; + fetchExecutionRanges.AddRange(clientSideMetrics.FetchExecutionRanges); + } + + return new ClientSideMetrics( + retries: retries, + requestCharge: requestCharge, + fetchExecutionRanges: fetchExecutionRanges); + } + } +} diff --git a/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/IndexUtilizationInfo.cs b/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/IndexUtilizationInfo.cs index 2dba73132e..e34a7902ad 100644 --- a/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/IndexUtilizationInfo.cs +++ b/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/IndexUtilizationInfo.cs @@ -125,43 +125,5 @@ public static IndexUtilizationInfo CreateFromString(string delimitedString, bool return indexUtilizationInfo; } - - public ref struct Accumulator - { - public Accumulator( - IEnumerable utilizedSingleIndexes, - IEnumerable potentialSingleIndexes, - IEnumerable utilizedCompositeIndexes, - IEnumerable potentialCompositeIndexes) - { - this.UtilizedSingleIndexes = utilizedSingleIndexes; - this.PotentialSingleIndexes = potentialSingleIndexes; - this.UtilizedCompositeIndexes = utilizedCompositeIndexes; - this.PotentialCompositeIndexes = potentialCompositeIndexes; - } - - public IEnumerable UtilizedSingleIndexes { get; } - public IEnumerable PotentialSingleIndexes { get; } - public IEnumerable UtilizedCompositeIndexes { get; } - public IEnumerable PotentialCompositeIndexes { get; } - - public Accumulator Accumulate(IndexUtilizationInfo indexUtilizationInfo) - { - return new Accumulator( - utilizedSingleIndexes: (this.UtilizedSingleIndexes ?? Enumerable.Empty()).Concat(indexUtilizationInfo.UtilizedSingleIndexes), - potentialSingleIndexes: (this.PotentialSingleIndexes ?? Enumerable.Empty()).Concat(indexUtilizationInfo.PotentialSingleIndexes), - utilizedCompositeIndexes: (this.UtilizedCompositeIndexes ?? Enumerable.Empty()).Concat(indexUtilizationInfo.UtilizedCompositeIndexes), - potentialCompositeIndexes: (this.PotentialCompositeIndexes ?? Enumerable.Empty()).Concat(indexUtilizationInfo.PotentialCompositeIndexes)); - } - - public static IndexUtilizationInfo ToIndexUtilizationInfo(Accumulator accumulator) - { - return new IndexUtilizationInfo( - utilizedSingleIndexes: accumulator.UtilizedSingleIndexes.ToList(), - potentialSingleIndexes: accumulator.PotentialSingleIndexes.ToList(), - utilizedCompositeIndexes: accumulator.UtilizedCompositeIndexes.ToList(), - potentialCompositeIndexes: accumulator.PotentialCompositeIndexes.ToList()); - } - } } } diff --git a/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/IndexUtilizationInfoAccumulator.cs b/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/IndexUtilizationInfoAccumulator.cs new file mode 100644 index 0000000000..978abba77a --- /dev/null +++ b/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/IndexUtilizationInfoAccumulator.cs @@ -0,0 +1,51 @@ +//------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------ + +namespace Microsoft.Azure.Cosmos.Query.Core.Metrics +{ + using System; + using System.Collections.Generic; + + internal sealed class IndexUtilizationInfoAccumulator + { + private readonly List indexUtilizationInfoList; + + public IndexUtilizationInfoAccumulator() + { + this.indexUtilizationInfoList = new List(); + } + + public void Accumulate(IndexUtilizationInfo indexUtilizationInfo) + { + if (indexUtilizationInfo == null) + { + throw new ArgumentNullException(nameof(indexUtilizationInfo)); + } + + this.indexUtilizationInfoList.Add(indexUtilizationInfo); + } + + public IndexUtilizationInfo GetIndexUtilizationInfo() + { + List utilizedSingleIndexes = new List(); + List potentialSingleIndexes = new List(); + List utilizedCompositeIndexes = new List(); + List potentialCompositeIndexes = new List(); + + foreach (IndexUtilizationInfo indexUtilizationInfo in this.indexUtilizationInfoList) + { + utilizedSingleIndexes.AddRange(indexUtilizationInfo.UtilizedSingleIndexes); + potentialSingleIndexes.AddRange(indexUtilizationInfo.PotentialSingleIndexes); + utilizedCompositeIndexes.AddRange(indexUtilizationInfo.UtilizedCompositeIndexes); + potentialCompositeIndexes.AddRange(indexUtilizationInfo.PotentialCompositeIndexes); + } + + return new IndexUtilizationInfo( + utilizedSingleIndexes: utilizedSingleIndexes, + potentialSingleIndexes: potentialSingleIndexes, + utilizedCompositeIndexes: utilizedCompositeIndexes, + potentialCompositeIndexes: potentialCompositeIndexes); + } + } +} diff --git a/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/QueryMetrics.cs b/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/QueryMetrics.cs index 5a7e9377ed..ed3993d47e 100644 --- a/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/QueryMetrics.cs +++ b/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/QueryMetrics.cs @@ -29,11 +29,11 @@ sealed class QueryMetrics clientSideMetrics: ClientSideMetrics.Empty); public QueryMetrics( - BackendMetrics backendMetrics, - IndexUtilizationInfo indexUtilizationInfo, - ClientSideMetrics clientSideMetrics) + ServerSideMetricsInternal serverSideMetrics, + IndexUtilizationInfo indexUtilizationInfo, + ClientSideMetrics clientSideMetrics) { - this.BackendMetrics = backendMetrics ?? throw new ArgumentNullException(nameof(backendMetrics)); + this.ServerSideMetrics = serverSideMetrics ?? throw new ArgumentNullException(nameof(serverSideMetrics)); this.IndexUtilizationInfo = indexUtilizationInfo ?? throw new ArgumentNullException(nameof(indexUtilizationInfo)); this.ClientSideMetrics = clientSideMetrics ?? throw new ArgumentNullException(nameof(clientSideMetrics)); } @@ -43,13 +43,13 @@ public QueryMetrics( IndexUtilizationInfo indexUtilizationInfo, ClientSideMetrics clientSideMetrics) : this(!String.IsNullOrWhiteSpace(deliminatedString) && - BackendMetricsParser.TryParse(deliminatedString, out BackendMetrics backendMetrics) - ? backendMetrics - : BackendMetrics.Empty, indexUtilizationInfo, clientSideMetrics) + ServerSideMetricsParser.TryParse(deliminatedString, out ServerSideMetricsInternal serverSideMetrics) + ? serverSideMetrics + : ServerSideMetricsInternal.Empty, indexUtilizationInfo, clientSideMetrics) { } - public BackendMetrics BackendMetrics { get; } + public ServerSideMetricsInternal ServerSideMetrics { get; } public IndexUtilizationInfo IndexUtilizationInfo { get; } @@ -63,11 +63,11 @@ public QueryMetrics( /// A new instance that is the sum of two instances public static QueryMetrics operator +(QueryMetrics queryMetrics1, QueryMetrics queryMetrics2) { - QueryMetrics.Accumulator queryMetricsAccumulator = new QueryMetrics.Accumulator(); - queryMetricsAccumulator = queryMetricsAccumulator.Accumulate(queryMetrics1); - queryMetricsAccumulator = queryMetricsAccumulator.Accumulate(queryMetrics2); + QueryMetricsAccumulator queryMetricsAccumulator = new QueryMetricsAccumulator(); + queryMetricsAccumulator.Accumulate(queryMetrics1); + queryMetricsAccumulator.Accumulate(queryMetrics2); - return QueryMetrics.Accumulator.ToQueryMetrics(queryMetricsAccumulator); + return queryMetricsAccumulator.GetQueryMetrics(); } /// @@ -94,53 +94,13 @@ public static QueryMetrics CreateFromIEnumerable(IEnumerable query throw new ArgumentNullException(nameof(queryMetricsList)); } - QueryMetrics.Accumulator queryMetricsAccumulator = new QueryMetrics.Accumulator(); + QueryMetricsAccumulator queryMetricsAccumulator = new QueryMetricsAccumulator(); foreach (QueryMetrics queryMetrics in queryMetricsList) { - queryMetricsAccumulator = queryMetricsAccumulator.Accumulate(queryMetrics); + queryMetricsAccumulator.Accumulate(queryMetrics); } - return QueryMetrics.Accumulator.ToQueryMetrics(queryMetricsAccumulator); - } - - public ref struct Accumulator - { - public Accumulator( - BackendMetrics.Accumulator backendMetricsAccumulator, - IndexUtilizationInfo.Accumulator indexUtilizationInfoAccumulator, - ClientSideMetrics.Accumulator clientSideMetricsAccumulator) - { - this.BackendMetricsAccumulator = backendMetricsAccumulator; - this.IndexUtilizationInfoAccumulator = indexUtilizationInfoAccumulator; - this.ClientSideMetricsAccumulator = clientSideMetricsAccumulator; - } - - public BackendMetrics.Accumulator BackendMetricsAccumulator { get; } - - public IndexUtilizationInfo.Accumulator IndexUtilizationInfoAccumulator { get; } - - public ClientSideMetrics.Accumulator ClientSideMetricsAccumulator { get; } - - public Accumulator Accumulate(QueryMetrics queryMetrics) - { - if (queryMetrics == null) - { - throw new ArgumentNullException(nameof(queryMetrics)); - } - - return new Accumulator( - backendMetricsAccumulator: this.BackendMetricsAccumulator.Accumulate(queryMetrics.BackendMetrics), - indexUtilizationInfoAccumulator: this.IndexUtilizationInfoAccumulator.Accumulate(queryMetrics.IndexUtilizationInfo), - clientSideMetricsAccumulator: this.ClientSideMetricsAccumulator.Accumulate(queryMetrics.ClientSideMetrics)); - } - - public static QueryMetrics ToQueryMetrics(Accumulator accumulator) - { - return new QueryMetrics( - BackendMetrics.Accumulator.ToBackendMetrics(accumulator.BackendMetricsAccumulator), - IndexUtilizationInfo.Accumulator.ToIndexUtilizationInfo(accumulator.IndexUtilizationInfoAccumulator), - ClientSideMetrics.Accumulator.ToClientSideMetrics(accumulator.ClientSideMetricsAccumulator)); - } + return queryMetricsAccumulator.GetQueryMetrics(); } } } \ No newline at end of file diff --git a/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/QueryMetricsAccumulator.cs b/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/QueryMetricsAccumulator.cs new file mode 100644 index 0000000000..b6b817e95d --- /dev/null +++ b/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/QueryMetricsAccumulator.cs @@ -0,0 +1,48 @@ +//------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------ + +namespace Microsoft.Azure.Cosmos.Query.Core.Metrics +{ + using System; + using System.Collections.Generic; + + internal sealed class QueryMetricsAccumulator + { + private readonly List queryMetricsList; + + public QueryMetricsAccumulator() + { + this.queryMetricsList = new List(); + } + + public void Accumulate(QueryMetrics queryMetrics) + { + if (queryMetrics == null) + { + throw new ArgumentNullException(nameof(queryMetrics)); + } + + this.queryMetricsList.Add(queryMetrics); + } + + public QueryMetrics GetQueryMetrics() + { + ServerSideMetricsInternalAccumulator serverSideMetricsAccumulator = new ServerSideMetricsInternalAccumulator(); + IndexUtilizationInfoAccumulator indexUtilizationInfoAccumulator = new IndexUtilizationInfoAccumulator(); + ClientSideMetricsAccumulator clientSideMetricsAccumulator = new ClientSideMetricsAccumulator(); + + foreach (QueryMetrics queryMetrics in this.queryMetricsList) + { + serverSideMetricsAccumulator.Accumulate(queryMetrics.ServerSideMetrics); + indexUtilizationInfoAccumulator.Accumulate(queryMetrics.IndexUtilizationInfo); + clientSideMetricsAccumulator.Accumulate(queryMetrics.ClientSideMetrics); + } + + return new QueryMetrics( + serverSideMetricsAccumulator.GetServerSideMetrics(), + indexUtilizationInfoAccumulator.GetIndexUtilizationInfo(), + clientSideMetricsAccumulator.GetClientSideMetrics()); + } + } +} diff --git a/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/QueryMetricsTextWriter.cs b/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/QueryMetricsTextWriter.cs index bd634815e9..1802e60e28 100644 --- a/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/QueryMetricsTextWriter.cs +++ b/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/QueryMetricsTextWriter.cs @@ -215,7 +215,7 @@ protected override void WriteTotalQueryExecutionTime(TimeSpan totalQueryExecutio indentLevel: 0); } - protected override void WriteQueryPreparationTime(QueryPreparationTimes queryPreparationTimes) + protected override void WriteQueryPreparationTime(QueryPreparationTimesInternal queryPreparationTimes) { QueryMetricsTextWriter.AppendTimeSpanToStringBuilder( this.stringBuilder, @@ -250,7 +250,7 @@ protected override void WriteVMExecutionTime(TimeSpan vmExecutionTime) // Do Nothing } - protected override void WriteRuntimeExecutionTime(RuntimeExecutionTimes runtimeExecutionTimes) + protected override void WriteRuntimeExecutionTime(RuntimeExecutionTimesInternal runtimeExecutionTimes) { QueryMetricsTextWriter.AppendTimeSpanToStringBuilder( this.stringBuilder, diff --git a/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/QueryMetricsWriter.cs b/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/QueryMetricsWriter.cs index 2fbb455152..f0d6f7b0fa 100644 --- a/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/QueryMetricsWriter.cs +++ b/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/QueryMetricsWriter.cs @@ -23,25 +23,25 @@ public void WriteQueryMetrics(QueryMetrics queryMetrics) this.WriteBeforeQueryMetrics(); // Top Level Properties - this.WriteRetrievedDocumentCount(queryMetrics.BackendMetrics.RetrievedDocumentCount); - this.WriteRetrievedDocumentSize(queryMetrics.BackendMetrics.RetrievedDocumentSize); - this.WriteOutputDocumentCount(queryMetrics.BackendMetrics.OutputDocumentCount); - this.WriteOutputDocumentSize(queryMetrics.BackendMetrics.OutputDocumentSize); - this.WriteIndexHitRatio(queryMetrics.BackendMetrics.IndexHitRatio); + this.WriteRetrievedDocumentCount(queryMetrics.ServerSideMetrics.RetrievedDocumentCount); + this.WriteRetrievedDocumentSize(queryMetrics.ServerSideMetrics.RetrievedDocumentSize); + this.WriteOutputDocumentCount(queryMetrics.ServerSideMetrics.OutputDocumentCount); + this.WriteOutputDocumentSize(queryMetrics.ServerSideMetrics.OutputDocumentSize); + this.WriteIndexHitRatio(queryMetrics.ServerSideMetrics.IndexHitRatio); - this.WriteTotalQueryExecutionTime(queryMetrics.BackendMetrics.TotalTime); + this.WriteTotalQueryExecutionTime(queryMetrics.ServerSideMetrics.TotalTime); // QueryPreparationTimes - this.WriteQueryPreparationTime(queryMetrics.BackendMetrics.QueryPreparationTimes); + this.WriteQueryPreparationTime(queryMetrics.ServerSideMetrics.QueryPreparationTimes); - this.WriteIndexLookupTime(queryMetrics.BackendMetrics.IndexLookupTime); - this.WriteDocumentLoadTime(queryMetrics.BackendMetrics.DocumentLoadTime); - this.WriteVMExecutionTime(queryMetrics.BackendMetrics.VMExecutionTime); + this.WriteIndexLookupTime(queryMetrics.ServerSideMetrics.IndexLookupTime); + this.WriteDocumentLoadTime(queryMetrics.ServerSideMetrics.DocumentLoadTime); + this.WriteVMExecutionTime(queryMetrics.ServerSideMetrics.VMExecutionTime); // RuntimesExecutionTimes - this.WriteRuntimeExecutionTime(queryMetrics.BackendMetrics.RuntimeExecutionTimes); + this.WriteRuntimeExecutionTime(queryMetrics.ServerSideMetrics.RuntimeExecutionTimes); - this.WriteDocumentWriteTime(queryMetrics.BackendMetrics.DocumentWriteTime); + this.WriteDocumentWriteTime(queryMetrics.ServerSideMetrics.DocumentWriteTime); #if false // ClientSideMetrics this.WriteClientSideMetrics(queryMetrics.ClientSideMetrics); @@ -70,7 +70,7 @@ public void WriteQueryMetrics(QueryMetrics queryMetrics) protected abstract void WriteTotalQueryExecutionTime(TimeSpan totalQueryExecutionTime); - protected abstract void WriteQueryPreparationTime(QueryPreparationTimes queryPreparationTimes); + protected abstract void WriteQueryPreparationTime(QueryPreparationTimesInternal queryPreparationTimes); protected abstract void WriteIndexLookupTime(TimeSpan indexLookupTime); @@ -78,7 +78,7 @@ public void WriteQueryMetrics(QueryMetrics queryMetrics) protected abstract void WriteVMExecutionTime(TimeSpan vMExecutionTime); - protected abstract void WriteRuntimeExecutionTime(RuntimeExecutionTimes runtimeExecutionTimes); + protected abstract void WriteRuntimeExecutionTime(RuntimeExecutionTimesInternal runtimeExecutionTimes); protected abstract void WriteDocumentWriteTime(TimeSpan documentWriteTime); diff --git a/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/QueryPreparationTimes.cs b/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/QueryPreparationTimes.cs deleted file mode 100644 index 4b2d3b1b20..0000000000 --- a/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/QueryPreparationTimes.cs +++ /dev/null @@ -1,104 +0,0 @@ -//------------------------------------------------------------ -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------ -namespace Microsoft.Azure.Cosmos.Query.Core.Metrics -{ - using System; - - /// - /// Query preparation metrics in the Azure DocumentDB database service. - /// -#if INTERNAL -#pragma warning disable SA1600 -#pragma warning disable CS1591 - public -#else - internal -#endif - sealed class QueryPreparationTimes - { - public static readonly QueryPreparationTimes Zero = new QueryPreparationTimes( - queryCompilationTime: default, - logicalPlanBuildTime: default, - physicalPlanBuildTime: default, - queryOptimizationTime: default); - - /// - /// Initializes a new instance of the QueryPreparationTimes class. - /// - /// Query compile and optimization time - /// Query logical plan build time - /// Query physical plan build time - /// Query optimization time - public QueryPreparationTimes( - TimeSpan queryCompilationTime, - TimeSpan logicalPlanBuildTime, - TimeSpan physicalPlanBuildTime, - TimeSpan queryOptimizationTime) - { - this.QueryCompilationTime = queryCompilationTime; - this.LogicalPlanBuildTime = logicalPlanBuildTime; - this.PhysicalPlanBuildTime = physicalPlanBuildTime; - this.QueryOptimizationTime = queryOptimizationTime; - } - - /// - /// Gets the query compile time in the Azure DocumentDB database service. - /// - public TimeSpan QueryCompilationTime { get; } - - /// - /// Gets the query logical plan build time in the Azure DocumentDB database service. - /// - public TimeSpan LogicalPlanBuildTime { get; } - - /// - /// Gets the query physical plan build time in the Azure DocumentDB database service. - /// - public TimeSpan PhysicalPlanBuildTime { get; } - - /// - /// Gets the query optimization time in the Azure DocumentDB database service. - /// - public TimeSpan QueryOptimizationTime { get; } - - public ref struct Accumulator - { - public Accumulator(TimeSpan queryCompliationTime, TimeSpan logicalPlanBuildTime, TimeSpan physicalPlanBuildTime, TimeSpan queryOptimizationTime) - { - this.QueryCompilationTime = queryCompliationTime; - this.LogicalPlanBuildTime = logicalPlanBuildTime; - this.PhysicalPlanBuildTime = physicalPlanBuildTime; - this.QueryOptimizationTime = queryOptimizationTime; - } - - public TimeSpan QueryCompilationTime { get; } - public TimeSpan LogicalPlanBuildTime { get; } - public TimeSpan PhysicalPlanBuildTime { get; } - public TimeSpan QueryOptimizationTime { get; } - - public Accumulator Accumulate(QueryPreparationTimes queryPreparationTimes) - { - if (queryPreparationTimes == null) - { - throw new ArgumentNullException(nameof(queryPreparationTimes)); - } - - return new Accumulator( - queryCompliationTime: this.QueryCompilationTime + queryPreparationTimes.QueryCompilationTime, - logicalPlanBuildTime: this.LogicalPlanBuildTime + queryPreparationTimes.LogicalPlanBuildTime, - physicalPlanBuildTime: this.PhysicalPlanBuildTime + queryPreparationTimes.PhysicalPlanBuildTime, - queryOptimizationTime: this.QueryOptimizationTime + queryPreparationTimes.QueryOptimizationTime); - } - - public static QueryPreparationTimes ToQueryPreparationTimes(QueryPreparationTimes.Accumulator accumulator) - { - return new QueryPreparationTimes( - queryCompilationTime: accumulator.QueryCompilationTime, - logicalPlanBuildTime: accumulator.LogicalPlanBuildTime, - physicalPlanBuildTime: accumulator.PhysicalPlanBuildTime, - queryOptimizationTime: accumulator.QueryOptimizationTime); - } - } - } -} \ No newline at end of file diff --git a/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/QueryPreparationTimesAccumulator.cs b/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/QueryPreparationTimesAccumulator.cs new file mode 100644 index 0000000000..6b79e8c1f8 --- /dev/null +++ b/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/QueryPreparationTimesAccumulator.cs @@ -0,0 +1,51 @@ +//------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------ + +namespace Microsoft.Azure.Cosmos.Query.Core.Metrics +{ + using System; + using System.Collections.Generic; + + internal sealed class QueryPreparationTimesAccumulator + { + private readonly List queryPreparationTimesList; + + public QueryPreparationTimesAccumulator() + { + this.queryPreparationTimesList = new List(); + } + + public void Accumulate(QueryPreparationTimesInternal queryPreparationTimes) + { + if (queryPreparationTimes == null) + { + throw new ArgumentNullException(nameof(queryPreparationTimes)); + } + + this.queryPreparationTimesList.Add(queryPreparationTimes); + } + + public QueryPreparationTimesInternal GetQueryPreparationTimes() + { + TimeSpan queryCompilationTime = TimeSpan.Zero; + TimeSpan logicalPlanBuildTime = TimeSpan.Zero; + TimeSpan physicalPlanBuildTime = TimeSpan.Zero; + TimeSpan queryOptimizationTime = TimeSpan.Zero; + + foreach (QueryPreparationTimesInternal queryPreparationTimes in this.queryPreparationTimesList) + { + queryCompilationTime += queryPreparationTimes.QueryCompilationTime; + logicalPlanBuildTime += queryPreparationTimes.LogicalPlanBuildTime; + physicalPlanBuildTime += queryPreparationTimes.PhysicalPlanBuildTime; + queryOptimizationTime += queryPreparationTimes.QueryOptimizationTime; + } + + return new QueryPreparationTimesInternal( + queryCompilationTime: queryCompilationTime, + logicalPlanBuildTime: logicalPlanBuildTime, + physicalPlanBuildTime: physicalPlanBuildTime, + queryOptimizationTime: queryOptimizationTime); + } + } +} diff --git a/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/QueryPreparationTimesInternal.cs b/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/QueryPreparationTimesInternal.cs new file mode 100644 index 0000000000..4e8ee38276 --- /dev/null +++ b/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/QueryPreparationTimesInternal.cs @@ -0,0 +1,65 @@ +//------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------ +namespace Microsoft.Azure.Cosmos.Query.Core.Metrics +{ + using System; + + /// + /// Query preparation metrics in the Azure DocumentDB database service. + /// +#if INTERNAL +#pragma warning disable SA1600 +#pragma warning disable CS1591 + public +#else + internal +#endif + sealed class QueryPreparationTimesInternal + { + public static readonly QueryPreparationTimesInternal Zero = new QueryPreparationTimesInternal( + queryCompilationTime: TimeSpan.Zero, + logicalPlanBuildTime: TimeSpan.Zero, + physicalPlanBuildTime: TimeSpan.Zero, + queryOptimizationTime: TimeSpan.Zero); + + /// + /// Initializes a new instance of the QueryPreparationTimes class. + /// + /// Query compile and optimization time + /// Query logical plan build time + /// Query physical plan build time + /// Query optimization time + public QueryPreparationTimesInternal( + TimeSpan queryCompilationTime, + TimeSpan logicalPlanBuildTime, + TimeSpan physicalPlanBuildTime, + TimeSpan queryOptimizationTime) + { + this.QueryCompilationTime = queryCompilationTime; + this.LogicalPlanBuildTime = logicalPlanBuildTime; + this.PhysicalPlanBuildTime = physicalPlanBuildTime; + this.QueryOptimizationTime = queryOptimizationTime; + } + + /// + /// Gets the query compile time in the Azure DocumentDB database service. + /// + public TimeSpan QueryCompilationTime { get; } + + /// + /// Gets the query logical plan build time in the Azure DocumentDB database service. + /// + public TimeSpan LogicalPlanBuildTime { get; } + + /// + /// Gets the query physical plan build time in the Azure DocumentDB database service. + /// + public TimeSpan PhysicalPlanBuildTime { get; } + + /// + /// Gets the query optimization time in the Azure DocumentDB database service. + /// + public TimeSpan QueryOptimizationTime { get; } + } +} \ No newline at end of file diff --git a/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/RuntimeExecutionTimes.cs b/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/RuntimeExecutionTimes.cs deleted file mode 100644 index 0fd8dc22f0..0000000000 --- a/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/RuntimeExecutionTimes.cs +++ /dev/null @@ -1,91 +0,0 @@ -//------------------------------------------------------------ -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------ -namespace Microsoft.Azure.Cosmos.Query.Core.Metrics -{ - using System; - - /// - /// Query runtime execution times in the Azure Cosmos DB service. - /// -#if INTERNAL -#pragma warning disable SA1600 -#pragma warning disable CS1591 - public -#else - internal -#endif - sealed class RuntimeExecutionTimes - { - public static readonly RuntimeExecutionTimes Empty = new RuntimeExecutionTimes( - queryEngineExecutionTime: default, - systemFunctionExecutionTime: default, - userDefinedFunctionExecutionTime: default); - - /// - /// Initializes a new instance of the RuntimeExecutionTimes class. - /// - /// Query end - to - end execution time - /// Total time spent executing system functions - /// Total time spent executing user - defined functions - public RuntimeExecutionTimes( - TimeSpan queryEngineExecutionTime, - TimeSpan systemFunctionExecutionTime, - TimeSpan userDefinedFunctionExecutionTime) - { - this.QueryEngineExecutionTime = queryEngineExecutionTime; - this.SystemFunctionExecutionTime = systemFunctionExecutionTime; - this.UserDefinedFunctionExecutionTime = userDefinedFunctionExecutionTime; - } - - /// - /// Gets the total query runtime execution time in the Azure Cosmos DB service. - /// - public TimeSpan QueryEngineExecutionTime { get; } - - /// - /// Gets the query system function execution time in the Azure Cosmos DB service. - /// - public TimeSpan SystemFunctionExecutionTime { get; } - - /// - /// Gets the query user defined function execution time in the Azure Cosmos DB service. - /// - public TimeSpan UserDefinedFunctionExecutionTime { get; } - - public ref struct Accumulator - { - public Accumulator(TimeSpan queryEngineExecutionTime, TimeSpan systemFunctionExecutionTime, TimeSpan userDefinedFunctionExecutionTimes) - { - this.QueryEngineExecutionTime = queryEngineExecutionTime; - this.SystemFunctionExecutionTime = systemFunctionExecutionTime; - this.UserDefinedFunctionExecutionTime = userDefinedFunctionExecutionTimes; - } - - public TimeSpan QueryEngineExecutionTime { get; set; } - public TimeSpan SystemFunctionExecutionTime { get; set; } - public TimeSpan UserDefinedFunctionExecutionTime { get; set; } - - public Accumulator Accumulate(RuntimeExecutionTimes runtimeExecutionTimes) - { - if (runtimeExecutionTimes == null) - { - throw new ArgumentNullException(nameof(runtimeExecutionTimes)); - } - - return new Accumulator( - queryEngineExecutionTime: this.QueryEngineExecutionTime + runtimeExecutionTimes.QueryEngineExecutionTime, - systemFunctionExecutionTime: this.SystemFunctionExecutionTime + runtimeExecutionTimes.SystemFunctionExecutionTime, - userDefinedFunctionExecutionTimes: this.UserDefinedFunctionExecutionTime + runtimeExecutionTimes.UserDefinedFunctionExecutionTime); - } - - public static RuntimeExecutionTimes ToRuntimeExecutionTimes(Accumulator accumulator) - { - return new RuntimeExecutionTimes( - queryEngineExecutionTime: accumulator.QueryEngineExecutionTime, - systemFunctionExecutionTime: accumulator.SystemFunctionExecutionTime, - userDefinedFunctionExecutionTime: accumulator.UserDefinedFunctionExecutionTime); - } - } - } -} \ No newline at end of file diff --git a/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/RuntimeExecutionTimesAccumulator.cs b/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/RuntimeExecutionTimesAccumulator.cs new file mode 100644 index 0000000000..60f5e37573 --- /dev/null +++ b/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/RuntimeExecutionTimesAccumulator.cs @@ -0,0 +1,48 @@ +//------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------ + +namespace Microsoft.Azure.Cosmos.Query.Core.Metrics +{ + using System; + using System.Collections.Generic; + + internal sealed class RuntimeExecutionTimesAccumulator + { + private readonly List runtimeExecutionTimesList; + + public RuntimeExecutionTimesAccumulator() + { + this.runtimeExecutionTimesList = new List(); + } + + public void Accumulate(RuntimeExecutionTimesInternal runtimeExecutionTimes) + { + if (runtimeExecutionTimes == null) + { + throw new ArgumentNullException(nameof(runtimeExecutionTimes)); + } + + this.runtimeExecutionTimesList.Add(runtimeExecutionTimes); + } + + public RuntimeExecutionTimesInternal GetRuntimeExecutionTimes() + { + TimeSpan queryEngineExecutionTime = TimeSpan.Zero; + TimeSpan systemFunctionExecutionTime = TimeSpan.Zero; + TimeSpan userDefinedFunctionExecutionTime = TimeSpan.Zero; + + foreach (RuntimeExecutionTimesInternal runtimeExecutionTimes in this.runtimeExecutionTimesList) + { + queryEngineExecutionTime += runtimeExecutionTimes.QueryEngineExecutionTime; + systemFunctionExecutionTime += runtimeExecutionTimes.SystemFunctionExecutionTime; + userDefinedFunctionExecutionTime += runtimeExecutionTimes.UserDefinedFunctionExecutionTime; + } + + return new RuntimeExecutionTimesInternal( + queryEngineExecutionTime: queryEngineExecutionTime, + systemFunctionExecutionTime: systemFunctionExecutionTime, + userDefinedFunctionExecutionTime: userDefinedFunctionExecutionTime); + } + } +} diff --git a/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/RuntimeExecutionTimesInternal.cs b/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/RuntimeExecutionTimesInternal.cs new file mode 100644 index 0000000000..bbd97ca45d --- /dev/null +++ b/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/RuntimeExecutionTimesInternal.cs @@ -0,0 +1,56 @@ +//------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------ +namespace Microsoft.Azure.Cosmos.Query.Core.Metrics +{ + using System; + + /// + /// Query runtime execution times in the Azure Cosmos DB service. + /// +#if INTERNAL +#pragma warning disable SA1600 +#pragma warning disable CS1591 + public +#else + internal +#endif + sealed class RuntimeExecutionTimesInternal + { + public static readonly RuntimeExecutionTimesInternal Empty = new RuntimeExecutionTimesInternal( + queryEngineExecutionTime: TimeSpan.Zero, + systemFunctionExecutionTime: TimeSpan.Zero, + userDefinedFunctionExecutionTime: TimeSpan.Zero); + + /// + /// Initializes a new instance of the RuntimeExecutionTimes class. + /// + /// Query end - to - end execution time + /// Total time spent executing system functions + /// Total time spent executing user - defined functions + public RuntimeExecutionTimesInternal( + TimeSpan queryEngineExecutionTime, + TimeSpan systemFunctionExecutionTime, + TimeSpan userDefinedFunctionExecutionTime) + { + this.QueryEngineExecutionTime = queryEngineExecutionTime; + this.SystemFunctionExecutionTime = systemFunctionExecutionTime; + this.UserDefinedFunctionExecutionTime = userDefinedFunctionExecutionTime; + } + + /// + /// Gets the total query runtime execution time in the Azure Cosmos DB service. + /// + public TimeSpan QueryEngineExecutionTime { get; } + + /// + /// Gets the query system function execution time in the Azure Cosmos DB service. + /// + public TimeSpan SystemFunctionExecutionTime { get; } + + /// + /// Gets the query user defined function execution time in the Azure Cosmos DB service. + /// + public TimeSpan UserDefinedFunctionExecutionTime { get; } + } +} \ No newline at end of file diff --git a/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/ServerSideCumulativeMetrics.cs b/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/ServerSideCumulativeMetrics.cs new file mode 100644 index 0000000000..3e7364f957 --- /dev/null +++ b/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/ServerSideCumulativeMetrics.cs @@ -0,0 +1,23 @@ +//------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------ +namespace Microsoft.Azure.Cosmos +{ + using System.Collections.Generic; + + /// + /// Metrics received for queries from the backend. + /// + public abstract class ServerSideCumulativeMetrics + { + /// + /// Gets the ServerSideMetrics accumulated for a single round trip. + /// + public abstract ServerSideMetrics CumulativeMetrics { get; } + + /// + /// Gets the list of ServerSideMetrics, one for for each partition. + /// + public abstract IReadOnlyList PartitionedMetrics { get; } + } +} diff --git a/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/ServerSideCumulativeMetricsInternal.cs b/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/ServerSideCumulativeMetricsInternal.cs new file mode 100644 index 0000000000..5405482bb5 --- /dev/null +++ b/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/ServerSideCumulativeMetricsInternal.cs @@ -0,0 +1,29 @@ +//------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------ +namespace Microsoft.Azure.Cosmos +{ + using System.Collections.Generic; + using System.Linq; + using Microsoft.Azure.Cosmos.Query.Core.Metrics; + + /// + /// Internal implementation of metrics received for queries from the backend. + /// + internal class ServerSideCumulativeMetricsInternal : ServerSideCumulativeMetrics + { + /// + /// Initializes a new instance of the class. + /// + /// + internal ServerSideCumulativeMetricsInternal(IEnumerable serverSideMetricsList) + { + this.PartitionedMetrics = serverSideMetricsList.ToList(); + this.CumulativeMetrics = ServerSideMetricsInternal.Create(serverSideMetricsList.Select(partitionedMetrics => partitionedMetrics.ServerSideMetricsInternal)); + } + + public override ServerSideMetrics CumulativeMetrics { get; } + + public override IReadOnlyList PartitionedMetrics { get; } + } +} diff --git a/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/ServerSideMetrics.cs b/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/ServerSideMetrics.cs new file mode 100644 index 0000000000..ff215a582e --- /dev/null +++ b/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/ServerSideMetrics.cs @@ -0,0 +1,74 @@ +//------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------ + +namespace Microsoft.Azure.Cosmos +{ + using System; + + /// + /// Metrics received for queries from the backend. + /// + public abstract class ServerSideMetrics + { + /// + /// Gets the total query time in the Azure Cosmos database service. + /// + public abstract TimeSpan TotalTime { get; } + + /// + /// Gets the number of documents retrieved during query in the Azure Cosmos database service. + /// + public abstract long RetrievedDocumentCount { get; } + + /// + /// Gets the size of documents retrieved in bytes during query in the Azure Cosmos DB service. + /// + public abstract long RetrievedDocumentSize { get; } + + /// + /// Gets the number of documents returned by query in the Azure Cosmos DB service. + /// + public abstract long OutputDocumentCount { get; } + + /// + /// Gets the size of documents outputted in bytes during query in the Azure Cosmos database service. + /// + public abstract long OutputDocumentSize { get; } + + /// + /// Gets the query preparation time in the Azure Cosmos database service. + /// + public abstract TimeSpan QueryPreparationTime { get; } + + /// + /// Gets the query index lookup time in the Azure Cosmos database service. + /// + public abstract TimeSpan IndexLookupTime { get; } + + /// + /// Gets the document loading time during query in the Azure Cosmos database service. + /// + public abstract TimeSpan DocumentLoadTime { get; } + + /// + /// Gets the query runtime execution time during query in the Azure Cosmos database service. + /// + public abstract TimeSpan RuntimeExecutionTime { get; } + + /// + /// Gets the output writing/serializing time during query in the Azure Cosmos database service. + /// + public abstract TimeSpan DocumentWriteTime { get; } + + /// + /// Gets the index hit ratio by query in the Azure Cosmos database service. Value is within the range [0,1]. + /// + public abstract double IndexHitRatio { get; } + + /// + /// Gets the VMExecution Time. + /// + public abstract TimeSpan VMExecutionTime { get; } + } +} diff --git a/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/ServerSideMetricsInternal.cs b/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/ServerSideMetricsInternal.cs new file mode 100644 index 0000000000..6e80de06a5 --- /dev/null +++ b/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/ServerSideMetricsInternal.cs @@ -0,0 +1,153 @@ +//------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------ + +namespace Microsoft.Azure.Cosmos.Query.Core.Metrics +{ + using System; + using System.Collections.Generic; + + /// + /// internal implementation of metrics received for queries from the backend. + /// +#if INTERNAL +#pragma warning disable SA1600 +#pragma warning disable CS1591 + public +#else + internal +#endif + sealed class ServerSideMetricsInternal : ServerSideMetrics + { + /// + /// QueryMetrics with all members having default (but not null) members. + /// + public static readonly ServerSideMetricsInternal Empty = new ServerSideMetricsInternal( + retrievedDocumentCount: 0, + retrievedDocumentSize: 0, + outputDocumentCount: 0, + outputDocumentSize: 0, + indexHitRatio: 0, + totalQueryExecutionTime: TimeSpan.Zero, + queryPreparationTimes: QueryPreparationTimesInternal.Zero, + indexLookupTime: TimeSpan.Zero, + documentLoadTime: TimeSpan.Zero, + vmExecutionTime: TimeSpan.Zero, + runtimeExecutionTimes: RuntimeExecutionTimesInternal.Empty, + documentWriteTime: TimeSpan.Zero); + + /// + /// Initializes a new instance of the class. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public ServerSideMetricsInternal( + long retrievedDocumentCount, + long retrievedDocumentSize, + long outputDocumentCount, + long outputDocumentSize, + double indexHitRatio, + TimeSpan totalQueryExecutionTime, + QueryPreparationTimesInternal queryPreparationTimes, + TimeSpan indexLookupTime, + TimeSpan documentLoadTime, + TimeSpan vmExecutionTime, + RuntimeExecutionTimesInternal runtimeExecutionTimes, + TimeSpan documentWriteTime, + string feedRange = null, + int? partitionKeyRangeId = null) + { + this.RetrievedDocumentCount = retrievedDocumentCount; + this.RetrievedDocumentSize = retrievedDocumentSize; + this.OutputDocumentCount = outputDocumentCount; + this.OutputDocumentSize = outputDocumentSize; + this.IndexHitRatio = indexHitRatio; + this.TotalTime = totalQueryExecutionTime; + this.QueryPreparationTimes = queryPreparationTimes ?? throw new ArgumentNullException($"{nameof(queryPreparationTimes)} can not be null."); + this.IndexLookupTime = indexLookupTime; + this.DocumentLoadTime = documentLoadTime; + this.VMExecutionTime = vmExecutionTime; + this.RuntimeExecutionTimes = runtimeExecutionTimes ?? throw new ArgumentNullException($"{nameof(runtimeExecutionTimes)} can not be null."); + this.DocumentWriteTime = documentWriteTime; + this.FeedRange = feedRange; + this.PartitionKeyRangeId = partitionKeyRangeId; + } + + public override TimeSpan TotalTime { get; } + + public override long RetrievedDocumentCount { get; } + + public override long RetrievedDocumentSize { get; } + + public override long OutputDocumentCount { get; } + + public override long OutputDocumentSize { get; } + + public QueryPreparationTimesInternal QueryPreparationTimes { get; } + + public override TimeSpan QueryPreparationTime => + this.QueryPreparationTimes.LogicalPlanBuildTime + + this.QueryPreparationTimes.PhysicalPlanBuildTime + + this.QueryPreparationTimes.QueryCompilationTime + + this.QueryPreparationTimes.QueryOptimizationTime; + + public override TimeSpan IndexLookupTime { get; } + + public override TimeSpan DocumentLoadTime { get; } + + public RuntimeExecutionTimesInternal RuntimeExecutionTimes { get; } + + public override TimeSpan RuntimeExecutionTime => + this.RuntimeExecutionTimes.QueryEngineExecutionTime + + this.RuntimeExecutionTimes.SystemFunctionExecutionTime + + this.RuntimeExecutionTimes.UserDefinedFunctionExecutionTime; + + public override TimeSpan DocumentWriteTime { get; } + + public override double IndexHitRatio { get; } + + public override TimeSpan VMExecutionTime { get; } + + public string FeedRange { get; set; } + + public int? PartitionKeyRangeId { get; set; } + + public static ServerSideMetricsInternal Create(IEnumerable serverSideMetricsEnumerable) + { + ServerSideMetricsInternalAccumulator accumulator = new ServerSideMetricsInternalAccumulator(); + foreach (ServerSideMetricsInternal serverSideMetrics in serverSideMetricsEnumerable) + { + accumulator.Accumulate(serverSideMetrics); + } + + return accumulator.GetServerSideMetrics(); + } + + public static bool TryParseFromDelimitedString(string delimitedString, out ServerSideMetricsInternal serverSideMetrics) + { + return ServerSideMetricsParser.TryParse(delimitedString, out serverSideMetrics); + } + + public static ServerSideMetricsInternal ParseFromDelimitedString(string delimitedString) + { + if (!ServerSideMetricsParser.TryParse(delimitedString, out ServerSideMetricsInternal serverSideMetrics)) + { + throw new FormatException(); + } + + return serverSideMetrics; + } + } +} diff --git a/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/ServerSideMetricsInternalAccumulator.cs b/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/ServerSideMetricsInternalAccumulator.cs new file mode 100644 index 0000000000..64be05e6b8 --- /dev/null +++ b/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/ServerSideMetricsInternalAccumulator.cs @@ -0,0 +1,146 @@ +//------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------ + +namespace Microsoft.Azure.Cosmos.Query.Core.Metrics +{ + using System; + using System.Collections.Generic; + using Microsoft.Azure.Cosmos.Tracing; + using Microsoft.Azure.Cosmos.Tracing.TraceData; + + internal sealed class ServerSideMetricsInternalAccumulator + { + private readonly List serverSideMetricsList; + + public ServerSideMetricsInternalAccumulator() + { + this.serverSideMetricsList = new List(); + } + + public void Accumulate(ServerSideMetricsInternal serverSideMetrics) + { + if (serverSideMetrics == null) + { + throw new ArgumentNullException(nameof(serverSideMetrics)); + } + + this.serverSideMetricsList.Add(serverSideMetrics); + } + + public ServerSideMetricsInternal GetServerSideMetrics() + { + TimeSpan totalTime = TimeSpan.Zero; + long retrievedDocumentCount = 0; + long retrievedDocumentSize = 0; + long outputDocumentCount = 0; + long outputDocumentSize = 0; + double indexHitRatio = 0; + QueryPreparationTimesAccumulator queryPreparationTimesAccumulator = new QueryPreparationTimesAccumulator(); + TimeSpan indexLookupTime = TimeSpan.Zero; + TimeSpan documentLoadTime = TimeSpan.Zero; + RuntimeExecutionTimesAccumulator runtimeExecutionTimesAccumulator = new RuntimeExecutionTimesAccumulator(); + TimeSpan documentWriteTime = TimeSpan.Zero; + TimeSpan vMExecutionTime = TimeSpan.Zero; + + foreach (ServerSideMetricsInternal serverSideMetrics in this.serverSideMetricsList) + { + indexHitRatio = (retrievedDocumentCount + serverSideMetrics.RetrievedDocumentCount) != 0 ? + ((retrievedDocumentCount * indexHitRatio) + (serverSideMetrics.RetrievedDocumentCount * serverSideMetrics.IndexHitRatio)) / (retrievedDocumentCount + serverSideMetrics.RetrievedDocumentCount) : + 0; + totalTime += serverSideMetrics.TotalTime; + retrievedDocumentCount += serverSideMetrics.RetrievedDocumentCount; + retrievedDocumentSize += serverSideMetrics.RetrievedDocumentSize; + outputDocumentCount += serverSideMetrics.OutputDocumentCount; + outputDocumentSize += serverSideMetrics.OutputDocumentSize; + queryPreparationTimesAccumulator.Accumulate(serverSideMetrics.QueryPreparationTimes); + indexLookupTime += serverSideMetrics.IndexLookupTime; + documentLoadTime += serverSideMetrics.DocumentLoadTime; + runtimeExecutionTimesAccumulator.Accumulate(serverSideMetrics.RuntimeExecutionTimes); + documentWriteTime += serverSideMetrics.DocumentWriteTime; + vMExecutionTime += serverSideMetrics.VMExecutionTime; + } + + return new ServerSideMetricsInternal( + retrievedDocumentCount: retrievedDocumentCount, + retrievedDocumentSize: retrievedDocumentSize, + outputDocumentCount: outputDocumentCount, + outputDocumentSize: outputDocumentSize, + indexHitRatio: indexHitRatio, + totalQueryExecutionTime: totalTime, + queryPreparationTimes: queryPreparationTimesAccumulator.GetQueryPreparationTimes(), + indexLookupTime: indexLookupTime, + documentLoadTime: documentLoadTime, + vmExecutionTime: vMExecutionTime, + runtimeExecutionTimes: runtimeExecutionTimesAccumulator.GetRuntimeExecutionTimes(), + documentWriteTime: documentWriteTime); + } + + public List GetPartitionedServerSideMetrics() + { + return this.serverSideMetricsList; + } + + public static void WalkTraceTreeForQueryMetrics(ITrace currentTrace, ServerSideMetricsInternalAccumulator accumulator) + { + if (currentTrace == null) + { + return; + } + + foreach (object datum in currentTrace.Data.Values) + { + if (datum is QueryMetricsTraceDatum queryMetricsTraceDatum) + { + queryMetricsTraceDatum.QueryMetrics.ServerSideMetrics.FeedRange = currentTrace.Name; + queryMetricsTraceDatum.QueryMetrics.ServerSideMetrics.PartitionKeyRangeId = WalkTraceTreeForPartitionKeyRangeId(currentTrace); + accumulator.Accumulate(queryMetricsTraceDatum.QueryMetrics.ServerSideMetrics); + return; + } + } + + foreach (ITrace childTrace in currentTrace.Children) + { + WalkTraceTreeForQueryMetrics(childTrace, accumulator); + } + + return; + } + + private static int? WalkTraceTreeForPartitionKeyRangeId(ITrace currentTrace) + { + if (currentTrace == null) + { + return null; + } + + foreach (Object datum in currentTrace.Data.Values) + { + if (datum is ClientSideRequestStatisticsTraceDatum clientSideRequestStatisticsTraceDatum) + { + if (clientSideRequestStatisticsTraceDatum.StoreResponseStatisticsList.Count > 0) + { + return int.TryParse(clientSideRequestStatisticsTraceDatum.StoreResponseStatisticsList[0].StoreResult.PartitionKeyRangeId, out int pKRangeId) + ? pKRangeId + : null; + } + else + { + return null; + } + } + } + + foreach (ITrace childTrace in currentTrace.Children) + { + int? partitionKeyRangeId = WalkTraceTreeForPartitionKeyRangeId(childTrace); + if (partitionKeyRangeId != null) + { + return partitionKeyRangeId; + } + } + + return null; + } + } +} diff --git a/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/BackendMetricsParser.cs b/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/ServerSideMetricsParser.cs similarity index 53% rename from Microsoft.Azure.Cosmos/src/Query/Core/Metrics/BackendMetricsParser.cs rename to Microsoft.Azure.Cosmos/src/Query/Core/Metrics/ServerSideMetricsParser.cs index ecd5becdd4..eeba3c6c85 100644 --- a/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/BackendMetricsParser.cs +++ b/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/ServerSideMetricsParser.cs @@ -8,7 +8,7 @@ namespace Microsoft.Azure.Cosmos.Query.Core.Metrics using System.Text; /// - /// Parser for . + /// Parser for . /// #if INTERNAL #pragma warning disable SA1600 @@ -17,9 +17,9 @@ namespace Microsoft.Azure.Cosmos.Query.Core.Metrics #else internal #endif - static class BackendMetricsParser + static class ServerSideMetricsParser { - public static unsafe bool TryParse(string deliminatedString, out BackendMetrics backendMetrics) + public static unsafe bool TryParse(string deliminatedString, out ServerSideMetricsInternal serverSideMetrics) { if (deliminatedString == null) { @@ -30,7 +30,7 @@ public static unsafe bool TryParse(string deliminatedString, out BackendMetrics { // Stack allocating a zero length buffer returns a null pointer // so we special case the zero length string. - backendMetrics = BackendMetrics.Empty; + serverSideMetrics = ServerSideMetricsInternal.Empty; return true; } @@ -72,7 +72,7 @@ public static unsafe bool TryParse(string deliminatedString, out BackendMetrics while (!corpus.IsEmpty) { - (BackendMetricsTokenizer.TokenType? tokenType, ReadOnlyMemory buffer) = BackendMetricsTokenizer.Read(corpus); + (ServerSideMetricsTokenizer.TokenType? tokenType, ReadOnlyMemory buffer) = ServerSideMetricsTokenizer.Read(corpus); int bytesConsumed; if (!tokenType.HasValue) @@ -95,162 +95,162 @@ public static unsafe bool TryParse(string deliminatedString, out BackendMetrics { switch (tokenType.Value) { - case BackendMetricsTokenizer.TokenType.DocumentLoadTimeInMs: - corpus = corpus.Slice(BackendMetricsTokenizer.TokenBuffers.DocumentLoadTimeInMs.Length); - if (!BackendMetricsParser.TryParseTimeSpanField(corpus, out documentLoadTime, out bytesConsumed)) + case ServerSideMetricsTokenizer.TokenType.DocumentLoadTimeInMs: + corpus = corpus.Slice(ServerSideMetricsTokenizer.TokenBuffers.DocumentLoadTimeInMs.Length); + if (!ServerSideMetricsParser.TryParseTimeSpanField(corpus, out documentLoadTime, out bytesConsumed)) { - backendMetrics = default; + serverSideMetrics = default; return false; } break; - case BackendMetricsTokenizer.TokenType.WriteOutputTimeInMs: - corpus = corpus.Slice(BackendMetricsTokenizer.TokenBuffers.WriteOutputTimeInMs.Length); - if (!BackendMetricsParser.TryParseTimeSpanField(corpus, out documentWriteTime, out bytesConsumed)) + case ServerSideMetricsTokenizer.TokenType.WriteOutputTimeInMs: + corpus = corpus.Slice(ServerSideMetricsTokenizer.TokenBuffers.WriteOutputTimeInMs.Length); + if (!ServerSideMetricsParser.TryParseTimeSpanField(corpus, out documentWriteTime, out bytesConsumed)) { - backendMetrics = default; + serverSideMetrics = default; return false; } break; - case BackendMetricsTokenizer.TokenType.IndexLookupTimeInMs: - corpus = corpus.Slice(BackendMetricsTokenizer.TokenBuffers.IndexLookupTimeInMs.Length); - if (!BackendMetricsParser.TryParseTimeSpanField(corpus, out indexLookupTime, out bytesConsumed)) + case ServerSideMetricsTokenizer.TokenType.IndexLookupTimeInMs: + corpus = corpus.Slice(ServerSideMetricsTokenizer.TokenBuffers.IndexLookupTimeInMs.Length); + if (!ServerSideMetricsParser.TryParseTimeSpanField(corpus, out indexLookupTime, out bytesConsumed)) { - backendMetrics = default; + serverSideMetrics = default; return false; } break; - case BackendMetricsTokenizer.TokenType.IndexUtilizationRatio: - corpus = corpus.Slice(BackendMetricsTokenizer.TokenBuffers.IndexUtilizationRatio.Length); - if (!BackendMetricsParser.TryParseDoubleField(corpus, out indexHitRatio, out bytesConsumed)) + case ServerSideMetricsTokenizer.TokenType.IndexUtilizationRatio: + corpus = corpus.Slice(ServerSideMetricsTokenizer.TokenBuffers.IndexUtilizationRatio.Length); + if (!ServerSideMetricsParser.TryParseDoubleField(corpus, out indexHitRatio, out bytesConsumed)) { - backendMetrics = default; + serverSideMetrics = default; return false; } break; - case BackendMetricsTokenizer.TokenType.QueryLogicalPlanBuildTimeInMs: - corpus = corpus.Slice(BackendMetricsTokenizer.TokenBuffers.QueryLogicalPlanBuildTimeInMs.Length); - if (!BackendMetricsParser.TryParseTimeSpanField(corpus, out logicalPlanBuildTime, out bytesConsumed)) + case ServerSideMetricsTokenizer.TokenType.QueryLogicalPlanBuildTimeInMs: + corpus = corpus.Slice(ServerSideMetricsTokenizer.TokenBuffers.QueryLogicalPlanBuildTimeInMs.Length); + if (!ServerSideMetricsParser.TryParseTimeSpanField(corpus, out logicalPlanBuildTime, out bytesConsumed)) { - backendMetrics = default; + serverSideMetrics = default; return false; } break; - case BackendMetricsTokenizer.TokenType.OutputDocumentCount: - corpus = corpus.Slice(BackendMetricsTokenizer.TokenBuffers.OutputDocumentCount.Length); - if (!BackendMetricsParser.TryParseLongField(corpus, out outputDocumentCount, out bytesConsumed)) + case ServerSideMetricsTokenizer.TokenType.OutputDocumentCount: + corpus = corpus.Slice(ServerSideMetricsTokenizer.TokenBuffers.OutputDocumentCount.Length); + if (!ServerSideMetricsParser.TryParseLongField(corpus, out outputDocumentCount, out bytesConsumed)) { - backendMetrics = default; + serverSideMetrics = default; return false; } break; - case BackendMetricsTokenizer.TokenType.OutputDocumentSize: - corpus = corpus.Slice(BackendMetricsTokenizer.TokenBuffers.OutputDocumentSize.Length); - if (!BackendMetricsParser.TryParseLongField(corpus, out outputDocumentSize, out bytesConsumed)) + case ServerSideMetricsTokenizer.TokenType.OutputDocumentSize: + corpus = corpus.Slice(ServerSideMetricsTokenizer.TokenBuffers.OutputDocumentSize.Length); + if (!ServerSideMetricsParser.TryParseLongField(corpus, out outputDocumentSize, out bytesConsumed)) { - backendMetrics = default; + serverSideMetrics = default; return false; } break; - case BackendMetricsTokenizer.TokenType.QueryPhysicalPlanBuildTimeInMs: - corpus = corpus.Slice(BackendMetricsTokenizer.TokenBuffers.QueryPhysicalPlanBuildTimeInMs.Length); - if (!BackendMetricsParser.TryParseTimeSpanField(corpus, out physicalPlanBuildTime, out bytesConsumed)) + case ServerSideMetricsTokenizer.TokenType.QueryPhysicalPlanBuildTimeInMs: + corpus = corpus.Slice(ServerSideMetricsTokenizer.TokenBuffers.QueryPhysicalPlanBuildTimeInMs.Length); + if (!ServerSideMetricsParser.TryParseTimeSpanField(corpus, out physicalPlanBuildTime, out bytesConsumed)) { - backendMetrics = default; + serverSideMetrics = default; return false; } break; - case BackendMetricsTokenizer.TokenType.QueryCompileTimeInMs: - corpus = corpus.Slice(BackendMetricsTokenizer.TokenBuffers.QueryCompileTimeInMs.Length); - if (!BackendMetricsParser.TryParseTimeSpanField(corpus, out queryCompilationTime, out bytesConsumed)) + case ServerSideMetricsTokenizer.TokenType.QueryCompileTimeInMs: + corpus = corpus.Slice(ServerSideMetricsTokenizer.TokenBuffers.QueryCompileTimeInMs.Length); + if (!ServerSideMetricsParser.TryParseTimeSpanField(corpus, out queryCompilationTime, out bytesConsumed)) { - backendMetrics = default; + serverSideMetrics = default; return false; } break; - case BackendMetricsTokenizer.TokenType.QueryOptimizationTimeInMs: - corpus = corpus.Slice(BackendMetricsTokenizer.TokenBuffers.QueryOptimizationTimeInMs.Length); - if (!BackendMetricsParser.TryParseTimeSpanField(corpus, out queryOptimizationTime, out bytesConsumed)) + case ServerSideMetricsTokenizer.TokenType.QueryOptimizationTimeInMs: + corpus = corpus.Slice(ServerSideMetricsTokenizer.TokenBuffers.QueryOptimizationTimeInMs.Length); + if (!ServerSideMetricsParser.TryParseTimeSpanField(corpus, out queryOptimizationTime, out bytesConsumed)) { - backendMetrics = default; + serverSideMetrics = default; return false; } break; - case BackendMetricsTokenizer.TokenType.RetrievedDocumentCount: - corpus = corpus.Slice(BackendMetricsTokenizer.TokenBuffers.RetrievedDocumentCount.Length); - if (!BackendMetricsParser.TryParseLongField(corpus, out retrievedDocumentCount, out bytesConsumed)) + case ServerSideMetricsTokenizer.TokenType.RetrievedDocumentCount: + corpus = corpus.Slice(ServerSideMetricsTokenizer.TokenBuffers.RetrievedDocumentCount.Length); + if (!ServerSideMetricsParser.TryParseLongField(corpus, out retrievedDocumentCount, out bytesConsumed)) { - backendMetrics = default; + serverSideMetrics = default; return false; } break; - case BackendMetricsTokenizer.TokenType.RetrievedDocumentSize: - corpus = corpus.Slice(BackendMetricsTokenizer.TokenBuffers.RetrievedDocumentSize.Length); - if (!BackendMetricsParser.TryParseLongField(corpus, out retrievedDocumentSize, out bytesConsumed)) + case ServerSideMetricsTokenizer.TokenType.RetrievedDocumentSize: + corpus = corpus.Slice(ServerSideMetricsTokenizer.TokenBuffers.RetrievedDocumentSize.Length); + if (!ServerSideMetricsParser.TryParseLongField(corpus, out retrievedDocumentSize, out bytesConsumed)) { - backendMetrics = default; + serverSideMetrics = default; return false; } break; - case BackendMetricsTokenizer.TokenType.SystemFunctionExecuteTimeInMs: - corpus = corpus.Slice(BackendMetricsTokenizer.TokenBuffers.SystemFunctionExecuteTimeInMs.Length); - if (!BackendMetricsParser.TryParseTimeSpanField(corpus, out systemFunctionExecutionTime, out bytesConsumed)) + case ServerSideMetricsTokenizer.TokenType.SystemFunctionExecuteTimeInMs: + corpus = corpus.Slice(ServerSideMetricsTokenizer.TokenBuffers.SystemFunctionExecuteTimeInMs.Length); + if (!ServerSideMetricsParser.TryParseTimeSpanField(corpus, out systemFunctionExecutionTime, out bytesConsumed)) { - backendMetrics = default; + serverSideMetrics = default; return false; } break; - case BackendMetricsTokenizer.TokenType.TotalExecutionTimeInMs: - corpus = corpus.Slice(BackendMetricsTokenizer.TokenBuffers.TotalExecutionTimeInMs.Length); - if (!BackendMetricsParser.TryParseTimeSpanField(corpus, out totalQueryExecutionTime, out bytesConsumed)) + case ServerSideMetricsTokenizer.TokenType.TotalExecutionTimeInMs: + corpus = corpus.Slice(ServerSideMetricsTokenizer.TokenBuffers.TotalExecutionTimeInMs.Length); + if (!ServerSideMetricsParser.TryParseTimeSpanField(corpus, out totalQueryExecutionTime, out bytesConsumed)) { - backendMetrics = default; + serverSideMetrics = default; return false; } break; - case BackendMetricsTokenizer.TokenType.UserFunctionExecuteTimeInMs: - corpus = corpus.Slice(BackendMetricsTokenizer.TokenBuffers.UserFunctionExecuteTimeInMs.Length); - if (!BackendMetricsParser.TryParseTimeSpanField(corpus, out userDefinedFunctionExecutionTime, out bytesConsumed)) + case ServerSideMetricsTokenizer.TokenType.UserFunctionExecuteTimeInMs: + corpus = corpus.Slice(ServerSideMetricsTokenizer.TokenBuffers.UserFunctionExecuteTimeInMs.Length); + if (!ServerSideMetricsParser.TryParseTimeSpanField(corpus, out userDefinedFunctionExecutionTime, out bytesConsumed)) { - backendMetrics = default; + serverSideMetrics = default; return false; } break; - case BackendMetricsTokenizer.TokenType.VMExecutionTimeInMs: - corpus = corpus.Slice(BackendMetricsTokenizer.TokenBuffers.VMExecutionTimeInMs.Length); - if (!BackendMetricsParser.TryParseTimeSpanField(corpus, out vmExecutionTime, out bytesConsumed)) + case ServerSideMetricsTokenizer.TokenType.VMExecutionTimeInMs: + corpus = corpus.Slice(ServerSideMetricsTokenizer.TokenBuffers.VMExecutionTimeInMs.Length); + if (!ServerSideMetricsParser.TryParseTimeSpanField(corpus, out vmExecutionTime, out bytesConsumed)) { - backendMetrics = default; + serverSideMetrics = default; return false; } break; default: - backendMetrics = default; + serverSideMetrics = default; return false; } } corpus = corpus.Slice(bytesConsumed); if (!corpus.IsEmpty) { - (BackendMetricsTokenizer.TokenType? semicolonToken, ReadOnlyMemory semicolonBuffer) = BackendMetricsTokenizer.Read(corpus); - if (!semicolonToken.HasValue || (semicolonToken != BackendMetricsTokenizer.TokenType.SemiColonDelimiter)) + (ServerSideMetricsTokenizer.TokenType? semicolonToken, ReadOnlyMemory semicolonBuffer) = ServerSideMetricsTokenizer.Read(corpus); + if (!semicolonToken.HasValue || (semicolonToken != ServerSideMetricsTokenizer.TokenType.SemiColonDelimiter)) { - backendMetrics = default; + serverSideMetrics = default; return false; } @@ -258,14 +258,14 @@ public static unsafe bool TryParse(string deliminatedString, out BackendMetrics } } - backendMetrics = new BackendMetrics( + serverSideMetrics = new ServerSideMetricsInternal( retrievedDocumentCount: retrievedDocumentCount, retrievedDocumentSize: retrievedDocumentSize, outputDocumentCount: outputDocumentCount, outputDocumentSize: outputDocumentSize, indexHitRatio: indexHitRatio, totalQueryExecutionTime: totalQueryExecutionTime, - queryPreparationTimes: new QueryPreparationTimes( + queryPreparationTimes: new QueryPreparationTimesInternal( queryCompilationTime: queryCompilationTime, logicalPlanBuildTime: logicalPlanBuildTime, physicalPlanBuildTime: physicalPlanBuildTime, @@ -273,7 +273,7 @@ public static unsafe bool TryParse(string deliminatedString, out BackendMetrics indexLookupTime: indexLookupTime, documentLoadTime: documentLoadTime, vmExecutionTime: vmExecutionTime, - runtimeExecutionTimes: new RuntimeExecutionTimes( + runtimeExecutionTimes: new RuntimeExecutionTimesInternal( queryEngineExecutionTime: vmExecutionTime - indexLookupTime - documentLoadTime - documentWriteTime, systemFunctionExecutionTime: systemFunctionExecutionTime, userDefinedFunctionExecutionTime: userDefinedFunctionExecutionTime), @@ -283,8 +283,8 @@ public static unsafe bool TryParse(string deliminatedString, out BackendMetrics private static bool TryParseTimeSpanField(ReadOnlySpan corpus, out TimeSpan timeSpan, out int bytesConsumed) { - (BackendMetricsTokenizer.TokenType? tokenType, ReadOnlyMemory buffer) = BackendMetricsTokenizer.Read(corpus); - if (!tokenType.HasValue || (tokenType.Value != BackendMetricsTokenizer.TokenType.EqualsDelimiter)) + (ServerSideMetricsTokenizer.TokenType? tokenType, ReadOnlyMemory buffer) = ServerSideMetricsTokenizer.Read(corpus); + if (!tokenType.HasValue || (tokenType.Value != ServerSideMetricsTokenizer.TokenType.EqualsDelimiter)) { timeSpan = default; bytesConsumed = default; @@ -306,8 +306,8 @@ private static bool TryParseTimeSpanField(ReadOnlySpan corpus, out TimeSpa private static bool TryParseLongField(ReadOnlySpan corpus, out long value, out int bytesConsumed) { - (BackendMetricsTokenizer.TokenType? tokenType, ReadOnlyMemory buffer) = BackendMetricsTokenizer.Read(corpus); - if (!tokenType.HasValue || (tokenType.Value != BackendMetricsTokenizer.TokenType.EqualsDelimiter)) + (ServerSideMetricsTokenizer.TokenType? tokenType, ReadOnlyMemory buffer) = ServerSideMetricsTokenizer.Read(corpus); + if (!tokenType.HasValue || (tokenType.Value != ServerSideMetricsTokenizer.TokenType.EqualsDelimiter)) { value = default; bytesConsumed = default; @@ -327,8 +327,8 @@ private static bool TryParseLongField(ReadOnlySpan corpus, out long value, private static bool TryParseDoubleField(ReadOnlySpan corpus, out double value, out int bytesConsumed) { - (BackendMetricsTokenizer.TokenType? tokenType, ReadOnlyMemory buffer) = BackendMetricsTokenizer.Read(corpus); - if (!tokenType.HasValue || (tokenType.Value != BackendMetricsTokenizer.TokenType.EqualsDelimiter)) + (ServerSideMetricsTokenizer.TokenType? tokenType, ReadOnlyMemory buffer) = ServerSideMetricsTokenizer.Read(corpus); + if (!tokenType.HasValue || (tokenType.Value != ServerSideMetricsTokenizer.TokenType.EqualsDelimiter)) { value = default; bytesConsumed = default; diff --git a/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/BackendMetricsTokenizer.cs b/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/ServerSideMetricsTokenizer.cs similarity index 98% rename from Microsoft.Azure.Cosmos/src/Query/Core/Metrics/BackendMetricsTokenizer.cs rename to Microsoft.Azure.Cosmos/src/Query/Core/Metrics/ServerSideMetricsTokenizer.cs index f17e6afbf4..431f3add64 100644 --- a/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/BackendMetricsTokenizer.cs +++ b/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/ServerSideMetricsTokenizer.cs @@ -8,7 +8,7 @@ namespace Microsoft.Azure.Cosmos.Query.Core.Metrics using System.Text; /// - /// Tokenizer for + /// Tokenizer for /// #if INTERNAL #pragma warning disable SA1600 @@ -18,7 +18,7 @@ namespace Microsoft.Azure.Cosmos.Query.Core.Metrics #else internal #endif - static class BackendMetricsTokenizer + static class ServerSideMetricsTokenizer { public enum TokenType { diff --git a/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/ServerSideMetricsUtils.cs b/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/ServerSideMetricsUtils.cs new file mode 100644 index 0000000000..a439bdfd57 --- /dev/null +++ b/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/ServerSideMetricsUtils.cs @@ -0,0 +1,13 @@ +//------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------ +namespace Microsoft.Azure.Cosmos.Query.Core.Metrics +{ + internal static class ServerSideMetricsUtils + { + public static string FormatTrace(this ServerSideMetricsInternal serverSideMetrics) + { + return $"totalExecutionTimeInMs={serverSideMetrics.TotalTime.TotalMilliseconds};queryCompileTimeInMs={serverSideMetrics.QueryPreparationTimes.QueryCompilationTime.TotalMilliseconds};queryLogicalPlanBuildTimeInMs={serverSideMetrics.QueryPreparationTimes.LogicalPlanBuildTime.TotalMilliseconds};queryPhysicalPlanBuildTimeInMs={serverSideMetrics.QueryPreparationTimes.PhysicalPlanBuildTime.TotalMilliseconds};queryOptimizationTimeInMs={serverSideMetrics.QueryPreparationTimes.QueryOptimizationTime.TotalMilliseconds};indexLookupTimeInMs={serverSideMetrics.IndexLookupTime.TotalMilliseconds};documentLoadTimeInMs={serverSideMetrics.DocumentLoadTime.TotalMilliseconds};systemFunctionExecuteTimeInMs={serverSideMetrics.RuntimeExecutionTimes.SystemFunctionExecutionTime.TotalMilliseconds};userFunctionExecuteTimeInMs={serverSideMetrics.RuntimeExecutionTimes.UserDefinedFunctionExecutionTime.TotalMilliseconds};retrievedDocumentCount={serverSideMetrics.RetrievedDocumentCount};retrievedDocumentSize={serverSideMetrics.RetrievedDocumentSize};outputDocumentCount={serverSideMetrics.OutputDocumentCount};outputDocumentSize={serverSideMetrics.OutputDocumentSize};writeOutputTimeInMs={serverSideMetrics.DocumentWriteTime.TotalMilliseconds};indexUtilizationRatio={serverSideMetrics.IndexHitRatio}"; + } + } +} diff --git a/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/ServerSidePartitionedMetrics.cs b/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/ServerSidePartitionedMetrics.cs new file mode 100644 index 0000000000..3fd1f47094 --- /dev/null +++ b/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/ServerSidePartitionedMetrics.cs @@ -0,0 +1,27 @@ +//------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------ + +namespace Microsoft.Azure.Cosmos +{ + /// + /// Represents server side metrics specific for a single partition. + /// + public abstract class ServerSidePartitionedMetrics + { + /// + /// Gets the backend metrics for the request. + /// + public abstract ServerSideMetrics ServerSideMetrics { get; } + + /// + /// Gets the FeedRange for the partition. + /// + public abstract string FeedRange { get; } + + /// + /// Gets the partition key range id for the partition. + /// + public abstract int? PartitionKeyRangeId { get; } + } +} diff --git a/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/ServerSidePartitionedMetricsInternal.cs b/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/ServerSidePartitionedMetricsInternal.cs new file mode 100644 index 0000000000..9ed30963a6 --- /dev/null +++ b/Microsoft.Azure.Cosmos/src/Query/Core/Metrics/ServerSidePartitionedMetricsInternal.cs @@ -0,0 +1,40 @@ +//------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------ + +namespace Microsoft.Azure.Cosmos +{ + using Microsoft.Azure.Cosmos.Query.Core.Metrics; + + /// + /// The internal implementation for server side metrics specific for a single partition. + /// + internal class ServerSidePartitionedMetricsInternal : ServerSidePartitionedMetrics + { + internal ServerSidePartitionedMetricsInternal(ServerSideMetricsInternal serverSideMetricsInternal) + : this(serverSideMetricsInternal, serverSideMetricsInternal.FeedRange, serverSideMetricsInternal.PartitionKeyRangeId) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// + /// + internal ServerSidePartitionedMetricsInternal(ServerSideMetricsInternal serverSideMetricsInternal, string feedRange, int? partitionKeyRangeId) + { + this.ServerSideMetricsInternal = serverSideMetricsInternal; + this.FeedRange = feedRange; + this.PartitionKeyRangeId = partitionKeyRangeId; + } + + public ServerSideMetricsInternal ServerSideMetricsInternal { get; } + + public override ServerSideMetrics ServerSideMetrics => this.ServerSideMetricsInternal; + + public override string FeedRange { get; } + + public override int? PartitionKeyRangeId { get; } + } +} diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemTests.cs index b237c68c2a..dd09fde938 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemTests.cs @@ -33,6 +33,7 @@ namespace Microsoft.Azure.Cosmos.SDK.EmulatorTests using System.Reflection; using System.Text.RegularExpressions; using Microsoft.Azure.Cosmos.Diagnostics; + using Microsoft.Azure.Cosmos.Query.Core.Metrics; [TestClass] public class CosmosItemTests : BaseCosmosClientHelper @@ -141,6 +142,7 @@ public async Task CreateDropItemTest() Assert.IsFalse(string.IsNullOrEmpty(diagnostics.ToString())); Assert.IsTrue(diagnostics.GetClientElapsedTime() > TimeSpan.Zero); Assert.AreEqual(0, response.Diagnostics.GetFailedRequestCount()); + Assert.IsNull(response.Diagnostics.GetQueryMetrics()); response = await this.Container.ReadItemAsync(testItem.id, new Cosmos.PartitionKey(testItem.pk)); Assert.IsNotNull(response); @@ -158,6 +160,7 @@ public async Task CreateDropItemTest() Assert.IsNotNull(response.Diagnostics); Assert.IsFalse(string.IsNullOrEmpty(response.Diagnostics.ToString())); Assert.IsTrue(response.Diagnostics.GetClientElapsedTime() > TimeSpan.Zero); + Assert.IsNull(response.Diagnostics.GetQueryMetrics()); } [TestMethod] @@ -386,6 +389,7 @@ public async Task CreateDropItemMultiPartPartitionKeyTest() ItemResponse response = await multiPartPkContainer.CreateItemAsync(item: testItem); Assert.IsNotNull(response); Assert.AreEqual(HttpStatusCode.Created, response.StatusCode); + Assert.IsNull(response.Diagnostics.GetQueryMetrics()); ItemResponse readResponse = await multiPartPkContainer.ReadItemAsync(id: testItem.id, partitionKey: new Cosmos.PartitionKey("pk1")); Assert.IsNotNull(readResponse); @@ -603,6 +607,7 @@ public async Task UpsertItemTest() Assert.IsNotNull(response); Assert.AreEqual(HttpStatusCode.Created, response.StatusCode); Assert.IsNotNull(response.Headers.Session); + Assert.IsNull(response.Diagnostics.GetQueryMetrics()); } { @@ -613,6 +618,7 @@ public async Task UpsertItemTest() Assert.IsNotNull(response); Assert.AreEqual(HttpStatusCode.OK, response.StatusCode); Assert.IsNotNull(response.Headers.Session); + Assert.IsNull(response.Diagnostics.GetQueryMetrics()); } } @@ -703,6 +709,7 @@ await feedIterator.ReadNextAsync(this.cancellationToken)) } } + Assert.IsNull(responseMessage.Diagnostics.GetQueryMetrics()); } } @@ -842,7 +849,7 @@ public async Task PartitionKeyDeleteTestForSubpartitionedContainer() } [TestMethod] - public async Task ItemCustomSerialzierTest() + public async Task ItemCustomSerializerTest() { DateTime createDateTime = DateTime.UtcNow; Dictionary keyValuePairs = new Dictionary() @@ -1278,6 +1285,22 @@ public async Task QuerySinglePartitionItemStreamTest(int perPKItemCount, int max System.Diagnostics.Trace.TraceInformation($"ContinuationToken: {lastContinuationToken}"); Newtonsoft.Json.JsonSerializer serializer = new Newtonsoft.Json.JsonSerializer(); + ServerSideCumulativeMetrics metrics = response.Diagnostics.GetQueryMetrics(); + Assert.IsTrue(metrics.PartitionedMetrics.Count == 1); + Assert.IsTrue(metrics.CumulativeMetrics.TotalTime > TimeSpan.Zero); + Assert.IsTrue(metrics.CumulativeMetrics.QueryPreparationTime > TimeSpan.Zero); + + if (metrics.CumulativeMetrics.RetrievedDocumentCount >= 1) + { + Assert.IsTrue(metrics.CumulativeMetrics.RetrievedDocumentSize > 0); + Assert.IsTrue(metrics.CumulativeMetrics.DocumentLoadTime > TimeSpan.Zero); + Assert.IsTrue(metrics.CumulativeMetrics.RuntimeExecutionTime > TimeSpan.Zero); + } + else + { + Assert.AreEqual(0, metrics.CumulativeMetrics.RetrievedDocumentSize); + } + using (StreamReader sr = new StreamReader(response.Content)) using (JsonTextReader jtr = new JsonTextReader(sr)) { @@ -1317,9 +1340,9 @@ public async Task QuerySinglePartitionItemStreamTest(int perPKItemCount, int max [TestMethod] public async Task ItemMultiplePartitionQuery() { - IList deleteList = await ToDoActivity.CreateRandomItems(this.Container, 3, randomPartitionKey: true); + IList itemList = await ToDoActivity.CreateRandomItems(this.Container, 3, randomPartitionKey: true); - ToDoActivity find = deleteList.First(); + ToDoActivity find = itemList.First(); QueryDefinition sql = new QueryDefinition("select * from toDoActivity t where t.id = '" + find.id + "'"); QueryRequestOptions requestOptions = new QueryRequestOptions() @@ -1345,6 +1368,111 @@ public async Task ItemMultiplePartitionQuery() ToDoActivity response = iter.First(); Assert.AreEqual(find.id, response.id); } + + ServerSideCumulativeMetrics metrics = iter.Diagnostics.GetQueryMetrics(); + + if (metrics != null) + { + Assert.IsTrue(metrics.PartitionedMetrics.Count == 3); + Assert.IsTrue(metrics.CumulativeMetrics.TotalTime > TimeSpan.Zero); + Assert.IsTrue(metrics.CumulativeMetrics.QueryPreparationTime > TimeSpan.Zero); + + foreach (ServerSidePartitionedMetrics partitionedMetrics in metrics.PartitionedMetrics) + { + Assert.IsNotNull(partitionedMetrics); + Assert.IsNotNull(partitionedMetrics.PartitionKeyRangeId); + } + + if (metrics.CumulativeMetrics.RetrievedDocumentCount >= 1) + { + Assert.IsTrue(metrics.CumulativeMetrics.RetrievedDocumentSize > 0); + Assert.IsTrue(metrics.CumulativeMetrics.DocumentLoadTime > TimeSpan.Zero); + Assert.IsTrue(metrics.CumulativeMetrics.RuntimeExecutionTime > TimeSpan.Zero); + } + else + { + Assert.AreEqual(0, metrics.CumulativeMetrics.RetrievedDocumentSize); + } + } + else + { + string diag = iter.Diagnostics.ToString(); + Assert.IsNotNull(diag); + } + } + + Assert.IsTrue(found); + } + + /// + /// Validate single partition query using gateway mode. + /// + [TestMethod] + public async Task ItemSinglePartitionQueryGateway() + { + ContainerResponse containerResponse = await this.database.CreateContainerAsync( + new ContainerProperties(id: Guid.NewGuid().ToString(), partitionKeyPath: "/pk")); + + Container createdContainer = (ContainerInlineCore)containerResponse; + CosmosClient client1 = TestCommon.CreateCosmosClient(useGateway: true); + + Container container = client1.GetContainer(this.database.Id, createdContainer.Id); + + string findId = "id2002"; + ToDoActivity item = ToDoActivity.CreateRandomToDoActivity("pk2002", findId); + await container.CreateItemAsync(item); + + QueryDefinition sql = new QueryDefinition("select * from toDoActivity t where t.id = '" + findId + "'"); + + QueryRequestOptions requestOptions = new QueryRequestOptions() + { + MaxBufferedItemCount = 10, + ResponseContinuationTokenLimitInKb = 500, + MaxItemCount = 1, + MaxConcurrency = 1, + }; + + FeedIterator feedIterator = container.GetItemQueryIterator( + sql, + requestOptions: requestOptions); + + bool found = false; + while (feedIterator.HasMoreResults) + { + FeedResponse iter = await feedIterator.ReadNextAsync(); + Assert.IsTrue(iter.Count() <= 1); + if (iter.Count() == 1) + { + found = true; + ToDoActivity response = iter.First(); + Assert.AreEqual(findId, response.id); + } + + ServerSideCumulativeMetrics metrics = iter.Diagnostics.GetQueryMetrics(); + + if (metrics != null) + { + Assert.IsTrue(metrics.PartitionedMetrics.Count == 1); + Assert.IsTrue(metrics.CumulativeMetrics.TotalTime > TimeSpan.Zero); + Assert.IsTrue(metrics.CumulativeMetrics.QueryPreparationTime > TimeSpan.Zero); + + foreach (ServerSidePartitionedMetrics partitionedMetrics in metrics.PartitionedMetrics) + { + Assert.IsNotNull(partitionedMetrics); + Assert.IsNull(partitionedMetrics.PartitionKeyRangeId); + } + + if (metrics.CumulativeMetrics.RetrievedDocumentCount >= 1) + { + Assert.IsTrue(metrics.CumulativeMetrics.RetrievedDocumentSize > 0); + Assert.IsTrue(metrics.CumulativeMetrics.DocumentLoadTime > TimeSpan.Zero); + Assert.IsTrue(metrics.CumulativeMetrics.RuntimeExecutionTime > TimeSpan.Zero); + } + else + { + Assert.AreEqual(0, metrics.CumulativeMetrics.RetrievedDocumentSize); + } + } } Assert.IsTrue(found); diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/QueryPerfTest/QueryStatisticsDatumVisitor.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/QueryPerfTest/QueryStatisticsDatumVisitor.cs index 200150875b..c100146bdb 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/QueryPerfTest/QueryStatisticsDatumVisitor.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/QueryPerfTest/QueryStatisticsDatumVisitor.cs @@ -41,13 +41,13 @@ public void AddGetCosmosElementResponseTime(double time) public void Visit(QueryMetricsTraceDatum queryMetricsTraceDatum) { - this.queryMetrics.RetrievedDocumentCount = queryMetricsTraceDatum.QueryMetrics.BackendMetrics.RetrievedDocumentCount; - this.queryMetrics.RetrievedDocumentSize = queryMetricsTraceDatum.QueryMetrics.BackendMetrics.RetrievedDocumentSize; - this.queryMetrics.OutputDocumentCount = queryMetricsTraceDatum.QueryMetrics.BackendMetrics.OutputDocumentCount; - this.queryMetrics.OutputDocumentSize = queryMetricsTraceDatum.QueryMetrics.BackendMetrics.OutputDocumentSize; - this.queryMetrics.TotalQueryExecutionTime = queryMetricsTraceDatum.QueryMetrics.BackendMetrics.TotalTime.TotalMilliseconds; - this.queryMetrics.DocumentLoadTime = queryMetricsTraceDatum.QueryMetrics.BackendMetrics.DocumentLoadTime.TotalMilliseconds; - this.queryMetrics.DocumentWriteTime = queryMetricsTraceDatum.QueryMetrics.BackendMetrics.DocumentWriteTime.TotalMilliseconds; + this.queryMetrics.RetrievedDocumentCount = queryMetricsTraceDatum.QueryMetrics.ServerSideMetrics.RetrievedDocumentCount; + this.queryMetrics.RetrievedDocumentSize = queryMetricsTraceDatum.QueryMetrics.ServerSideMetrics.RetrievedDocumentSize; + this.queryMetrics.OutputDocumentCount = queryMetricsTraceDatum.QueryMetrics.ServerSideMetrics.OutputDocumentCount; + this.queryMetrics.OutputDocumentSize = queryMetricsTraceDatum.QueryMetrics.ServerSideMetrics.OutputDocumentSize; + this.queryMetrics.TotalQueryExecutionTime = queryMetricsTraceDatum.QueryMetrics.ServerSideMetrics.TotalTime.TotalMilliseconds; + this.queryMetrics.DocumentLoadTime = queryMetricsTraceDatum.QueryMetrics.ServerSideMetrics.DocumentLoadTime.TotalMilliseconds; + this.queryMetrics.DocumentWriteTime = queryMetricsTraceDatum.QueryMetrics.ServerSideMetrics.DocumentWriteTime.TotalMilliseconds; } public void Visit(ClientSideRequestStatisticsTraceDatum clientSideRequestStatisticsTraceDatum) diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/QueryTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/QueryTests.cs index afc25ec771..d971223f09 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/QueryTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/QueryTests.cs @@ -1870,11 +1870,11 @@ public async Task TestQueryMetricsNonZero() QueryMetrics queryMetrics = QueryMetrics.CreateFromIEnumerable(feedResonse.QueryMetrics.Values); - Assert.IsTrue(queryMetrics.BackendMetrics.RetrievedDocumentCount > 0); - Assert.IsTrue(queryMetrics.BackendMetrics.RetrievedDocumentSize > 0); - Assert.IsTrue(queryMetrics.BackendMetrics.OutputDocumentCount > 0); - Assert.IsTrue(queryMetrics.BackendMetrics.OutputDocumentSize > 0); - Assert.IsTrue(queryMetrics.BackendMetrics.IndexHitRatio > 0); + Assert.IsTrue(queryMetrics.ServerSideMetrics.RetrievedDocumentCount > 0); + Assert.IsTrue(queryMetrics.ServerSideMetrics.RetrievedDocumentSize > 0); + Assert.IsTrue(queryMetrics.ServerSideMetrics.OutputDocumentCount > 0); + Assert.IsTrue(queryMetrics.ServerSideMetrics.OutputDocumentSize > 0); + Assert.IsTrue(queryMetrics.ServerSideMetrics.IndexHitRatio > 0); await client.DeleteDatabaseAsync(database); } @@ -1960,7 +1960,7 @@ private void TestForceQueryScanHeaders(Database database, bool partitionedCollec query, feedOptions).AsDocumentQuery().ExecuteNextAsync().Result; queryMetrics = result.QueryMetrics.Values.Aggregate((curr, acc) => curr + acc); - Assert.AreEqual(TimeSpan.Zero, queryMetrics.BackendMetrics.IndexLookupTime); + Assert.AreEqual(TimeSpan.Zero, queryMetrics.ServerSideMetrics.IndexLookupTime); // Without ForceQueryScan feedOptions = new FeedOptions() @@ -1976,7 +1976,7 @@ private void TestForceQueryScanHeaders(Database database, bool partitionedCollec query, feedOptions).AsDocumentQuery().ExecuteNextAsync().Result; queryMetrics = result.QueryMetrics.Values.Aggregate((curr, acc) => curr + acc); - Assert.AreNotEqual(TimeSpan.Zero, queryMetrics.BackendMetrics.IndexLookupTime); + Assert.AreNotEqual(TimeSpan.Zero, queryMetrics.ServerSideMetrics.IndexLookupTime); } private void TestFeedOptionInput( @@ -2315,19 +2315,19 @@ private void ValidateQueryMetrics(QueryMetrics metrics) Assert.AreEqual(0, metrics.ClientSideMetrics.Retries); //We are not checking VMExecutionTime, since that is not a public property //Assert.IsTrue(metrics.QueryEngineTimes.VMExecutionTime.TotalMilliseconds > 0, "Expected VMExecutionTimeInMs to be > 0, metrics = {0}", metrics); - Assert.IsTrue(metrics.BackendMetrics.QueryPreparationTimes.QueryCompilationTime.TotalMilliseconds > 0, "Expected CompileTimeInMs to be > 0, metrics = {0}", metrics); + Assert.IsTrue(metrics.ServerSideMetrics.QueryPreparationTimes.QueryCompilationTime.TotalMilliseconds > 0, "Expected CompileTimeInMs to be > 0, metrics = {0}", metrics); //We are not checking DocumentLoadTime and RetrievedDocumentCount, since some queries don't return any documents (especially in the last continuation). //Assert.IsTrue(metrics.QueryEngineTimes.DocumentLoadTime.TotalMilliseconds > 0, "Expected DocumentLoadTimeInMs to be > 0, metrics = {0}", metrics); //Assert.IsTrue(metrics.RetrievedDocumentCount > 0, "Expected RetrievedDocumentCount to be > 0, metrics = {0}", metrics); - Assert.IsTrue(metrics.BackendMetrics.TotalTime.TotalMilliseconds > 0, "Expected TotalExecutionTimeInMs to be > 0, metrics = {0}", metrics); + Assert.IsTrue(metrics.ServerSideMetrics.TotalTime.TotalMilliseconds > 0, "Expected TotalExecutionTimeInMs to be > 0, metrics = {0}", metrics); //Assert.IsTrue(metrics.QueryEngineTimes.WriteOutputTime.TotalMilliseconds > 0, "Expected WriteOutputTimeInMs to be > 0, metrics = {0}", metrics); //Assert.IsTrue(metrics.RetrievedDocumentSize > 0, "Expected RetrievedDocumentSize to be > 0, metrics = {0}", metrics); - Assert.IsTrue(metrics.BackendMetrics.IndexLookupTime.TotalMilliseconds > 0, "Expected IndexLookupTimeInMs to be > 0, metrics = {0}", metrics); - Assert.IsTrue(metrics.BackendMetrics.QueryPreparationTimes.LogicalPlanBuildTime.TotalMilliseconds > 0, "Expected LogicalPlanBuildTimeInMs to be > 0, metrics = {0}", metrics); + Assert.IsTrue(metrics.ServerSideMetrics.IndexLookupTime.TotalMilliseconds > 0, "Expected IndexLookupTimeInMs to be > 0, metrics = {0}", metrics); + Assert.IsTrue(metrics.ServerSideMetrics.QueryPreparationTimes.LogicalPlanBuildTime.TotalMilliseconds > 0, "Expected LogicalPlanBuildTimeInMs to be > 0, metrics = {0}", metrics); //Assert.AreEqual(metrics.QueryEngineTimes.VMExecutionTime - metrics.QueryEngineTimes.IndexLookupTime - metrics.QueryEngineTimes.DocumentLoadTime - metrics.QueryEngineTimes.WriteOutputTime, // metrics.QueryEngineTimes.RuntimeExecutionTimes.TotalTime); - Assert.IsTrue(metrics.BackendMetrics.RuntimeExecutionTimes.QueryEngineExecutionTime >= metrics.BackendMetrics.RuntimeExecutionTimes.SystemFunctionExecutionTime + metrics.BackendMetrics.RuntimeExecutionTimes.UserDefinedFunctionExecutionTime, - "Expected Query VM Execution Time to be > {0}, metrics = {1}", metrics.BackendMetrics.RuntimeExecutionTimes.SystemFunctionExecutionTime + metrics.BackendMetrics.RuntimeExecutionTimes.UserDefinedFunctionExecutionTime, metrics); + Assert.IsTrue(metrics.ServerSideMetrics.RuntimeExecutionTimes.QueryEngineExecutionTime >= metrics.ServerSideMetrics.RuntimeExecutionTimes.SystemFunctionExecutionTime + metrics.ServerSideMetrics.RuntimeExecutionTimes.UserDefinedFunctionExecutionTime, + "Expected Query VM Execution Time to be > {0}, metrics = {1}", metrics.ServerSideMetrics.RuntimeExecutionTimes.SystemFunctionExecutionTime + metrics.ServerSideMetrics.RuntimeExecutionTimes.UserDefinedFunctionExecutionTime, metrics); //Assert.IsTrue(metrics.QueryEngineTimes.VMExecutionTime >= metrics.QueryEngineTimes.RuntimeExecutionTimes.TotalTime, // "Expected Query VM Execution Time to be > {0}, metrics = {1}", metrics.QueryEngineTimes.RuntimeExecutionTimes.TotalTime, metrics); } diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Performance.Tests/Query/Metrics/Performance.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Performance.Tests/Query/Metrics/Performance.cs index 6d5db62d6d..40484e792c 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Performance.Tests/Query/Metrics/Performance.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Performance.Tests/Query/Metrics/Performance.cs @@ -37,7 +37,7 @@ public void TestParse() ValueStopwatch stopwatch = ValueStopwatch.StartNew(); for (int i = 0; i < 100000; i++) { - BackendMetricsParser.TryParse(delimitedString, out BackendMetrics backendMetrics); + ServerSideMetricsParser.TryParse(delimitedString, out ServerSideMetricsInternal serverSideMetrics); } stopwatch.Stop(); Console.WriteLine(stopwatch.ElapsedMilliseconds); diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/BaselineTest/TestBaseline/TraceWriterBaselineTests.TraceData.xml b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/BaselineTest/TestBaseline/TraceWriterBaselineTests.TraceData.xml index d1dee72a0f..75cd9894de 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/BaselineTest/TestBaseline/TraceWriterBaselineTests.TraceData.xml +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/BaselineTest/TestBaseline/TraceWriterBaselineTests.TraceData.xml @@ -126,7 +126,7 @@ { QueryMetricsTraceDatum datum = new QueryMetricsTraceDatum( new Lazy(() => new QueryMetrics( - BackendMetricsTests.MockBackendMetrics, + ServerSideMetricsTests.ServerSideMetrics, IndexUtilizationInfoTests.MockIndexUtilizationInfo, ClientSideMetricsTests.MockClientSideMetrics))); rootTrace.AddDatum("Query Metrics", datum); diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Contracts/DotNetSDKAPI.json b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Contracts/DotNetSDKAPI.json index 7fde376d49..759762f21f 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Contracts/DotNetSDKAPI.json +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Contracts/DotNetSDKAPI.json @@ -3124,6 +3124,11 @@ "Attributes": [], "MethodInfo": "Int32 GetFailedRequestCount();IsAbstract:False;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" }, + "Microsoft.Azure.Cosmos.ServerSideCumulativeMetrics GetQueryMetrics()": { + "Type": "Method", + "Attributes": [], + "MethodInfo": "Microsoft.Azure.Cosmos.ServerSideCumulativeMetrics GetQueryMetrics();IsAbstract:False;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" + }, "System.Collections.Generic.IReadOnlyList`1[System.ValueTuple`2[System.String,System.Uri]] GetContactedRegions()": { "Type": "Method", "Attributes": [], @@ -9029,6 +9034,194 @@ }, "NestedTypes": {} }, + "Microsoft.Azure.Cosmos.ServerSideCumulativeMetrics;System.Object;IsAbstract:True;IsSealed:False;IsInterface:False;IsEnum:False;IsClass:True;IsValueType:False;IsNested:False;IsGenericType:False;IsSerializable:False": { + "Subclasses": {}, + "Members": { + "Microsoft.Azure.Cosmos.ServerSideMetrics CumulativeMetrics": { + "Type": "Property", + "Attributes": [], + "MethodInfo": "Microsoft.Azure.Cosmos.ServerSideMetrics CumulativeMetrics;CanRead:True;CanWrite:False;Microsoft.Azure.Cosmos.ServerSideMetrics get_CumulativeMetrics();IsAbstract:True;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" + }, + "Microsoft.Azure.Cosmos.ServerSideMetrics get_CumulativeMetrics()": { + "Type": "Method", + "Attributes": [], + "MethodInfo": "Microsoft.Azure.Cosmos.ServerSideMetrics get_CumulativeMetrics();IsAbstract:True;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" + }, + "System.Collections.Generic.IReadOnlyList`1[Microsoft.Azure.Cosmos.ServerSidePartitionedMetrics] get_PartitionedMetrics()": { + "Type": "Method", + "Attributes": [], + "MethodInfo": "System.Collections.Generic.IReadOnlyList`1[Microsoft.Azure.Cosmos.ServerSidePartitionedMetrics] get_PartitionedMetrics();IsAbstract:True;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" + }, + "System.Collections.Generic.IReadOnlyList`1[Microsoft.Azure.Cosmos.ServerSidePartitionedMetrics] PartitionedMetrics": { + "Type": "Property", + "Attributes": [], + "MethodInfo": "System.Collections.Generic.IReadOnlyList`1[Microsoft.Azure.Cosmos.ServerSidePartitionedMetrics] PartitionedMetrics;CanRead:True;CanWrite:False;System.Collections.Generic.IReadOnlyList`1[Microsoft.Azure.Cosmos.ServerSidePartitionedMetrics] get_PartitionedMetrics();IsAbstract:True;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" + } + }, + "NestedTypes": {} + }, + "Microsoft.Azure.Cosmos.ServerSideMetrics;System.Object;IsAbstract:True;IsSealed:False;IsInterface:False;IsEnum:False;IsClass:True;IsValueType:False;IsNested:False;IsGenericType:False;IsSerializable:False": { + "Subclasses": {}, + "Members": { + "Double get_IndexHitRatio()": { + "Type": "Method", + "Attributes": [], + "MethodInfo": "Double get_IndexHitRatio();IsAbstract:True;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" + }, + "Double IndexHitRatio": { + "Type": "Property", + "Attributes": [], + "MethodInfo": "Double IndexHitRatio;CanRead:True;CanWrite:False;Double get_IndexHitRatio();IsAbstract:True;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" + }, + "Int64 get_OutputDocumentCount()": { + "Type": "Method", + "Attributes": [], + "MethodInfo": "Int64 get_OutputDocumentCount();IsAbstract:True;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" + }, + "Int64 get_OutputDocumentSize()": { + "Type": "Method", + "Attributes": [], + "MethodInfo": "Int64 get_OutputDocumentSize();IsAbstract:True;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" + }, + "Int64 get_RetrievedDocumentCount()": { + "Type": "Method", + "Attributes": [], + "MethodInfo": "Int64 get_RetrievedDocumentCount();IsAbstract:True;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" + }, + "Int64 get_RetrievedDocumentSize()": { + "Type": "Method", + "Attributes": [], + "MethodInfo": "Int64 get_RetrievedDocumentSize();IsAbstract:True;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" + }, + "Int64 OutputDocumentCount": { + "Type": "Property", + "Attributes": [], + "MethodInfo": "Int64 OutputDocumentCount;CanRead:True;CanWrite:False;Int64 get_OutputDocumentCount();IsAbstract:True;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" + }, + "Int64 OutputDocumentSize": { + "Type": "Property", + "Attributes": [], + "MethodInfo": "Int64 OutputDocumentSize;CanRead:True;CanWrite:False;Int64 get_OutputDocumentSize();IsAbstract:True;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" + }, + "Int64 RetrievedDocumentCount": { + "Type": "Property", + "Attributes": [], + "MethodInfo": "Int64 RetrievedDocumentCount;CanRead:True;CanWrite:False;Int64 get_RetrievedDocumentCount();IsAbstract:True;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" + }, + "Int64 RetrievedDocumentSize": { + "Type": "Property", + "Attributes": [], + "MethodInfo": "Int64 RetrievedDocumentSize;CanRead:True;CanWrite:False;Int64 get_RetrievedDocumentSize();IsAbstract:True;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" + }, + "System.TimeSpan DocumentLoadTime": { + "Type": "Property", + "Attributes": [], + "MethodInfo": "System.TimeSpan DocumentLoadTime;CanRead:True;CanWrite:False;System.TimeSpan get_DocumentLoadTime();IsAbstract:True;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" + }, + "System.TimeSpan DocumentWriteTime": { + "Type": "Property", + "Attributes": [], + "MethodInfo": "System.TimeSpan DocumentWriteTime;CanRead:True;CanWrite:False;System.TimeSpan get_DocumentWriteTime();IsAbstract:True;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" + }, + "System.TimeSpan get_DocumentLoadTime()": { + "Type": "Method", + "Attributes": [], + "MethodInfo": "System.TimeSpan get_DocumentLoadTime();IsAbstract:True;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" + }, + "System.TimeSpan get_DocumentWriteTime()": { + "Type": "Method", + "Attributes": [], + "MethodInfo": "System.TimeSpan get_DocumentWriteTime();IsAbstract:True;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" + }, + "System.TimeSpan get_IndexLookupTime()": { + "Type": "Method", + "Attributes": [], + "MethodInfo": "System.TimeSpan get_IndexLookupTime();IsAbstract:True;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" + }, + "System.TimeSpan get_QueryPreparationTime()": { + "Type": "Method", + "Attributes": [], + "MethodInfo": "System.TimeSpan get_QueryPreparationTime();IsAbstract:True;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" + }, + "System.TimeSpan get_RuntimeExecutionTime()": { + "Type": "Method", + "Attributes": [], + "MethodInfo": "System.TimeSpan get_RuntimeExecutionTime();IsAbstract:True;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" + }, + "System.TimeSpan get_TotalTime()": { + "Type": "Method", + "Attributes": [], + "MethodInfo": "System.TimeSpan get_TotalTime();IsAbstract:True;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" + }, + "System.TimeSpan get_VMExecutionTime()": { + "Type": "Method", + "Attributes": [], + "MethodInfo": "System.TimeSpan get_VMExecutionTime();IsAbstract:True;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" + }, + "System.TimeSpan IndexLookupTime": { + "Type": "Property", + "Attributes": [], + "MethodInfo": "System.TimeSpan IndexLookupTime;CanRead:True;CanWrite:False;System.TimeSpan get_IndexLookupTime();IsAbstract:True;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" + }, + "System.TimeSpan QueryPreparationTime": { + "Type": "Property", + "Attributes": [], + "MethodInfo": "System.TimeSpan QueryPreparationTime;CanRead:True;CanWrite:False;System.TimeSpan get_QueryPreparationTime();IsAbstract:True;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" + }, + "System.TimeSpan RuntimeExecutionTime": { + "Type": "Property", + "Attributes": [], + "MethodInfo": "System.TimeSpan RuntimeExecutionTime;CanRead:True;CanWrite:False;System.TimeSpan get_RuntimeExecutionTime();IsAbstract:True;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" + }, + "System.TimeSpan TotalTime": { + "Type": "Property", + "Attributes": [], + "MethodInfo": "System.TimeSpan TotalTime;CanRead:True;CanWrite:False;System.TimeSpan get_TotalTime();IsAbstract:True;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" + }, + "System.TimeSpan VMExecutionTime": { + "Type": "Property", + "Attributes": [], + "MethodInfo": "System.TimeSpan VMExecutionTime;CanRead:True;CanWrite:False;System.TimeSpan get_VMExecutionTime();IsAbstract:True;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" + } + }, + "NestedTypes": {} + }, + "Microsoft.Azure.Cosmos.ServerSidePartitionedMetrics;System.Object;IsAbstract:True;IsSealed:False;IsInterface:False;IsEnum:False;IsClass:True;IsValueType:False;IsNested:False;IsGenericType:False;IsSerializable:False": { + "Subclasses": {}, + "Members": { + "Microsoft.Azure.Cosmos.ServerSideMetrics get_ServerSideMetrics()": { + "Type": "Method", + "Attributes": [], + "MethodInfo": "Microsoft.Azure.Cosmos.ServerSideMetrics get_ServerSideMetrics();IsAbstract:True;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" + }, + "Microsoft.Azure.Cosmos.ServerSideMetrics ServerSideMetrics": { + "Type": "Property", + "Attributes": [], + "MethodInfo": "Microsoft.Azure.Cosmos.ServerSideMetrics ServerSideMetrics;CanRead:True;CanWrite:False;Microsoft.Azure.Cosmos.ServerSideMetrics get_ServerSideMetrics();IsAbstract:True;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" + }, + "System.Nullable`1[System.Int32] get_PartitionKeyRangeId()": { + "Type": "Method", + "Attributes": [], + "MethodInfo": "System.Nullable`1[System.Int32] get_PartitionKeyRangeId();IsAbstract:True;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" + }, + "System.Nullable`1[System.Int32] PartitionKeyRangeId": { + "Type": "Property", + "Attributes": [], + "MethodInfo": "System.Nullable`1[System.Int32] PartitionKeyRangeId;CanRead:True;CanWrite:False;System.Nullable`1[System.Int32] get_PartitionKeyRangeId();IsAbstract:True;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" + }, + "System.String FeedRange": { + "Type": "Property", + "Attributes": [], + "MethodInfo": "System.String FeedRange;CanRead:True;CanWrite:False;System.String get_FeedRange();IsAbstract:True;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" + }, + "System.String get_FeedRange()": { + "Type": "Method", + "Attributes": [], + "MethodInfo": "System.String get_FeedRange();IsAbstract:True;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" + } + }, + "NestedTypes": {} + }, "Microsoft.Azure.Cosmos.Spatial.BoundingBox;System.Object;IsAbstract:False;IsSealed:True;IsInterface:False;IsEnum:False;IsClass:True;IsValueType:False;IsNested:False;IsGenericType:False;IsSerializable:False": { "Subclasses": {}, "Members": { diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Metrics/ClientSideMetricsTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Metrics/ClientSideMetricsTests.cs index 4a446bb933..90f9fec8ad 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Metrics/ClientSideMetricsTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Metrics/ClientSideMetricsTests.cs @@ -21,11 +21,11 @@ public class ClientSideMetricsTests [TestMethod] public void TestAccumulator() { - ClientSideMetrics.Accumulator accumulator = new ClientSideMetrics.Accumulator(); - accumulator = accumulator.Accumulate(MockClientSideMetrics); - accumulator = accumulator.Accumulate(MockClientSideMetrics); + ClientSideMetricsAccumulator accumulator = new ClientSideMetricsAccumulator(); + accumulator.Accumulate(MockClientSideMetrics); + accumulator.Accumulate(MockClientSideMetrics); - ClientSideMetrics doubleMetrics = ClientSideMetrics.Accumulator.ToClientSideMetrics(accumulator); + ClientSideMetrics doubleMetrics = accumulator.GetClientSideMetrics(); Assert.AreEqual(2 * MockClientSideMetrics.Retries, doubleMetrics.Retries); Assert.AreEqual(2 * MockClientSideMetrics.RequestCharge, doubleMetrics.RequestCharge); Assert.AreEqual(2 * MockClientSideMetrics.FetchExecutionRanges.Count(), doubleMetrics.FetchExecutionRanges.Count()); diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Metrics/IndexUtilizationInfoTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Metrics/IndexUtilizationInfoTests.cs index 13702de3b5..9fe272a6bd 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Metrics/IndexUtilizationInfoTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Metrics/IndexUtilizationInfoTests.cs @@ -8,7 +8,6 @@ namespace Microsoft.Azure.Cosmos.Tests.Query.Metrics using VisualStudio.TestTools.UnitTesting; using Microsoft.Azure.Cosmos.Query.Core.Metrics; using System.Collections.Generic; - using System.Text; [TestClass] public class IndexUtilizationInfoTests @@ -35,11 +34,11 @@ public class IndexUtilizationInfoTests [TestMethod] public void TestAccumulator() { - IndexUtilizationInfo.Accumulator accumulator = new IndexUtilizationInfo.Accumulator(); - accumulator = accumulator.Accumulate(MockIndexUtilizationInfo); - accumulator = accumulator.Accumulate(MockIndexUtilizationInfo); + IndexUtilizationInfoAccumulator accumulator = new IndexUtilizationInfoAccumulator(); + accumulator.Accumulate(MockIndexUtilizationInfo); + accumulator.Accumulate(MockIndexUtilizationInfo); - IndexUtilizationInfo doubleInfo = IndexUtilizationInfo.Accumulator.ToIndexUtilizationInfo(accumulator); + IndexUtilizationInfo doubleInfo = accumulator.GetIndexUtilizationInfo(); Assert.AreEqual(2 * MockIndexUtilizationInfo.PotentialSingleIndexes.Count, doubleInfo.PotentialSingleIndexes.Count); Assert.AreEqual(2 * MockIndexUtilizationInfo.UtilizedSingleIndexes.Count, doubleInfo.UtilizedSingleIndexes.Count); Assert.AreEqual(2 * MockIndexUtilizationInfo.PotentialCompositeIndexes.Count, doubleInfo.PotentialCompositeIndexes.Count); diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Metrics/QueryMetricsTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Metrics/QueryMetricsTests.cs index d655de097a..17f73616c2 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Metrics/QueryMetricsTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Metrics/QueryMetricsTests.cs @@ -12,21 +12,21 @@ namespace Microsoft.Azure.Cosmos.Tests.Query.Metrics public class QueryMetricsTests { private static readonly QueryMetrics MockQueryMetrics = new QueryMetrics( - BackendMetricsTests.MockBackendMetrics, + ServerSideMetricsTests.ServerSideMetrics, IndexUtilizationInfoTests.MockIndexUtilizationInfo, ClientSideMetricsTests.MockClientSideMetrics); [TestMethod] public void TestAccumulator() { - QueryMetrics.Accumulator accumulator = new QueryMetrics.Accumulator(); - accumulator = accumulator.Accumulate(MockQueryMetrics); - accumulator = accumulator.Accumulate(MockQueryMetrics); + QueryMetricsAccumulator accumulator = new QueryMetricsAccumulator(); + accumulator.Accumulate(MockQueryMetrics); + accumulator.Accumulate(MockQueryMetrics); - QueryMetrics doubleQueryMetrics = QueryMetrics.Accumulator.ToQueryMetrics(accumulator); + QueryMetrics doubleQueryMetrics = accumulator.GetQueryMetrics(); // Spot check - Assert.AreEqual(2 * BackendMetricsTests.MockBackendMetrics.IndexLookupTime, doubleQueryMetrics.BackendMetrics.IndexLookupTime); + Assert.AreEqual(2 * ServerSideMetricsTests.ServerSideMetrics.IndexLookupTime, doubleQueryMetrics.ServerSideMetrics.IndexLookupTime); Assert.AreEqual(2 * IndexUtilizationInfoTests.MockIndexUtilizationInfo.PotentialSingleIndexes.Count, doubleQueryMetrics.IndexUtilizationInfo.PotentialSingleIndexes.Count); Assert.AreEqual(2 * ClientSideMetricsTests.MockClientSideMetrics.RequestCharge, doubleQueryMetrics.ClientSideMetrics.RequestCharge); } @@ -37,7 +37,7 @@ public void TestAddition() QueryMetrics doubleQueryMetrics = MockQueryMetrics + MockQueryMetrics; // Spot check - Assert.AreEqual(2 * BackendMetricsTests.MockBackendMetrics.IndexLookupTime, doubleQueryMetrics.BackendMetrics.IndexLookupTime); + Assert.AreEqual(2 * ServerSideMetricsTests.ServerSideMetrics.IndexLookupTime, doubleQueryMetrics.ServerSideMetrics.IndexLookupTime); Assert.AreEqual(2 * IndexUtilizationInfoTests.MockIndexUtilizationInfo.PotentialSingleIndexes.Count, doubleQueryMetrics.IndexUtilizationInfo.PotentialSingleIndexes.Count); Assert.AreEqual(2 * ClientSideMetricsTests.MockClientSideMetrics.RequestCharge, doubleQueryMetrics.ClientSideMetrics.RequestCharge); } @@ -48,7 +48,7 @@ public void TestCreateFromEnumerable() QueryMetrics tripleQueryMetrics = QueryMetrics.CreateFromIEnumerable(new List() { MockQueryMetrics, MockQueryMetrics, MockQueryMetrics }); // Spot check - Assert.AreEqual(3 * BackendMetricsTests.MockBackendMetrics.IndexLookupTime, tripleQueryMetrics.BackendMetrics.IndexLookupTime); + Assert.AreEqual(3 * ServerSideMetricsTests.ServerSideMetrics.IndexLookupTime, tripleQueryMetrics.ServerSideMetrics.IndexLookupTime); Assert.AreEqual(3 * IndexUtilizationInfoTests.MockIndexUtilizationInfo.PotentialSingleIndexes.Count, tripleQueryMetrics.IndexUtilizationInfo.PotentialSingleIndexes.Count); Assert.AreEqual(3 * ClientSideMetricsTests.MockClientSideMetrics.RequestCharge, tripleQueryMetrics.ClientSideMetrics.RequestCharge); } diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Metrics/BackendMetricsTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Metrics/ServerSideMetricsTests.cs similarity index 78% rename from Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Metrics/BackendMetricsTests.cs rename to Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Metrics/ServerSideMetricsTests.cs index 221057790d..4c6e382ebf 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Metrics/BackendMetricsTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/Metrics/ServerSideMetricsTests.cs @@ -7,11 +7,10 @@ namespace Microsoft.Azure.Cosmos.Tests.Query.Metrics using System; using VisualStudio.TestTools.UnitTesting; using Microsoft.Azure.Cosmos.Query.Core.Metrics; - using System.Diagnostics; using System.Collections.Generic; [TestClass] - public class BackendMetricsTests + public class ServerSideMetricsTests { private static readonly TimeSpan totalExecutionTime = TimeSpan.FromTicks((long)(TimeSpan.TicksPerMillisecond * 33.67)); private static readonly TimeSpan queryCompileTime = TimeSpan.FromTicks((long)(TimeSpan.TicksPerMillisecond * 0.06)); @@ -32,14 +31,14 @@ public class BackendMetricsTests private static readonly string delimitedString = $"totalExecutionTimeInMs={totalExecutionTime.TotalMilliseconds};queryCompileTimeInMs={queryCompileTime.TotalMilliseconds};queryLogicalPlanBuildTimeInMs={logicalPlanBuildTime.TotalMilliseconds};queryPhysicalPlanBuildTimeInMs={physicalPlanBuildTime.TotalMilliseconds};queryOptimizationTimeInMs={queryOptimizationTime.TotalMilliseconds};VMExecutionTimeInMs={vmExecutionTime.TotalMilliseconds};indexLookupTimeInMs={indexLookupTime.TotalMilliseconds};documentLoadTimeInMs={documentLoadTime.TotalMilliseconds};systemFunctionExecuteTimeInMs={systemFunctionExecuteTime.TotalMilliseconds};userFunctionExecuteTimeInMs={userFunctionExecuteTime.TotalMilliseconds};retrievedDocumentCount={retrievedDocumentCount};retrievedDocumentSize={retrievedDocumentSize};outputDocumentCount={outputDocumentCount};outputDocumentSize={outputDocumentSize};writeOutputTimeInMs={documentWriteTime.TotalMilliseconds};indexUtilizationRatio={indexHitRatio}"; - internal static readonly BackendMetrics MockBackendMetrics = new BackendMetrics( + internal static readonly ServerSideMetricsInternal ServerSideMetrics = new ServerSideMetricsInternal( retrievedDocumentCount, retrievedDocumentSize, outputDocumentCount, outputDocumentSize, indexHitRatio, totalExecutionTime, - new QueryPreparationTimes( + new QueryPreparationTimesInternal( queryCompileTime, logicalPlanBuildTime, physicalPlanBuildTime, @@ -47,7 +46,7 @@ public class BackendMetricsTests indexLookupTime, documentLoadTime, vmExecutionTime, - new RuntimeExecutionTimes( + new RuntimeExecutionTimesInternal( totalExecutionTime - systemFunctionExecuteTime - userFunctionExecuteTime, systemFunctionExecuteTime, userFunctionExecuteTime), @@ -57,13 +56,13 @@ public class BackendMetricsTests [TestMethod] public void TestParse() { - BackendMetricsTests.ValidateParse(delimitedString, MockBackendMetrics); + ServerSideMetricsTests.ValidateParse(delimitedString, ServerSideMetrics); } [TestMethod] public void TestParseEmptyString() { - BackendMetricsTests.ValidateParse(string.Empty, BackendMetrics.Empty); + ServerSideMetricsTests.ValidateParse(string.Empty, ServerSideMetricsInternal.Empty); } [TestMethod] @@ -72,14 +71,14 @@ public void TestParseStringWithMissingFields() TimeSpan totalExecutionTime = TimeSpan.FromTicks((long)(TimeSpan.TicksPerMillisecond * 33.67)); string delimitedString = $"totalExecutionTimeInMs={totalExecutionTime.TotalMilliseconds}"; - BackendMetrics expected = new BackendMetrics( + ServerSideMetricsInternal expected = new ServerSideMetricsInternal( default(long), default(long), default(long), default(long), default(double), totalExecutionTime, - new QueryPreparationTimes( + new QueryPreparationTimesInternal( default(TimeSpan), default(TimeSpan), default(TimeSpan), @@ -87,27 +86,27 @@ public void TestParseStringWithMissingFields() default(TimeSpan), default(TimeSpan), default(TimeSpan), - new RuntimeExecutionTimes( + new RuntimeExecutionTimesInternal( default(TimeSpan), default(TimeSpan), default(TimeSpan)), default(TimeSpan)); - BackendMetricsTests.ValidateParse(delimitedString, expected); + ServerSideMetricsTests.ValidateParse(delimitedString, expected); } [TestMethod] public void TestParseStringWithTrailingUnknownField() { string delimitedString = $"thisIsNotAKnownField=asdf"; - BackendMetrics expected = new BackendMetrics( + ServerSideMetricsInternal expected = new ServerSideMetricsInternal( default(long), default(long), default(long), default(long), default(double), default(TimeSpan), - new QueryPreparationTimes( + new QueryPreparationTimesInternal( default(TimeSpan), default(TimeSpan), default(TimeSpan), @@ -115,13 +114,13 @@ public void TestParseStringWithTrailingUnknownField() default(TimeSpan), default(TimeSpan), default(TimeSpan), - new RuntimeExecutionTimes( + new RuntimeExecutionTimesInternal( default(TimeSpan), default(TimeSpan), default(TimeSpan)), default(TimeSpan)); - BackendMetricsTests.ValidateParse(delimitedString, expected); + ServerSideMetricsTests.ValidateParse(delimitedString, expected); } [TestMethod] @@ -129,7 +128,7 @@ public void TestParseStringWithTrailingUnknownField() [DataRow("totalExecutionTimeInMs=33.6+totalExecutionTimeInMs=33.6", DisplayName = "Wrong Delimiter")] public void TestNegativeCases(string delimitedString) { - Assert.IsFalse(BackendMetricsParser.TryParse(delimitedString, out BackendMetrics backendMetrics)); + Assert.IsFalse(ServerSideMetricsParser.TryParse(delimitedString, out ServerSideMetricsInternal serverSideMetrics)); } [TestMethod] @@ -137,14 +136,14 @@ public void TestParseStringWithUnknownField() { TimeSpan totalExecutionTime = TimeSpan.FromTicks((long)(TimeSpan.TicksPerMillisecond * 33.67)); string delimitedString = $"totalExecutionTimeInMs={totalExecutionTime.TotalMilliseconds};thisIsNotAKnownField={totalExecutionTime.TotalMilliseconds};totalExecutionTimeInMs={totalExecutionTime.TotalMilliseconds}"; - BackendMetrics expected = new BackendMetrics( + ServerSideMetricsInternal expected = new ServerSideMetricsInternal( default(long), default(long), default(long), default(long), default(double), totalExecutionTime, - new QueryPreparationTimes( + new QueryPreparationTimesInternal( default(TimeSpan), default(TimeSpan), default(TimeSpan), @@ -152,31 +151,34 @@ public void TestParseStringWithUnknownField() default(TimeSpan), default(TimeSpan), default(TimeSpan), - new RuntimeExecutionTimes( + new RuntimeExecutionTimesInternal( default(TimeSpan), default(TimeSpan), default(TimeSpan)), default(TimeSpan)); - BackendMetricsTests.ValidateParse(delimitedString, expected); + ServerSideMetricsTests.ValidateParse(delimitedString, expected); } [TestMethod] public void TestAccumulator() { - BackendMetrics.Accumulator accumulator = new BackendMetrics.Accumulator(); - accumulator = accumulator.Accumulate(MockBackendMetrics); - accumulator = accumulator.Accumulate(MockBackendMetrics); + ServerSideMetricsInternalAccumulator accumulator = new ServerSideMetricsInternalAccumulator(); + accumulator.Accumulate(ServerSideMetrics); + accumulator.Accumulate(ServerSideMetrics); + ServerSideMetricsInternal serverSideMetricsFromAddition = accumulator.GetServerSideMetrics(); - BackendMetrics backendMetricsFromAddition = BackendMetrics.Accumulator.ToBackendMetrics(accumulator); - BackendMetrics expected = new BackendMetrics( + List metricsList = new List { ServerSideMetrics, ServerSideMetrics }; + ServerSideMetricsInternal serverSideMetricsFromCreate = ServerSideMetricsInternal.Create(metricsList); + + ServerSideMetricsInternal expected = new ServerSideMetricsInternal( retrievedDocumentCount * 2, retrievedDocumentSize * 2, outputDocumentCount * 2, outputDocumentSize * 2, indexHitRatio, totalExecutionTime * 2, - new QueryPreparationTimes( + new QueryPreparationTimesInternal( queryCompileTime * 2, logicalPlanBuildTime * 2, physicalPlanBuildTime * 2, @@ -184,22 +186,22 @@ public void TestAccumulator() indexLookupTime * 2, documentLoadTime * 2, vmExecutionTime * 2, - new RuntimeExecutionTimes( + new RuntimeExecutionTimesInternal( (totalExecutionTime - systemFunctionExecuteTime - userFunctionExecuteTime) * 2, systemFunctionExecuteTime * 2, userFunctionExecuteTime * 2), documentWriteTime * 2); - BackendMetricsTests.ValidateBackendMetricsEquals(expected, backendMetricsFromAddition); + ServerSideMetricsTests.ValidateServerSideMetricsEquals(expected, serverSideMetricsFromAddition); + ServerSideMetricsTests.ValidateServerSideMetricsEquals(expected, serverSideMetricsFromCreate); } - - private static void ValidateParse(string delimitedString, BackendMetrics expected) + private static void ValidateParse(string delimitedString, ServerSideMetricsInternal expected) { - Assert.IsTrue(BackendMetricsParser.TryParse(delimitedString, out BackendMetrics actual)); - BackendMetricsTests.ValidateBackendMetricsEquals(expected, actual); + Assert.IsTrue(ServerSideMetricsParser.TryParse(delimitedString, out ServerSideMetricsInternal actual)); + ServerSideMetricsTests.ValidateServerSideMetricsEquals(expected, actual); } - private static void ValidateBackendMetricsEquals(BackendMetrics expected, BackendMetrics actual) + private static void ValidateServerSideMetricsEquals(ServerSideMetricsInternal expected, ServerSideMetricsInternal actual) { Assert.AreEqual(expected.DocumentLoadTime, actual.DocumentLoadTime); Assert.AreEqual(expected.DocumentWriteTime, actual.DocumentWriteTime); diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Tracing/TraceWriterBaselineTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Tracing/TraceWriterBaselineTests.cs index fe3dc7054f..2d69341182 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Tracing/TraceWriterBaselineTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Tracing/TraceWriterBaselineTests.cs @@ -41,7 +41,7 @@ namespace Microsoft.Azure.Cosmos.Tests.Tracing public sealed class TraceWriterBaselineTests : BaselineTests { private static readonly Lazy MockQueryMetrics = new Lazy(() => new QueryMetrics( - BackendMetricsTests.MockBackendMetrics, + ServerSideMetricsTests.ServerSideMetrics, IndexUtilizationInfoTests.MockIndexUtilizationInfo, ClientSideMetricsTests.MockClientSideMetrics)); @@ -316,7 +316,7 @@ public void TraceData() { QueryMetricsTraceDatum datum = new QueryMetricsTraceDatum( new Lazy(() => new QueryMetrics( - BackendMetricsTests.MockBackendMetrics, + ServerSideMetricsTests.ServerSideMetrics, IndexUtilizationInfoTests.MockIndexUtilizationInfo, ClientSideMetricsTests.MockClientSideMetrics))); rootTrace.AddDatum("Query Metrics", datum);