Skip to content

Commit

Permalink
Replace OPTIMIZE_FOR_SIZE with feature switch (#111743)
Browse files Browse the repository at this point in the history
  • Loading branch information
MichalStrehovsky authored Jan 30, 2025
1 parent 7693b6d commit adf123c
Show file tree
Hide file tree
Showing 26 changed files with 92 additions and 105 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -142,8 +142,17 @@ public static int SlowRuntimeTimeoutModifier

public static bool IsStartingProcessesSupported => !IsiOS && !IstvOS;

public static bool IsSpeedOptimized => !IsSizeOptimized;
public static bool IsSizeOptimized => IsBrowser || IsWasi || IsAndroid || IsAppleMobile;
public static bool IsLinqSpeedOptimized => !IsLinqSizeOptimized;
public static bool IsLinqSizeOptimized => s_linqIsSizeOptimized.Value;
private static readonly Lazy<bool> s_linqIsSizeOptimized = new Lazy<bool>(ComputeIsLinqSizeOptimized);
private static bool ComputeIsLinqSizeOptimized()
{
#if NET
return (bool)typeof(Enumerable).GetMethod("get_IsSizeOptimized", BindingFlags.NonPublic | BindingFlags.Static).Invoke(null, Array.Empty<object>());
#else
return false;
#endif
}

public static bool IsBrowserDomSupported => IsEnvironmentVariableTrue("IsBrowserDomSupported");
public static bool IsBrowserDomSupportedOrNotBrowser => IsNotBrowser || IsBrowserDomSupported;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace System.IO.Compression.Tests;
[Collection(nameof(DisableParallelization))]
public class zip_LargeFiles : ZipFileTestBase
{
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsSpeedOptimized), nameof(PlatformDetection.Is64BitProcess))] // don't run it on slower runtimes
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotMobile), nameof(PlatformDetection.Is64BitProcess))] // don't run it on slower runtimes
[OuterLoop("It requires almost 12 GB of free disk space")]
public static void UnzipOver4GBZipFile()
{
Expand Down Expand Up @@ -49,7 +49,7 @@ private static void FillWithHardToCompressData(byte[] buffer)
Random.Shared.NextBytes(buffer);
}

[ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsSpeedOptimized), nameof(PlatformDetection.Is64BitProcess))] // don't run it on slower runtimes
[ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotMobile), nameof(PlatformDetection.Is64BitProcess))] // don't run it on slower runtimes
[OuterLoop("It requires 5~6 GB of free disk space and a lot of CPU time for compressed tests")]
[InlineData(false)]
[InlineData(true)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ private static void FillWithHardToCompressData(byte[] buffer)
Random.Shared.NextBytes(buffer);
}

[ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsSpeedOptimized), nameof(PlatformDetection.Is64BitProcess))] // don't run it on slower runtimes
[ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotMobile), nameof(PlatformDetection.Is64BitProcess))] // don't run it on slower runtimes
[InlineData(false)]
[InlineData(true)]
[OuterLoop("It requires 5~6 GB of free disk space and a lot of CPU time for compressed tests")]
Expand Down
59 changes: 23 additions & 36 deletions src/libraries/System.Linq/src/System.Linq.csproj
Original file line number Diff line number Diff line change
@@ -1,98 +1,85 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>$(NetCoreAppCurrent);$(NetCoreAppCurrent)-browser;$(NetCoreAppCurrent)-wasi;$(NetCoreAppCurrent)-android;$(NetCoreAppCurrent)-ios;$(NetCoreAppCurrent)-tvos</TargetFrameworks>
<TargetFramework>$(NetCoreAppCurrent)</TargetFramework>
<UseCompilerGeneratedDocXmlFile>false</UseCompilerGeneratedDocXmlFile>
</PropertyGroup>

<!-- DesignTimeBuild requires all the TargetFramework Derived Properties to not be present in the first property group. -->
<PropertyGroup>
<TargetPlatformIdentifier>$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)'))</TargetPlatformIdentifier>
<OptimizeForSize Condition="'$(TargetPlatformIdentifier)' == 'browser' or '$(TargetPlatformIdentifier)' == 'android' or '$(TargetPlatformIdentifier)' == 'ios' or '$(TargetPlatformIdentifier)' == 'tvos'">true</OptimizeForSize>
<DefineConstants Condition="'$(OptimizeForSize)' == 'true'">$(DefineConstants);OPTIMIZE_FOR_SIZE</DefineConstants>
</PropertyGroup>

