Posts about C#

Measuring Performance Improvements in .NET Core with BenchmarkDotNet (Part 1)



A few days ago Stephen Toub published a great post at the Microsoft .NET Blog: Performance Improvements in .NET Core. He showed some significant performance changes in .NET Core 2.0 Preview 1 (compared with .NET Framework 4.7). The .NET Core uses RyuJIT for generating assembly code. When I first tried RyuJIT (e.g., CTP2, CTP5, 2014), I wasn't excited about this: the preview versions had some bugs, and it worked slowly on my applications. However, the idea of a rethought and open-source JIT-compiler was a huge step forward and investment in the future. RyuJIT had been developed very actively in recent years: not only by Microsoft but with the help of the community. I'm still not happy about the generated assembly code in some methods, but I have to admit that the RyuJIT (as a part of .NET Core) works pretty well today: it shows a good performance level not only on artificial benchmarks but also on real user code. Also, there are a lot of changes not only in dotnet/coreclr (the .NET Core runtime), but also in dotnet/corefx (the .NET Core foundational libraries). It's very nice to watch how the community helps to optimize well-used classes which have not changed for years.

Now let's talk about benchmarks. For the demonstration, Stephen wrote a set of handwritten benchmarks. A few people (in comments and on HackerNews) asked about BenchmarkDotNet regarding these samples (as a better tool for performance measurements). So, I decided to try all these benchmarks on BenchmarkDotNet.

In this post, we will discuss how can BenchmarkDotNet help in such performance investigations, which benchmarking approaches (and when) are better to use, and how can we improve these measurements.

Read more    Comments


BenchmarkDotNet v0.10.7



BenchmarkDotNet v0.10.7 has been released. In this post, I will briefly cover the following features:

  • LINQPad support
  • Filters and categories
  • Updated Setup/Cleanup attributes
  • Better Value Types support
  • Building Sources on Linux

Read more    Comments


LegacyJIT-x86 and first method call



