Eric S. Raymond's Blog, page 34

October 11, 2014

A low-performance mystery

OK, I’ll admit it. I’m stumped by a software-engineering problem.


This is not a thing that happens often, but I’m in waters relatively unknown to me. I’ve been assiduously avoiding multi-threaded programming for a long time, because solving deadlock, starvation, and insidious data-corruption-by-concurrency problems isn’t really my idea of fun. Other than one minor brush with it handling PPS signals in GPSD I’ve managed before this to avoid any thread-entanglement at all.


But I’m still trying to make cvs-fast-export run faster. About a week ago an Aussie hacker named David Leonard landed a brilliant patch series in my mailbox. Familiar story: has a huge, gnarly CVS repo that needs converting, got tired of watching it grind for days, went in to speed it up, found a way. In fact he applied a technique I’d never heard of (Bloom filtering) to flatten the worst hot spot in the code, an O(n**3) pass used to compute parent/child links in the export code. But it still needed to be faster.


After some discussion we decided to tackle parallelizing the code in the first stage of analysis. This works – separately – on each of the input CVS masters, digesting them into in-core revision lists and generating whole-file snapshots for each CVS delta; later these will become the blobs in the fast-export stream. Then there’s a second stage that merges these per-file revision lists, and a third stage that exports the merged result.


Here’s more detail, because you’ll need it to understand the rest. Each CVS master consists of a sequence of deltas (sequences of add-line and delete-line operations) summing up to a sequence of whole-file states (snapshots – eventually these will become blobs in the translated fast-import-stream). Each delta has an author, a revision date, and a revision number (like 1.3 or 1.2.1.1). Implicitly they form a tree. At the top of the file is a tag table mapping names to revision numbers, and some other relatively unimportand metadtaa.


The goal of stage 1 is to digest each CVS master into an in-core tree of metadata and a sequence of whole-file snapshots, with unique IDs in the tree indexing the snapshots. The entire collection of masters is made into a linked list of these trees; this is passed to stage 2, where black magic that nobody understands happens.


This first stage seems like a good target for parallelization because the analysis of each master consists of lumps of I/O separated by irregular stretches of compute-intensive data-shuffling in core. In theory, if the program were properly parallelized, it would seldom actually block on an I/O operation; instead while any one thread was waiting on I/O, the data shuffling for other masters would continue. The program would get faster – possibly much faster, depending on the time distribution of I/O demand.


Well, that’s the theory, anyway. Here’s what actually happened…



First, I had to make the parser for the master file format re-entrant. I did that, and then documented the method.


Then I had to examine every single other bit of global state and figure out if it needed to be encapsulated into a local-context data structure for each first-stage parse or could remain shared. Doing this made me happy; I hate globals, they make a program’s dataflow harder to grok. Re-entrant structures are prettier.


Once I thought I had the data structures properly refactored, I had to introduce actual threading. OK, time to actually learn the pthreads API. Did that. Wrote a multi-threading tasklet scheduler; I’d never done one before and took me about four tries to get it right, but I knew I was going in a good direction because the design kept getting simpler. Current version is less than 70 LOC, that’s for the dispatcher loop and the worker-subthread code both. I am proud of this code – it’s pretty, it works, and it’s tight.


While this was going on, my Aussie friend was writing a huge complex map/reduce-based scheduler to do the same job. He realized he’d succumbed to overengineering and gave it up just about the time I got mine working.


Not all was wine and roses. Of course I missed some shared state the first time through; multithreaded operation revealed this by sporadically crashing. I misunderstood the documentation for pthreads condition variables and had a few headaches in consequence until David clued me in. But these were solvable problems.


I got the code to the point where I could choose between straight sequential and N-threaded operation by flipping a command-line switch, and it was solid either way. Felt a warm glow of accomplishment. Then I profiled it – and got a deeply unpleasant shock. The threaded version was slower. Seriously slower. Like, less than half the throughput of naive one-master-at-at-time sequential parsing.


I know what the book says to suspect in this situation – mutex contention overhead. But I knew from the beginning this was unlikely. To explain why, I have to be more specific about what the contention points are.


The scheduler manages an array of worker threads. There’s one slot mutex for each worker thread slot, asserted when it’s active (that is, there’s a live thread processing a master in it). There’s one wakeup mutex associated with a condition variable that each worker thread uses to wake up the manager loop when it’s done, so another master-parsing thread can be scheduled into the vacant slot. And there’s another output mutex to make updates to the list of parsed masters atomic.


