Log in

Or connect using:
Entries feed for fanf
johnskeet July 26 2014, 11:23

New blog hosting

http://feedproxy.google.com/~r/JonSkeetCodingBlog/~3/aN0BFrNjgIw/

http://jonskeetcodingblog.wordpress.com/?p=1373

As some of you have noticed (and let me know), my old blog hosting provider recently moved off Community Server to WordPress. I figured that as all the links we being broken anyway, now would be a good time to move off msmvps.com anyway. The old posts are still there, but my blog’s new home is codeblog.jonskeet.uk. Hopefully I’ve fixed (almost) all the internal links from one blog post to another, and Nick Craver has generously agreed to fix up links on Stack Overflow, too. I’ll fix up my web site references when I get the chance, and hopefully things will get back to (mostly) normal as soon as possible. Obviously there’ll be plenty of links elsewhere around the web which I can’t fix, but I suspect I’m my own primary consumer, so to speak.

There are still bound to be teething issues, commenting problems, goodness knows what – but hopefully the blog itself will be in a better state than it was before, overall.

Additionally, I’m hoping to gradually (very gradually) coalesce my online presence around the jonskeet.uk domain. I haven’t set that up at all yet, but that’s the plan.

Apologies for link breakage, and fingers crossed it’ll be relatively smooth sailing from here on.


johnskeet July 26 2014, 11:23

Micro-optimization: the surprising inefficiency of readonly fields

http://feedproxy.google.com/~r/JonSkeetCodingBlog/~3/BOi0n9PaXlY/

Introduction

Recently I’ve been optimizing the heck out of Noda Time. Most of the time this has been a case of the normal measurement, find bottlenecks, carefully analyse them, lather, rinse, repeat. Yesterday I had a hunch about a particular cost, and decided to experiment… leading to a surprising optimization.

Noda Time’s core types are mostly value types – date/time values are naturally value types, just as DateTime and DateTimeOffset are in the BCL. Noda Time’s types are a bit bigger than most value types, however – the largest being ZonedDateTime, weighing in at 40 bytes in an x64 CLR at the moment. (I can shrink it down to 32 bytes with a bit of messing around, although it’s not terribly pleasant to do so.) The main reason for the bulk is that we have two reference types involved (the time zone and the calendar system), and in Noda Time 2.0 we’re going to have nanosecond resolution instead of tick resolution (so we need 12 bytes just to store a point in time). While this goes against the Class Library Design Guidelines, it would be odd for the smaller types (LocalDate, LocalTime) to be value types and the larger ones to be reference types. Overall, these still feel like value types.

A lot of these value types are logically composed of each other:

  • A LocalDate is a YearMonthDay and a CalendarSystem reference
  • A LocalDateTime is a LocalDate and a LocalTime
  • An OffsetDateTime is a LocalDateTime and an Offset
  • A ZonedDateTime is an OffsetDateTime and a DateTimeZone reference

This leads to a lot of delegation, potentially – asking a ZonedDateTime for its Year could mean asking the OffsetDateTime, which would ask the LocalDateTime, which would ask the LocalDate, which would ask the YearMonthDay. Very nice from a code reuse point of view, but potentially inefficient due to copying data.

Why would there be data copying involved? Well, that’s where this blog post comes in.

Behaviour of value type member invocations

When an instance member (method or property) belonging to a value type is invoked, the exact behaviour depends on the kind of expression it is called on. From the C# 5 spec, section 7.5.5 (where E is the expression the member M is invoked on, and the type declaring M is a value type):

If E is not classified as a variable, then a temporary local variable of E’s type is created and the value of E is assigned to that variable. E is then reclassified as a reference to that temporary local variable. The temporary variable is accessible as this within M, but not in any other way. Thus, only when E is a true variable is it possible for the caller to observe the changes that M makes to this.

So when is a variable not a variable? When it’s readonly… from section 7.6.4 (emphasis mine) :

If T is a struct-type and I identifies an instance field of that class-type:

  • If E is a value, or if the field is readonly and the reference occurs outside an instance constructor of the struct in which the field is declared, then the result is a value, namely the value of the field I in the struct instance given by E.

