The Rants, Raves, Gripes, and Prophecies of Paul R. Potts
Contents by Category
Contents by Date
Let's imagine for a moment that I had the money to order a brand-spanking-new G5 system from Apple and assume that I wanted to get some Apple LCD screens. (Yes, I know 3rd-party LCD screens are much cheaper, but I also notice that the cheap ones don't have digital video input, which somewhat reduces the actual image quality I get out of them). Today the prices on the Apple displays are as follows, at least when I spec them together with a computer:
17" screen: $699
20" screen: $1299
23" screen: $1999
Now, the Apple 23" screen is certainly beautiful. It gives you a lot more real estate. Let's assume for a moment that screen real estate is fungible: that is, that I don't care about the exact dot pitch, that I want as many pixels as possible, and that it does not matter to me if they are all on one screen, or two... or even three. In this scenario, does it make any sense to buy the 23" screen? Or even the 20" screen?
The answer is no. The 17" has a native resolution of 1280 by 1024; the 20", 1680 by 1050; the 23", 1920 by 1200. We can calculate a cost-per-pixel ratio. Rounding the prices to the nearest dollar, the cost per pixel is about 0.053 cents for the 17" screen. It goes up to about 0.087 cents per pixel for the 23" screen. (When you consider that the 23" screen has about 2.3 million pixels, the cost doesn't seem quite so ridiculous).
If pixels cost the same on all three screens, the 20" screen would cost about $940 and the 23" would cost about $1230. If the high-end screen prices come down to or below these points, it would make sense to buy them. (Of course, by the time this happens, one might assume the 17" screen will cost less as well). And of course there is some fixed overhead per unit: the power supply, the backlight, the casing, the cost of packaging and manufacturing.
For now, for my needs, it would make better sense to buy two 17" screens. That would give me about 2.6 million pixels, more than the number of pixels available on the 23" screen, at a cost of $1400, or 70% of the cost of the 23" screen. I don't truly have a need to view large layouts on a single monitor the way a graphic designer or digital photographer might, but as a developer, I like to have multiple source files open at once, along with, perhaps, several terminal windows, a project view, and a source-level debugger. Sticking two monitors next to each other is good enough.
Of course, this does not take into account the minor thrill of watching a DVD on a 23" flat panel. Were money no object, I'd consider two 23" screens. But this is all pretty much a speculative exercise to begin with, and if I speculate more realistically, I'll be a bit less disappointed!Second-guessing the Compiler
So, did you hear the one about the programmer who decided to rewrite all the logical tests of the form
if ((x) || (y))
if !(!(x)) && (!(y))
On the grounds that the PowerPC uses "NAND gates," where the Pentium used "AND gates," so the second expression would run faster on PowerPC hardware?
When I heard this, it caused me to utter some kind of sound... I don't remember the details, but I think it involved spraying coffee all over my monitor.
Of course, the two are logically equivalent (work out the truth table for yourself, if you don't believe me). I don't have any idea whether there really is a difference in the performance of OR logical operators on the PowerPC. I sincerely doubt it, keeping in mind that even the assembly instructions are abstract, as far as the hardware is concerned, and I don't have any way of knowing what is really happening in the hardware when a simple OR test is executed. If the hardware chose to execute the OR comparison using NOT and AND, I'd never know, and wouldn't care. But the second one certainly looks a lot more obscure, and that was the programmer's real point. (The "baffle 'em with bullshit" defense; if it looks complex, it must be complex; it will be harder for someone else to maintain; perhaps it will ensure job security.) (Don't bet on it; if anyone who worked under my supervision wrote this without a very good reason, he or she would be out on his or her ass).
It gets better. CodeWarrior is pretty good compiler. It looked at this code, and determined, pretty much as a human could with a little thought, that it made more sense to reduce the code to a simple logical OR. So that's what it did. So even if the original programmer had been right, the processor wasn't executing the logic he wrote. He hadn't looked at the resulting code. So there was, for yet another reason, no reason to write it that way.
Now, the people who wrote CodeWarrior's optimizer aren't dumb. It has undergone years of tweaking by very smart people. If there was some great optimization to be gained by rewriting logical operations to support the PowerPC's "NAND gates" more efficiently, they would have implemented it; it would be described in the PowerPC documentation, to guide compiler writers; and programmers would be griping about it. IBM and Motorola have a vested information in getting optimization advice out there, to make their chips appear more competitive. There isn't a reason to rewrite the logic like this, so they didn't.
If you've been living under a rock and haven't heard: optimize after you get it working. Optimize what you can measure. But the best initial optimization you can do on your code is to design it well and express it clearly. After you've tested it, crank up the compiler optimizations and test it some more. Measure its performance. Profile the hot spots. Optimize those parts. It doesn't make sense to waste effort optimizing instructions that are only executed once, during the startup of the program, which is not noticeably slow. If your program is slow on a modern CPU, it is far more likely that you are doing something wrong algorithmically: looking up some information by traversing a long linked list every time a function is called, for example, instead of using a more efficient structure such as a tree or hash.
Don't get me wrong: there's a place for serious hand-optimization. I've worked hard to hand-optimize DSP assembly code in order to reduce the number of cycles necessary to restart a disconnected data transfer across a PCI bus. I've tweaked interrupt routines to block for as few instructions as possible. I've also worked to determine why a program that draws animated meters is using thousands of times more CPU time than I expected. (Because it was drawing far too much, far too often, due to a bug that was easy to find by single-stepping the code with a source-level debugger). But in these cases I had some way, even if it was an imperfect way, of measuring the results. And you can bet your ass I was carefully commenting the code to explain why the implementation no longer appeared to be as simple and straightforward as possible. Not just to benefit some abstract future maintenance programmer; that maintenance programmer could be someone I know and love - myself.