These mutexes, the ones for the scheduler itself, don’t change state very often. The history of a CVS master parse causes only these events: slot mutex up, output mutex up, output mutex down, slot mutex down, wakeup mutex up, signal, wakeup mutex down. The critical regions are small. This just isn’t enough traffic to generate noticeable overhead.


There are just two real mutexes that handle contention among the masters. One guards a counter so that the code can issue sequential blob IDs common to all threads; that one gets called every time a delta gets turned into a revision blob. The other guards a common table of named tags. Neither showed up as hotspots in profiling.


Only the counter mutex seemed even remotely likely to be getting enough hits to reduce throughput by half, so I replaced it with an atomic fetch-and-increment instruction (the comment reads /* the sexy lockless method */). That worked, but…no joy as far as increased performance went.


(Yes, I know, I could be replacing the guard mutex with an equally sexy lockless read-copy-update operation on the output linked list. Not worth it; there’s only one of these per master file, and at their fastest they’re on the order of 50 milliseconds apart).


Time to seriously profile. David had clued me in about Linux perf and I knew about gprof of old; armed with those tools, I went in and tried to figure out where the hell all those cycles were going in the threaded version. Some things stood out…


One: Mutex calls were not – repeat not – showing up in the top-ten lists.


Two: The first stage, which should have been sped up by multithreading, was running a factor of two slower than the straight sequential one-master-at-a-time version.


Three: Stage two, the merge magic, was running about the same speed as before.


Four: Here’s where it gets not just puzzling but outright weird. Stage three, the report generator, as far as it’s possible to get from any mutex and still be in the same program – running two to four times slower, consistently.


Very, very strange.


I noticed that the threaded version has a much bigger memory footprint. That’s as expected, it’s holding data for multiple masters at the same time. Could I be seeing heavy swap overhead?


Turns out not. I profiled on a much smaller repo, enough smaller for the working set to fit in physical core without swapping. Same strange statistics – Stage 1 slower, stage 3 much slower than the unthreaded code. Factors of about 2 and 4 respectively, same as for the larger repo.


(For those of you curious, the large repo is groff – 2300 deltas. The small one is robotfindskitten, 269 deltas. These are my standard benchmark repos.)


Now I’m fresh out of ideas. But I have noticed something separately interesting. According to the profiles, both of them are spending upwards of 40% of their time in one small routine, a copy operation in the delta-assembly code. Having no better plan, I decide to try to flatten this hot spot. Maybe something will shake loose?


I start putting in const and restricted declarations. Replace some array indexing with pointers. I normally don’t bother with this kind of micro-optimization; usually, when you have a speed problem you need a better algorithm rather than microtweaks. But in this case I think I already have good algorithms – I’m trying to help the compiler optimizer do a better job of reducing them to fast machine instructions, and hoping for insight into the slowdown on the way.


This works rather better than I expected. A few hours of work later Stage 1 is running at rough speed parity in threaded amd unthreaded versions. It ought to be faster, but at least the threaded version is no longer absurdly slow,


Stage 3 of threaded execution is still absurdly slow.


And that’s where things stand now. I wrote this partly to clarify my own thoughts and partly to invite comment from people with more experience optimizing threaded code than I have.


Does anything jump out of this fact pattern and say boo? If you were in my shoes, what forensics would you try?


Code is here: https://gitorious.org/cvs-fast-export/


Benchmark repos can be fetched with cvssync as follows:


cvssync cvs.sourceforge.net:/cvsroot/rfk robotfindskitten


cvssync anonymous@cvs.savannah.gnu.org:/sources/groff groff

 •  0 comments  •  flag
Share on Twitter
Published on October 11, 2014 14:01

Apologies for premature epostulation

I made a finger error. Full version of A Low Performance Mystery to follow shortly.

 •  0 comments  •  flag
Share on Twitter
Published on October 11, 2014 12:35

October 9, 2014

Implementing re-entrant parsers in Bison and Flex

In days of yore, Yacc and Lex were two of the most useful tools in a Unix hacker’s kit. The way they interfaced to client code was, however, pretty ugly – global variables and magic macros hanging out all over the place. Their modern descendants, Bison and Flex, have preserved that ugliness in order to be backward-compatible.


