Discussion:
smoke and mirrors
(too old to reply)
Allen Brunson
2005-10-15 01:09:39 UTC
Permalink
as it turns out, my powerbook can't beat up your powerbook after all. several
of my beta testers complied with my request, downloaded the benchmark, and
submitted results. it turns out my computers are average (my powerbook) and
slower than average (the powermac i use for development). however, my
computers do have more than the average amount of ram, and that may well trump
hard disk access speed. i am not able to google up anything on how macosx
allocates ram for disk buffers, but it stands to reason that more ram means
bigger disk buffers. the fastest disk access is one that isn't performed at
all.

but to tell you the truth, i think "speed" is about 85 percent perception, and
has very little to do with how quickly stuff actually happens. for example,
the perception that my mark-all-read function is slow. the way it currently
works is: a background thread marks all messages read, then informs the main
gui thread, which re-reads the group, finds there's nothing to display, and
therefore leaves the headers view empty. this works in the general case for
all forms of mark-read and mark-unread, such as marking a thread read instead
of all messages, marking selected messages, and so on. but 85 percent of the
time, the user is marking all messages read. so i could have added optimized
code for just that particular case, and done things differently. rather than
marking-read first, which is the slow part, and updating the headers view
later, i could just remove all contents from the headers view and set the
unread count for that group in the storage view to zero. zing! done!
instantly! then, the background thread could go about its business of
silently and s-l-o-w-l-y doing the actual job of marking the messages read in
the group, without displaying any progress at all. going slowly would keep
the hard disk from making any tell-tale grinding noises. remember, we're
trying to give the user the illusion that the process is already finished,
long ago. so the entire operation in reality would take several times LONGER
than it did before, but from the user's vantage point, it finished instantly.

it might sound like i am being flippant here, or making fun of people who
value perceptions over reality, but i'm actually not. perceptions are indeed
more important than reality. and i am seriously considering pulling little
tricks like this in the future.

there are, of course, problems. as long as you don't try to access the group
that was just marked-all-read for awhile, the illusion will hold. but if you
should try to go look at that group before the background thread is finished,
you'll discover the emperor has no clothes. you won't be able to view it,
because the background thread has the cache database for that group locked,
while it marks all messages read. you have to pay now, or pay later.

i'm trying to find opportunities where you can "pay later." one of my
greatest strengths as a programmer is writing multi-threaded code that does
not crash or trip over its own feet. it's a rare skill, because most
operating systems treat multi-threading as a bad joke, bolted-on,
under-documented, de-emphasized, and not well integrated with the platform's
other features. many mac apps have a serious "beachball problem," where they
put up the beachball cursor that means they are not responding to gui events,
because they are performing some long-winded operation in the main thread that
really should have been farmed out to a background thread. perhaps the author
actually tried that, but made the usual beginner's mistakes, and ended up with
a bunch of nasty bugs that were very difficult to reproduce or fix. so he
ripped out the threading code and settled for the lesser evil, beachballing.

too bad more of those guys didn't spend a year or two in beos, like i did.
it's the only operating system i've used so far that makes multi-threading as
easy as possible. it still wasn't actually "easy," but at least the os didn't
actively discourage you. in fact, they gave you no choice: every beos window
runs in its own thread, so your gui app WILL be multi-threaded, whether you
like it or not.
Alexander G. M. Smith
2005-10-15 15:18:28 UTC
Permalink
rather than marking-read first, which is the slow part, and
updating the headers view later, i could just remove all contents
from the headers view and set the unread count for that group in
the storage view to zero. zing! done! instantly!
I prefer the multitasking approach. Like BeOS Pineapple uses. If
the task doesn't complete immediately, run it in the background with
updates once in a while to the GUI - so you see the unread message
counter counting down rapidly when you mark a group unread. I guess
you can't use BeOS style file change notifications so you have to
mark all your things read in one batch, then update the GUI in MacOS?

Isn't there some way of doing a bunch of smaller updates or monitoring
the changes as they happen from the GUI? I had something similar for
my spam detection program when it's loading the database - the GUI
thread tries to get a lock on accessing the data (there's a semaphore)
and if the lock times out (half a second timeout) then it just reads
the word counters and doesn't display anything else (reading the word
counters is multitasking safe while reading the data structures that
actually store the words isn't safe and thus needs the semaphore).
Maybe you can have similar unread counters that are multitasking safe
while the actual group display is protected by a lock? Or are you
currently playing it super safe and protecting everything by a lock?

- Alex
Allen Brunson
2005-10-17 07:23:30 UTC
Permalink
Post by Alexander G. M. Smith
I prefer the multitasking approach. Like BeOS Pineapple uses. If
the task doesn't complete immediately, run it in the background with
updates once in a while to the GUI - so you see the unread message
counter counting down rapidly when you mark a group unread.
that's pretty much what happens in macosx/pnews now. i haven't actually made
good on my threat to use deception to make it appear that it all happens
instantaneously. heh!
Post by Alexander G. M. Smith
I guess you can't use BeOS style file change notifications so you have
to mark all your things read in one batch, then update the GUI in MacOS?
it's true, i can't use beos-style file change notifications anymore. even if
i could, it wouldn't help much in my current scheme, because of the cache
databases. but that's one of many things that NSNotifications are good for.
the background thread sends updates regarding what it's doing, and the main
thread uses that information to update the status bar, reload the headers
view, and so on.
Post by Alexander G. M. Smith
Maybe you can have similar unread counters that are multitasking safe
while the actual group display is protected by a lock? Or are you
currently playing it super safe and protecting everything by a lock?
i'm not really sure what problem that would address.

the real problem was: mark-all-read was slow. the main reason was that i was
doing it in a stupid way. it iterated across all files in a folder and marked
them all read, whether they needed it or not. this was one of the first
things i wrote, and it hadn't really dawned on me that i could use the cache
databases for things other than quickly populating the headers view.

a good thing about mark-all-read is that, most of the time, most of the
messages are *already* marked read. so i rewrote the operation so that it
doesn't slowly iterate across all files, it quickly iterates across the cache
database. when it encounters one that has the wrong unread state, the message
file is changed, and the cache database is updated. this will usually be at
least ten times faster than the old way.

unfortunately, mark-all-read and mark-for-download are about the only bulk
operations (i.e., ones that operate on all messages in a folder) that can be
speeded up this way. delete-all-messages still has to iterate across all
files, obviously. parse-all-messages and reindex-all-messages also can't take
shortcuts. fortunately, mark-all-read seems to be the most popular bulk
operation, and the only one that's used with any frequency.

after i fixed this, i asked both of the guys that had complained about it to
name the next-slowest thing, so i could speed that up as well. i haven't
heard anything from either of them, so i guess nothing else is really sticking
out like a sore thumb, as that one was.

Loading...