(There’s a very similar bullet for T being a class-type; the important part is that the field type is a value type

The upshot is that if you have a method call of:

int result = someField.Foo();

then it’s effectively converted into this:

var tmp = someField;
int result = tmp.Foo();

Now if the type of the field is quite a large value type, but Foo() doesn’t modify the value (which it never does within my value types), that’s performing a copy completely unnecessarily.

To see this in action outside Noda Time, I’ve built a little sample app.

Show me the code!

Our example is a simple 256-bit type, composed of 4 Int64 values. The type itself doesn’t do anything useful – it just holds the four values, and exposes them via properties. We then measure how long it takes to sum the four properties lots of times.

using System;
using System.Diagnostics; </p>

public struct Int256
{
    private readonly long bits0;
    private readonly long bits1;
    private readonly long bits2;
    private readonly long bits3;
    
    public Int256(long bits0, long bits1, long bits2, long bits3)
    {
        this.bits0 = bits0;
        this.bits1 = bits1;
        this.bits2 = bits2;
        this.bits3 = bits3;
    }
    
    public long Bits0 { get { return bits0; } }
    public long Bits1 { get { return bits1; } }
    public long Bits2 { get { return bits2; } }
    public long Bits3 { get { return bits3; } }
}

class Test
{
    private readonly Int256 value;

    public Test()
    {
        value = new Int256(1L, 5L, 10L, 100L);
    }
    
    public long TotalValue 
    { 
        get 
        {
            return value.Bits0 + value.Bits1 + value.Bits2 + value.Bits3; 
        }
    }
    
    public void RunTest()
    {
        // Just make sure it’s JITted…
        var sample = TotalValue;
        Stopwatch sw = Stopwatch.StartNew();
        long total = 0;
        for (int i = 0; i < 1000000000; i++)
        {
            total += TotalValue;
        }
        sw.Stop();
        Console.WriteLine("Total time: {0}ms", sw.ElapsedMilliseconds);
    }
    
    static void Main()
    {
        new Test().RunTest();
    }
}

Building this from the command line with /o+ /debug- and running (in a 64-bit CLR, but no RyuJIT) this takes about 20 seconds to run on my laptop. We can make it much faster with just one small change:

class Test
{
    private Int256 value;

    // Code as before
}

The same test now takes about 4 seconds – a 5-fold speed improvement, just by making a field non-readonly. If we look at the IL for the TotalValue property, the copying becomes obvious. Here it is when the field is readonly:

.method public hidebysig specialname instance int64 
        get_TotalValue() cil managed
{
  // Code size       60 (0x3c)
  .maxstack  2
  .locals init (valuetype Int256 V_0,
           valuetype Int256 V_1,
           valuetype Int256 V_2,
           valuetype Int256 V_3)
  IL_0000:  ldarg.0
  IL_0001:  ldfld      valuetype Int256 Test::’value’
  IL_0006:  stloc.0
  IL_0007:  ldloca.s   V_0
  IL_0009:  call       instance int64 Int256::get_Bits0()
  IL_000e:  ldarg.0
  IL_000f:  ldfld      valuetype Int256 Test::’value’
  IL_0014:  stloc.1
  IL_0015:  ldloca.s   V_1
  IL_0017:  call       instance int64 Int256::get_Bits1()
  IL_001c:  add
  IL_001d:  ldarg.0
  IL_001e:  ldfld      valuetype Int256 Test::’value’
  IL_0023:  stloc.2
  IL_0024:  ldloca.s   V_2
  IL_0026:  call       instance int64 Int256::get_Bits2()
  IL_002b:  add
  IL_002c:  ldarg.0
  IL_002d:  ldfld      valuetype Int256 Test::’value’
  IL_0032:  stloc.3
  IL_0033:  ldloca.s   V_3
  IL_0035:  call       instance int64 Int256::get_Bits3()
  IL_003a:  add
  IL_003b:  ret
} // end of method Test::get_TotalValue

And here it is when the field’s not readonly:

.method public hidebysig specialname instance int64 
        get_TotalValue() cil managed
{
  // Code size       48 (0×30)
  .maxstack  8
  IL_0000:  ldarg.0
  IL_0001:  ldflda     valuetype Int256 Test::’value’
  IL_0006:  call       instance int64 Int256::get_Bits0()
  IL_000b:  ldarg.0
  IL_000c:  ldflda     valuetype Int256 Test::’value’
  IL_0011:  call       instance int64 Int256::get_Bits1()
  IL_0016:  add
  IL_0017:  ldarg.0
  IL_0018:  ldflda     valuetype Int256 Test::’value’
  IL_001d:  call       instance int64 Int256::get_Bits2()
  IL_0022:  add
  IL_0023:  ldarg.0
  IL_0024:  ldflda     valuetype Int256 Test::’value’
  IL_0029:  call       instance int64 Int256::get_Bits3()
  IL_002e:  add
  IL_002f:  ret
} // end of method Test::get_TotalValue

Note that it’s still loading the field address (ldflda) four times. You might expect that copying the field onto the stack once via a temporary variable would be faster, but that ends up at about 6.5 seconds on my machine.

There is an optimization which is even faster – moving the totalling property into Int256. That way (with the non-readonly field, still) the total time is less than a second – twenty times faster than the original code!

Conclusion

This isn’t an optimization I’d recommend in general. Most code really doesn’t need to be micro-optimized this hard, and most code doesn’t deal with large value types like the ones in Noda Time. However, I regard Noda Time as a sort of "system level" library, and I don’t ever want someone to decide not to use it on  performance grounds. My benchmarks show that for potentially-frequently-called operations (such as the properties on ZonedDateTime) it really does make a difference, so I’m going to go for it.

I intend to apply a custom attribute to each of these "would normally be readonly" fields to document the intended behaviour of the field – and then when Roslyn is fully released, I’ll probably write a test to validate that all of these fields would still compile if the field were made readonly (e.g. that they’re never assigned to outside the constructor).

Aside from anything else, I find the subtle difference in behaviour between a readonly field and a read/write field fascinating… it’s something I’d been vaguely aware of in the past, but this is the first time that it’s had a practical impact on me. Maybe it’ll never make any difference to your code… but it’s probably worth being aware of anyway.


jwz_blog July 26 2014, 11:00

Today in Meatsack Furniture News

http://www.jwz.org/blog/2014/07/today-in-meatsack-furniture-news/

http://jwz.org/b/yh6x

Gigi Barker:

Moulded silicone is used as a base to create a series of squidgy seats designed to mimic rolls of fat. The silicone is mixed with human pheromones and aftershave so the seats have the smell of skin as well as the appearance.

west_of_ealing July 26 2014, 10:42

There But For The Grace of God......

http://magistratesblog.blogspot.com/2014/07/there-but-for-grace-of-god.html

This Judge (in fact a Recorder, who has the powers of a circuit judge but sits part-time) has been reported to the authorities for apparently falling asleep on the Bench. The usual suspects have lined up to denounce him, and Vera Baird, who ought to know better, has just told the BBC  this casts the criminal system in a bad light, or words to that effect. She is reported thus: 
 Former solicitor general Vera Baird said she was shocked by the allegation.
"It's a pretty personally insulting thing for somebody when you're describing probably the most important event in your life.
"But also what does it say about the state, about judicial governance, about the criminal justice system?"
She added it would reinforce general views that the judiciary "are out of touch".
This is utter nonsense: what it proves is that the judiciary is made up of human beings, most of them well the wrong side of forty, and some a good deal older than that, and therefore prone to nodding off at times
Now if the unfortunate  Recorder  had bullied a witness or misdirected the jury, or committed any one of the judicial sins that amount to misconduct, then they are sins of commission. To fall asleep is a misfortune: I have sometimes felt drowsiness creeping up on me, particularly on a warm afternoon two hours in to the afternoon in a court with ineffective air conditioning and being forced to listen to an advocate who thinks he is being paid by the yard. I sit with two colleagues, and as I am usually the one in the middle I keep an eye on the other two, and I hope that they will keep an eye on me.
I used to sit with a colleague, now retired, who was a local GP. In potentially soporific cases we agreed to monitor each other.
There cannot be many magistrates and judges who have never come close to dropping off.

I hope that the JCO cuts the guy a little slack. Unfortunately the rules will forbid him from ever disclosing his point of view.
statusq July 26 2014, 10:13

All-you-can-eat books

http://feedproxy.google.com/~r/statusq/~3/xGcYmI11rl0/

http://www.statusq.org/?p=5968

John Naughton’s Observer column this week discusses the leaked plans for Amazon’s ‘Kindle Unlimited’ service.

Amazon’s move will be as discombobulating for the book publishing industry as the advent of Spotify was for the music industry.

The analogy is a good one. Creative content is being commoditised: as a rough approximation, you can’t make money from selling music any more, only from going on tours. You can’t make a living from selling photos, only from running photography workshops. And for some time it’s been pretty rare for anyone to be the family bread-winner by writing books — you also need to teach creative writing at the local Further-Ed college — but I think it’s going to become much rarer. Expect authors to start charging a lot more for their appearances at literary festivals.

And, lest you think, “Oh, this isjust a wild idea from somebody in marketing that was leaked by accident”, it has now been launched in the US. Six quid a month for all the books you can read, available instantly.

Just think what those monks in the scriptoria would have said.

hackernewsdaily July 26 2014, 00:17

Daily Hacker News for 2014-07-25

Welcome to the new LiveJournal

Some changes have been made to LiveJournal, and we hope you enjoy them! As we continue to improve the site on a daily basis to make your experience here better and faster, we would greatly appreciate your feedback about these changes. Please let us know what we can do for you!

Send feedback

Switch back to old version

LiveJournal Feedback

See a bug? Let us know! Here you can also share your thoughts and ideas about updates to LiveJournal

Your request has been filed. You can track the progress of your request at:
If you have any other questions or comments, you can add them to that request at any time.

Send another report Close feedback form

If you're a LiveJournal user, you will be logged in after submitting your request.

(optional, if you're a LiveJournal user only)

(optional, if you're a LiveJournal user only)

(not shown to the public)

If you have a billing inquiry, please go here to submit your question.

Provide a link to the page where you are experiencing the error

Do not include any sensitive information, such as your password or phone number. No HTML allowed.

If you can't pass the human test, email your inquiry to: support@livejournal.com