That rebarbative old interface generally broke a lot of rules about program structure and information hiding that we now accept as givens (to be fair, most of those had barely been invented at the time it was written in 1970 and were still pretty novel). It becomes a particular problem if you want to run multiple instances of your generated parser (or, heaven forfend, multiple parsers with different grammars) in the same binary without having them interfere with each other.


But it can be done. I’m going to describe how because (a) it’s difficult to extract from the documentation, and (b) right now (that is, using Bison 3.0.2 and Flex 2.5.35) the interface is in fact slightly broken and there’s a workaround you need to know.



First, motivation. I had to figure out how to do this for cvs-fast-export, which contains a Bison/Flex grammar that parses CVS master files – often thousands of them in a single run. In the never-ending quest for faster performance (because there are some very old, very gnarly, and very large CVS repositories out there that we would nevertheless like to be able to convert without grinding at them for days or weeks) I have recently been trying to parallelize the parsing stage. The goal is to (a) to be able to spread the job across multiple processors so the work gets done faster, and (b) not to allow I/O waits for some masters being parsed to block compute-intensive operations on others.


In order to make this happen, cvs-fast-export has to manage a bunch of worker threads with a parser instance inside each one. And in order for that to work, the yyparse() and yylex() driver functions in the generated code have to be reentrant. No globals allowed; they have to keep their parsing and lexing state in purely stack- and thread-local storage, and deliver their results back the way ordinary reentrant C functions would do it (that is, through structures referenced by pointer arguments).


Stock Yacc and Lex couldn’t do this. A very long time ago I wrote a workaround – a tool that would hack the code they generated to encapsulate it. That hack is obsolete because (a) nobody uses those heirloom versions any more, and (b) Bison/Flex have built-in support for this. If you read the docs carefully. And it’s partly broken.


Here’s how you start. In your Bison grammar, you need to include include something that begins with these options:



Þfine api.pure full
%lex-param {yyscan_t scanner}
%parse-param {yyscan_t scanner}

Here, yyscan_t is (in effect) a special private structure used to hold your scanner state. (That’s a slight fib, which I’ll rectify later; it will do for now.)


And your Flex specification must contain these options:



%option reentrant bison-bridge

These are the basics required to make your parser re-entrant. The signatures of the parser and lexer driver functions change from yyparse() and yylex() (no arguments) to these:



yyparse(yyscan_t *scanner)
yylex(YYSTYPE *yylval_param, yyscan_t yyscanner)

A yyscan_t is a private structure used to hold your scanner state; yylval is where yylex() will put its token value when it’s called by yyparse().


You may be puzzled by the fact that the %lex-param declaration says ‘scanner’ but the scanner state argument ends up being ‘yyscanner’. That’s reasonable, I’m a bit puzzled by it myself. In the generated scanner code, if there is a scanner-state argument (forced by %reentrant) it is always the first one and it is always named yyscanner regardless of what the first %lex-param declaration says – that first declaration seems to be a placeholder. In contrast, the first argument name in the %parse-params declaration actually gets used as is.


You must call yyparse() like this:



yyscan_t myscanner;

yylex_init(&myscanner);
yyparse(myscanner);
yylex_destroy(myscanner);

The yyinit() function call sets scanner to hold the address of a private malloced block holding scanner state; that’s why you have to destroy it explicitly.


The old-style global variables, like yyin, become macros that reference members of the yyscan_t structure; for a more modern look you can use accessor functions instead. For yyin that is the pair yyget_in() and yyset_in().


I hear your question coming. “But, Eric! How do I pass stuff out of the parser?” Good question. My Bison declarations actually look like this:



Þfine api.pure full
%lex-param {yyscan_t scanner} {cvs_file *cvsfile}
%parse-param {yyscan_t scanner} {cvs_file *cvsfile}

Notice there’s an additional argument. This should change the function signatures to look like this:



yyparse(yyscan_t scanner, cvs_file *cvs)
yylex(YYSTYPE *yylval_param, yyscan_t yyscanner, cvs_file *cvs)

Now you will call yyparse() like this:



yyscan_t myscanner;

yylex_init(&myscanner);
yyparse(myscanner, mycvs);
yylex_destroy(myscanner);

Le voila! The cvs argument will now be visible to the handler functions you write in your Bison grammar and your Lex specification. You can use it to pass data to the caller – typically, as in my code, the type of the second argument will be a structure of some sort. The documentation insists you can add more curly-brace-wrapped argument declarations to %lex-param and %parse-param to declare multiple extra arguments; I have not tested this.


