Two months ago I published the usage statistics for March 2010. This month’s data shows a drop in usage for the first time (6.3%), as well as a surprising and unexplained nosedive in the Turkish usage base. I checked the web server’s 404 (“not found”) logs, and it doesn’t account for it, so I’m at a loss to explain it.
In any case, the trends that I’m the most interested in are still showing positive gains. The upward march for Windows 7 (+27.9%!) and 64-bit (+21.1%!) continues, which of course is very good news. Windows 7, at almost 26% total share, has now overtaken Windows Vista, and I’m hoping to see Windows XP fall below the 50% mark soon. I expect that to happen within the next 2 months. The percentages for both English and Russian have gone up, although this may simply be a statistical rebalancing from the mysterious Turkish falloff.
Paint.NET v4.0 is progressing steadily. I’m still in the middle of the “MQ” phase, which is a time for investing in code quality and technology upgrades (“MQ” stands for “Milestone Quality”). I’ve established a good programming model for Direct2D and DirectWrite, improved the super sampling quality for Image->Resize, converted Rotate/Zoom to use IndirectUI, and also significantly improved the way error dialogs and crash logs work.
In previous versions of Paint.NET (which includes the latest v3.5.5), a crash brings a sudden halt to the program with an unfriendly and needlessly verbose dialog:
The user then clicks OK and has no idea what to do about it. This dialog violates the principle of “users don’t read errors” (or anything, honestly, myself included!). Even if they did, it’s unlikely that the crash log would make much sense for them. In Paint.NET v4.0 this will still result in the application shutting down, but at least the UI is improved:
Further improvements may involve hooking into Windows Error Reporting (WER) so that crash logs can be uploaded to me automatically (while respecting your privacy settings, of course).
Clicking on the “Show Details” button will give access to a simple “Copy to clipboard” button and “Open crash log folder” link. The crash logs are no longer unceremoniously (and unprofessionally, I might add) dumped to the desktop. Instead, the last 20 of them are stored in the local (non-roaming) AppData directory (e.g., c:\users\UserName\AppData\Local\Paint.NET\CrashLogs). Most people won’t see that many crashes, of course, but I wanted to ensure these couldn’t gobble up an unbounded amount of disk space. The log files are also stored using NTFS compression to further reduce their disk space impact (although they’re fairly small to begin with).
A similar dialog is also used for reporting other errors. For instance, instead of displaying a nebulous “There was an unspecified error opening the file” error, Paint.NET will now tell you that there was an error (not an “unspecified” error) and let you see the .NET exception. For most situations this won’t really improve the situation, but it will greatly aid troubleshooting – on the forum we can simply ask someone to copy+paste the exception details which will help to speed things up.
Other planned improvements include an “operation restart manager” so that insufficient disk space errors (and others) can be recovered from without data loss, as well as the implementation of a “segmented list” class. The latter will help Paint.NET avoid problems with allocating larger and larger arrays for things like polygon lists (among other things). Instead, the array will be broken up into smaller chunks which a 32-bit system can deal with much more easily.
For instance, if a 200MB array needs to be allocated in a situation where sufficient memory is available but a large enough region of contiguous virtual address space isn’t, this will greatly improve the probability that the allocation will succeed. In fact, often times the problem is that a 150MB (for example) array needs to grow to 200MB, in which case a total of 350MB of memory is required to complete the operation! The SegmentedList<T> class will also avoid the overhead (CPU and memory bandwidth) of constantly copying all those blocks of data, at a cost of higher CPU usage when reading and writing to individual elements within the array. It seems to be a fair tradeoff.
Another improvement coming, one which is long overdue, is fault tolerance when saving an image. Currently, Paint.NET always overwrites the file you are saving and this can have disastrous consequences if an error is encountered in this process. The end result is a 0-byte file even for users who’ve been diligent about saving regularly. The solution is simple, involving first saving to a temporary file and then deleting the old one only when the operation has succeeded. You might ask why this wasn’t implemented a long time ago, and I’ll defer to Raymond Chen’s discussion of the Windows taskbar for an explanation.
The installer now has a hard block on having a minimum amount of memory (RAM). I’m occasionally humored with a crash log from a poor Windows XP user trying to run Paint.NET with 96MB of RAM (which is usually 128MB with a sizable chunk carved out for slow integrated graphics). Sorry, but it just isn’t going to be reliable with so little memory available!
I’ll skip the boring pie charts this month. Here’s the usual tabular data though:
|March 2010||May 2010|
|Total update manifest hits||4,528,824||4,243,221|
|Hits per day||146,091||136,878|
|Windows Vista / 2008||23.72%||22.64%|
|Windows 7 / 2008 R2||20.29%||25.95%|
|All other languages||0.81%||0.86%|
|Don’t have translations||20.55%||18.62%|
Bold indicates that Paint.NET ships with the translation. Korean had a translation in v3.36, but not in v3.5+. For Russian, the reverse is true.
8 thoughts on “May 2010 usage statistics – Windows 7 reaches 26%, overtakes Vista”
Are you ever planning to share some info on how you implemented the SegmentedList class? It sounds interesting and something that would be useful to me.
I assume that you internally you’ll be splitting the list up into chunks, how do you choose the chunk size to make it efficient by still fit in the available memory?
Matt, it’s pretty simple stuff.
@Matt: I would assume a SegmentedList is really just a List<List> (or maybe List?) with an implementation of IList to make it “look like” one big contiguous list.
Seems like a good idea for when you’re dealing lots of large lists of things.
It’s a custom implementation of IList. It doesn’t derive from List.
But yeah, Dean, you got the gist.
Imaging the implementation of GeometryList.GetInteriorScans(), which current returns an array of rectangles that constitute the interior of a polygon. This is pretty useful for things like filling a selection, or clipping an effect to the selected area. Anyway, for a very complicated polygon this array can grow and grow and grow (magic wand anyone?) … by switching to returning an IList implemented by SegmentedList, this array can be allocated without the need for contiguous blocks. Nor is the CPU overhead of growing the array (re-alloc + copy + free old array) needed.
To save on the CPU costs, the segment size is constrained to be a power of 2. That way the segment index can be calculated using a quick shift-right, and the secondary index can be calculated using a mask (bit-wise AND operation).
Thanks for the info it makes sense now.
I actually miss-understood how it was being used, I thought you were storing 1 image in a segmented list/array as a way of storing large images in memory when there isn’t enough contiguous memory to allocate it all in one go. But not I’ve re-read your post and I understand.
Matt, I’m starting with the data structures used for geometry. I do intend to store bitmap surfaces using a tile scheme, but I’m not to that point yet. That will require much more time to complete since it impacts all areas of the application in significant ways. With a 1-dimensional array it is much easier, as only code that needs to use pointers is strongly affected by the change in access semantics.
Yeah you’re, I guess there’s big performance issues with storing an image in a non-contiguous array, especially for processing.
In the future ‘d be interested to see your approach (if you’re happy to share it), as I have some upcoming projects at work where this could be an issue.
Comments are closed.