<ItemGroup Condition="'$(OptimizeForSize)' == true">
<Compile Include="System\Linq\Skip.SizeOpt.cs" />
<Compile Include="System\Linq\Take.SizeOpt.cs" />
</ItemGroup>

<ItemGroup Condition="'$(OptimizeForSize)' != true">
<Compile Include="System\Linq\AppendPrepend.SpeedOpt.cs" />
<Compile Include="System\Linq\Cast.SpeedOpt.cs" />
<Compile Include="System\Linq\Concat.SpeedOpt.cs" />
<Compile Include="System\Linq\DefaultIfEmpty.SpeedOpt.cs" />
<Compile Include="System\Linq\Distinct.SpeedOpt.cs" />
<Compile Include="System\Linq\Grouping.SpeedOpt.cs" />
<Compile Include="System\Linq\Iterator.SpeedOpt.cs" />
<Compile Include="System\Linq\Lookup.SpeedOpt.cs" />
<Compile Include="System\Linq\OfType.SpeedOpt.cs" />
<Compile Include="System\Linq\OrderedEnumerable.SpeedOpt.cs" />
<Compile Include="System\Linq\Range.SpeedOpt.cs" />
<Compile Include="System\Linq\Repeat.SpeedOpt.cs" />
<Compile Include="System\Linq\Reverse.SpeedOpt.cs" />
<Compile Include="System\Linq\Select.SpeedOpt.cs" />
<Compile Include="System\Linq\SelectMany.SpeedOpt.cs" />
<Compile Include="System\Linq\Skip.SpeedOpt.cs" />
<Compile Include="System\Linq\SkipTake.SpeedOpt.cs" />
<Compile Include="System\Linq\Take.SpeedOpt.cs" />
<Compile Include="System\Linq\Union.SpeedOpt.cs" />
<Compile Include="System\Linq\Where.SpeedOpt.cs" />
</ItemGroup>