Anyway, the ‘yyscanner’ argument will be visible to the helper code in your lex specification. The ‘scanner’ argument will be visible, under its right name, in your Bison grammar’s handler code. In both cases this is useful for calling accessors like yyget_in() and yyget_lineno() on. The cvs argument, as noted before, will be visible in both places.


There is, however, one gotcha (and yes, I have filed a bug report about it). Bison should arrange things so that all the %lex-params information is automatically passed to the generated parser and scanner code via the header file Bison generates (which is typically included in the C preambles to your Bison grammar and Lex specification). But it does not.


You have to work around this, until it’s fixed, by defining a YY_DECL macro that expands to the correct prototype and is #included by both generated source code files. When those files are expanded by the C preprocessor, the payload of YY_DECL will be put in the correct places.


Mine, which corresponds to the second set of declarations above, looks like this:



#define YY_DECL int yylex \
(YYSTYPE * yylval_param, yyscan_t yyscanner, cvs_file *cvs)

There you have it. Reentrancy, proper information hiding – it’s not yer father’s parser generator. For the fully worked example, see the following files in the cvs-fast-export sources: gram.y, lex.l, cvs.h, and import.c.


Mention should be made of Make a reentrant parser with Flex and Bison, another page on this topic. The author describes a different technique requiring an uglier macro hack. I wasn’t able to make it work, but it started me looking in approximately the right direction.

 •  0 comments  •  flag
Share on Twitter
Published on October 09, 2014 06:55

October 8, 2014

Time, Clock and Calendar Programming 1.0

A bit late, because I’ve been hammering on some code the last several days. But here it is: Time, Clock, and Calendar Programming In C.


Suggestions for 1.1 revisions and improvements will of course be cheerfully accepted. Comments here or email will be fine.

 •  0 comments  •  flag
Share on Twitter
Published on October 08, 2014 23:58

October 5, 2014

In which I have reason to sound like Master Po

This landed in my mailbox yesterday. I reproduce it verbatim except for the sender’s name.


> Dear authors of the RFC 3092,

>

> I am writing this email on behalf of your Request For Comment “Etymology of

> ‘Foo’.” We are currently learning about the internet organizations that set

> the standards of the internet and our teacher tasked us with finding an RFC

> that was humorous. Me and my two friends have found the “Etymology of

> ‘Foo'” and have found it to be almost as ridiculous as the RFC about

> infinite monkeys; however, we then became quite curious as to why you wrote

> this. Obviously, it is wrote for humor as not everything in life can be

> serious, but did your manager task you to write this? Are you a part of an

> organization in charge of writing humorous RFC’s? Are you getting paid to

> write those? If so, where do you work, and how may we apply? Any comments

> on these inquiries would be greatly appreciated and thank you in advance.

>

> Sincerely,

>

> XXXXXXXXXXXXXX, confused Networking student


I felt as though this seriously demanded a ha-ha-only-serious answer – and next thing you know I was channeling Master Po from the old Kung Fu TV series. Reply follows…





Don may have his own answer, but I have one you may find helpful.


There is a long tradition of writing parody RFCs on April 1st. No

manager tasks us to write these; they arise as a form of folk art

among Internet hackers. I think my personal favorite is still RFC1149

"A Standard for the Transmission of IP Datagrams on Avian Carriers"

from 1 April 1990, universally considered a classic of the joke-RFC

form.


As to why we write these...ah, grasshopper, that is not for us to

explain but for you to experience. If and when you achieve the

hacker-nature, you will understand.


Sadly, odds are Confused Networking Student is too young to get the “grasshopper” reference. (Unless Kung Fu is still in reruns out there, which I wouldn’t know because I basically gave up on TV decades ago.) One hopes the Zen-master schtick will be recognizable anyway.

 •  0 comments  •  flag
Share on Twitter
Published on October 05, 2014 15:42

October 3, 2014

RFC for a better C calendaring library

In the process of working on my Time, Clock, and Calendar Programming In C document, I have learned something sad but important: the standard Unix calendar API is irremediably broken.


The document list a lot of consequences of the breakage, but here I want to zero in on what I think is the primary causes. That is: the standard struct tm (a) fails to be an unambiguous representation of time, and (b) violates the SPOT (Single Point of Truth) design rule. It has some other more historically contingent problems as well, but these problems (and especially (a)) are the core of its numerous failure modes.


