diff options
author | Adam Sitnik <adam.sitnik@gmail.com> | 2019-08-08 18:50:03 +0300 |
---|---|---|
committer | Marek Safar <marek.safar@gmail.com> | 2019-08-08 19:55:19 +0300 |
commit | b15518dd5e487cccf98815d9831d0a4b681269fc (patch) | |
tree | 6deff2b66c9370dbfff21f5bb3625acf704ee494 /netcore | |
parent | 7c59cd14fe9f888452bfc550b430332e1c883ca1 (diff) |
make DateTime.UtcNow 5% faster to minimize the leap second performance impact (#26046)
* make few methods used by DateTime.UtcNow inlinable to minimize the leap second performance regression impact, related to #25728
* apply suggested micro-optimizations
Signed-off-by: dotnet-bot <dotnet-bot@microsoft.com>
Diffstat (limited to 'netcore')
3 files changed, 55 insertions, 15 deletions
diff --git a/netcore/System.Private.CoreLib/shared/System/DateTime.cs b/netcore/System.Private.CoreLib/shared/System/DateTime.cs index 2317221b5a7..cc621dae21a 100644 --- a/netcore/System.Private.CoreLib/shared/System/DateTime.cs +++ b/netcore/System.Private.CoreLib/shared/System/DateTime.cs @@ -641,32 +641,38 @@ namespace System // Returns the tick count corresponding to the given year, month, and day. // Will check the if the parameters are valid. + [MethodImpl(MethodImplOptions.AggressiveInlining)] private static long DateToTicks(int year, int month, int day) { - if (year >= 1 && year <= 9999 && month >= 1 && month <= 12) + if (year < 1 || year > 9999 || month < 1 || month > 12 || day < 1) { - int[] days = IsLeapYear(year) ? s_daysToMonth366 : s_daysToMonth365; - if (day >= 1 && day <= days[month] - days[month - 1]) - { - int y = year - 1; - int n = y * 365 + y / 4 - y / 100 + y / 400 + days[month - 1] + day - 1; - return n * TicksPerDay; - } + ThrowHelper.ThrowArgumentOutOfRange_BadYearMonthDay(); + } + + int[] days = IsLeapYear(year) ? s_daysToMonth366 : s_daysToMonth365; + if (day > days[month] - days[month - 1]) + { + ThrowHelper.ThrowArgumentOutOfRange_BadYearMonthDay(); } - throw new ArgumentOutOfRangeException(null, SR.ArgumentOutOfRange_BadYearMonthDay); + + int y = year - 1; + int n = y * 365 + y / 4 - y / 100 + y / 400 + days[month - 1] + day - 1; + return n * TicksPerDay; } // Return the tick count corresponding to the given hour, minute, second. // Will check the if the parameters are valid. + [MethodImpl(MethodImplOptions.AggressiveInlining)] private static long TimeToTicks(int hour, int minute, int second) { //TimeSpan.TimeToTicks is a family access function which does no error checking, so //we need to put some error checking out here. - if (hour >= 0 && hour < 24 && minute >= 0 && minute < 60 && second >= 0 && second < 60) + if ((uint)hour >= 24 || (uint)minute >= 60 || (uint)second >= 60) { - return (TimeSpan.TimeToTicks(hour, minute, second)); + ThrowHelper.ThrowArgumentOutOfRange_BadHourMinuteSecond(); } - throw new ArgumentOutOfRangeException(null, SR.ArgumentOutOfRange_BadHourMinuteSecond); + + return TimeSpan.TimeToTicks(hour, minute, second); } // Returns the number of days in the month given by the year and @@ -1182,13 +1188,14 @@ namespace System // Checks whether a given year is a leap year. This method returns true if // year is a leap year, or false if not. // + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsLeapYear(int year) { if (year < 1 || year > 9999) { - throw new ArgumentOutOfRangeException(nameof(year), SR.ArgumentOutOfRange_Year); + ThrowHelper.ThrowArgumentOutOfRange_Year(); } - return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0); + return (year & 3) == 0 && ((year & 15) == 0 || (year % 25) != 0); } // Constructs a DateTime from a string. The string must specify a diff --git a/netcore/System.Private.CoreLib/shared/System/ThrowHelper.cs b/netcore/System.Private.CoreLib/shared/System/ThrowHelper.cs index e79b785e66e..c8ccd4fb93e 100644 --- a/netcore/System.Private.CoreLib/shared/System/ThrowHelper.cs +++ b/netcore/System.Private.CoreLib/shared/System/ThrowHelper.cs @@ -132,6 +132,31 @@ namespace System } [DoesNotReturn] + internal static void ThrowArgumentOutOfRange_Year() + { + throw GetArgumentOutOfRangeException(ExceptionArgument.year, + ExceptionResource.ArgumentOutOfRange_Year); + } + + [DoesNotReturn] + internal static void ThrowArgumentOutOfRange_BadYearMonthDay() + { + throw new ArgumentOutOfRangeException(null, SR.ArgumentOutOfRange_BadYearMonthDay); + } + + [DoesNotReturn] + internal static void ThrowArgumentOutOfRange_BadHourMinuteSecond() + { + throw new ArgumentOutOfRangeException(null, SR.ArgumentOutOfRange_BadHourMinuteSecond); + } + + [DoesNotReturn] + internal static void ThrowArgumentOutOfRange_TimeSpanTooLong() + { + throw new ArgumentOutOfRangeException(null, SR.Overflow_TimeSpanTooLong); + } + + [DoesNotReturn] internal static void ThrowWrongKeyTypeArgumentException<T>(T key, Type targetType) { // Generic key to move the boxing to the right hand side of throw @@ -657,6 +682,8 @@ namespace System return "elementType"; case ExceptionArgument.arrayIndex: return "arrayIndex"; + case ExceptionArgument.year: + return "year"; default: Debug.Fail("The enum value is not defined, please check the ExceptionArgument Enum."); return ""; @@ -687,6 +714,8 @@ namespace System return SR.ArgumentOutOfRange_IndexCountBuffer; case ExceptionResource.ArgumentOutOfRange_Count: return SR.ArgumentOutOfRange_Count; + case ExceptionResource.ArgumentOutOfRange_Year: + return SR.ArgumentOutOfRange_Year; case ExceptionResource.Arg_ArrayPlusOffTooSmall: return SR.Arg_ArrayPlusOffTooSmall; case ExceptionResource.NotSupported_ReadOnlyCollection: @@ -901,6 +930,7 @@ namespace System endIndex, elementType, arrayIndex, + year, } // @@ -912,6 +942,7 @@ namespace System ArgumentOutOfRange_IndexCount, ArgumentOutOfRange_IndexCountBuffer, ArgumentOutOfRange_Count, + ArgumentOutOfRange_Year, Arg_ArrayPlusOffTooSmall, NotSupported_ReadOnlyCollection, Arg_RankMultiDimNotSupported, diff --git a/netcore/System.Private.CoreLib/shared/System/TimeSpan.cs b/netcore/System.Private.CoreLib/shared/System/TimeSpan.cs index f08b9048d75..5d5af9a93ba 100644 --- a/netcore/System.Private.CoreLib/shared/System/TimeSpan.cs +++ b/netcore/System.Private.CoreLib/shared/System/TimeSpan.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Globalization; +using System.Runtime.CompilerServices; namespace System { @@ -288,13 +289,14 @@ namespace System return new TimeSpan(value); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static long TimeToTicks(int hour, int minute, int second) { // totalSeconds is bounded by 2^31 * 2^12 + 2^31 * 2^8 + 2^31, // which is less than 2^44, meaning we won't overflow totalSeconds. long totalSeconds = (long)hour * 3600 + (long)minute * 60 + (long)second; if (totalSeconds > MaxSeconds || totalSeconds < MinSeconds) - throw new ArgumentOutOfRangeException(null, SR.Overflow_TimeSpanTooLong); + ThrowHelper.ThrowArgumentOutOfRange_TimeSpanTooLong(); return totalSeconds * TicksPerSecond; } |