<ItemGroup>
<Compile Include="System\Linq\Aggregate.cs" />
<Compile Include="System\Linq\AnyAll.cs" />
<Compile Include="System\Linq\AppendPrepend.cs" />
<Compile Include="System\Linq\AppendPrepend.SpeedOpt.cs" />
<Compile Include="System\Linq\Average.cs" />
<Compile Include="System\Linq\Cast.cs" />
<Compile Include="System\Linq\Cast.SpeedOpt.cs" />
<Compile Include="System\Linq\Chunk.cs" />
<Compile Include="System\Linq\Concat.cs" />
<Compile Include="System\Linq\Concat.SpeedOpt.cs" />
<Compile Include="System\Linq\Contains.cs" />
<Compile Include="System\Linq\AggregateBy.cs" />
<Compile Include="System\Linq\CountBy.cs" />
<Compile Include="System\Linq\Count.cs" />
<Compile Include="System\Linq\DebugView.cs" />
<Compile Include="System\Linq\DefaultIfEmpty.cs" />
<Compile Include="System\Linq\DefaultIfEmpty.SpeedOpt.cs" />
<Compile Include="System\Linq\Distinct.cs" />
<Compile Include="System\Linq\Distinct.SpeedOpt.cs" />
<Compile Include="System\Linq\ElementAt.cs" />
<Compile Include="System\Linq\Enumerable.cs" />
<Compile Include="System\Linq\Except.cs" />
<Compile Include="System\Linq\First.cs" />
<Compile Include="System\Linq\Grouping.cs" />
<Compile Include="System\Linq\Grouping.SpeedOpt.cs" />
<Compile Include="System\Linq\GroupJoin.cs" />
<Compile Include="System\Linq\Index.cs" />
<Compile Include="System\Linq\Intersect.cs" />
<Compile Include="System\Linq\Iterator.cs" />
<Compile Include="System\Linq\Iterator.SpeedOpt.cs" />
<Compile Include="System\Linq\Join.cs" />
<Compile Include="System\Linq\Last.cs" />
<Compile Include="System\Linq\LeftJoin.cs" />
<Compile Include="System\Linq\Lookup.cs" />
<Compile Include="System\Linq\Lookup.SpeedOpt.cs" />
<Compile Include="System\Linq\Max.cs" />
<Compile Include="System\Linq\MaxMin.cs" />
<Compile Include="System\Linq\Min.cs" />
<Compile Include="System\Linq\OfType.cs" />
<Compile Include="System\Linq\OfType.SpeedOpt.cs" />
<Compile Include="System\Linq\OrderBy.cs" />
<Compile Include="System\Linq\OrderedEnumerable.cs" />
<Compile Include="System\Linq\OrderedEnumerable.SpeedOpt.cs" />
<Compile Include="System\Linq\PartialArrayEnumerator.cs" />
<Compile Include="System\Linq\Range.cs" />
<Compile Include="System\Linq\Range.SpeedOpt.cs" />
<Compile Include="System\Linq\Repeat.cs" />
<Compile Include="System\Linq\Repeat.SpeedOpt.cs" />
<Compile Include="System\Linq\Reverse.cs" />
<Compile Include="System\Linq\Reverse.SpeedOpt.cs" />
<Compile Include="System\Linq\RightJoin.cs" />
<Compile Include="System\Linq\SegmentedArrayBuilder.cs" />
<Compile Include="System\Linq\Select.cs" />
<Compile Include="System\Linq\Select.SpeedOpt.cs" />
<Compile Include="System\Linq\SelectMany.cs" />
<Compile Include="System\Linq\SelectMany.SpeedOpt.cs" />
<Compile Include="System\Linq\SequenceEqual.cs" />
<Compile Include="System\Linq\Single.cs" />
<Compile Include="System\Linq\SingleLinkedNode.cs" />
<Compile Include="System\Linq\Skip.cs" />
<Compile Include="System\Linq\Skip.SizeOpt.cs" />
<Compile Include="System\Linq\Skip.SpeedOpt.cs" />
<Compile Include="System\Linq\SkipTake.SpeedOpt.cs" />
<Compile Include="System\Linq\Sum.cs" />
<Compile Include="System\Linq\Take.cs" />
<Compile Include="System\Linq\Take.SizeOpt.cs" />
<Compile Include="System\Linq\Take.SpeedOpt.cs" />
<Compile Include="System\Linq\ThrowHelper.cs" />
<Compile Include="System\Linq\ToCollection.cs" />
<Compile Include="System\Linq\Union.cs" />
<Compile Include="System\Linq\Union.SpeedOpt.cs" />
<Compile Include="System\Linq\Utilities.cs" />
<Compile Include="System\Linq\Where.cs" />
<Compile Include="System\Linq\Where.SpeedOpt.cs" />
<Compile Include="System\Linq\Zip.cs" />
</ItemGroup>

Expand Down
4 changes: 1 addition & 3 deletions src/libraries/System.Linq/src/System/Linq/AnyAll.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@ public static bool Any<TSource>(this IEnumerable<TSource> source)
return gc.Count != 0;
}

#if !OPTIMIZE_FOR_SIZE
if (source is Iterator<TSource> iterator)
if (!IsSizeOptimized && source is Iterator<TSource> iterator)
{
int count = iterator.GetCount(onlyIfCheap: true);
if (count >= 0)
Expand All @@ -32,7 +31,6 @@ public static bool Any<TSource>(this IEnumerable<TSource> source)
iterator.TryGetFirst(out bool found);
return found;
}
#endif

if (source is ICollection ngc)
{
Expand Down
8 changes: 2 additions & 6 deletions src/libraries/System.Linq/src/System/Linq/Count.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,10 @@ public static int Count<TSource>(this IEnumerable<TSource> source)
return collectionoft.Count;
}

#if !OPTIMIZE_FOR_SIZE
if (source is Iterator<TSource> iterator)
if (!IsSizeOptimized && source is Iterator<TSource> iterator)
{
return iterator.GetCount(onlyIfCheap: false);
}
#endif