These problems cannot be solved in a backwards-compatible way. I think it’s time for a clean-sheet redesign. In the remainder of this post I’ll develop what I think the premises of the design ought to be, and some consequences.



The functions we are talking about here are tzset(), localtime(3), gmtime(3), mktime(3), strftime(3), and strptime() – everything (ignoring some obsolete entry points) that takes a struct tm argument and/or has timezone issues.


The central problem with this group of functions is the fact that the standard struct tm (what manual pages hilariously call “broken-down-time”) was designed to hold a local time/date without an offset from UTC time. The consequences of this omission cascade through the entire API in unfortunate ways.


Here are the standard members:



struct tm
{
int tm_sec; /* seconds [0,60] (60 for + leap second) */
int tm_min; /* minutes [0,59] */
int tm_hour; /* hour [0,23] */
int tm_mday; /* day of month [1,31] */
int tm_mon ; /* month of year [0,11] */
int tm_year; /* years since 1900 */
int tm_wday; /* day of week [0,6] (Sunday = 0) */
int tm_yday; /* day of year [0,365] */
int tm_isdst; /* daylight saving flag */
};

The presence of the day of year and day of week members violates SPOT. This leads to some strange behaviors – mktime(3) “normalizes” its input structure by fixing up these members. This can produce subtle gotchas.


Also, note that there is no way to represent dates with subsecond precision in this structure. Therefore strftime(3) cannot format them and strptime(3) cannot parse them.


The GNU C library takes a swing at the most serious problem by adding a GMT offset member, but only half-heartedly. Because it is concerned with maintaining backward compatibility, that member is underused.


Here’s what I think it ought to look like instead



struct gregorian
{
float sec; /* seconds [0,60] (60 for + leap second) */
int min; /* minutes [0,59] */
int hour; /* hour [0,23] */
int mday; /* day of month [1,31] */
int mon; /* month of year [1,12] */
int year; /* years Gregorian */
int zoffset; /* zone offset, seconds east of Greenwich */
char *zone; /* zone name or NULL */
int dst; /* daylight saving offset, seconds */
};

Some of you, I know, are looking at the float seconds member and bridling. What about roundoff errors? What about comparisons? Here’s where I introduce another basic premise of the redesign: integral floats are safe to play with..


That wasn’t true when the Unix calendar API was designed, but IEEE754 solved the problem. Most modern FPUs are well-behaved on integral quantities. There is not in fact a fuzziness risk if you stick to integral seconds values.


The other way to handle this – the classic Unix way – would have been to add a decimal subseconds member in some unit, probably nanoseconds in 2014. The problem with this is that it’s not future-proof. Who’s to say we won’t want finer resolution in a century?


Yes, this does means decimal subsecond times will have round-off issues when you do certain kinds of arithmetic on them. I think this is tolerable in calendar dates, where subsecond arithmetic is unusual thing to do to them.


The above structure fixes some quirks and inconsistencies, The silly 1900 offset for years is gone. Time divisions of a day or larger are consistently 1-origin as humans expect; this will reduce problems when writing and reading debug messages. SPOT is restored for the calendar portion of dates.


The zoffset/zone/dst group do not have the SPOT property – zone can be inconsistent with the other two members. This is, alas, unavoidable if we’re going to have a zone member at all, which is pretty much a requirement in order for the analogs of strftime(3) and strptime() to have good behavior.


Now I need to revisit another basic assumption of the Unix time API: that the basic time type is integral seconds since the epoch. In the HOWTO I pointed out that this assumption made sense in a world of 32-bit registers and expensive floating point, but no longer in a world of 64-bit machines and cheap floating point.


So here’s the other basic decision: the time scalar for this library is quad-precision seconds since the epoch in IEEE74 (that is, 112 bits of mantissa).


Now we can begin to sketch some function calls. Here are the basic two:


struct gregorian *unix_to_gregorian(double time, struct gregorian *date, char *zone)


Float seconds since epoch to broken-down time. A NULL zone argument means UTC, not local time. This is important because we want to be able to build a version of this code that doesn’t do lookups through the IANA zone database for embedded applications.


double gregorian_to_unix(struct gregorian *date)


Broken-down time to float seconds. No zone argument because it’s contained in the structure. Actually this function wouldn’t use the zone member but just the zoffset member; this is significant because we want to limit lookups to the timezone database for performance reasons.


