runtime: Performance regression in System.ServiceProcess.ServiceController, .Net Core App 2.1

This was found in PowerShell Core6 (https://github.com/PowerShell/PowerShell) while investigating PowerShell cmdlet perf regression. I tracked the perf regression to this .Net type:

System.ServiceProcess.ServiceController

Using this type is approximately 30 times slower when running under .Net CoreApp 2.1

Repro steps:

using System;
using System.ServiceProcess;

namespace ConsoleApp3
{
    class Program
    {
        static void Main(string[] args)
        {
            System.Console.WriteLine("Starting loop");
            var start = DateTime.Now;

            for (var i=0; i<100; i++)
            {
                var winRMService = new ServiceController("WinRM");
                if (winRMService != null)
                {
                    var status = winRMService.Status;
                }
            }

            var end = DateTime.Now;

            System.Console.WriteLine("End loop");
            System.Console.WriteLine(String.Format("Time in milliseconds = {0}", (end - start).Milliseconds));
            System.Console.WriteLine("Press any key to continue");
            System.Console.ReadKey();
        }
    }
}

Results: Under .Net Core App 2.1 Time in milliseconds = 714

Under .Net Full CLR Time in milliseconds = 24

Expected: Use of ServiceController type should have approximately the same performance between each version of .Net.

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Comments: 20 (13 by maintainers)

Most upvoted comments

I wrote small micro-benchmark to verify it. It proves that on .NET Core given property (.Status) is actually 23% faster:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFrameworks>net461;netcoreapp2.0;netcoreapp2.1</TargetFrameworks>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="BenchmarkDotNet" Version="0.11.1" />
    <PackageReference Include="System.ServiceProcess.ServiceController" Version="4.5.0" />
  </ItemGroup>

</Project>
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Jobs;
using BenchmarkDotNet.Running;
using BenchmarkDotNet.Toolchains.CsProj;
using System.ServiceProcess;

namespace ServiceControllerPerf
{
    class Program
    {
        static void Main(string[] args) 
            => BenchmarkRunner.Run<Perf>(
                DefaultConfig.Instance
                  .With(Job.Clr.AsBaseline())
                  .With(Job.Core.With(CsProjCoreToolchain.NetCoreApp20).WithId("Core 2.0"))
                  .With(Job.Core.With(CsProjCoreToolchain.NetCoreApp21).WithId("Core 2.1")));
    }

    public class Perf
    {
        private readonly ServiceController winRMService = new ServiceController("WinRM");

        [Benchmark]
        public ServiceControllerStatus GetStatus() => winRMService.Status;
    }
}

dotnet run -c Release -f netcoreapp2.1


BenchmarkDotNet=v0.11.1, OS=Windows 10.0.17134.228 (1803/April2018Update/Redstone4)
Intel Xeon CPU E5-1650 v4 3.60GHz (Max: 2.10GHz), 1 CPU, 12 logical and 6 physical cores
.NET Core SDK=2.1.301
  [Host]   : .NET Core 2.1.1 (CoreCLR 4.6.26606.02, CoreFX 4.6.26606.05), 64bit RyuJIT
  Clr      : .NET Framework 4.7.2 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.3132.0
  Core 2.0 : .NET Core 2.0.7 (CoreCLR 4.6.26328.01, CoreFX 4.6.26403.03), 64bit RyuJIT
  Core 2.1 : .NET Core 2.1.1 (CoreCLR 4.6.26606.02, CoreFX 4.6.26606.05), 64bit RyuJIT


Method Job Mean Error StdDev Scaled
GetStatus Clr 10.996 ns 0.0461 ns 0.0409 ns 1.00
GetStatus Core 2.0 8.496 ns 0.0237 ns 0.0210 ns 0.77
GetStatus Core 2.1 8.469 ns 0.0406 ns 0.0360 ns 0.77

@PaulHigin which profiler did you use? Could you share some traces?