February, 2013

  • The Old New Thing

    This code would be a lot faster if it weren't for the synchronization

    • 56 Comments

    This is a story from a friend of a friend, which makes it probably untrue, but I still like the story.

    One of my colleagues jokingly suggested that we could speed up our code by adding these lines to our project

    #define EnterCriticalSection(p) ((void)0)
    #define LeaveCriticalSection(p) ((void)0)
    

    I replied, "You think you're joking, but you're not."

    According to legend, there was a project whose product was running too slow, so they spun off a subteam to see what architectural changes would help them improve their performance. The subteam returned some time later with a fork of the project that they had "tuned". And it was indeed the case that the performance-tuned version ran a lot faster.

    Later, the development team discovered that part of the "tuning" involved simply deleting all the synchronization. They didn't replace it with lock-free algorithms or anything that clever. They just removed all the critical sections.

  • The Old New Thing

    For the Nitpickers: Enhanced-mode Windows 3.0 didn't exactly run a copy of standard-mode Windows inside the virtual machine

    • 45 Comments

    Generally speaking, Enhanced-mode Windows 3.0 ran a copy of standard-mode Windows inside the virtual machine. This statement isn't exactly true, but it's true enough.

    Commenter Nitpicker objected, "Why are you threatening us with the Nitpicker's Corner for asking about this issue instead of explaining it once and linking it everywhere?"

    Okay, first of all, as far as I can tell, you're the first person to ask about the issue. So you can't say "Everybody who asks about the issue is threatened with the Nitpicker's Corner" because up until you made your comment, nobody ever asked. Okay, well, technically you can say it, because every statement quantified over the empty set is true. But it is equally true that, at the time you made your comment, that "Everybody who asks about the issue is awarded a new car." So it is not a meaningfully true statement.

    I haven't bothered explaining the issue because the issue has never been central to the main point of whatever article happens to bring it up. The statement is true enough for the purpose of discussion, and the various little corners in which the statement breaks down have no bearing on the original topic. Nitpickers would point out that you can't combine velocities by simple addition because of the laws of Special Relativity. Even when the situation under discussion takes place at non-relativistic speeds.

    As for the suggestion, "Explain it once and link it everywhere," you're assuming that I can even explain it once, that doing so is less work than just saying "not exactly true, but true enough," and that I would enjoy explaining it in the first place.

    If you don't like it, you can ask for your money back.

    Okay, I went back and dug through the old Windows 3.0 source code to answer this question. It took me about four hours to study it all, try to understand what the code was doing, and then distill the conclusions into this article. Writing up the results took another two hours. That's six hours I could've spent doing something enjoyable.

    The 16-bit Windows kernel was actually three kernels. One if you were using an 8086 processor, another if you were using an 80286 processor, and a third if you were using an 80386 processor. The 8086 kernel was a completely separate beast, but the 80286 and 80386 kernels shared a lot of code in common. The major difference between the 80286 and 80386 kernels was in how they managed memory, because the descriptor tables on the 80386 were a different format from the descriptor tables on the 80286. The 80386 memory manager could also take advantage of the new 32-bit registers.

    But the difference between the 80286 and 80386 kernels were not based on whether you were running Standard or Enhanced mode. If you're running on an 80386 processor, then you get the 80386 kernel, regardless of whether you're using Standard or Enhanced mode Windows. And since Enhanced mode Windows required an 80386 processor, the behavioral changes between Standard and Enhanced mode were restricted to the 80386 kernel.

    The 80386 kernel was designed to run as a DPMI client. It asked the DPMI host to take it into protected mode, then used the DPMI interface to do things like allocate selectors and allocate memory. If you ran Windows in Standard mode, then the DPMI host was a custom-built DOS extender that was created just for Standard mode Windows. If you ran Windows in Enhanced mode, then the DPMI host was the 32-bit virtual machine manager. Abstracting to the DPMI interface allowed a single 80386 kernel to run in both Standard and Enhanced modes.

    And in fact if you ran Enhanced mode Windows with paging disabled, then the code running in the 80386 kernel was pretty much the same code that ran if you had run the 80386 kernel under Standard mode Windows.

    One obvious place where the behavior changed was in the code to manage MS-DOS applications, because Enhanced mode Windows could multi-task MS-DOS applications, and Standard mode Windows could not.

    Another place where the behavior changed was in in the code to allocate more selectors: The attempt to retry after extending the local descriptor table was skipped if you were running under the Standard mode DOS extender, because the Standard mode DOS extender didn't support extending the local descriptor table.

    And another difference is that the Windows idle loop in Enhanced mode would issue a special call to release its time slice to any multi-tasking MS-DOS applications. (If you were running in Standard mode, there were no multi-tasking MS-DOS applications, so there was nobody to release your time slice to.)

    Another thing special that the 80386 kernel did was register with the virtual machine manager so that it could display an appropriate message when you pressed Ctrl+Alt+Del. For example, you saw this message if you hit Ctrl+Alt+Del while there was a hung Windows application:

    Contoso Deluxe Music Composer


    This Windows application has stopped responding to the system.

    *  Press ESC to cancel and return to Windows.
    *  Press ENTER to close this application that is not responding.
       You will lose any unsaved information in this application.
    *  Press CTRL+ALT+DEL again to restart your computer. You will
       lose any unsaved information in all applications.

    But all these differences are minor in the grand scheme of things. The window manager behaved the same in Standard mode and Enhanced mode. GDI behaved the same in Standard mode and Enhanced mode. Printer drivers behaved the same in Standard mode and Enhanced mode. Only the low-level kernel bits had to change behavior between Standard mode and Enhanced mode, and as you can see, even those behavior changes were relatively minor.

    That's why I said it was "true enough" that what was running inside the virtual machine was a copy of Standard-mode Windows.

  • The Old New Thing

    What's the story of the onestop.mid file in the Media directory?

    • 45 Comments

    If you look in your C:\Windows\Media folder, you'll find a MIDI file called onestop. What's the story behind this odd little MIDI file? Aaron Margosis considers this file a security risk because "if an attacker can cause that file to be played, it will cause lasting mental pain and anguish to everybody within earshot."

    Despite Wikipedia's claims[citation needed], the file is not an Easter Egg. The file was added in in Windows XP with the comment "Add cool MIDI files to replace bad old ones." So as bad as onestop is, the old ones must have been even worse!

    Okay, but why were they added?

    For product support.

    The product support team wants at least one MIDI file present on the system by default for troubleshooting purposes. That way, problems with MIDI playback can be diagnosed without making the customer go to a Web page and download a MIDI file. When asked why the song is so awful, the developer who added the file explained, "Believe it or not, OneStop is 'less bad' than the ones that it replaced. (Dance of the Sugar Plum Fairy, etc.)" Another reason for replacing the old MIDI file is that the new one exercises more instruments.

    The song was composed by David Yackley.

    On the other hand, we lost clock.avi.

  • The Old New Thing

    What does 1#J mean? A strange corner case of the printing of special values

    • 44 Comments

    As a puzzle, commenter nobugz asks, "What kind of infinity is 1.#J?"

    double z = 0;
    printf("%.2f", 1/z);
    

    Now, the division by zero results in IEEE positive infinity, would would normally be printed as 1#INF. But the catch here is that the print format says "Display at most two places after the decimal point." But where is the decimal point in infinity?

    The Visual C runtime library arbitrarily decided that all of the exceptional values have one digit before the decimal (namely, the "1"). Actually, it turns out that this puzzle might be an answer to Random832's question, "What's the 1 for?" Maybe the 1 is there so that there is a digit at all.

    Okay, so now you have one digit before the decimal (the "1"), and now you need to show at most two places after the decimal. But "#INF" is too long to fit into two characters. The C runtime then says, "Well, then I'd better round it off to two places, then."

    The first character is "#". The second character is "I". Now we need to round it. That's done by inspecting the third character, which is "N". We all learned in grade school that you round up if the next digit is 5 or greater. And it so happens that the code point for "N" is numerically higher than the code point for "5", so the value is rounded up by incrementing the previous digit. Incrementing "I" gives you "J".

    That's why printing IEEE positive infinity to two places gives you the strange-looking "1#J". The J is an I that got rounded up.

    I doubt this behavior was intended; it's just a consequence of taking a rounding algorithm intended for digits and applying it to non-digits.

    Of course, in phonetics, rounding an i produces a ü. Imagine the nerdiness of rounding "1#INF" to two places and producing "1#Ü". That would have been awesome.

  • The Old New Thing

    Now that version 4 of the .NET Framework supports in-process side-by-side runtimes, is it now okay to write shell extensions in managed code?

    • 36 Comments

    Many years ago, I wrote, "Do not write in-process shell extensions in managed code." Since I originally wrote that article, version 4 of the .NET Framework was released, and one of the features of that version is that it supports in-process side-by-side runtimes. Does that mean that it's now okay to write shell extensions in managed code?

    The answer is still no.

    The Guidance for implementing in-process extensions has been revised, and it continues the recommendation against writing shell extensions and Internet Explorer extensions (and other types of in-process extensions) in managed code, even if you're using version 4 or higher.

    Although version 4 addresses the side-by-side issue, it is still the case that the .NET Framework is a high-impact runtime, and that there are various part of COM interop in the .NET Framework that are not suitable for use in an extension model designed around native code.

    Note that managed code remains acceptable for out-of-process extensions.

  • The Old New Thing

    The annual sporting event involving a football that dare not speak its name and a digression into the sportsmanship of wasting time in nonproductive activity

    • 34 Comments

    I always wonder about people who are so protective of the name of their event that they don't even allow people to mention it by name. One of the most notorious examples is the organization which runs a major international gathering of athletes which takes place every four years (or every two years if you consider warm-weather sports and cold-weather sports). Another example is that you aren't allowed to refer to the championship game of the major professional American football league by its actual name without permission. You have to use some alternate phrasing like the big game. I propose that all media organizations which cover these types of events accept the event organizers' wishes and refuse to call it by its name. Or even simply refuse to cover it until they relax their rules.

    The alternate name the big game is itself confusing, since there are many things that go by that name. Even within the realm of American football, the phrase big game can also refer to the annual match between Stanford University and the University of California at Berkeley, whose final play in 1982 was particularly memorable.

    For those not familiar with the timekeeping rules of American football (which includes the Stanford band, it seems): American football is not a continuous-play game. The game is broken up into relatively short units known as plays. Typically, a whistle is blown to indicate that a play has ended. Between plays are much longer units of time called standing around doing nothing. If time runs out while a play is in progress, the play is allowed to run to completion, and the results of the play are valid. An analogue in the sport of basketball is the case where time runs out while the ball is in flight. The ball's trajectory is permitted to run to completion, and if it goes into the basket, the points count.

    The amount of standing around doing nothing is determined by the offensive team. Some teams employ a strategy known as not standing around doing nothing quite so much (technically known as the no-huddle offense), the goal of which is to deprive the defense of time to prepare for the next play.

    Some sports such as soccer (known to most of the world as the one true football accept no substitutes) have a penalty of the form not making an honest effort to advance the ball which is assessed if a team appears to be wasting time in nonproductive activity. One thing I find odd about American football is that wasting time in nonproductive activity is not only permitted by the rules, it is actively pursued as a tactic. You are allowed to waste up to 40 seconds of time (subject to other adjustments) before incurring a delay of game penalty, which more accurately should be named excessive delay of game. The result of this formalization of the concept of wasting time is that the amount of time which elapses between plays tends to be approximately 39.5 seconds. This is actually handy if you are watching a game that you previously recorded: When you hear the whistle which ends a play, you can hit the skip ahead 30 seconds button and skip over nearly all of the standing around doing nothing.

    The fact that maximum time wastage is completely normal and expected leads to the odd phenomenon of teams walking off the field before the game has ended: If the remaining time is less than 40 seconds and the team with possession of the ball is winning, then it assumed that the winning team will merely stand around doing nothing until time runs out. As a result, everybody just leaves immediately instead of standing around doing nothing waiting for the end-of-game whistle. (Indeed, if a team in this situation actually tries to play the game, it will probably be criticized for attempting to run up the score.)

  • The Old New Thing

    What does -1.#IND mean?: A survey of how the Visual C runtime library prints special floating point values

    • 29 Comments

    As every computer scientist knows, the IEEE floating point format reserves a number of representations for infinity and non-numeric values (collectively known as NaN, short for not a number). If you try to print one of these special values with the Visual C runtime library, you will get a corresponding special result:

    Output Meaning
    1#INF Positive infinity
    -1#INF Negative infinity
    1#SNAN Positive signaling NaN
    -1#SNAN Negative signaling NaN
    1#QNAN Positive quiet NaN
    -1#QNAN Negative quiet NaN
    1#IND Positive indefinite NaN
    -1#IND Negative indefinite NaN

    Positive and negative infinity are generated by arithmetic overflow, or when the mathematical result of an operation is infinite, such as taking the logarithm of positive zero. (Don't forget that IEEE floating point supports both positive and negative zero.) For math nerds: IEEE arithmetic uses affine infinity, not projective, so there is no point at infinity.

    Signaling and quiet NaNs are not normally generated by computations (with one exception noted below), but you can explicitly create one for a floating-point type by using the std::numeric_limits<T> class, methods signaling_NaN() and quiet_NaN().

    Recall that there is not just one signaling and quiet NaN, but rather a whole collection of them. The C runtime does not distinguish among them when printing, however. All signaling NaNs are reported as 1#SNAN, regardless of the signal bits. The C runtime does report the sign of the NaN, for what little that is worth.

    The weird one is the Indefinite NaN, which is a special type of quiet NaN generated under specific conditions. If you perform an invalid arithmetic operation like add positive infinity and negative infinity, or take the square root of a negative number, then the IEEE standard requires that the result be a quiet NaN, but it doesn't appear to specify what quiet NaN exactly. Different floating point processor manufacturers chose different paths. The term Indefinite NaN refers to this special quiet NaN, whatever the processor ends up choosing it to be.

    Some floating point processors generate a quiet NaN with the signal bits clear but the sign bit set. Setting the sign bit makes the result negative, so on those processors, you will see the indefinite NaN rendered as a negative indefinite NaN. (The x86 is one of these processors.)

    Other floating point processors generate a quiet NaN with the signal bits and the sign bit all clear. Clearing the sign bit makes the result positive, so on those processors, you will see the indefinite NaN rendered as a positive indefinite NaN.

    In practice, the difference is not important, because either way, you have an indefinite NaN.

  • The Old New Thing

    The curious pattern of pre-emptively rejecting the solution to your problem

    • 28 Comments

    A frustrating pattern that shows up occasionally in customer questions is the case where the customer poses a problem, and pre-emptively rejects the mechanism explicitly designed to solve that problem.

    How can we change the widget color without using IWidget::Set­Color?

    Um, the whole point of IWidget::Set­Color is to change the color of a widget. Why are you rejecting the mechanism whose sole purpose in life is to solve the very problem you are having?

    Usually, if you press hard enough, they will cough up the reason why they think they cannot use the solution specifically designed to do what they want. Various excuses tend to come up over and over.

    One excuse is the belief that the proposed solution does not work in a particular scenario. "We cannot use ACLs because they don't work on network volumes." Um, yes they do. Check it out.

    Or that the proposed solution doesn't fit their choice of technology. "We are programming in a language that does not support COM objects. We can only p/invoke to C-style APIs." Well, you can work around that problem by writing a helper DLL that exposes a C-style API, and implements it by calling the COM method.

    Or that the proposed solution violates some vague corporate policy. "We have a corporate policy that users cannot change widget colors, so the IWidget::Set­Color method returns E_ACCESS­DENIED. We're looking for a way around that policy." Okay, well, now that's something you need to take up with the people who establish your corporate policies. Don't come to us looking for ways to circumvent corporate policy.

    One time, the reason came from our own technical support staff: "We cannot write a C++ program that calls IWidget::Set­Color and provide it to the customer because we are not a developer support team. We are not allowed to send compiled binaries to the customer for liability reasons, and we generally do not send source code because our customers typically do not have the expertise or desire to install Visual Studio and the Platform SDK just to compile and run a five-line C++ program. (Did I mention that we are not a developer support team?) Can it be done from a batch file?"

    Yeah, how about this batch file:

     >changeColor.cs echo using System;
    >>changeColor.cs echo class Program {
    >>changeColor.cs echo public static void Main(string[] args) {
    >>changeColor.cs echo ...
    >>changeColor.cs echo }
    >>changeColor.cs echo }
    %windir%\Microsoft.NET\Framework\v4.0.30319\csc changeColor.cs
    changeColor blue
    

    Only half-joking.

    The non-joking answer is "The customer can take this information to a developer support team, or at least somebody who will write the program for them, if they don't know how to write a program themselves." Microsoft Consulting Services exists for this, but that is likely overkill for a five-line program.

  • The Old New Thing

    Optimizing the Chili's dining experience

    • 26 Comments

    Back in the days of Windows 95, one of my colleagues paid a visit to his counterparts over in the Windows NT team as part of a continuing informal engagement to keep the Windows NT developers aware of the crazy stuff we've been doing on the Windows 95 side.

    One particular time, his visit occurred in late morning, and it ran longer than usual, so the Windows NT folks said, "Hey, it's lunchtime. Do you want to join us for lunch? It's sort of our tradition to go to Chili's for lunch on Thursdays."

    My colleague cheerfully accepted their offer.

    The group were shown to their table, and the Windows NT folks didn't even look at the menus. After all, they've been here every week for who-knows-how-long, so they know the menu inside-out.

    When the server came to take the orders, they naturally let my colleague order first, seeing as he was their special guest.

    "I'll have a chicken ranch sandwich."

    The folks from the Windows NT team then placed their orders.

    "I'll have the turkey sandwich."

    "Turkey sandwich."

    "A turkey sandwich for me, please."

    Every single person ordered a turkey sandwich.

    After the server left, my colleague asked, "Why do you all order the turkey sandwich?"

    They explained, "We've been coming here for a long time, and we eventually figured out that, at least at this restaurant, the turkey sandwich takes the least time to prepare."

    What my colleague forgot to ask was, "Well, since I already ordered something else, I naturally screwed up your highly-optimized algorithm. So why didn't you order something else?"

    Note: I actually don't know who ordered first. I just made up that part of the story to make it funnier. (Note that I make up parts of other stories, too. I'm not a historian. I'm a storyteller.)

  • The Old New Thing

    Once you know something can be done, doing it is much easier

    • 22 Comments

    Unfortunately, I don't remember the name of the star of this story, but I'm told that there was a notable mathematician who believed the Perfect Graph Conjecture to be false and spent many years trying to prove it one way or another.

    Meanwhile, another mathematician (presumably László Lovász) announced that he had found a proof (in the affirmative).

    Upon hearing the news that the open question had been resolved, the first mathematician was able to produce a proof within 90 minutes.

    Once again showing that it's much easier to do something once you know it can be done.

Page 1 of 3 (29 items) 123