4 ms·
What I've never understood is what exactly makes a computer snappy. My RAM is never fully used, CPU percentage often in the single digits, Solid state drive -
by EricDeb 14y ago
What I've never understood is what exactly makes a computer snappy. My RAM is never fully used, CPU percentage often in the single digits, Solid state drive - still I feel like it could be snappier. I wonder where the deficit is?
- StavrosK 14y agoI have the same question. I press the shortcut for "open nautilus", it takes a bit less than a second to open. What's the holdup, Gnome? At least, in Windows, explorer is pretty much instant.
- chubot 14y agoThe deficit is software. Hardware has gotten crazy fast, but software is struggling to make use of that speed in ways that are valuable to average users (e.g. reducing perceived latency). At the risk of stating the obvious, a computer feels snappy when it responds to user actions (clicks, keypresses) quickly. That is a holistic problem -- one that concerns all parts of the system -- so it's hard to optimize. Software tends to evolve "within the lines"; it's hard to make changes that cross abstraction boundaries. But that's where performance is. On the other hand, hardware has gotten faster unevenly. Disk seeks are the slowest thing your computer does besides WAN access, but those haven't sped up much over the last decade. Disk throughput (and size) have increased orders of magnitude faster than seek time. But we're still using the same software abstractions (and the same software!) for these radically different machines. For example, stat() is still a synchronous call. In the old days it wasn't all that slow relative to CPU operations. Now it can take 30ms, which is 30,000,000 cycles on a 1 Ghz CPU. So arguably the default should be async. C is another abstraction that had a reasonable performance model when it was invented, but no longer does. It's hard for the average developer to have a decent (portable) model of a CPU these days, especially with regard to concurrency.
- chipsy 14y agoI generally agree, but would present a specific software-architecture cause for most responsiveness issues: the simplest way to perform a UI update is "toss and rebuild" - remove all the elements and replace them with new ones containing changes. This method is straightforward and much more maintainable than the performant alternative: hold everything in place and manipulate the minimum needed to update. It's a particularly important trade-off as you start considering, for example, more complex layouts where the size and positioning of one element may affect any number of others, elements get added or removed, etc. There's a spectrum of variations between these two extremes that let you choose between maintainable and fast, but neither end really has an ideal combination of both. Language and coding style changes can help, too, but a truly complete solution still seems absent. The initial load is the second major source of peril for responsiveness. Even if a custom cache for the load is used, the user's first-run impression is still going to be of an uncached experience. Here the disk seek, as you mention, is of huge importance. But I find that I'm personally less irritated by load times than I am by software with intermittent spikes of high CPU usage, which will slow down the whole system at unexpected moments.
- chubot 14y agoWell, I agree that there are specific program architectures that can cause problems, but I haven't had the experience where "toss and rebuild" is the bottleneck. One of the other responses nailed what is a more common problem IME -- network activity and UI activity on the same single-threaded event loop. Firefox and Chrome both have this problem (or what amounts to it essentially). For example, in Chrome: http://code.google.com/p/chromium/issues/detail?id=113389 http://code.google.com/p/chromium/issues/detail?id=113389 This bug has gone unfixed for YEARS (older ones were marked dupes of later ones). The way we write software now is just too difficult to get right. Once you have 1M lines of C++ code there are going to be crazy performance bugs that nobody can fix. Chrome has some of the best engineers on the planet and they're not immune to this by any means. I guess I would amend my original answer to say that "software size" is the problem. Everybody thinks they know how to write performant software. But that's only when you can fit everything in your head. I would say that "toss and rebuild" isn't the #1 culprit because the web browser is the ultimate "toss and rebuild" architecture -- that is, every request and response stand alone. Yes web pages can be ungodly slow and unresponsive. But it's possible to make them responsive if you really simplify -- i.e. Google or craigslist. In theory we could have a stateful web and make it faster. But I think our collective programming skill and our languages/tools just aren't up to the task. I think the web exists as it is, and is as popular as it is, because lots of people with "domain knowledge" could write dirty PHP scripts and such. They aren't fast but they get the job that users want done.
- Chris_Newton 14y agoThe apparent lack of responsiveness we see with a lot of modern software is usually a product of three factors. Firstly, architectures today tend to be multitasking and event-driven. A modern GUI application is usually built around an “event loop” that waits for various interesting things to happen, such as the user pushing a key or clicking a mouse, reaching a certain time, or receiving a signal from an external device. When an event of interest takes place, the relevant part of the loop will detect it next time around, and then run the relevant code to react. However, if that code takes a significant amount of time to run, then the event loop won’t have a chance to react to anything else that is going on until the last event is dealt with. The catch is that things like repainting your application window because the user happened to move another window over the top of it are also handled by the event loop, so if you’ve got an application that is trying to check for new mail every five minutes but your network connection has dropped and it takes 30 seconds to time out, the application might be completely unresponsive to any other kind of user interaction during that time, and might not even redraw properly if you move other windows over it. The usual solution to this problem is to introduce a degree of concurrency, so that any event-handling code that isn’t guaranteed to complete very quickly is executed in a new thread in parallel with the event loop. The loop itself is therefore immediately free to continue responding to other events, possibly kicking off still more new threads, as necessary. Unfortunately, there are significant overheads to coding this way, so a lot of simple applications don’t bother and just accept that they might become unresponsive now and then. And of course it’s always possible to make a mistake in the design, responding to a certain type of event that is usually dealt with quickly in the main thread without realising that under some circumstances it will take much longer. The second factor is abstraction. We used to program pretty close to the metal, because you couldn’t get acceptable performance any other way. Today, we build on top of OS kernels, hardware abstraction layers, device drivers, virtual machines, run-time libraries, and who knows how many other tools, all stacked up and each composed of many layers themselves. The benefits of this approach are many: faster development time, more effective testing and more robust software, ease of porting software to run on different hardware or operating systems, and so on. The downside is that every time you introduce another abstraction, you are potentially introducing an overhead, and those effects multiply. Even if your abstraction is say 90% efficient compared to programming directly to whatever lies beneath it, if you’ve got 10 layers of abstraction between the code you’re writing in your end user application and the hardware you’re ultimately talking to, the effect is to reduce performance by about 2/3. And there are a lot more than 10 layers between your average end user code and the hardware on most systems today, and some of them are far from 90% efficient. The third and final factor is somewhat related: if development time (or, if you prefer, time to market) is more of a priority than raw performance, it’s easy to skip over the kind of optimization work that used to be essential to produce software that ran acceptably quickly and within the relatively limited RAM and permanent storage capacity available. It’s one thing to skip the fine details and hand-tweaked assembly language, which was often a very expensive activity in terms of time spent vs. resulting speed-up. It’s another thing to just throw in the first data structure or algorithm that comes to mind, often because whatever software development toolkit you’re using has a limited set of options available and maybe it’s not worth the time to code up something more appropriate, or maybe because as the industry has grown a lot of developers aren’t either formally trained or keen hobbyist geeks any more and not everyone knows about all the options. This is how you wind up with abstractions that are a lot worse than 90%, or that don’t scale well as the amount of data they have to deal with increases and assumptions that the hardware is “fast enough to make up for it these days” break down. So, in summary, and in more of a cause-to-effect order: 1. The emphasis on reducing development time because of commercial pressures or other non-technical factors, combined with a certain complacency about the capabilities of modern hardware, means that not as much optimization tends to be done before code ships today. Sometimes this introduces a modest overhead, but it can be severe if a poor choice leads to scalability problems. 2. Even if the overheads of any one function are modest, we build modern systems from a stack of many abstraction layers, and their overheads multiply. The compound effect can easily be the equivalent of running on hardware from several years ago, even if no individual layer was grossly wasteful. 3. Because we tend to use event-driven architectures for a lot of modern software, including most GUIs, a single slow operation can block the whole event loop and effectively make the whole UI unresponsive indefinitely. More advanced architectures that would prevent this have significant development costs and aren’t always used for the same reasons as above. [Edit: OK, this is getting a few upvotes and no-one’s replied suggested cutting it down, so I’ll leave the whole post as it is. Sorry if anyone does feel it’s too long.]