if (source is ICollection collection)
{
Expand Down Expand Up @@ -115,8 +113,7 @@ public static bool TryGetNonEnumeratedCount<TSource>(this IEnumerable<TSource> s
return true;
}

#if !OPTIMIZE_FOR_SIZE
if (source is Iterator<TSource> iterator)
if (!IsSizeOptimized && source is Iterator<TSource> iterator)
{
int c = iterator.GetCount(onlyIfCheap: true);
if (c >= 0)
Expand All @@ -125,7 +122,6 @@ public static bool TryGetNonEnumeratedCount<TSource>(this IEnumerable<TSource> s
return true;
}
}
#endif

if (source is ICollection collection)
{
Expand Down
8 changes: 2 additions & 6 deletions src/libraries/System.Linq/src/System/Linq/ElementAt.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,7 @@ public static TSource ElementAt<TSource>(this IEnumerable<TSource> source, int i

bool found;
TSource? element =
#if !OPTIMIZE_FOR_SIZE
source is Iterator<TSource> iterator ? iterator.TryGetElementAt(index, out found) :
#endif
!IsSizeOptimized && source is Iterator<TSource> iterator ? iterator.TryGetElementAt(index, out found) :
TryGetElementAtNonIterator(source, index, out found);

if (!found)
Expand Down Expand Up @@ -123,9 +121,7 @@ public static TSource ElementAt<TSource>(this IEnumerable<TSource> source, Index
}

return
#if !OPTIMIZE_FOR_SIZE
source is Iterator<TSource> iterator ? iterator.TryGetElementAt(index, out found) :
#endif
!IsSizeOptimized && source is Iterator<TSource> iterator ? iterator.TryGetElementAt(index, out found) :
TryGetElementAtNonIterator(source, index, out found);
}

Expand Down
4 changes: 4 additions & 0 deletions src/libraries/System.Linq/src/System/Linq/Enumerable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

namespace System.Linq
{
public static partial class Enumerable
{
[FeatureSwitchDefinition("System.Linq.Enumerable.IsSizeOptimized")]
internal static bool IsSizeOptimized { get; } = AppContext.TryGetSwitch("System.Linq.Enumerable.IsSizeOptimized", out bool isEnabled) ? isEnabled : false;

public static IEnumerable<TSource> AsEnumerable<TSource>(this IEnumerable<TSource> source) => source;

/// <summary>Returns an empty <see cref="IEnumerable{TResult}"/>.</summary>
Expand Down
4 changes: 1 addition & 3 deletions src/libraries/System.Linq/src/System/Linq/First.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,7 @@ public static TSource FirstOrDefault<TSource>(this IEnumerable<TSource> source,
}

return
#if !OPTIMIZE_FOR_SIZE
source is Iterator<TSource> iterator ? iterator.TryGetFirst(out found) :
#endif
!IsSizeOptimized && source is Iterator<TSource> iterator ? iterator.TryGetFirst(out found) :
TryGetFirstNonIterator(source, out found);
}

Expand Down
8 changes: 3 additions & 5 deletions src/libraries/System.Linq/src/System/Linq/Iterator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,9 @@ public Iterator<TSource> GetEnumerator()
/// <typeparam name="TResult">The type of the mapped items.</typeparam>
/// <param name="selector">The selector used to map each item.</param>
public virtual IEnumerable<TResult> Select<TResult>(Func<TSource, TResult> selector) =>
#if OPTIMIZE_FOR_SIZE
new IEnumerableSelectIterator<TSource, TResult>(this, selector);
#else
new IteratorSelectIterator<TSource, TResult>(this, selector);
#endif
!IsSizeOptimized
? new IteratorSelectIterator<TSource, TResult>(this, selector)
: new IEnumerableSelectIterator<TSource, TResult>(this, selector);


/// <summary>
Expand Down
4 changes: 1 addition & 3 deletions src/libraries/System.Linq/src/System/Linq/Last.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,7 @@ public static TSource LastOrDefault<TSource>(this IEnumerable<TSource> source, F
}

return
#if !OPTIMIZE_FOR_SIZE
source is Iterator<TSource> iterator ? iterator.TryGetLast(out found) :
#endif
!IsSizeOptimized && source is Iterator<TSource> iterator ? iterator.TryGetLast(out found) :
TryGetLastNonIterator(source, out found);
}

Expand Down
2 changes: 1 addition & 1 deletion src/libraries/System.Linq/src/System/Linq/Skip.SizeOpt.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace System.Linq
{
public static partial class Enumerable
{
private static IEnumerable<TSource> SkipIterator<TSource>(IEnumerable<TSource> source, int count)
private static IEnumerable<TSource> SizeOptimizedSkipIterator<TSource>(IEnumerable<TSource> source, int count)
{
using IEnumerator<TSource> e = source.GetEnumerator();
while (count > 0 && e.MoveNext()) count--;
Expand Down
2 changes: 1 addition & 1 deletion src/libraries/System.Linq/src/System/Linq/Skip.SpeedOpt.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace System.Linq
{
public static partial class Enumerable
{
private static IEnumerable<TSource> SkipIterator<TSource>(IEnumerable<TSource> source, int count) =>
private static IEnumerable<TSource> SpeedOptimizedSkipIterator<TSource>(IEnumerable<TSource> source, int count) =>
source is IList<TSource> sourceList ?
(IEnumerable<TSource>)new IListSkipTakeIterator<TSource>(sourceList, count, int.MaxValue) :
new IEnumerableSkipTakeIterator<TSource>(source, count, -1);
Expand Down
6 changes: 2 additions & 4 deletions src/libraries/System.Linq/src/System/Linq/Skip.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,12 @@ public static IEnumerable<TSource> Skip<TSource>(this IEnumerable<TSource> sourc

count = 0;
}
#if !OPTIMIZE_FOR_SIZE
else if (source is Iterator<TSource> iterator)
else if (!IsSizeOptimized && source is Iterator<TSource> iterator)
{
return iterator.Skip(count) ?? Empty<TSource>();
}
#endif

return SkipIterator(source, count);
return IsSizeOptimized ? SizeOptimizedSkipIterator(source, count) : SpeedOptimizedSkipIterator(source, count);
}

public static IEnumerable<TSource> SkipWhile<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
Expand Down
4 changes: 2 additions & 2 deletions src/libraries/System.Linq/src/System/Linq/Take.SizeOpt.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace System.Linq
{
public static partial class Enumerable
{
private static IEnumerable<TSource> TakeIterator<TSource>(IEnumerable<TSource> source, int count)
private static IEnumerable<TSource> SizeOptimizedTakeIterator<TSource>(IEnumerable<TSource> source, int count)
{
Debug.Assert(count > 0);

Expand All @@ -19,7 +19,7 @@ private static IEnumerable<TSource> TakeIterator<TSource>(IEnumerable<TSource> s
}
}

private static IEnumerable<TSource> TakeRangeIterator<TSource>(IEnumerable<TSource> source, int startIndex, int endIndex)
private static IEnumerable<TSource> SizeOptimizedTakeRangeIterator<TSource>(IEnumerable<TSource> source, int startIndex, int endIndex)
{
Debug.Assert(source is not null);
Debug.Assert(startIndex >= 0 && startIndex < endIndex);
Expand Down
4 changes: 2 additions & 2 deletions src/libraries/System.Linq/src/System/Linq/Take.SpeedOpt.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace System.Linq
{
public static partial class Enumerable
{
private static IEnumerable<TSource> TakeIterator<TSource>(IEnumerable<TSource> source, int count)
private static IEnumerable<TSource> SpeedOptimizedTakeIterator<TSource>(IEnumerable<TSource> source, int count)
{
Debug.Assert(source is not null && !IsEmptyArray(source));
Debug.Assert(count > 0);
Expand All @@ -19,7 +19,7 @@ private static IEnumerable<TSource> TakeIterator<TSource>(IEnumerable<TSource> s
new IEnumerableSkipTakeIterator<TSource>(source, 0, count - 1);
}

private static IEnumerable<TSource> TakeRangeIterator<TSource>(IEnumerable<TSource> source, int startIndex, int endIndex)
private static IEnumerable<TSource> SpeedOptimizedTakeRangeIterator<TSource>(IEnumerable<TSource> source, int startIndex, int endIndex)
{
Debug.Assert(source is not null && !IsEmptyArray(source));
Debug.Assert(startIndex >= 0 && startIndex < endIndex);
Expand Down
Loading

0 comments on commit adf123c

Please sign in to comment.