|
30sep09
«
faded wallpaper
triviality « Hey, I don't always have something interesting to say. For example, this short piece is hardly worth bothering to write. Note I'm not religious, at all. I just like mythology. If you ever suspect a whiff of religion in my fiction, it's really just mythology. Because my mother was a practicing Roman Catholic, she dragged us to church when I was in grade school. I hated church, both from discomfort and boredom. (Kneeling for long periods of time was physically painful.) She started taking us when I was eight. Sometime during the year I was nine, I had one of my first big social insights. As I've mentioned before, I'm one of five kids—the oldest two years older than me, and the youngest four years younger than me. So in the car after church, there weren't enough window seats to go around. Thus, we had to race to secure a good spot. If this sounds like a familiar meme of church folks departing in poor grace, you're on the right track. One day, the amount of effort we spent in pursuit of a good seat struck me as odd. The reward wasn't worth the trouble, especially irritation of losing when it happened. In a flash, I had a new idea: what if I just didn't care? After all, what difference did it make if I had a window seat? I could think about something else entirely, if I didn't care. So I stopped running to the car, and immediately had a better experience. It annoyed my siblings I no longer cared about losing, and my parents noticed enough to ask: are you okay? I was better than okay: I was terrific. How I felt was no longer subject to stupid games I had no particular interest in playing. Competition wasn't much fun, really, and reward was too trivial. So at age nine, I decided competition was a waste of time. Since then, I've seen little reason to think otherwise. All jostling for position is a pointless nuisance. But most people get pretty worked up about it. Hmm. Doesn't it seem childish to you, too? threads and fibers « I'm grinding away at setting up a thread pool to service blocking requests from fibers. Often, after I know the answer to a problem, it always takes a lot more staging to get to square one than I expect. Well-defined doesn't seem complex until you hit details. research « I managed to whet my appetite again for reading trivia in history. I was going to draft some fiction, and stopped to look up a couple minor details; next thing I knew, I'd spent two evenings reading online for entertainment. Last night I studied the history of handguns, because I don't know a blessed thing about them. I was fleshing out a wolf in Wil's fable about Briar Pig, and got carried away, with some productive results. There's a possible connection with Wil's interaction with Finch; more fodder for time travel side plots. I'm working on four story lines I'll touch very soon after I post more fiction. They include Wil's fable; Ulf's dream; Wil and Eli in Venice; and the arrival of Aleph and Mick, with a lot of side chatter with Finch and other folks showing signs of her viewpoint. The last has been ongoing a long time now, featuring Finch's next surprise for Wil, as well as hints regarding whatever job she has for Wil. (Wil doesn't want the job, which is why he's suited.) Recently I'm focused on tactical parts of Wil's fable and Venice conversation context. 27sep09
«
zoot suits
cloud mania « Technically, some of what I do in WAN optimization is related to cloud computing, but I don't think about that. In fact, I'm not even sure what layer of the network is home to my code. I'm somewhere in a blurry zone under layer seven, but above cut-and-dried parts. Currently I control a very specialized compression codec with elements in common with several similar things, which I'm not going to name. (If I did, that might be construed as telling you how our code works.) The goal of my code is dedup (short for deduplication) as quickly as possible, on data sets as large as we can manage, in ways reducing network bandwidth without incurring more latency. In principle, this works on any data streams, and doesn't depend on network particulars, which is why I ignore network details. So my code gets plugged in wherever it fits best in the network stack. From talking with coworkers, I get an idea some of my work sounds like math, though I don't think of it that way. But I borrow terms from math when it helps explain any part that otherwise sounds arbitrary. I often mention entropy when comparing one tactic to another, when I talk about how much use you can get out of how many bits. I gather my explanations sound like math to others, in the sense of defining terms, leveraging relationships and situations, and walking through an algorithm in enough detail. It's unclear to me what I'm supposed to be good at doing. Part of it is actually understanding what I do, so I can order choices strictly in terms of whether one option is better than another with respect to desired results, and then back this up with results of empirical tests I design carefully. But I often do several things other folks do less often. I fix broken things, simplify complex things, discard unused things, redefine blurry things, optimize slow things, fortify fragile things, generalize narrow things, shrink bloated things, and increase degrees of freedom by sidestepping unnecessary constraints. Just a little of each one of these has a good effect. I tend to look at all these as getting more bang for the buck, with less risk and more robust behavior. I don't see what's hard about it. But maybe all INTP's feel that way. Stuff I touch usually gets better. That's the main thing. I'm not much of a theorist, except for occasional design work from scratch, which I'm asked to do when fewer failure modes are desired. (I expect systems to fail, so I try to define them in a way accepting failure as normal, so error cases are part of normal behavior when possible.) I don't think about cloud computing, even though working on distributed systems. Why are folks so excited about cloud computing? I don't know. I wonder if folks expect something magic to happen, as if distribution will make systems less fragile, instead of moreso. The more things you own, the more your things own you. This applies to tech as well as meatspace objects. 26sep09
«
rural games
bike riding « I learned to ride a bike in about 30 seconds, at age five, when my father seated me on a small, solid-tired bike and pushed me, running, up to speed before letting go. When I didn't fall, he said (basically), "Hey, that wasn't so hard." It's unclear to me how training wheels help. I never had a problem. Maybe five is old for bikes. learning to play « I suspect boredom helped me learn to play. There wasn't a lot to do when I was a kid. So I spent a lot of time outdoors, making stuff up, mostly with other kids. When I was four and my younger brother was three, we staged a few pretend television shows in the living room. I think my mom thought this odd. A few years later, aged eight and seven, we told infinite stories to other kids. While one of us talked, the other considered a next plot twist to introduce. Our favorite segue began with the phrase, "Meanwhile, on the other side of the world..." We grew up in an age and place letting kids wander off until dinner. I spent all of grade school in Georgia and Tennessee, so I didn't spend all my time in Iowa. Of those two, Tennessee was better. We lived on the top of a ridge, and land between ridges was not developed, so my backyard abutted on "the woods" where we often played all day. A firetrail partway down the ridge provided a dirt road we could wander for long distances, looking for adventure. We imagined magical places and played ad-libbed dramas. Naturally, we sometimes did dangerous things, but never got hurt. A neighbor kid had a hatchet, so we could cut trivial amounts of wood at need—but no one lost a finger. The neighbors also shot BB guns, but no one lost an eye. Some kids had gas powered motorbikes, but no one got run over. My mother denied us all these things because they were dangerous. But we never saw the evidence. Most of the bad accidents were collisions, either in the road or a back yard. The next door neighbor's grown son was killed just down the road on his motorcycle. My youngest brother was hit by a car in Georgia, and lost some of his hearing. My next youngest brother, mentioned above, was hit by a falling metal slide in a neighbor's yard, at the age of eight, crushing the eyebrow ridge above one eye, so it had to be rebuilt. Many years later, in college, it finally occurred to me he might have frontal lobe damage, because he was more than a little casual with the needs of others. I wished I still had the same brother I told stories with before the accident. Television was rarely interesting, unless you count Dark Shadows after school. (It was a vampire oriented horror show structured as a daytime soap opera.) Cartoons were aired only on Saturday and Sunday mornings. So distracting media was a trickle. After doing homework and exhausting myself outdoors, I still had time on my hands. Much of this I spent reading library books, starting with astronomy at age eight. I read a lot of science fiction, starting with my mother's copy of The Andromeda Strain. I made my way through the science fiction section in the public library in junior high. (At age nine I tested at high school level in "science," whatever that means in standardized tests. My seventh grade science teacher asked us if we knew why the sky was blue, so I raised my hand. I said blue light refracts more than light with longer wavelengths, so it scatters more passing through the atmosphere, which also explains why sunsets are red, because after passing through so much atmosphere—with the sun lighting the earth from the side—colors with shorter wavelengths were filtered out by refraction. My science teacher stared at me. Finally he asked me: was I sure? Then he badgered me to admit I might have my facts wrong, even though that was what I recalled. At that point he told the class I was absolutely right, and that my mistake was in not sticking to my guns. The most important thing, my science teacher told the class, was acting like you were certain and refusing to give in. Personally, I thought he had an attitude problem.) My peers were inane, so talking to them was boring. It never occurred to me I might enjoy talking to people because they had interesting ideas. That just didn't happen, as far as I saw. So I spent even more time in the public library. One of my favorite sections was the pseudo science part of the Dewey decimal system, where you could find everything from Bigfoot to flying saucers. Basically, I sampled the entire thing: all the books in this or related sections, while thinking about how one sifts through content like that, judging it when you can't perform empirical experiments. I slowly got a sense of how gullible folks must be, in general, to get taken in by this sort of thing. Why did I read that stuff? I was looking for edges in what was known. I didn't want to study only things that made sense, but also things people believed when they should not, because this might tell me why people were so irrational. I didn't find whatever it was I sought. So after age fifteen I mostly read science fiction, instead of trawling through non-fiction too. I read through the SF golden age in high school. In college I sampled library stacks by pursuing a topic thread from one place to another. As a result, I slowly started getting an idea what I learned in undergraduate classes was just a thin slice ignoring almost everything. So, why did I start out by describing childhood play before telling you my library habits in college? Because the latter was also play, just a different kind. Wandering through ideas was like wandering through the woods. I didn't have any reason to do it beyond satisfying my curiosity, which was large. Many things outside a library were boring, because it was mostly social posturing, and it always went the same way. When other kids partied and got drunk, I browsed the library until closing time. I never went to parties, which seemed like sensory deprivation. The weirdest thing I did in the library was skim the Encyclopedia Brittanica, in order from A to Z, looking for topics I had never noticed before. This took many sittings, since I could hardly go through more than a volume or two at a time. I was looking for patterns in what was thought notable, as well as anything odd that I might not ever notice otherwise, stuck in my tiny slice of space-time. 25sep09
«
trompe l'oeil
return values « I'm slightly stuck on return values from lane-based fibers. By stuck, I mean I'm dithering because several nearly okay choices are close to one another. First I had to answer, "Is it a good idea for fibers to return values?" Finally I decided 'yes' because it's easy in one process address space, and is likely to be useful. I'm leaning toward making it feasible to return the same sort of value from a fiber as any continuation can return, but I needn't encourage that. In general I'd like a fiber to resemble a process or thread, but whichever has weaker semantics when they differ. For example, a process doesn't normally return arbitrary values because being in another address space is awkward. So a natural minimal choice would be a status value only, plus an indication of whether a fiber was terminated by a signal. Threads also typically have a smaller api than processes, because more finesse is needed for OS processes; so fibers should be small in api like threads. Signals (by a lane engine) to terminate fibers seem like a good idea. When a task distributed over several fibers goes wrong, it should easy to shut down all loose ends. You don't want cleanup to be hard, so stopping suddenly without finishing should be easy. In the absence of signals, I want a fiber to exit only when an exit is called explicitly. But in addition to an exit status, you can return a value to anyone waiting. (You might instead force return values to be passed sideways through other channels, but it would just be gratuitously awkward.) I already had a plan to handle waiting for replies from a thread pool, when worker threads make blocking calls (typically for i/o, for example). This involved sending a msg (short for message) as a request in a thread-safe queue; then a reply afterwards comes back in another thread-safe queue. Waiting for that reply could easily deliver the original msg request itself, after a round trip, to minimize what must be done to recognize the original request. You can just say: here it is, and it contains a return status. But when one fiber waits for another fiber to exit, how does that work? Complex, like waiting on a child process? Or simple, like joining a thread that exits? I worked through some plausible implementation tactics while thinking about it. Eventually, I decided it would be easy to store a list of msgs in a child fiber, which get sent when a child exits. So everyone who wants to wait on a fiber can add a self-addressed message to this onexit queue in a fiber. A lane engine would deliver each msg in that queue when a fiber ended by exit or signal. Then I noticed if I used the same msg format as used when issuing requests for service by a thread pool, but when you wait on a fiber, this looks just like waiting on a thread pool request. In short, you wouldn't be able to tell whether an async request was handled by another fiber or by a thread. Then you'd be able to do things like issue async system calls A and B; then start new child fibers C, D, and E; then wait for a response from any of these—system call reply or child fiber exiting—and exactly the same code would run in every case. All of them could be turned into a msg queued in a lane fiber's inbox, then putting that fiber in the scheduler's ready queue if the fiber was waiting. The idea of using one mechanism seemed a lot more elegant than two completely different ones. I suppose I should let you wait for different classes of msg separately, but that would make an api bigger—maybe in a later rev. A msg has two independent mechanisms inside for causing activity: 1) a function pointer to be called (with the msg as an arg), and 2) an ID of the fiber to receive each msg as an inbox reply. Each of these two parts is optional. But to get a thread pool to do something when a msg arrives, you really need (1). If a call is one-way, with no reply needed, you can leave a msg fiber ID invalid to say "no reply." When putting a msg in a new fiber's onexit queue, you could include (1) or (2) or both. Maybe all you want is specific code to run when a fiber exits, so the function pointer is enough. Or maybe all you need is delivery in the listening fiber's inbox when a fiber exits. If you built a dynamic language around this, you'd mostly use msg delivery. But in a C++ app, you might prefer callbacks. Did you notice a weird part about the function pointer in a msg? When a msg goes to a thread pool, it's called by a worker thread. But when a message goes in an onexit queue for delvery on fiber exit, it's called in a lane engine thread. This feels slightly off to me, but I can't see anything wrong. But effectively, function pointer type changes slightly depending on where a message goes. You can't touch any mutable state in the lane engine from a worker thread, but you can when a msg gets delivered to an inbox on fiber exit. 23sep09
«
spin doctors
complexity « Yeah, complexity's a bitch. Sure, avoiding it's a great idea. Don't use fancy technique when plain works. But sometimes you have no choice. I can give you a simple example—you already know this one, most likely. Say you use plain vanilla code style only, doing something hard. You chase down details one by one, and slowly, ever so slowly, the result gets righteously gnarly, with the kind of complexity giving you vertigo when you think about some parts. Chances are, somewhere in there, you should have made some piece—maybe even more than one—just a bit more abstract, to control some of the wildness. Then total complexity might have been less. Or at least, scary bits might have some locality, so you can do experiments and get your head around them. A key idea is: in order to just play with something, it can't overwhelm you from go. If each piece of code snakes into all the other pieces, so you can't wiggle, you need more order. You can't easily figure this out up front, though. But the third or fourth time you do something again, you already know what's going to happen when you do it the "simple" way. Then if you write a slightly more complex mechanism first, to do a part you know loses control, it's not such a big sin. In some problems you can see conservation of complexity: it's going to go somewhere. You can only choose how to fold it. Just for example, ask someone who wrote a highly async product whether any part of it was complex. Ask them how often efforts had to be abandoned because they didn't gel, or because they were too hard to use after scaffolding was done. Ask whether some problems remained unsolved because they were too hard to think about, when current behavior is acceptable (if not perfect). Most computing tools evolved in a sync coding style natural selection environment, so nothing async is easy if it pervades a large enough scope of control. When should you use a complex technique? When you think you'll fail if you don't, and you still need to solve the problem. Failing includes taking too long, by some large amount (say N more months in an N month total schedule). Here's a typical clue: your coworker tells you not to go down in that gorge—the kraken will eat you. He doesn't think you'll survive. So you say you have a complex plan that might work this time, because in the critical spot where everyone gets killed, you'll be safe. To vet your idea, your coworker is interested in exactly how invulnerable you'll be, in that spot. That's what complexity is for: invulnerability in a spot of mortal jeopardy. C++ « C++ sucks. I know, because I've used it a lot—more than twenty years. But every time I got really pissed off and rewrote code in C, it didn't get simpler. This surprised me, so I kept trying. I've taken code through revisions from X in C++, to Y in C, to Z in C++, and the last version is most simple because C is ever so slightly more verbose at some things. Maybe the effect is more pronounced for 100,000 line projects. Dunno. But I know my C++ code is shorter than my C code. In addition, I get slightly more type safety in C++ (when I aim for it). If you do it just right, you can often write a lot of code that runs right the first time, provided it compiles without error. Doing this in C is very hard. I usually have one third or one fourth the number of squirrelly bugs to find in C++, which is big. But learning how to do this, if you don't know already, might not be worth your time. You'll swear C++ is taking years off your life; it's exactly one of those tools leading to a like/hate relationship. (In case you're wondering, I learned C first, around 1983, and spent a few thousand hours coding in it before I learned C++.) threads « Threads suck, too. Wow, there's an emerging pattern here! I've worked on projects (on Linux) converting from single-threaded, event-based style to a multi-threaded concurrent style, and vice versa. I'm the one who makes things thread-safe if they weren't before. It's easier to go from threads to single threaded (unless your starting event-based code was horrific). There aren't quite as many things that can go wrong in a subtle but disastrous way. It's hard to use threads correctly, but it's totally doable—just maybe not worth your time to learn how, if you don't know already. I've seen folks use threads wrong in surprising ways. (Why dedicate a helper thread to each main thread on a one-to-one basis, instead of using a thread pool? Bizarre.) But if you already know how to use threads safely and efficiently, it can be more complex to not use them. For example, I recently mentioned an idea of using a thread pool to service blocking calls issued by non-blocking fiber code in a main thread. Is it really necessary to use a thread pool? No, it's not. Let's define how to avoid a thread pool in terms of how you'd do it using a thread pool. Okay, you pass two thread-safe queues to each thread in the pool: one for incoming requests and one for outgoing replies. Each pool thread blocks popping the inbound queue until an arriving request signals one thread to wake up and handle the request. Replies go in an outbound queue, which a main thread polls using a thread-safe but non-blocking trypop() call, returning nil on empty queue. What's the main idea here? There's two queues. That's also how you can solve the problem when you avoid using a thread pool. You can make a non-blocking runtime engine completely threadless, as an embedded machine. When you want the machine to do something, you stick requests in an inbound queue. Then you give an engine cycles to spin for a while, until it returns after (either) running out of its timeslice or running out of things to do without blocking. Every blocking operation goes into an outbound queue for you to service on behalf of the engine. How you do this is your problem—maybe you have async api to do everything, or maybe you too are just an embedded single threaded engine, so you can pass the buck. I think the second version is more complex: a threadless api for an outbound queue of blocking calls to be serviced is slightly more complicated than a thread pool that just does it. If you haven't done both, yourself, you aren't entitled to an opinion, because you don't know how complex each would be. Just saying "oh my god, threads!" isn't a valid opinion. Not unless you know how a counterpoint "oh my god, state machines!" goes too. It's just folded differently. 21sep09
«
bureaucratopia
coroutines « I'm not especially excited about coroutines per se, but it's nice to have simple dataflow support for pipe-like mechanisms without much effort. I treat coroutines as a use case, so any mechanism making continuations easy ought to make coroutines easy too. The idea is to avoid a mistake. For example, suppose you get so excited about fibers that you can't switch between continuations unless they're in two different fibers. That's a mistake: it means you constrained what's allowed for some arbitrary reason. The way I plan to do continuations and coroutines is awful with respect to keeping source code looking natural. When you find support for coroutines in C now, a typical aim is avoiding basic code restructuring to make them work. I'm not aiming for that, and I can't use a solution that involves using any tool changing the C runtime. What I wrote recently merely noted you can easily write continuations in C by hand if you don't mind forgoing many high level conveniences of a C stack. If you do stack frames by hand, a C runtime can't do them for you. Among other things, it means stack frames need a name—they can't be anonymous, as they are when a C compiler does them for you. You can either define a specialized struct for every method (what a C compiler does), or you can share one frame format among many similar methods. This is a sort of parameter block approach. non-blocking fibers « Since fibers are single threaded, you don't want a fiber to block in a way blocking all fibers in the same thread. So fiber oriented code must be non-blocking in the sense of not blocking a calling thread. So, how do you handle blocking calls like system calls? You use a thread pool, of course. (See the thread demo.) When a fiber needs to make a blocking call, it queues an async request to a pool of threads servicing requests put in that queue. So a thread in the pool (of worker threads) blocks instead of a fiber-running thread. The original calling fiber cooperatively blocks on a reply using fiber scheduler api. When a worker thread finishes a request, it needs to make a return value known to a calling fiber while making it runnable again by the fiber scheduler. (Or you could poll events in a fiber scheduler, but that might be messier.) In any case, care must be taken to avoid awkward races between a fiber thread and worker thread. For example, you wouldn't want a worker thread to finish a request before a calling fiber even finished marking itself blocked. awkward inlines « I'm doing another rev of in-stream and out-stream code to use lane-based fibers and a worker thread pool, and I'm finding it very hard to preserve inline methods for efficiency. In ordinary C++ it's easy to write a method that runs inline code N times for every virtual call required, without this affecting a caller in any way, because virtual calls are synchronous, meaning a calling thread stalls until a call returns. But that doesn't work in async code. The natural way to write a method—in api I use now—requires a return to a trampoline for any call that might need to delay while an async request goes to a thread pool for service. This quite subverts the idea of inlines for efficiency, because it adds multiple function calls per operation, which is very expensive if you just wanted to read a stream one byte at a time. The way I'm doing continuations now assumes you aren't using them in a tight loop—which is false when you parse i/o a byte at a time in a tight loop using any api that might have an async delay on any byte read. So, what to do? Hmmm. One approach is to ensure an async delay cannot occur because enough bytes are already buffered. Say you're parsing tokens. As long as an in-stream buffer has more than N bytes, where N is a maximum-sized token, you won't need to block when parsing a token. Then you could use fast inlines without needing heavyweight trampoline traffic for continuations between two bytes read efficiently. But this tactic could easily get complex. Logic behind keeping a buffer full could be hairy, especially when ensuring you did not stall waiting for more bytes when a stream is done. I thought about this a little. I'm inclined to use refcounted buffers (as usual) and have multiple inbound buffers in an in-stream, with a outstanding read requests keeping inbound buffers arriving in a pipeline under some flow control. Then when a fiber starts a non-blocking leaf method, it can check whether N bytes are buffered (or if the stream is exhausted after fewer bytes) and block when this isn't true. Otherwise, when at least N bytes are present, a fiber can impose an execution slice on itself bounded by those N bytes, yielding when exhausted. This way methods can arrange to block until at least N bytes can be done at once in a go. 19sep09
«
minimalist flirting
haircut « I got a haircut today, and the flirting was different. This is a purely personal story, so you can skip it, unless you like social nuance. My main reason to tell you about it is to emphasize how little I socialize. I usually go to the same woman who has cut my hair most often the last six years, since just before I was divorced. Note she's divorced and I've never asked her out. But there's been a certain amount of flirting, which I usually assume is mechanical on her part, except for an interesting edge of definite interest which she does not pursue. She would not mind if I tried harder. (For clarity, she needs a name below. Let's call her E.) I keep going back because I like E, and it gives me something to think about, and because she does the best job of cutting hair I know; I can just say, "Do whatever you think looks good." The result is always better than anyone else's efforts. Mainly I go back for a haircut; I don't encourage flirting. She's about my age, from South Vietnam, strikingly cute, and very intelligent socially, which makes everything she does very subtle. (But she's tiny; I have trouble with tiny.) She has young women working for her who seem either immediate or extended family. I often get a weird sense, from body language of everyone present, that I'm encouraged to flirt with them because it's expected they need a man twenty plus years their senior. Whatever. I seem a bit eccentric when I only act friendly to the matriarch. Lots of busy eye movement. I left the gym today in a muscle shirt and decided to go get a haircut because it was hot, and hair makes a terrific insulator. I was broiling, and several weeks overdue. I was under-dressed, but decided they wouldn't mind. (I have fairly good muscle definition. To the picture in the upper right, add ten pounds of fat and forty pounds of muscle added the last four years: big shoulders.) When I arrived, E had a customer, and a half dozen young women were cooling their heels waiting for work. But they know I prefer E, and didn't press me after I sat to wait. But everyone had to come by and look at me because the shirt makes me easy on the eyes, apparently. Lots of smiles; lots of conversations with someone near me, while facing me directly instead of the other girl. I got looked long and hard in the eyes, like something was on the tip of their tongues. All I had to do was say something, anything. But I didn't. Finally I got seated at E's station and E clapped her hands on my shoulders—my upper trapezius is big now—and asked me, "So... how's your love life?" Her tone of voice was slightly too hearty, like she felt she was stepping over a line. "It doesn't exist," I shook my head casually. "Why not?" she prompted while getting clippers. I sighed. "Mainly because I don't talk to people," I explained simply. "Well, why don't you talk to people?" E demanded, her tone saying she deserved more than a glib response. "Because even though I like people, and they're fun," I explained, "usually they're also a lot of trouble. Know what I mean?" "Yeah, I know what you mean," E agreed, starting with clippers. "I'm not that into trouble," I continued. "Also, I don't enjoy pursuit much. And without it, nothing happens." E asked whether I was enjoying myself, and asked about my sons—she often cuts their hair, too. (She's known my family since before my divorce, and watched me fall apart when it happened.) I told her the boys were doing fine, and that I was now finally out of debt, having just finished paying my ex back all the child support in arrears we agreed upon when the divorce settled. After digging into the financial angle a little, E said when she got divorced, she didn't ask her ex to pay anything—she just wanted it over with. Other people said she should have gotten more, but just being out of it was enough. "So," I finally reciprocated. "How's your love life?" "It sucks," E replied in a tone hinting I should dig. "Why is that?" I asked in real interest. "Every time I get involved with a man," E looked me in the eye and paused, "he cheats. You know what I mean?" She went back to cutting. "Yeah, I know what you mean," I agreed softly. "That seems to be the usual problem. That and lying. Lying is pretty common too." E didn't reply, which was probably a good idea since one might construe my remark as a vague sideways question about whether she ever lies, and it's best to completely sidestep questions like that. (My last girlfriend—gone now two years—said all women lie, all the time, about everything. Interestingly, she didn't exclude herself, like she expected it was my job to man up and start coping, because that's how the world works. I thought her perspective was interesting, because she persisted in espousing a belief many women feel they must say whatever seems to fit in any context, especially if she believes she is defending her interests. Engaging theory, no?) "How do you spend your time, then, since your love life sucks?" I asked E with more than casual interest. "I guess I spend all my time working," E claimed, her tone suggesting this was an idea she visited often in conversation. "That's all I can do, I guess, until I find the right guy." I'm summarizing here—it was more discursive, and sounded like banter inviting discussion, such as inserting myself. However, I don't like the meme of women who stop working when they have a relationship obviating a need to work. I had that problem with my last girlfriend: she kept losing her job in a way that looked voluntary. The rest of the conversation wasn't as interesting. We covered the important issues: are you thinking about what I'm thinking about? I settled the tab by paying double: a 100% tip—a bit more than usual. E hesitated and smiled while taking both my hands, watching my eyes to see if I had something to ask her. Now would be a good moment. Someday I'll probably ask a woman on a date again. But I'm not in a hurry, because I avoid trouble. Maybe in a year or two. 18sep09
«
huggable nanotubes
hitting nerves « Either my last post hit a nerve, or an unusual number of spiders decided to index here. (I don't bother figuring out which; how would it matter?) fiction train « I might resume fiction soon, because I seem on track with technical stuff in the pipe, and because lately imagined dialog is getting fun. It's that feeling you've got to write this down before it escapes, while you can keep it straight. This time I might let myself alter early drafts with later edits. The last several parts didn't need editing, because they were just what I had in mind, because they finished baking right around when I wrote them, so each had every bit of business I wanted. But this time I'm likely to forget a bit I planned some time ago, until after I finish an early draft. Since I like density, I'll add a missing piece if it improves any scene. When I re-read what I have so far, why do I like it so much? Am I just writing a story suiting my taste? I think so. In any case, I want more of it. I'd rather not do it myself, but I have trouble finding published fiction I like anymore. Today I managed to think of a line of banter prompting Flywheel to ask Wil, "Who are you?" Which I thought was funny. (Wil shrugged. "Just some guy," he guessed.) green threads « Today I tried to think of another short synonym for threads and fibers, fitting what I plan to try soon in code. I had trouble finding short words—that don't mean "string"—that I might use to convey path of execution for continuations in a flow of control. Basically I want another word for fiber that means very lightweight, userland, green thread. If possible, connoting something even lighter weight than fibers would be good. I might use lane to mean this idea. A lane is a place you can put a continuation and let it run like a fiber. As metaphor, think of either street lanes or swimming pool lanes. You can use it interchangeably with the word fiber, as long as you remember a lane need not have anything specific in common with any lore you associate with a fiber. The odd name is partly an excuse to frustrate random expectations. I might also do it the other way, and say "fiber" up until someone asks if I mean BigCorp's fibers? Then I can say, no I mean a hand-rolled fiber simulation called a lane; call this the get out of my face maneuver. The rest of this is a brief description of continuations leading up to fibers in the form of lanes. Let's back up and consider context. I read Appel's Compiling with Continuations around 1993 or 1994, and it gave me a lot of interesting ideas. I thought of some applied variations in the late 90's, and kept thinking about it until a few years ago. Now the whole hand-rolled continuation passing style (CPS) I thought about in C++ no longer gets my juices flowing. It's just one item in a bag of tricks I might use when a situation warrants, like lately. At work I need to simulate something very complicated, where the simulation will inform a large future project, and where some of the code might evolve into something that survives in shipping code after a few generations of evolution. (Or it might not; the simulation is a goal and not shippable code right now.) Basically I need to write things an amorphous distributed system might do, including things that might never happen in real platforms we use. I need to find out what can happen before we invest a lot of engineering in decisions we might later regret, if consequences are not pleasing enough. I could write a simulation in any dynamic language, and get the desired answer(s). But the code would have no hope of evolving into bits of infrastructure, unless the way it's done is acceptably equivalent to the fastest way we know how already. Also, I'm thinking this time we might want something easier to analyze. (I keep muttering backtraces under my breath when anyone listens.) Anyway, we already know something more formally like continuations would be a minor improvement in technique. So ironing out good continuation style in C++ is extra gravy that sounds good in a process of doing a simulation. So far I have a good idea how to adapt what I know about continuations to this context. I'm planning to use a fairly conventional trampolined style to avoid winding a C stack, using a heap based spaghetti stack of frames refcounted in continuations. With an effort to make meaningful backtraces, this will be a nicer tool to use than what we live with now. But it's overkill in product; the simulation might be hard to manage without them, though. The whole thing can work fine in one thread with event passing, especially if continuations work well as an event payload, so that's a design goal: a continuation frozen in an event is the only thing needed to respond when an event fires. It would be enough to use one flow of control in the trampoline, using continuations to get coroutines as needed. But as long as you're willing to use one fiber in a trampoline, you might as well consider N fibers, too. What's the cost? You just need a scheduler to service N fibers instead of one. Meanwhile, you can add mutexes and condition variables, and be able to model any complex synchronization problem that might come up. (Hey, I like monitors.) It was thinking about condition variables that got me on a path to lane fibers. It's all very well to think about passing continuations, like trading baseball cards, to manage control flow needed. Coroutines are trivial, for example. But it's hard to plan on waiting for multiple async events to finish, in order to pursue dependent actions, unless you have a little more structure. Say you want to wait on a condition variable; okay, what's the identity of the entity waiting? It can't be just a continuation—those are by-value objects copied here and there—which one do you mean? You want to say, "The continuation stored right here." Where is here? It's a lane in which you can put a continuation scheduled to run. A lane (or fiber) is a continuation and identity, plus enough bookkeeping to manage state of all operations needed (like blocking on a condition variable queue). So a lane behaves a bit like a thread, just like a fiber. It's really lightweight—it only needs state to handle each operation you can't live without. It's really just a fiber, but you can plan a game of making it radically small. If you're planning on a fixed memory format (pretty typical in servers with flow control) you likely want a maximum number of fibers that can be alive at once. Pick a number: let's say 32K fibers. Your trampoline can allocate an array of 32K lanes, each with a generation number, so each lane's ID is a pair (index, gen). Spawning a fiber is as simple as allocating a lane with a continuation to run. Then all you have to do is work out all the api, which could be horrific if you didn't exercise restraint. How much do you want a lane to act like a process or thread? If you fork a new lane from an old one, do you have parent and child relationships, and do you need to wait for a child to avoid zombies? Anyway, you have to define exactly what happens so everything you want to happen can be done. I'll describe this api later since it'll likely appear in a toy programming language with userland green threads built-in using lane style fibers. But not right now—have patience. (Do not nag me.) So for this simulation, I expect to code up lane-based fibers as infrastructure to get a simulation up and running. But this runtime is not part of the product. It's just a means to an end. Unless—if it racks up really good performance numbers, that would be a good reason to try evolving it into product later. To help jumpstart this, I'm thinking about spending some hobby coding time at home on it, to try another toy language runtime, so kinks get worked out in yet another test bed. This would help demonstrate fibers done this way actually seem to work. I'm trying to talk myself into writing a REPL for a Lisp variant using this runtime, so I get lots of practice writing hand-rolled continuation passing in C++, doing something with a known outcome I can play with in experiments. This is unlikely to be interesting, because I already know it will work, and because hand-CPS in C++ is going to be tedious. Except—get this—if I have a minimal Lisp exercising lane-based fibers, I can write a compiler to generate more CPS-based C++ for later static compilation, so I don't need to do it all by hand anymore. Then I can use this as a tool for generating C++ source used later. This is actually the plan I had for Mithril in the late 90's, but I've since lost passion in making languages just because they're cool. However, this is for a real purpose, and it would save me time at work someday, if the simulation keeps growing, and if we later want this style of CPS fibers in product infrastructure. I suspect it will be so hard to hand-write C++ in CPS style that no one will want to do it. So a compiler from Lisp syntax or some other DSL to a target source code is the only thing that make it palatable. Let's call the language Lathe, since Lisp is a family of similar languages, and not a particular one. If I pursue a path outlined above, I'll write about it here in the code section. There's not much good in spending time at home working on a language when I could spend that time with my kids instead, unless I can make it do double duty by publicizing it as I go, as a trivial kind of advertising. At work they want a simulation. But I can use the way it's done to write a compiler that unit tests the runtime, and then use the metacircularity of a compiler to emit more parts of the desired simulation, even if no one wants a compiler. Sound like a good trade to you? If you want me to write a hobby compiler, it's going to be a public compiler, not a private effort. Any time you want me to stop, just let me know. I can spend all my time writing fiction instead. 16sep09
«
hollow frontiers
naming things « When Phil Karlton said naming things was one of the two hard things in computing, he didn't mean giving things suitably clear and meaningful names. I'm certain what he actually meant was implementing identity lookup so names work and stick and do nothing strange. In other words, if you think naming things is easy, and distributed systems are hard, you missed the whole point. A distributed system has to have a naming scheme so nodes can say meaningful things to one another, under failure scenarios bounded by specific contracts afforded by the way you name things. When nodes A and B both refer to some object X ... do they refer to the same thing? For what definition of same? For what manner of change propagation? If A and B merge two versions of objects both named X, what does that mean? That's what Karlton meant when he said naming things was hard. And what was the second thing? Oh yeah, it was cache invalidation. Do you see how that's related to names? How you invalidate a thing depends entirely on what a name means, and how a cache manages names as keys, etc—so Karlton cited two facets of a single problem. Furthermore, many things act as names. For example, a pointer is a name, because a pointer lets you access an object... provided it has not been destroyed (invalidated) since you saved the pointer. In other words, garbage collection and memory management generally are actually types of naming problems. Do you get it yet? The difference between strong refs and weak refs (good for caches) is part of the naming scheme. clear names « Anyway, let's suppose you have a fetish for naming things clearly, and this means you prefer long names—the longer the better. In particular, you detest abbreviations because they (stop me if I'm getting this wrong) don't say enough and generally look unprofessional. Naming a class FancyUnicodeString is like wearing a suit, tie, and shiny shoes. Six syllables and eighteen characters are better because—am I getting this right?—code is read more often than written. So you prefer all code to be part of something read aloud, because everything is verbal to you, and otherwise you can't think. Am I warm? So, what about me? What don't I like about a long name like that? Well, it's not long enough. The name doesn't describe memory management, lifecycle, immutability, specific encoding, safe versus unsafe user input, access methods, contracts with other classes, or several other things I might feel critical in order to use a class correctly. Thus, I feel saddled with a verbose name that still doesn't tell me enough, so I have to treat it as an arbitrary key into docs or sources where I look up actual details I need to know. So a long name doesn't help much, and meanwhile it's a pain in the ass to type or say aloud. A good descriptive name would be a lot more words, and thus much too long to be practical. It would be silly to name all types with 96 or 128 character names, to include enough detail. So why not just make names short and sufficiently mnemonic? If your main string class is used everywhere, why not just name it S for string? Anyone who uses it is going to have to look up what it does anyway, whether or not you use the long or short version of a name. Names need to be distinct enough from one another, and suggest purpose with enough detail to disambiguate from a similar class. When I look at code, understanding how symbols relate to one another is what matters—a graph of code and data—and not names involved, which add no real value beyond spurring memory efficiently without being a burden. An isomorphic graph, with all names swapped for a different set of names, still does the same thing. No matter how you choose names, I treat them all as arbitrary keys that mean nothing, beyond a clue, until I look up its entire api. How something is used is what it means. Every once in a while I name a class so its name enumerates a hint of every relevant factor in its use. This is almost always too long. When I obscure some detail, by leaving some words out of a class name, while still keeping it distinct from other class names, the result is often much easier to digest. I think you should admit names are just things you memorize; they're not really descriptive, other than enough to jog your memory. Once a name is long enough to jog a memory distinct from other names, any more detail you put in a name is just a burden to memorization, and a burden to short term memory when reading code, finding your bearings while driving through a hail of words. In particular, more syllables is bad, because they penalize speed when anyone speaks them aloud, as well as impeding thought in folks who subvocalize syllables when reading. Try to think of people has having limited time capacity in syllables. If some object has a central role in your design, you should really aim for one syllable, because that word will be said constantly when developers chat. 13sep09
«
mildewed karma
intuitive vs analytical « I'm right-brained, guilty as charged. But I sure seem left-brained; otherwise, where does all that linear, analytical behavior come from? Well, it comes from talking, since intuitive imagery doesn't render well in words. Having folks prefer my analytical side has always felt like being upstaged by a chatty twin. I had a girlfriend prone to magical thinking once, who subscribed to a theory creative folks tap into a mystical broadcast station, tuning in the good stuff like a radio receiver. That's where she thought I got my ideas; it was the only way she could explain the bandwidth. If I saw a situation as a mental image, all at once, and then it took ten minutes to describe, she had to account for ten minutes of arriving data, if thought is verbal (which I claim isn't). eye focus « I don't have gaze aversion. When someone talks, I prefer to watch their eyes continuously. But I have a lot of evidence this makes a person uncomfortable when I do it longer than a normal person's attention span. So I look away and look back at a rate that seems to please other parties. In effect, I try to mimic your rate of eye contact, with a little more added. In group settings, when one person speaks or lectures, I let myself watch a speaker more continuously, up until a speaker starts to look solely at me too often. (Am I the only person in the room offering eye contact?) In high school and college, I had trouble with teachers giving a class to me personally while ignoring other students. Is it because I nod at good sense, then grimace at nonsense? But when I speak, I look around a lot, often staring into the distance when I translate inner visions into words, which aren't my main medium. In other words, I often act like someone who lies, according to popular theory. The harder something is to articulate, the harder eye contact is for me. (Job interviews are often interesting and taxing, since I try hard to get exactly a rate of eye contact others prefer; but some folks are hyper vigilant in interviews.) I'm one of five kids born inside a span of few years, so I had four siblings close to my age. Eye contact often meant more than what a sibling said. For example, it was the only accurate prediction of conflict. We all became quite skilled at reading each other's eyes; at least, I think so. When I meet folks who were an only child, or had but one sibling, something seems missing. In particular, such people often seem to rely on tone of voice a lot, while staring fixedly, as if there isn't another channel there. Doesn't that bother you, too? Obviously I like describing eye behavior in fiction. Sometimes I do this because I want a reaction shot, because movies have a convention that anything weird or funny requires someone who sees, or else it's like a tree falling in the forest. (Also, eyes are part of a theme I keep exploring in trust and privacy, while threatening red herrings right and left, if you read too much into such signals.) Eye contact doesn't bother me. I can do it forever. It's the panicky look in your eye that bothers me. Just because I watch your eyes doesn't mean I'm not also running a movie in my mind's eye. It's how I think. I'm aware women are often both surprised and pleased I don't rake any part of their bodies with my eyes, as if I believed this was not observable. Hey, my peripheral vision is pretty darned good; works for me. staring contest « In school I was challenged to a staring contest. I found I could make my eyes water slightly on demand by voluntarily inducing a partial yawn without opening my mouth. So my eyes don't dry out if I make them swim with tears. (I just tried again now, and I can still do it.) I can go several minutes without blinking this way, if I focus on stopping autonomous blink reactions. However, there's no practical application of this. Staring just threatens folks most of the time. I prefer seeming pleasant and relaxed. dry eyes « Around age 19, when juggling five balls, my eyes would dry out. As near as I could tell, it was because I could seldom afford to blink and still know what was going to happen. So I just kept my eyes open continuously until I dropped. I was also too busy to think of tactics like yawning. I no longer have that problem; I don't know when it changed. I guess, over time, the limiting factor was how my hands and arms felt, and not what I could see. After enough repetitions, you know what balls are going to do, so you only need to see enough to notice departure from the plan. dialog affect « When I write dialog, I like to set speech in proper context with emotional affect conveyed by a person speaking. So it's rare that I just say "he said." Thus I tend to write: ' "Drop it," Bob looked daggers,' instead of 'Bob said, looking daggers at Alice.' I think this improves dialog enormously; it might also seem less weird if I always say it this way. Besides, obviously Bob said it—that's what quotes mean. Also, there's something vaguely immediate when I never use omniscient voice, so you must rely on perceptions of a listener. For example, imagine Bob's frame of mind when the following happens in a story: "It wasn't me," Alice threw her voice from the teapot between them. 12sep09
«
worst cases
i/o page « I added a new io page under code so printing api won't bloat content in main. I'll append more i/o api later as it becomes relevant. painful outcomes « I wasn't prepared for a worst case outcome in my marriage years ago. While the divorce wasn't worst case, it was pretty bad, and invalidated more than a decade of past planning, and a decade of future opportunity, too. So I lost twenty years. I see this as a large fraction of my best adult years—very high cost. Am I bitter? I'm not sure that's the right word. Disillusioned comes closer; gunshy also comes to mind. Emotionally I'm quite scarred, and as a result I trust no one. From your perspective, I'm almost completely unreachable, in a sense I'll never engage, no matter what you do. But my emotional affect (which is not a pose) is basically a Zen apprehension this how the world goes, so I'm relatively calm about my lot, which strikes me as neutral on scales of fortune. However, I'm now the hardest sell you ever met. I was a hard sell before. Now I won't even stop to listen; I give a blank stare and keep going. 08sep09
«
discordian golden apples
evolution in action « No, you have a survivor bias problem there: if a jerk from the future cruises around picking up girls by saying, "Hey baby, I'm from the future," he's going to get caught by Time Police, who then debrief anyone who talked to him. However, that's exactly the kind of thing Mick might say, trusting Finch will save his ass. So maybe it's possible. refresh « Today I'm refreshing a lot of pages under code; these have been pending a while now, but I wasn't in a rush. In particular, reformating all demo pages under thorn was a little tedious, so I did it in small batches. Several code pages are still just stubs. Here's a list of ones with something interesting to see already. (But note I expect the most fun pages to be void, which is just a stub, and main, which is only just started.)
07sep09
«
slow reflexes
dropping « I drop juggling balls a lot, relative to how many hours I've practiced. I find this fairly interesting: it's a constant reminder how easy it is to screw up. This is one of the lessons I've learned juggling—that I'm going to screw up. So, um, all you can do is tolerate it. Also, when you meet folks who think they rarely screw up, they probably aren't doing something where negative feedback occurs fast enough to keep them honest. Do you aggressively avoid negative feedback? This is a big mistake if your goal is to have a realistic grasp of circumstances. Also, when you take care to seek out feedback, even when it's negative, it's easy to mistakenly assume others do too, when this is in fact very unlikely. Many folks are very attached to a positive version of story, and go to some trouble to avoid exposure to evidence it is false, because that's painful. dodging « I seldom think of my reflexes as fast, but I know they get faster when I plan ahead. If I know what I want to do in advance, and keep intention riding on a hair trigger, I can act far faster than if I had to think. Sometimes I think this is what both dreams and foresight are about: working out kinks in advance, so clever behavior happens at reflex speed. I have three related stories; the first two involve juggling. You'll notice I tend to use juggling as a standard context to falsify theories about cognition or philosopy. (You ask, philosophy? Yes, it plays havoc with determinism and other views emphasizing purpose.) Once I become familiar with a situation in juggling, I can often apply it as soon as I recognize a need. Since I learned to juggle in my teens, I've caught objects knocked off table tops a half dozen times. Unlike dodging described next, this actually involves a decision. As prerequisites, I need to see an object when it falls, and my hand needs to be able to pass through relevant space without obstruction. Finally, my hand must be able to reach a falling object before it accelerates out of range, since there's no time to move anything except my arm. I can sweep my hand through space much faster than an object can move, right after it hits free fall. I learned this skill from a thousand hours juggling hard rubber elastic balls that bounce—dog balls, typically, around 2.5 inches in diameter. When you juggle five balls, and three hit each other, the next practical game to play is recovery in minimum number of bouces, before they escape. Often I could grab the last ball after just one bounce, but this required judging whether I could sweep my hand through where it would be at the top of its arc. After a while, I knew whether a ball was catchable at a glance. I knew where the edge of the envelope was, because I tested it often, just barely grabbing a ball with nary an inch to spare. The first time I caught an object knocked off a table, I could tell it was still inside the envelope, and all I had to do was decide to get it; the rest was automatic. Okay, now let's talk about dodging. This one's more interesting. Imagine several hard rubber elastic balls sailing in the air in front of your face. Guess what happens? That's right, sometimes they hit each other, and one makes a beeline for your face. Hard rubber balls hurt quite a bit, especially if they catch you in teeth or lip, so you have a strong incentive to dodge. However, elapsed time between collision and hitting you is very small, since collisions occur maybe twelve inches from your face. I know for a fact I start dodging before I know why. It's like you have a little homunculus in your mind, riding shotgun, who screams, "Incoming!" Unfortunately, I can't seem to move my head fast enough to avoid anything aimed at a point under my nose, because this is too close to a center of rotation my neck attempts. Since a ball moves fast, only whipping your head aside is quick enough. I can still usually get my teeth out of the way first, though. After you've been hit in both teeth and lips, you find lips hurt more in the short term, but teeth hurt much longer. So it's better to get hit in the lips; would you rather break a tooth? Once I decided that, I also start clamping my mouth shut. Or you can juggle stuffed balls like hacky sacks instead; they don't bounce away, but you have to pick them up, instead of taking them on they fly. My last story is about a car accident that occurred in front of me on the highway, which I dodged. About twelve years ago, I was on the way to work, thinking about something else. But I happened to be looking directly at the accident when it happened, which was lucky, since I was only about three seconds behind vehicles involved. Other than monitoring, I wasn't attending my vision when it happened. But afterward I recalled everything starting from a half second before the collision as if I had studied it very intently the whole time. During the first second after the collision, my mind went into alarm mode, reconstructing what I just saw, going over short term memory carefully, trying to plan a course of action. Could I get out of the way? A third vehicle, very close, hit one of the first two, then spun across the highway sideways, closing off my only remaining free path—unless I could squeeze through first. But could I? Yes, but only if I used the narrow left shoulder, too, for extra space. In two seconds, I went from oblivious day dreaming to intent navigation through a closing gap. It was easy: I had a lot of room to spare—almost a lane's worth. Behind me, the highway ground to a halt. I was the last car through. And then I started getting the shakes. I wondered: should I go back? Do they need my story? But it looked like no one was hurt, since no car decelerated hard—just bounced away from one another, mostly in the same direction. Technically, I wasn't involved, and several other drivers trapped behind got a good look. However, I consider my reflexes slow in general. (Don't come up and take a swing at me: I won't see it coming... I think. And I don't want to find out.) 05sep09
«
dormant ability
assembler « Yes, I think programmers should learn machine code. Well, assembler anyway. Dumping object code for your language is an okay way to see how high level actions map to low level code. But it's even better if you experiment with changes and see what happens to the assembler. Ideally, you should try to predict what will happen. This is how you tell whether you're getting it; when outcomes always surprise you, you're not getting it well enough. I suck at Intel assembler, but I once knew Motorola 68K assembler well. In the early 90's at Apple and Taligent, our only debugger showed C++ in 68K machine code. So the only way to walk through code was to debug 68K and mentally track how it mapped to orginal C++. I seem to recall virtual dispatches typically took about six boilerplate instructions. (Note: cost of virtual dispatch is mostly irrelevant outside tight loop bottlenecks.) I once took special care to write C++ in a way that optimized well, because compilers were typically not very clever. But starting around 2003 or so, suddenly gcc began generating good code, no matter how I wrote it; so I stopped being very careful to order statements and expressions to get best results. However, I've noticed little instruction re-ordering occurs to minimize memory latency, so I still get values in advance of using them, when I have several expressions to evaluate. In my product space, L1 cache misses are a major source of speed loss, so much of my design work revolves around making useful sets of cache lines smaller when possible. I'm pretty good at this, according to our local assembler expert. Sometimes he profiles my code and says it could only be faster recoded in assembler by hand. (Actually, he's an assembler wizard because he impresses our other local experts.) On occasion I write something slightly intricate (in effect) in C++, but we want hand-rolled assembler for it, so I rewrite it in C first, so it makes sense to the wizard. Interestingly, the C++ version almost always runs faster than the C version. (This result surprised me, because I expected the C to be faster.) I believe this is because I use a lot of small inline methods, and these have an effect of advising the compiler about scope and lifetime better than the compiler can infer in the C version. Several months ago, my assembler wizard explained a detail about branches I hadn't heard before, and it explained a mystery we had at work about eighteen months ago. Here's the trick: branches are faster when the target is an aligned address. But C++ doesn't let you say whether you think a branch should be as fast as possible, and therefore aligned. Our C++ compiler doesn't waste space by forcing branch alignment. So, basically, random chance in code size determines whether branches are aligned. Slowdown for non-aligned branches varies from chip to chip and vendor to vendor (AMD and Intel differ here), but it can be quite signficant. For example, a small code change, when recompiled, can make a server change key metrics by ten percent—this is a lot—just because branch alignment changes. But this wasn't known by folks at work, who always assumed a performance change was due to a real algorithm difference. One day I checked in code; the next day our server ran 10% less effectively. I was told to back it out, so I said: it's impossible that change could cause that performance change. Finally, I thought of a test. I suggested: build the server again, exactly the same way, then see if speed changes again. This sounded eccentric to folks, but they did it anyway. And since you already know the explanation given above, you won't be surprised to hear the speed jumped back up by 10%. Experimentally, we verified rebuilding could make server results vary by 10%. But we didn't know why until we heard about aligned branches being faster. If this makes you nervous, welcome to the club. 02sep09
«
fickle crowds
decisions « Today I decided to start a code page (coming soon) presenting sample code in response to a line of inquiry, addressing one issue at a time. As detail mounts in complexity, I expect I'll have to explain my projects typically require making hundreds of consistent decisions, maybe thousands in a big code project lasting many months. You can't be shy about deciding. You just have to do it, then stick to what you chose. throwing « When I practice juggling in public (it's been a while now), one of the most common questions I hear goes like this: "What do you look at?" You can see from the photo it seems I look at the crest of arcs for the balls as they move. When this question is elaborated, I'm told they really mean, "What do you think about, in order to do that?" I never look at my hands; in fact, I can't see my hands, so I'm catching blind. My hands move fast. I explain I can only catch the balls accurately when I see exactly where a ball crests. (Sometimes I toss a ball and close my eyes when it hits a crest; I can still catch the ball from there, after a bit of practice.) My eyes track ball position, but my mind tracks several things, especially angle of ascent when I release a ball. Where a ball goes is very, very sensitive to angle on release, so I watch this angle and study how my hands feel. When juggling, you continuously do it slightly wrong, and correct as best you can. You know why you throw wrong, because of how your hand feels when catching or releasing, then seeing the result of this. Feedback is instant. You spend the whole time trying to get it into the groove: the perfect spot where it belongs. When throwing at speed, a ball must go exactly into the right spot in your hand, because there's no time to adjust. Losing a tenth of a second to shift a ball is a big problem. When I catch one, the ball doesn't just go into my hand... it lands on the base of my middle finger, with the ball's center of gravity in just the right place. (Similarly, when I catch all the balls at once, each hand has three specific places to grab a ball as it lands.) Usually I'm thinking about whether I can get a ball over to the base of the pipe it needs to ascend without imparting so much horizontal momentum it goes wide. That, and whether I can fit a ball through a gap too small this time after an earlier ball is off. I think almost entirely about throwing; catching is automatic. speculation « Now and again I'm sure I run across speculation about Finch. Often it's good stuff. I might be in a mood to tease you later by incorporating some, as hints. Please note Finch has limits and operates under constraints like other characters. For example, whatever her eyes do, it looks like she can't turn it off. Otherwise her shades would not really be necessary. That rules out some possibilities, doesn't it? And this constraint likely shapes her personality. Wil suspects a Midas touch problem in there. Try to make conjecture consistent with facts so far. I have the same problem. Sometimes I think of a neat story element, then realize it contradicts a premise under some part already established. This happens fairly often. Sooner or later I'll slip. Aleph will tell them a story about Finch posing as a blind woman. 01sep09
«
fairy tales
dictation « Yes, I use folksy phrases on occasion, and let my grammar go to hell, especially when repeating what others actually say. For example, I know perfectly well sentences should not end in prepositions, like for. But when common spoken phrases actually go that way, that's how I write them. Shrug. When I paraphrase someone, I don't reword to make them sound like Mr. Spock. Maybe you do, you insensitive clod. Now I'm going to brag about my English prowess in high school. To protect my freshman English teacher's privacy, let's pretend his name was Mr. Trout, which sounds like his actual name. (A lot like his actual name; yes, I'm being funny.) He was one of those guys who said he only made one mistake in his entire life, and it was thinking he'd made a mistake once, when he hadn't. Trout was a card—one of the funniest teachers I ever had—but was utterly dry and serious, pretending earnestly he wasn't being funny. Yes, all the kids ate this up ... when it wasn't too adversarial. Every week Trout gave us a spelling test. This was the easy part: getting 100 percent of words spelled right was easy enough. But the end of the test was a dictation test, and it was a holy terror. It typically consisted of five or six compound sentences, or groups of sentences, of twenty to forty words apiece with fancy punctuation. Trout used semi-colons, for example. Your score on this test was a count of how many mistakes you made. Zero never occurred in memory, because you had to get everything exactly right, to the letter, including punctuation and case. Generally, you got an A if you made only several mistakes. Five wrong was a good solid A, and only two wrong meant you had been inspired by gods. It happened once in a while. You know where I'm going with this, don't you? The number of mistakes I made decreased each week, and hit zero after about a month or so, after I got Trout's number. My classmates moaned the first time I only made one mistake, and moaned louder each time my score was zero thereafter. I had an almost perfect run the rest of the year. The tension every week was palpable, and if kids had been religious (which they weren't), they would have crossed themselves, since this was clearly due to a pact with the devil. No other perfect score I got ever alarmed folks as much. But to be honest, I could hear semi-colons in his tone of voice, and everything else besides. It's been a long time since I had anything to prove, so I write any way I please. And since I am the ranking officer on this ship, if you don't like it... I believe you can go to hell. Admittedly I could add a few more commas in my fiction. Oh well. I prefer using commas only when needed to disambiguate. sense of drama « Yes, most people do impose more drama on situations than might be present, objectively speaking. But it's far worse than that. However, before I explain how it's worse, let me go on a related tangent about Jack Vance, one of my favorite science fiction authors. (I go to the book store just to poll for his new books, which appear only every year or two—and now he's over 90, sigh.) Jack Vance is famous for inventing colorful cultural environments. I certainly enjoy them. But he's also quite funny on occasion, depicting characters in hilarious, crafty social machinations, which might be too subtle for some folks, but strike me as perfect. A couple of my favorites in this vein are Cugel's Saga and The Green Pearl. (Unfortunately the latter is in the middle of a series begun by Lyonesse, which is dry and slow, but not as slow as paint drying. For some reason Vance has trouble starting stories; but then he rips along in sequels.) Anyway, I once read Jack Vance's reply to a question about whether he had some formula in mind when writing. As I recall, Vance said he did, but wouldn't say what it was. Unlike a lot of authors, Vance avoids discussing technique. I had an idea what he might be doing, but I'm unsure. At first I thought he was writing fairy tales, but didn't want to call them that, since it would scare off males 18 to 35 in SciFi demographics. In any case, he's especially interested in irony with an old-fashioned flavor. One of Vance's short stories featured a very overcrowded earth. I forget the title, and lack interest in finding it. So, uh, pretend the title is Crowded Earth. Living spaces were so tiny that people had to move to allow visitors to change positions. One of the characters is fabulously rich, and can afford a room with actual free space inside, affording a luxury of walking around. This rich guy, as part of stating his social position, decides to take up a planet prospector's offer and buys half interest in a whole planet, building a house there a continent away from the prospector's house. The prospector has only one rule: don't invade his privacy. The rich guy's relatively impoverished visiting guests include some teenagers who can't think of anything to do, and lacking other ideas, decide to joyride over to the prospector's house on the other continent, and pull a serious prank: your classic pail of water perched atop a door, slightly ajar. This is pretty funny, isn't it? Somehow it's consistent with some unspoken principle latent in many of Vance's stories, where willingness to cause trouble expands to fill available space. Peace is not an option. Alright, so how does this relate to the opening paragraph? What is worse than just a tendency to over-dramatize life, just like a fairy tale? Let's assign a name to our everyman in this conversation. How about Joe? Or better yet Jack, so we can invoke Fight Club and discuss Jack's aching need to be the center of every matter. I am Jack's obsession with the spotlight. (You won't believe it's coincidence I just wrote about Jack Vance, and now I need to touch a Jack meme in Fight Club, too. Oh well. When I say Jack below, I don't mean Jack Vance, okay?) Jack has a worldview in which everything is subtly organized to revolve around Jack, so anything Jack sees will confirm his bias that, yes, Jack rules when we tally the score the way Jack keeps it. Since Jack has a central role in things—and a life with dramatic qualities to it—Jack likes stories about other folks to have dramatic flair too, because this helps affirm Jack's view that such people exist, because Jack is one. Jack prefers a story with issues like those he ranks as important, because it confirms Jack's ranking scheme. As long as a story has agendas like those in Jack's life, even if they aren't overtly about Jack, this is enough to show his worldview is valid, indirectly. Indirect is good enough, right? Ever notice a teenager's tendency to see his environment as a stage designed to remark upon the teenager, in some fashion? I am Jack's Facebook account. (As an unscrupulous entrepreneur, you have trouble resisting this bait, don't you?) Among other things, stories need to contain winners, because otherwise Jack misses affirmation he's a big winner himself, in all likelihood. Also, we need losers, peasants, and spear-carriers without portfolio, too, since otherwise Jack's exalted future might be lacking in little people to do shit work beneath his dignity. If you're half awake, you might suspect a connection between my bragging in the last section, and this section which castigates self centeredness in a casual way. Yes, you're on to something. When I tell a story about being special, in a narrow and arbitrary way, it caters to a reader's hunger to hear being-special stories are valid. |