[C is] still the fastest compiled language.
Well hold on there. This claim might be true when you’re working with small critical sections or microbenchmarks, but when you have a significant amount of code all of which is performance-sensitive, my experience is that’s way off-base. I work with image pipelines these days, which are characterized by a long sequence of relatively-simple array operations. In the good ol’ days this was all written in straight C, and if people wanted stages to be parallelized or vectorized or grouped or GPU offloaded or [next year’s new hotness] they did it themselves. The result, as you might guess, is a bunch of hairy bug-prone code that’s difficult to adapt to algorithm changes.
Nowadays there’s better options, such as Halide. In Halide you write out the computation stages equationally, and separately annotate how you want things parallelized/GPU offloaded/etc. The result is your code is high-level but you retain control over its implementation. And unlike in C, exploring different avenues to performance is pretty easy, and oh by the way, schedule annotations don’t change algorithm behavior so you know the optimizations you’re applying are safe.
Check out the paper for demonstrations of Halide’s effectiveness: using an automatic schedule search, they manage to beat a collection of hand-optimized kernels for real-world tasks, in a fraction of the code size. Also from personal experience, our project might not have even gotten off the ground without Halide, but with it we’ve been able to port a large camera pipeline with relative ease.
My point is providing primitives only nets you performance until you hit the cognitive ceiling of your programmers. All those high-performance schedules could’ve been coded up in C and Cuda, but they weren’t because at some point all the parts got too complicated for the experts to hand-code optimally. And if no one can manage to actually get high performance out of your language/system, is it really high performance? So I think in order for a language to stay high-performance in the presence of complex programs, it needs to be high-level. C and intrinsics just aren’t good enough.
Edit: for a great example, check out the snippets on the second page here.
Something clearly got this author’s goat; this rebuttal feels less like a reasoned response and more like someone yelling “NO U” into Wordpress.
Out of order execution is used to hide the latency from talking to other components of the system that aren’t the current CPU, not “to make C run faster”.
Also, attacking academics as people living in ivory towers is an obvious ad hominem. It doesn’t serve any purpose in this article and, if anything, weakens it. Tremendous amounts of practical CS come from academia and professional researchers. That doesn’t mean it should be thrown out.
So, in context, the bit you quote is:
The author criticizes things like “out-of-order” execution which has lead to the Spectre sidechannel vulnerabilities. Out-of-order execution is necessary to make C run faster.
The author was completely correct here, and substituting in JS/C++/D/Rust/Fortan/Ada would’ve still resulted in a correct statement.
The academic software preference (assuming that such a thing exists) is clearly for parallelism, for “dumb” chips (because computer science and PLT is cooler than computer/electrical engineering, one supposes), for “smart” compilers and PL tricks, and against “dumb” languages like C. That appears to be the assertion the author here would make, and I don’t think it’s particularly wrong.
Here’s thing though: none of that has been borne out in mainstream usage. In fact, the big failure the author mentioned here (the Sparc Tx line) was not alone! The other big offender of this you may have heard of is the Itanic, from the folks at Intel. A similar example of the philosophy not really getting traction is the (very neat and clever) Parallax Propeller line. Or the relative failure of the Adapteva Parallela boards and their Epiphany processors.
For completeness sake, the only chips with massive core counts and simple execution models are GPUs, and those are only really showing their talent in number crunching and hashing–and even then, for the last decade, somehow limping along with C variants!
One problem with the original article was that it located the requirement for ILP in the imagined defects of the C language. that’s just false.
Weird how nobody seems to remember the Terra.
In order to remember you would have to have learned about it first. My experience is that no one who isn’t studying computer architecture or compilers in graduate school will be exposed to more exotic architectures. For most technology professionals, working on anything other than x86 is way out of the mainstream. We can thank the iPhone for at least making “normal” software people aware of ARM.
I am so old, that I remember reading about the Tomasula algorithm in Computer Architecture class and wondering why anyone would need that on a modern computer with a fast cache - like a VAX.
Of course, I spelled it wrong.
The purpose of out of order execution is to increase instruction-level parallelism (ILP). And while it’s frequently the case that covering the latency of off chip access is one way out of order execution helps, the other (more common) reason is that non-dependent instructions that use independent ALUs can issue immediately and retire in whatever order instead of stalling the whole pipeline to maintain instruction ordering. When you mix this with good branch prediction and complex fetch and issue logic, then you get, in effect, unrolled, parallelized loops with vanilla C code.
Whether it’s fair to say the reasoning was “to make C run faster” is certainly debatable, but the first mainstream out of order processor was the Pentium Pro (1996). Back then, the vast majority of software was written in C, and Intel was hellbent on making each generation of Pentium run single-threaded code faster until they hit the inevitable power wall at the end of the NetBurst life. We only saw the proliferation of highly parallel programming languages and libraries in the mainstream consciousness after that, when multicores became the norm to keep the marketing materials full of speed gainz despite the roadblock on clockspeed and, relatedly, single-threaded performance.
“Your computer has plenty of RAM, so my app can be inefficient” gets a little irritating when I have to run ten other apps that did the exact same thing.
As Niklaus Wirth said: “…we do not consider it as good engineering practice to consume a resource lavishly just because it happens to be cheap.”
That’s not really true though. If your design balances the value you put on performance with, say, safety or debuggability, then performance is bumped by a factor of 10,000 (roughly 20 years of Moore’s Law progress), it makes sense to spend performance budget on the other concerns. To do otherwise is no more “good engineering practice” than saving weight on a bridge by not putting guard rails on it.
Which is not to say I think Electron is a good or acceptable trade-off. If Javascript were less error-prone than its native competition it might’ve been, but it seems to be the opposite. Which means, I think, that Electron quite literally is a waste of resources.
As a particular point, JavaScript may be a safe language (and perhaps node + qt would be a good framework), but the browser exposes a shit ton of attack surface and unexpected legacy behavior. I know we all love our lisp code is data and data is code, but it’s a poor model for reliable computing when the barrier between the code in the document and the code about the document is very thin.
Sure, and I don’t think Wirth would object. It’s the “lavish” part: Vala and GTK is just as if not more portable than Electron, produces faster and smaller code, is type-safe, works well with debuggers, works with the platform’s accessibility tools (disabled users often find Electron apps literally impossible to use), has a consistent UI (consistency between apps is another big Electron problem), etc.
Why bring along an entire web runtime that consumes tens of megs of memory if you could get the same or more bang for the buck with less?
(Note that I’m using Vala as an example; this would apply equally to any other desktop framework like Qt, etc.)
Any post that calls electron ultimately negative but doesn’t offer a sane replacement (where sane precludes having to use C/C++) can be easily ignored.
There’s nothing wrong with calling out a problem even if you lack a solution. The problem still exists, and brining it to people’s attention may cause other people to find a solution.
There is something wrong with the same type of article being submitted every few weeks with zero new information.
Complaining about Electron is just whinging and nothing more. It would be much more interesting to talk about how Electron could be improved since it’s clearly here to stay.
it’s clearly here to stay
I don’t think that’s been anywhere near established. There is a long history of failed technologies purporting to solve the cross-platform GUI problem, from Tcl/tk to Java applets to Flash, many of which in their heydays had achieved much more traction than Electron has, and none of which turned out in the end to be here to stay.
Thing is that Electron isn’t reinventing the wheel here, and it’s based on top of web tech that’s already the most used GUI technology today. That’s what makes it so attractive in the first place. Unless you think that the HTML/Js stack is going away, then there’s no reason to think that Electron should either.
It’s also worth noting that the resource consumption in Electron apps isn’t always representative of any inherent problems in Electron itself. Some apps are just not written with efficiency in mind.
Did writing C++ become insane in the past few years? All those GUI programs written before HTMLNative5.js still seem to work pretty well, and fast, too.
In answer to your question, Python and most of the other big scripting languages have bindings for gtk/qt/etc, Java has its own Swing and others, and it’s not uncommon for less mainstream languages (ex. Smalltalk, Racket, Factor) to have their own UI tools.
Did writing C++ become insane in the past few years? All those GUI programs written before HTMLNative5.js still seem to work pretty well, and fast, too.
It’s always been insane, you can tell by the fact that those programs “crashing” is regarded as normal.
In answer to your question, Python and most of the other big scripting languages have bindings for gtk/qt/etc, Java has its own Swing and others, and it’s not uncommon for less mainstream languages (ex. Smalltalk, Racket, Factor) to have their own UI tools.
Shipping a cross-platform native app written in Python with PyQt or similar is a royal pain. Possibly no real technical work would be required to make it as easy as electron, just someone putting in the legwork to connect up all the pieces and make it a one-liner that you put in your build definition. Nevertheless, that legwork hasn’t been done. I would lay money that the situation with Smalltalk/Racket/Factor is the same.
Java Swing has just always looked awful and performed terribly. In principle it ought to be possible to write good native-like apps in Java, but I’ve never seen it happen. Every GUI app I’ve seen in Java came with a splash screen to cover its loading time, even when it was doing something very simple (e.g. Azureus/Vuze).
Writing C++ has been insane for decades, but not for the reasons you mention. Template metaprogramming is a weird lispy thing that warps your mind in a bad way, and you can never be sane again once you’ve done it. I write C++ professionally in fintech and wouldn’t use anything else for achieving low latency; and I can’t remember the last time I had a crash in production. A portable GUI in C++ is so much work though that it’s not worth the time spent.
C++ the language becomes better and better every few years– but the developer tooling around it is still painful.
Maybe that’s just my personal bias against cmake / automake.
Don’t want overcommit? Turn it off.
me@host$ head -n3 /proc/meminfo
MemTotal: 32815780 kB
MemFree: 13309168 kB
MemAvailable: 19461460 kB
me@host$ cat /proc/sys/vm/overcommit_memory
0
me@host$ python -c 'import os; s = (12 << 30) * "."; print s[:3]; os.fork()'
...
Traceback (most recent call last):
File "<string>", line 1, in <module>
OSError: [Errno 12] Cannot allocate memory
Don’t want overcommit? Turn it off.
Just don’t do it in production, because sooner or later you’ll come to understand why it’s the default.
Sure, and I agree that it’s an appropriate default for most common-case systems (though there are legitimate reasons to want to disable it). My intent was basically “learn your system’s configuration options instead of griping about its defaults”.
The issue is fork makes no-overcommit unreasonable. With a spawn model you don’t see worst-case memory usage balloon every time you start a program.
I’m sure this is a minority opinion, but it would be nice if it were easy to opt-out of these changes.
For my home machines I’m not concerned about the security risk, and would rather have the better performance.
It looks like the pti=off flag should get the old behavior back.
Well, we know it involves user processes reading kernel memory, and I’m confident that I’m not running any malicious user processes that are attempting to do so.
And the real issue is almost certainly not as bad as the scare mongering in The Register’s article.
Why is the send bandwidth so much lower than receiving? Is the send just lower powered so it’s disproportionately effected?
ADSL is always biased towards downstream transmission (The “A” stands for asymmetric, there is also SDSL.)
For ADSL2 Annex A, the theoretical maximums are 12Mbit down and 1.3Mbit up so they’re getting 28% of max downstream and 5% of max upstream. If it’s actually ADSL2+, they’re getting 14% of max downstream.
My guess is that the percentages are so unequal because the wet string’s frequency response is not flat(!) ADSL only has one transmission medium (the phone line) so it splits concurrent upstream & downstream communications by frequency. Upstream gets the lower frequencies.
There’s a good table on Wikipedia: https://en.wikipedia.org/wiki/Asymmetric_digital_subscriber_line#ADSL_standards
Small correction: 128-bit CAS is supported on all(?) x64 processors. I used it for a lock-free hash table one time, since 16 character keys should be enough for anybody :).
Guy runs into two bugs involving stale data and concludes every app must have a refresh button? That seems a bit presumptuous.
That’s kind of reductive. The message I got from the post was “please provide users this simple and well-known way to work around synchronization bugs“. It’s usually easy to implement and has no drawbacks save for a tiny bit of UI clutter.
Okay, I see your point. I’m partial to the pull-to-refresh affordance since it stays out of the way the 95% of time you don’t need it. In apps that aren’t list-based, however, I don’t know what you’d do (shake-to-refresh?).
I think I was irked by “every app that doesn’t have this is broken” and the assumption that the web-based paradigm of throwing everything out and getting a fresh copy is the best one for every app. In some apps, it’d be the equivalent of an elevator door close button, where hitting it doesn’t really do anything it isn’t already doing.
I also think the real issue is how phones react to (or don’t) changes in network connectivity.
The author uses two examples to illustrate the fact that every application which synchronizes can get desynchronized (seriously, every single one) and providing users with a workaround is essential.
Going to have to agree with OP. Sometimes a refresh button doubles as an invaluable debugging tool.
Does it? It seems, at best, like a way to work around bugs by destroying the state you probably need to debug the problem.
As a user, what does destroying debug data matter to me? I’m not trying to debug your app, I’m trying to call a taxi. Further, how does omitting the refresh trigger help debugging? Most people don’t file bug reports, they just get annoyed, and denying them the tools to fix their problem will just make them more annoyed.
If you want debug information, I’d argue a refresh button could be actively helpful: users press it when they think something’s stale, so by collecting telemetry on refresh presses you can get a clue as to when desynchronizations happen.
Provide a refresh button in release, but not debug so that developers can’t use it to ignore real bugs :)
Even Gmail on Android allows the user to manually refresh despite it being timely, correct, and not error prone in 2017. I give some odds that the refresh action doesn’t do anything except address the user experience.
Not defending buggy apps, but there is a take-away here.
So I’ve only spent like two minutes looking, but I think you can also do pattern matching with switch(variant.index()) if you like.
What the author’s going for is selecting an alternative and getting the value out should be the same operation, so you can’t hit a runtime type error between checking the alternative and unboxing it.
A guarantee that the type won’t change in a concurrent environment is going to require a lot more machinery I think. There’s accessors to get pointers to the value. And in other cases, the value itself may be a pointer. If the type can change at any time, those pointers will invalidated. If you want the borrow checker, it’s over there I guess, but I didn’t really get the sense that the author wants atomic selectors.
I was unclear there. By “the same operation,” I just mean that selecting and unboxing shouldn’t be separate points in the code. I’m not about to argue that variant needs to be concurrent.
What I mean is just that in
select (boink.index()) {
case 0: int val = get<0>(boink);
...
}
you’re mentioning the index twice, and if you mistype one or the other you’ll only find out at runtime.
Oh, I see. Yeah, you could do switch ((idx = boink.index())) (always another workaround) but it is backtreading.
Then you’re writing exactly the same code as you would with a tagged union, except it’s actually worse because you don’t get -Wswitch. (warning: enumeration value ‘ASDF’ not handled in switch [-Wswitch])
Well, it’s solve the problem that the tag and the value diverge because you forget to update one. Guess you get to choose which is worse. It seems the return type of index could be an enum (though obviously they didn’t do that). Not sure how much more difficult that would have been.
During college I got a job at the research computing group, optimizing a researcher’s Fortran code from single-core to parallel and distributed. The code was some kind of field propagation across a 3d grid, and the main loop was what you might expect: each cell takes its new value from it and its neighbors’ old values. In parallelizing this I found something interesting, though: this was being done in-place, so three of the point’s six neighbors would be from the current iteration and three would be from the previous, so the graph would end up skewing towards one quadrant. This was pretty obviously broken, and the grad student who wrote it hadn’t noticed. I passed word and the optimized/fixed version back to him, so I hope they updated the results for whatever project they were working on.
The moral of the story being yes, code reviews for scientific codes would be super helpful. I would wager this sort of problem isn’t uncommon, and they don’t all get caught before release.
It’d be really neat to be able to tune into altitude data, if it were available in the data set. I’m not sure what the best option is for trying to express that dimension of information on a 2D canvas though. At a fixed altitude, as the author mentions, vertical winds are simply expressed as low or zero movement, and tend to indicate what looks like shear boundaries for converging fronts.
Maybe a depth-fade render would look nice, with particles fading into high saturation and brightness as they move toward the viewer, and out to transparent (but not completely invisible) as they move toward the ground?
Windy gives altitude data, though it just does it by letting you select a given altitude to slice. What would be really neat is if nullschool let you rotate the globe and showed 3d airmasses.
This really seems like much ado over nothing to me. If you read the initial message, all he’s actually saying is that init’s become more complicated so you can no longer just set a low stack size on it and be sure it’ll never overflow. “Linus hates systemd” seems like a stretch, and I think is mostly from people taking that “sane thing” quote out of context.
The article isn’t saying Linus hates systemd. It’s saying Linus doesn’t trust the systemd developers and considers their tactics to be harmful to his kernel. And it’s not about that one incident it’s about a pattern of incidents where Linus has dealt with fallout from systemd developers. The article is actually pretty balanced and paints Linus as pretty balanced as well.
Fun article, but the author has a skewed definition of “firmware”. If you look at those controllers sitting in engines or satellites, “no instructions in it that aren’t pertinent to the job at hand” isn’t what you’ll find. Satellite controllers are usually an RTOS with preemptive threading and all that “fanciness”. Some of them run Lisp. And Linux supports this sort of environment, with the RT patchset.
Now, if you want to argue that there’s no way a bunch of VC’d twentysomethings should be trusted to write real-time reliable code for a fire alarm, that’s a fair argument. The failure mode of the alarms apparently backs you up. It helps to have an accurate idea of what competent control software looks like, though.
Some of them run Lisp.
Actually that article says they do not run Lisp anymore.
This is a very interesting talk by the same author about something slightly different but which touches on the same points: https://www.youtube.com/watch?v=_gZK0tW8EhQ
IP version 6 (IPv6) is a new version of the Internet Protocol (IP),
Nice! Since I have a policy of not immediately jumping onboard with any new technology, I can reset my IPv6 clock. It has been 0 days since IPv6 was new.
That statement seems to carry over from the 1998 RFC: https://www.rfc-editor.org/rfc/rfc2460.txt
They rolled their own dependency management!? And at such a high cost (roughly 1000 engineer-hours, assuming a team of 4)? Why not just use Nix or Bazel? Do people not realize that these tools exist, or is it just NIH syndrome?
I think saying “just” use Nix understates the difficulty there significantly. I say this as someone who uses Nix, but if someone’s looking for an off-the-shelf dependency management system and the first step to use it is “hey, learn this functional language,” they could be forgiven for assuming it will create more problems than it could possibly solve. Also, packaging new things really is a pain. The build environment is under-documented, it’s hard to pull up an interactive equivalent to the build env, and failed builds are, as far as I know, thrown out instead of saved for debugging.
I haven’t used Bazel before, but its Github blurb claims it’s designed for “A massive, shared code repository,” which isn’t the problem these folks were trying to solve. Maybe it works fine for multi-repos as well, I don’t know.
I’m a big fan of Bazel (I’ve helped two companies now transition to it), but it’s not a polyglot panacea; if you’re using the languages Google uses (Java, C/++, Python, Go) and building for a platform that Google releases on (Android/iOS) then it’s wonderful; for anything else, you’d have to do a massive amount of work to integrate it. The article mentions using C# and Perl; you’d have a tough time using Bazel for those.
I think this gets at a serious difficulty of the very-in-vogue polyglot codebase: it’s all well and good to let programmers choose whatever tool they want, but it comes with a serious devops cost. I don’t know of any tools for building, dependency management or continuous integration that truly work well with a whole bunch of implementation languages. Bazel is the closest I’ve seen, but it doesn’t even support building on Windows.
I agree with many of your assessments, I hope we can improve in all of these areas :) For what it is worth, you are able to keep failed builds by passing --keep-failed to nix-build.
It’s the external version of Blaze, Google’s build system.
Some changes can rebuild the world. :P but Blaze/Bazel makes it possible and usable.
can anyone explain why I would be interested in this? or provide some context? otherwise this just seems like a badly written teaser ad.
The ThinkPad line has a long history of being known for build quality and reliability, particularly in the era when they were built by IBM, before being sold to Lenovo. This was epitomized by a ThinkPad that survived a fire. Additionally, in the older era of Linux driver compatibility, where buying a laptop was fraught with peril, ThinkPads had a reputation of being a safe bet. They would reliably work, or could be made to work with minimal tweaking. There is even an entire Wiki dedicated to this.
There is an insane aftermarket for still-working, 2010-era ThinkPads, especially those that can run without Intel’s Management Engine. People have gone to great lengths to upgrade these with newer CPUs (that they were never designed for), higher resolution screens, and all sorts of other interesting and inspiring upgrades.
A lot of devotees (ala Apple fans) look back fondly on the earlier era of ThinkPad hardware, and in doing so focus (rightly or wrongly) on some of the aesthetic aspects of the laptops of that era:
So on and so forth. You get the idea.
Two-ish years ago a half-joking product designer (engineer?) at Lenovo wrote a blog post asking what people might want in a “Retro” ThinkPad. The post went viral, so they did a followup of 4 surveys asking people for opinions on the specifics of what it would mean for a ThinkPad to be “retro” to them. Sort of saying “Okay, we went viral, that’s cool, but it was just a poorly-thought-out brainstormed idea. What do you people really want?”
I’m looking for these supposed leaks right now, but based on this post its safe to say the idea is that they are actually following through on a production model based on those surveys.
On a personal note: I am a ThinkPad fan, but not quite the devotee that many others are. During eras when the hardware was not to my liking, I have purchased elsewhere. I do enjoy my X1 Carbon 3rd Gen (from 2015) but the last time I used one before that was 2008. Oh, and this is definitely one of the coolest laptops keyboards I have ever seen.
I could see an argument, however, for this not meeting Lobsters’ bar for a quality topic of discussion. It’s not even a proper release of any sort. More of a psuedo-product announcement via acknowledgement of a leak.
There’s a certain nostalgia factor which I think overlooks the actual tangibles. Thinkpads, the X1 carbon line especially, have indeed gotten thinner and lighter, but it hasn’t been all bad. Here’s a T60 review for comparison: https://www.pcmag.com/article2/0,2817,1933653,00.asp
You can literally stack two X1 carbons on top of each other and they’re still thinner and lighter than a T60. Despite this, the T60 has only a 5:15 battery life. I doubt people are actually clamoring for a laptop that weighs twice as much and gets half the battery life, but “they don’t make em like they used to”. And while the T60 has a 4:3 1400x1050 screen, even in the vertical that’s less pixels than 2560x1440. At $2599 (in 2006 dollars!), that’s a bit spendy.
For more fun, the T40 review: https://www.pcmag.com/article2/0,2817,924264,00.asp Back when turning off the wifi was how one ran a proper battery test. All this can be yours for only $3399.
At the time, the Thinkpads were marvels of engineering, so I’d say that contributed significantly to their mystique. But familiarity breeds contempt. When everybody has a sweet laptop, nobody has a sweet laptop. Carrying a laptop, of any sort, just doesn’t signal serious baller to everyone in the room like it used to.
I mean, it’s not like super expensive super powerful laptops are entirely extinct. You can buy the Acer Predator with 64GB RAM and dual GTX 1080 graphics and quad nvme SSDs. http://www.anandtech.com/show/11532/acer-predator-21-x-laptop-with-curved-display-now-available-only-300-to-be-made Just in case today’s other laptops are too thin and light for your taste. :)
Where the older Thinkpads really shine is their durability. Old Thinkpads and those from the last twoish years have magnesium cases, but for a few years after Lenovo took over the line they used plastic for the main body, which I think is where a lot of the “Lenovo ruined the Thinkpads” sentiment comes from. I have a 2012-vintage plastic Thinkpad, and definitely doesn’t survive Sudden Loss of Altitude near as well as the T60’s.
Also the year after mine they switched the keyboard to some chiclet crap, which they haven’t had the sense to un-break yet.
Unfortunately for you, I think Lenovo has a lot of market data that morons like myself actually prefer the new keyboard now that we’ve used it for a bit. :)
Everyone’s entitled to their preference, especially when it’s wrong :). With luck, they’ll make the retro keyboard with the same mount as the newer laptops so they can be swapped out.
This is spot on. I bought my first MacBook in late 2013 when I needed more processing power than my 2007 Core2 Duo T61 wouldn’t do the job anymore. I upgraded that laptop from 2 to 4 to 8gb RAM, from a 60gb HDD, to a 256gb HDD, to a 240gb SSD. When the battery had hundreds of cycles on it and was only around 50% of its original capacity, I bought a new unused one on eBay for $70 and it was like new.
I gave it to my mom when I got my MacBook. She loved it for how it always just worked, up until it conked out a few weeks ago. 10 years.
Man, I loved that laptop.
My main machine I use regularly is a 2009 Thinkpad X301 which I use to SSH into a newer Thinkpad which has a much faster processor and more RAM, but a terrible 16:9 screen and a dramatically worse keyboard. Being able to have the equivalent chassis of an X301 but with a non-glossy screen that’s bright enough to use outdoors would basically be the best of both worlds.
For years I only bought tiny, slow laptops (various eBayed Thinkpad X-series, and later an 11-inch Macbook Air) and used them as basically SSH clients to my desktop Linux box. I’d probably still be doing that if I hadn’t ended up with a couple work-issued Macbooks Pro.
My main machine I use regularly is a 2009 Thinkpad X301 which I use to SSH into a newer Thinkpad which has a much faster processor and more RAM, but a terrible 16:9 screen and a dramatically worse keyboard.
Considering how dire the X301’s panel is, that’s an indictment of modern ThinkPads there.
The first blog post and the subsequent ones give a good insight as to why ThinkPad fans are ecstatic over this. Have a look at the comment section as well, there’s loads of good comments on why a retro ThinkPad would be awesome.
Can’t believe that it’s already been 2 years since that first blog post. Got a T460s (and have had X200, X230 and T430 and serviced quite a number of other models) and while it’s a nice laptop it doesn’t quite live up to my expectations.
UB discussion aside, please note that x[n] ^= x[n] is not faster than x[n] = 0. Assuming the compiler doesn’t clean up after you, XORing a memory location with itself will take more instructions, more registers, and a memory load/store instead of just a store. This is true on X86 and every other architecture I know of.
mov [rax+rbx], 0
vs
mov rcx, [rax+rbx]
xor [rax+rbx], rcx
The “xor to 0” pattern only makes sense for registers, and then only because of instruction encoding quirks on X86. On architectures with fixed-length instructions there’s no reason for this silliness. And again, your compiler will almost certainly pick the correct mechanism here regardless of whether the code is x=0 or x^=x. Unless, of course, x is indeterminate.
Why would you want to use uninitialized memory for entropy when arc4random exists? To me it seems entirely pointless to use undefined behavior for acquiring low-quality entropy when the system provides a much better source already.
The implication is that on some BSD and open ssl implementations, they use unitialized memory in the arc4random code.
In any event, to me, the question is why would you want to break working code?
The standards committee would argue that the code has always been broken, it’s just “worked” because compilers haven’t been as aggressive as they could be.
From a compiler perspective, it’s hard to distinguish between “this should obviously work” and undefined code that can be eliminated for a legitimate performance win. In this example, an expression optimizer that previously deleted all effects with indeterminate args now needs to prove that the expression doesn’t reduce to a constant. The alternative would be to remove the indeterminacy check entirely, which would be a non-starter for teams with a “no performance regressions” policy. Remember that this sort of thing doesn’t exist just to break people’s “obvious” code: you can save on code size by removing impossible branches of a function after inlining, for example.
Also, if this were to be “fixed” in the standard, what would the fix be? You could say that an expression is determinate if, for all possible values for the indeterminate inputs, the output is the same, but this raises questions about value range (e.g. if int a = indeterminate & 1;, what can you say about a?) You could replace the concept of “indeterminate” with value ranges where an uninitialized value has the widest possible range, but then when can you eliminate formerly-indeterminate effects? Is having a range greater than a single value enough? And remember, both of these increase the burden on compiler writers considerably, and if this were introduced in a new standards version several compilers would need to disable a lot of code until it could be properly fixed.
That would be a false argument. Note that the claim is that the contents of the variable are “implicitly” UB. The standard did not explicitly rule this read to be undefined - this is an expansion of UB. In fact it is an expansion of UB into territory explicitly exempted from UB; the exception for character data were intended to cushion the ill effects of previous UB edicts. More importantly, I’d really like to see an example of a non-trivial optimization - something that actually made working code run faster or take up less space using this approach. I can see how many micro-“optimizations” are possible but what are you optimizing when you claim the programmer intention is unknowable?
“(e.g. if int a = indeterminate & 1;, what can you say about a?)” - that it is either 0 or 1. Indeterminate is an implicit I/O like operation. There is nothing you can do to eliminate indeterminate effects and there is no need to do so. Compiler writers are solving the drunkards lampost problem: it’s easier to do “optimizations” if you knew or could assume something about these values, so let’s assume that we do or can.
C programmers would be much better served by compilers that did better static analysis than by compilers that produce unexpected program failure that is labeled “optimization”.’
“ And remember, both of these increase the burden on compiler writers considerably, and if this were introduced in a new standards version several compilers would need to disable a lot of code until it could be properly fixed.”
Far better than to impose silent failures on working code in e.g. widely used crypto applications.
Far better than to impose silent failures on working code in e.g. widely used crypto applications.
If you’re talking about seeding an RNG from stack “garbage” that approach was always crap. It never worked. The garbage on the stack is always the same.
for all the diligence required to solve this sort of problem, you’d think that would start pushing programming more towards, ya know, engineering as a way of building things, but at least its a cool story!
As it was a hardware issue in this case, I’m not sure I understand what you’re saying. Do you mean that if, say, the software was verified and guaranteed not to crash, they would have immediately diagnosed the crash as a hardware issue, thus saving a lot of time?
In general, you can do that sort of thing in Design-by-Contract with a certified and non-certified compiler. In debug mode, the contracts can all become runtime checks showing you exactly which module fed bad input into the system. That lets you probe around to localize exactly which bad box took input that accepted its preconditions, did something with it, and produced output that broke the system. When looking at that module, it will normally be a software bug. However, you can run all failing tests through both a certified and regular binary to see if the failure disappears in one. If it does, it’s probably a compiler error. Similar check running sequential vs concurrent in case it’s a concurrency bug. Similarly, if the logic makes sense, it’s not concurrency, and passes on certified compiler, it’s probably an error involving something else reaching into your memory or CPU to corrupt it. That’s going to be either a hardware fault or a privileged component in software. With some R&D, I think we could develop for those components techniques for doing something similar to DbC in software for quickly isolating hardware faults.
That said, I don’t think it was applicable in this specific case. They’d have not seen that problem coming unless they were highly-experienced, embedded engineers. I’ve read articles from them where they look into things like effects of temperature, bootloader starting before PLL’s sync up, etc. Although I can’t find link, this isn’t the first time sunlight has killed off a box or piece of software. I’ve definitely seen this before. I think a friend might have experienced it with a laptop, too. We might add to best practices for hardware/software development to make sure the box isn’t in sunlight or another situation that can throw its operating temperature. I mean, PC builders have always watched that a bit but maybe the developers on new hardware should ensure it’s true by default. The hardware builders should also test the effects of direct sunlight or other heat to make sure the boxes don’t crash. Some do already.
I don’t think that’s true, at least in C. I know CompCert at least takes “certified” to mean “guarantees well-defined output for well-defined input”, so it’s free to make hash of any UB-containing code the same as Clang.
That said, if your test results change between any two C compilers, it’s a strong suggestion you have a UB issue.
True, too. There’s teams out there that test with multiple compilers to catch stuff like that. OpenBSD folks mentioned it before as a side benefit of cross-platform support.
In C, this can also mean that you depend on implementation-defined bahaviour or unspecified bahaviour which are not the same as undefined behaviour (which often will also be a bad thing ;)).
Are you proposing gamedev companies should adopt that kind of techniques?
Im always pushing all programmers to adopt anything that helps them that they can fit in their constraints. Aside from Design-by-Contract, I’d hold off on recommending game developers do what I described until the tooling and workflow are ready for easy adoption. Ive got probably a dozen high-level designs for it turning around in my head trying to find the simplest route.
One thing Im sure about is using C++ is a drawback since it’s so hard go analyze. About everything I do runs into walls of complexity if the code starts in C++. Still working on ideas for that like C++-to-C compilers or converting it into equivalent, easier-to-analyze language that compiles to C (eg ZL in Scheme). So, I recommend avoiding anything as complex as C++ if one wants benefits from future work analyzing either C or intermediate languages.
Edit: Here was a case study that found DbC fit game dev requirements.
The other day there was a link to a project that does source-to-source transformation on C++ code to reduce the level of indirection: https://cppinsights.io
Try doing an exhaustive list of FOSS apps for C and C++ doing this stuff. You’ll find there’s several times more for C which also collectively get more done. There’s also several certifying compilers for C subsets with formal semantics for C++ still barely there despite it being around for a long time.
So, that’s neat but one anecdote goimg against a general trend.
This is meaningless - is there someone who doesn’t?
So the only one thing you propose would not help at all with problem with overheating console or with performance regression from that post ;)
Sure, it’s hard but there are tools that can do some sort of static analysis for it (for example Coverity or Klocwork). Either way, there are no alternatives today for c++ as language for engine that can be used for AAA games.
Have you actually read it? I have nothing against DbC, but as far as I can see that study doesn’t really show any great benefits of DbC nor is it realistic. They do show that writing assertions for pre/post conditions and class invariants helps in diagnosing bugs (which is obvious), but not much more.
They don’t show that really hard bugs are clearly easier to diagnose and fix with DbC, nor do they show that cost/benefit ratio is favourable for DbC.
Finally, that paper fails to describe in detail how was the experiment conducted - all I could gather is this:
Even it was an interesting paper (which imo it is not) it’s impossible to try and replicate it independently.
“This is meaningless - is there someone who doesn’t?”
Yes, most developers don’t if you look at the QA of both proprietary and FOSS codebases. I mean, every study done on formal specifications said developers found them helpful. Do you and most developers you see use them? Cuz I swore Ive been fighting an uphill battle for years even getting adoption of consistent interface checks and code inspection for common problems.
“but as far as I can see that study doesn’t really show any great benefits of DbC nor is it realistic. They do show that writing assertions for pre/post conditions and class invariants helps in diagnosing bugs (which is obvious)”
It’s so “obvious” most developers aren’t doing DbC. What it says is that DbC fits the requirements of game developers. Most formal methods don’t. It also helped find errors quickly. It’s not mere assertions in the common way they’re used: it can range from simple Booleans to more complex properties. One embedded project used a whole Prolog. Shen does something similar to model arbitrary, type systems so you can check what you want to. Finally, you can generate tests directly from contracts and runtime checks for combining with fuzzers taking one right to the failures. Is that standard practice among C developers like it has been in Eiffel for quite a while? Again, you must be working with some unusually-QA-focused developers.
“would not help at all with problem with overheating console “
First part of my comment was about general case. Second paragraph said exactly what you just asked me. Did you read it?
“Even it was an interesting paper (which imo it is not) it’s impossible to try and replicate it independently.”
The fact that it used evidence at all would put it ahead of many programming resources that are more like opinion pieces. Good news is you don’t have to replicate it: you can create a better study that tries same method against same criteria. Then, replicate that. If that’s the kind of thing you want to do.
Academic studies show one thing, while practitioners for unknown reasons do not adopt practices recommended by academics. Maybe, the studies are somehow flawed. Maybe the gains recommended in studies don’t have good roi for most of gamedev industry?
The study was using “mere assertions in the common way they’re used” so I don’t know what is the point of rest of that paragraph - techniques you mention there are not even mentioned in that paper so there is no proof of their applicability to gamedev.
I asked you about your recommendations for gamedevs not about some unconstrained general case and just pointed out that your particular recommendation would not help in case from the story - nothing more :)
Sure I have, but to make it easier in future try to make your posts more succinct ;)
I agree in the general case. Except that most practitioners trying some of these methods get good results. Then, most other practitioners ignore them. Like CompSci has it’s irrelevant stuff, the practitioners have their own cultures of chasing some things that work and some that don’t. However, DbC was deployed to industrial practice via Eiffel and EiffelStudio. The assertions that are a subset of it have obvious value. SPARK used them for proving absence of errors. Now, Ada 2012 programmers are using it as I described with contract-based testing. Lots of people are also praising property-based testing and fuzzing based on real bugs they’re finding.
So, this isn’t just a CompSci recommendation or study: it’s a combo of techniques that each have lots of industrial evidence they work and supporters that work well together that also have low cost. With that, either mainstream programmers don’t know about them or they’re ignoring effective techniques despite evidence. The latter is all too common.
“I asked you about your recommendations for gamedevs not about some unconstrained general case”
What helps programming in general often helps them, too. That’s true in this case.
“Sure I have, but to make it easier in future try to make your posts more succinct ;)”
Oh another one of you… Haha.
Those techniques are not what I would call “formal specifications” any more than simplest unit tests are, but if you consider them as such, than…
… I have no studies to back this up, but my experience is different. DbC (as shown in that study you linked), property based and fuzzing based testing are techniques that are used by the working programmers. Not for all the code, and not all the time but they are used.
When I wrote about studies showing one thing and real life showing something opposite I was thinking about methods like promela, spin or coq.
Makes more sense. I see where you’re going with Coq but Spin/Promela have lots of industrial success. Similar to TLA+ usage now. Found protocol or hardware errors easily that other methods missed. Check it out.