Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -629,6 +629,13 @@ internal static Delegate FindBuilder(MulticastDelegate mcd)

internal static long TimerCurrent() => DateTime.UtcNow.ToFileTimeUtc();

internal static long FastTimerCurrent() => Environment.TickCount;

internal static uint CalculateTickCountElapsed(long startTick, long endTick)
{
return (uint)(endTick - startTick);
}

internal static long TimerFromSeconds(int seconds)
{
long result = checked((long)seconds * TimeSpan.TicksPerSecond);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ internal static ValueSqlStatisticsScope TimedScope(SqlStatistics statistics)
// internal values that are not exposed through properties
internal long _closeTimestamp;
internal long _openTimestamp;
internal long _startExecutionTimestamp;
internal long? _startExecutionTimestamp;
internal long _startFetchTimestamp;
internal long _startNetworkServerTimestamp;

Expand Down Expand Up @@ -80,7 +80,7 @@ internal bool WaitForDoneAfterRow

internal void ContinueOnNewConnection()
{
_startExecutionTimestamp = 0;
_startExecutionTimestamp = null;
_startFetchTimestamp = 0;
_waitForDoneAfterRow = false;
_waitForReply = false;
Expand Down Expand Up @@ -108,7 +108,7 @@ internal IDictionary GetDictionary()
{ "UnpreparedExecs", _unpreparedExecs },

{ "ConnectionTime", ADP.TimerToMilliseconds(_connectionTime) },
{ "ExecutionTime", ADP.TimerToMilliseconds(_executionTime) },
{ "ExecutionTime", _executionTime },
{ "NetworkServerTime", ADP.TimerToMilliseconds(_networkServerTime) }
};
Debug.Assert(dictionary.Count == Count);
Expand All @@ -117,17 +117,17 @@ internal IDictionary GetDictionary()

internal bool RequestExecutionTimer()
{
if (_startExecutionTimestamp == 0)
if (!_startExecutionTimestamp.HasValue)
{
_startExecutionTimestamp = ADP.TimerCurrent();
_startExecutionTimestamp = ADP.FastTimerCurrent();
return true;
}
return false;
}

internal void RequestNetworkServerTimer()
{
Debug.Assert(_startExecutionTimestamp != 0, "No network time expected outside execution period");
Debug.Assert(_startExecutionTimestamp.HasValue, "No network time expected outside execution period");
if (_startNetworkServerTimestamp == 0)
{
_startNetworkServerTimestamp = ADP.TimerCurrent();
Expand All @@ -137,10 +137,11 @@ internal void RequestNetworkServerTimer()

internal void ReleaseAndUpdateExecutionTimer()
{
if (_startExecutionTimestamp > 0)
if (_startExecutionTimestamp.HasValue)
{
_executionTime += (ADP.TimerCurrent() - _startExecutionTimestamp);
_startExecutionTimestamp = 0;
uint elapsed = ADP.CalculateTickCountElapsed(_startExecutionTimestamp.Value, ADP.FastTimerCurrent());
_executionTime += elapsed;
_startExecutionTimestamp = null;
}
}

Expand Down Expand Up @@ -176,7 +177,7 @@ internal void Reset()
_unpreparedExecs = 0;
_waitForDoneAfterRow = false;
_waitForReply = false;
_startExecutionTimestamp = 0;
_startExecutionTimestamp = null;
_startNetworkServerTimestamp = 0;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,6 @@ public static void Test(string srcConstr, string dstConstr, string dstTable)

Assert.True(0 < (long)stats["BytesReceived"], "BytesReceived is non-positive.");
Assert.True(0 < (long)stats["BytesSent"], "BytesSent is non-positive.");
Assert.True((long)stats["ConnectionTime"] >= (long)stats["ExecutionTime"], "Connection Time is less than Execution Time.");
Assert.True((long)stats["ExecutionTime"] >= (long)stats["NetworkServerTime"], "Execution Time is less than Network Server Time.");
DataTestUtility.AssertEqualsWithDescription((long)0, (long)stats["UnpreparedExecs"], "Non-zero UnpreparedExecs value: " + (long)stats["UnpreparedExecs"]);
DataTestUtility.AssertEqualsWithDescription((long)0, (long)stats["PreparedExecs"], "Non-zero PreparedExecs value: " + (long)stats["PreparedExecs"]);
DataTestUtility.AssertEqualsWithDescription((long)0, (long)stats["Prepares"], "Non-zero Prepares value: " + (long)stats["Prepares"]);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using Microsoft.Data.Common;
using Xunit;

namespace Microsoft.Data.SqlClient.UnitTests;

/// <summary>
/// Tests for Environment.TickCount elapsed time calculation with wraparound handling.
/// </summary>
public sealed class TickCountElapsedTest
{
/// <summary>
/// Verifies that normal elapsed time calculation works correctly.
/// </summary>
[Fact]
public void CalculateTickCountElapsed_NormalCase_ReturnsCorrectElapsed()
{
uint elapsed = ADP.CalculateTickCountElapsed(1000, 1500);
Assert.Equal(500u, elapsed);
}

/// <summary>
/// Verifies that wraparound from int.MaxValue to int.MinValue is handled correctly.
/// </summary>
[Fact]
public void CalculateTickCountElapsed_MaxWraparound_ReturnsOne()
{
uint elapsed = ADP.CalculateTickCountElapsed(int.MaxValue, int.MinValue);
Assert.Equal(1u, elapsed);
}

/// <summary>
/// Verifies that partial wraparound scenarios work correctly.
/// </summary>
[Theory]
[InlineData(2147483600, -2147483600, 96u)]
[InlineData(2147483647, -2147483647, 2u)]
public void CalculateTickCountElapsed_PartialWraparound_ReturnsCorrectElapsed(long start, long end, uint expected)
{
uint elapsed = ADP.CalculateTickCountElapsed(start, end);
Assert.Equal(expected, elapsed);
}

/// <summary>
/// Verifies that zero elapsed time returns zero.
/// </summary>
[Fact]
public void CalculateTickCountElapsed_ZeroElapsed_ReturnsZero()
{
uint elapsed = ADP.CalculateTickCountElapsed(1000, 1000);
Assert.Equal(0u, elapsed);
}
}
Loading