struct gregorian *gregorian_to_local(struct gregorian *date, char *zone)


Broken-down time to broken-down time normalized for the specified zone. In this case a null zone just means normalize so there are no out-of-range structure elements (e.g. day 32 wraps to the 1st, 2nd, or 3rd of the next month) without applying any zone change. (Again, this is so the IANA timezone database is not a hard dependency).


Notice that both functions are re-entrant and can take constant arguments.


An auxiliary function we’ll need is:


char *local_timezone(void)


so we can say this:


unix_to_gregorian(time, datebuffer, local_timezone())


We only need two other functions: gregorian_strf() and gregorian_strp(), patterned after strftime() and strptime(). These present no great difficulties. Various strange bugs and glitches in the existing functions would disappear because zone offset and name are part of the structures they operate on.


Am I missing anything here? This seems like it would be a large improvement and not very difficult to write.

 •  0 comments  •  flag
Share on Twitter
Published on October 03, 2014 09:20

48-hour release heads-up for Time-Clock-Calendar HOWTO

I’ve been gifted with a lot of help on my draft of Time, Clock, and Calendar Programming In C. I think it’s almost time to ship 1.0, and plan to do so this weekend. Get your last-minute fixes in now!


I will of course continue to accept corrections and additions after 1.0. Thanks to everyone who contributed. My blog and G+ followers were very diligent in spotting typos, helping fill in and correct standards history, and pointing out the more obscure gotchas in the API.


What I’ve discovered is that the Unix calendar-related API is a pretty wretched shambles. Which leads directly to the topic of my next blog entry…

 •  0 comments  •  flag
Share on Twitter
Published on October 03, 2014 06:35

October 2, 2014

Press silence, black privilege, and unintended consequences

A provocative article at the conservative blog Hot Air comments on a pattern in American coverage of violent interracial crimes. When the perps are white and the victims are black, we can expect the press coverage to be explicit about it, with predictable assumption of racist motivations. On the other hand, when the perps are black and the victims are white, the races of all parties are normally suppressed and no one dares speak the r-word.


If I were a conservative, or a racist, I’d go off on some aggrieved semi-conspiratorial rant here. Instead I’ll observe what Hot Air did not: that the race of violent black criminals is routinely suppressed in news coverage even in the much more common case that their victims are also black. Hot Air is over-focusing here.


That said, Hot Air seems to have a a separate and valid point when it notes that white victims are most likely to have their race suppressed from the reporting when the criminals are black – especially if there was any hint of racist motivation. There is an effective taboo against truthfully reporting incidents in which black criminals yell racial epithets and threats at white victims during the commission of street crimes. If not for webbed security-camera footage we’d have no idea how depressingly common this seems to be – the press certainly won’t cop to it in their print stories.


No conspiracy theory is required to explain the silence here. Reporters and editors are nervous about being thought racist, or (worse) having “anti-racist” pressure groups demonstrating on their doorsteps. The easy route to avoiding this is a bit of suppressio veri – not lying, exactly, but not uttering facts that might be thought racially inflammatory.


The pattern of suppression is neatly explained by the following premises: Any association of black people with criminality is inflammatory. Any suggestion that black criminals are motivated by racism to prey on white victims is super-inflammatory. And above all, we must not inflame. Better to be silent.


I believe this silence is a dangerous mistake with long-term consequences that are bad for everyone, and perhaps worst of all for black people.



Journalistic silence has become a kind of black privilege. The gravamen of the Hot Air article is that gangs of black teenagers and twentysomethings can racially taunt whites and assault both whites and nonwhites confident in the knowledge that media coverage will describe them as neutrally as “youths” (ah, what an anodyne term that is!).


I’m here to say what that article could have but did not: suppressio veri, when performed systematically enough, itself becomes a code that can be read. What the press is teaching Americans to assume, story after story, is that if “youths” commit public violence and they are not specified to be white, or hispanic, or asian — then it’s yet another black street gang on a wilding.


Here is my advice to anti-racists and their media allies: it is in your interests to lift the veil of silence a little. You need to introduce some noise into the correlation – come clean about race in at least some small percentage of these incidents to create reasonable doubt about the implications of silence in others. You do not want your readers trained to assume that “youths” invariably decodes to “thug-life blacks on a casual rampage”. I don’t want this either, and I don’t think anyone should.