Today I tell you about one of my favorite benchmarks (this method doesn't return a useful value, we need it only as an example):

[Benchmark]
public string Sum()
{
    double a = 1, b = 1;
    var sw = new Stopwatch();
    for (int i = 0; i < 10001; i++)
        a = a + b;
    return string.Format("{0}{1}", a, sw.ElapsedMilliseconds);
}

An interesting fact: if you call Stopwatch.GetTimestamp() before the first call of the Sum method, you improve Sum performance several times (works only with LegacyJIT-x86).

Read more    Comments


Visual Studio and ProjectTypeGuids.cs



It's a story about how I tried to open a project in Visual Studio for a few hours. The other day, I was going to do some work. I pulled last commits from a repo, opened Visual Studio, and prepared to start coding. However, one of a project in my solution failed to open with a strange message:

error  : The operation could not be completed.

In the Solution Explorer, I had "load failed" as a project status and the following message instead of the file tree: "The project requires user input. Reload the project for more information." Hmm, ok, I reloaded the project and got a few more errors:

error  : The operation could not be completed.
error  : The operation could not be completed.

Read more    Comments


Blittable types



Challenge of the day: what will the following code display?

[StructLayout(LayoutKind.Explicit)]
public struct UInt128
{
    [FieldOffset(0)]
    public ulong Value1;
    [FieldOffset(8)]
    public ulong Value2;
}
[StructLayout(LayoutKind.Sequential)]
public struct MyStruct
{
    public UInt128 UInt128;
    public char Char;
}
class Program
{
    public static unsafe void Main()
    {
        var myStruct = new MyStruct();
        var baseAddress = (int)&myStruct;
        var uInt128Adress = (int)&myStruct.UInt128;
        Console.WriteLine(uInt128Adress - baseAddress);
        Console.WriteLine(Marshal.OffsetOf(typeof(MyStruct), "UInt128"));
    }
}

A hint: two zeros or two another same values are wrong answers in the general case. The following table shows the console output on different runtimes:

MS.NET-x86MS.NET-x64Mono
uInt128Adress - baseAddress 480
Marshal.OffsetOf(typeof(MyStruct), "UInt128")000

If you want to know why it happens, you probably should learn some useful information about blittable types.

Read more    Comments


RyuJIT RC and constant folding



Update: The below results are valid for the release version of RyuJIT.

The challenge of the day: which method is faster?

public double Sqrt13()
{
    return Math.Sqrt(1) + Math.Sqrt(2) + Math.Sqrt(3) + Math.Sqrt(4) + Math.Sqrt(5) + 
           Math.Sqrt(6) + Math.Sqrt(7) + Math.Sqrt(8) + Math.Sqrt(9) + Math.Sqrt(10) + 
           Math.Sqrt(11) + Math.Sqrt(12) + Math.Sqrt(13);
}
public double Sqrt14()
{
    return Math.Sqrt(1) + Math.Sqrt(2) + Math.Sqrt(3) + Math.Sqrt(4) + Math.Sqrt(5) + 
           Math.Sqrt(6) + Math.Sqrt(7) + Math.Sqrt(8) + Math.Sqrt(9) + Math.Sqrt(10) + 
           Math.Sqrt(11) + Math.Sqrt(12) + Math.Sqrt(13) + Math.Sqrt(14);
}

I have measured the methods performance with help of BenchmarkDotNet for RyuJIT RC (a part of .NET Framework 4.6 RC) and received the following results:

// BenchmarkDotNet=v0.7.4.0
// OS=Microsoft Windows NT 6.2.9200.0
// Processor=Intel(R) Core(TM) i7-4702MQ CPU @ 2.20GHz, ProcessorCount=8
// CLR=MS.NET 4.0.30319.0, Arch=64-bit  [RyuJIT]
Common:  Type=Math_DoubleSqrtAvx  Mode=Throughput  Platform=X64  Jit=RyuJit  .NET=Current  

 Method |  AvrTime |    StdDev |         op/s |
------- |--------- |---------- |------------- |
 Sqrt13 | 55.40 ns |  0.571 ns |  18050993.06 |
 Sqrt14 |  1.43 ns | 0.0224 ns | 697125029.18 |

How so? If I add one more Math.Sqrt to the expression, the method starts work 40 times faster! Let's examine the situation..

Read more    Comments


Unrolling of small loops in different JIT versions



Challenge of the day: what will the following code display?

struct Point
{
    public int X;
    public int Y;
}
static void Print(Point p)
{
    Console.WriteLine(p.X + " " + p.Y);
}
static void Main()
{
    var p = new Point();
    for (p.X = 0; p.X < 2; p.X++)
        Print(p);
}

The right answer: it depends. There is a bug in CLR2 JIT-x86 which spoil this wonderful program. This story is about optimization that called unrolling of small loops. This is a very interesting theme, let's discuss it in detail.

Read more    Comments


RyuJIT CTP5 and loop unrolling



RyuJIT will be available soon. It is a next generation JIT-compiler for .NET-applications. Microsoft likes to tell us about the benefits of SIMD using and JIT-compilation time reducing. But what about basic code optimization which is usually applying by a compiler? Today we talk about the loop unrolling (unwinding) optimization. In general, in this type of code optimization, the code

for (int i = 0; i < 1024; i++)
    Foo(i);

transforms to

for (int i = 0; i < 1024; i += 4)
{
    Foo(i);
    Foo(i + 1);
    Foo(i + 2);
    Foo(i + 3);
}

Such approach can significantly increase performance of your code. So, what's about loop unrolling in .NET?

Read more    Comments


JIT version determining in runtime



Sometimes I want to know used JIT compiler version in my little C# experiments. It is clear that it is possible to determine the version in advance based on the environment. However, sometimes I want to know it in runtime to perform specific code for the current JIT compiler. More formally, I want to get the value from the following enum:

public enum JitVersion
{
    Mono, MsX86, MsX64, RyuJit
}

It is easy to detect Mono by existing of the Mono.Runtime class. Otherwise, we can assume that we work with Microsoft JIT implementation. It is easy to detect JIT-x86 with help of IntPtr.Size == 4. The challenge is to distinguish JIT-x64 and RyuJIT. Next, I will show how you can do it with help of the bug from my previous post.

Read more    Comments


A bug story about JIT-x64



Can you say, what will the following code display for step=1?

public void Foo(int step)
{
    for (int i = 0; i < step; i++)
    {
        bar = i + 10;
        for (int j = 0; j < 2 * step; j += step)
            Console.WriteLine(j + 10);
    }
}

If you think about specific numbers, you are wrong. The right answer: it depends. The post title suggests to us, the program can has a strange behavior for x64.

Read more    Comments


A story about JIT-x86 inlining and starg



Sometimes you can learn a lot during reading source .NET. Let's open the source code of a Decimal constructor from .NET Reference Source (mscorlib/system/decimal.cs,158):

// Constructs a Decimal from an integer value.
//
public Decimal(int value) {
    //  JIT today can't inline methods that contains "starg" opcode.
    //  For more details, see DevDiv Bugs 81184: x86 JIT CQ: Removing the inline striction of "starg".
    int value_copy = value;
    if (value_copy >= 0) {
        flags = 0;
    }
    else {
        flags = SignMask;
        value_copy = -value_copy;
    }
    lo = value_copy;
    mid = 0;
    hi = 0;
}

The comment states that JIT-x86 can't apply the inlining optimization for a method that contains the starg IL-opcode. Curious, is not it?

Read more    Comments


Strange behavior of FindElementsInHostCoordinates in WinRT



Silverlight features a splendid method: VisualTreeHelper.FindElementsInHostCoordinates. It allows the HitTest, i.e. makes it possible for a point or rectangle to search for all visual sub-tree objects that intersect this rectangle or point. Formally the same method VisualTreeHelper.FindElementsInHostCoordinates is available in WinRT. And it seems the method looks in the same way, but there is a little nuance. It works differently in different versions of the platform. So, let’s see what’s going on.

Read more    Comments


About System.Drawing.Color and operator ==



Operator == that allows easy comparison of your objects is overridden for many standard structures in .NET. Unfortunately, not every developer really knows what is actually compared when working with this wonderful operator. This brief blog post will show the comparison logic based on a sample of System.Drawing.Color. What do you think the following code will get:

var redName = Color.Red;
var redArgb = Color.FromArgb(255, 255, 0, 0);
Console.WriteLine(redName == redArgb);

Read more    Comments


Jon Skeet's Quiz



Jon Skeet was once asked to give three questions to check how well you know C#. He asked the following questions:

  • Q1. What constructor call can you write such that this prints True (at least on the Microsoft .NET implementation)?
object x = new /* fill in code here */;
object y = new /* fill in code here */;
Console.WriteLine(x == y);

Note that it’s just a constructor call, and you can’t change the type of the variables.

  • Q2. How can you make this code compile such that it calls three different method overloads?
void Foo()
{
    EvilMethod<string>();
    EvilMethod<int>();
    EvilMethod<int?>();
}
  • Q3. With a local variable (so no changing the variable value cunningly), how can you make this code fail on the second line?
string text = x.ToString(); // No exception
Type type = x.GetType(); // Bang!

These questions seemed interesting to me, that is why I decided to discuss the solutions.

Read more    Comments


Unobviousness in use of C# closures



C# gives us an ability to use closures. This is a powerful tool that allows anonymous methods and lambda-functions to capture unbound variables in their lexical scope. And many programmers in .NET world like using closures very much, but only few of them understand how they really work. Let’s start with a simple sample:

public void Run()
{
  int e = 1;
  Foo(x => x + e);
}

Nothing complicated happens here: we just captured a local variable e in its lambda that is passed to some Foo method. Let’s see how the compiler will expand such construction.*

public void Run()
{
  DisplayClass c = new DisplayClass();
  c.e = 1;  
  Foo(c.Action);
}
private sealed class DisplayClass
{
  public int e;
  public int Action(int x)
  {
    return x + e;
  }
}

Read more    Comments


Wrapping C# class for use in COM



Let us have a C# class that makes something useful, for example:

public class Calculator
{
    public int Sum(int a, int b)
    {
        return a + b;
    }
}

Let’s create a COM interface for this class to make it possible to use its functionality in other areas. At the end we will see how this class is used in Delphi environment.

Read more    Comments