I am not mocking or satirizing or being sarcastic when I say this. I don’t like where I think the well-meant suppressio veri is taking us. I think it’s bound to empower people who are genuinely and viciously bigoted by giving them an exclusive on truthful reporting. I don’t think it’s good for anyone of any color for bigots to have that power.


Nor is it any good thing that “youths” now behave as though they think they’re operating with a kind of immunity. We saw this in Ferguson, when Michael Brown apparently believed he could could beat up a Pakistani shopkeeper and then assault a cop without fearing consequences. (“What are you going to do, shoot me?” he sneered, just before he was shot) As he found out, eventually that shit’ll get you killed; it would have been much better for everybody if he hadn’t been encouraged to believe that his skin color gave him a free pass.


I have no doubt that studiously blind press coverage was a significant enabler of that belief. The Michael Browns of the world may not be very bright, but they too can read the code. Every instance of suppressio veri told Brown that if he committed even a violent crime in public a lot of white people in newsrooms and elsewhere would avert their eyes. The press’s attempted canonization of Trayvon Martin only put the cherry on top of this.


It’s not clear to me that this kind of indulgence is any better – even for blacks themselves – than the old racist arrangement in which blacks “knew their place” and were systematically cowed into submission to the law. After all – if it needs pointing out again – the victims of black crime and trash culture are mainly other blacks. Press silence is empowering thugs.


Are we ever going to stop doing this? Anyone looking for a way that the system keeps black people down need look no further than the way we feed them fantasies of victimization and entitlement. For this our press bears much of the blame.

 •  0 comments  •  flag
Share on Twitter
Published on October 02, 2014 10:53

September 30, 2014

Underestimate Terry Pratchett? I never have.

Neil Gaiman writes On Terry Pratchett, he is not a jolly old elf at all.. It’s worth reading.


I know that what Neil Gaiman says here is true, because I’ve known Terry, a little. Not as well as Neil does; we’re not that close, though he has been known to answer my email. But I did have one experience back in 2003 that would have forever dispelled any notion of Terry as a mere jolly elf, assuming I’d been foolish enough to entertain it.


I taught Terry Pratchett how to shoot a pistol.


(We were being co-guests of honor at Penguicon I at the time. This was at the first Penguicon Geeks with Guns event, at a shooting range west of Detroit. It was something Terry had wanted to do for a long time, but opportunities in Britain are quite limited.)


This is actually a very revealing thing to do with anyone. You learn a great deal about how the person handles stress and adrenalin. You learn a lot about their ability to concentrate. If the student has fears about violence, or self-doubt, or masculinity/femininity issues, that stuff is going to tend to come out in the student’s reactions in ways that are not difficult to read.


Terry was rock-steady. He was a good shot from the first three minutes. He listened, he followed directions intelligently, he always played safe, and he developed impressive competence at anything he was shown very quickly. To this day he’s one of the three or four best shooting students I’ve ever had.


That is not the profile of anyone you can safely trivialize as a jolly old elf. I wasn’t inclined to do that anyway; I’d known him on and off since 1991, which was long enough that I believe I got a bit of look-in before he fully developed his Famous Author charm defense.


But it was teaching Terry pistol that brought home to me how natively tough-minded he really is. After that, the realism and courage with which he faced his Alzheimer’s diagnosis came as no surprise to me whatsoever.

 •  0 comments  •  flag
Share on Twitter
Published on September 30, 2014 05:50

September 29, 2014

Announcing: Time, Clock, and Calendar Programming In C

The C/UNIX library support for time and calendar programming is a nasty mess of historical contingency. I have grown tired of having to re-learn its quirks every time I’ve had to deal with it, so I’m doing something about that.


Announcing Time, Clock, and Calendar Programming In C, a document which attempts to chart the historical clutter (so you can ignore it once you know why it’s there) and explain the mysteries.


What I’ve released is an 0.9 beta version. My hope is that it will rapidly attract some thoroughgoing reviews so I can release a 1.0 in a week or so. More than that, I would welcome a subject matter expert as a collaborator.

 •  0 comments  •  flag
Share on Twitter
Published on September 29, 2014 20:22

Eric S. Raymond's Blog

Eric S. Raymond
Eric S. Raymond isn't a Goodreads Author (yet), but they do have a blog, so here are some recent posts imported from their feed.
Follow Eric S. Raymond's blog with rss.