So, I’ve implemented BlkSize and WhetherProvides as accelerated functions, with some modest improvements. Along the way, though, I’ve learned something I find pretty interesting.
The slowest command by far is “put.” Something like “put hat in chest” could take upwards of 17 seconds on the Kindle (down from almost 30 without acceleration; never say I’m not making progress
). And some investigation has revealed that it’s all in the parsing phase.
“Put” is a really complicated verb for the parser to deal with, because it can mean so many things. “Put hat in chest” parses to the Insert action; “Put hat on table” parses to Put On; “Put on hat” parses to Wear; “Put down hat” parses to Drop; etc. In addition, there are different ways to phrase each variation: “Put on hat” vs. “Put hat on”, etc. There are 19 separate syntax lines for “Put” in the game I’m working with, many of them quite complicated with prepositions and indirect objects. As it happens, “Put x in x” (leading to Insert, and one of the most common constructions of “Put”) is near the end of that group. The parser apparently loops through the syntax lines until it finds a match, and then quits. Thus the Wear variation, which comes at the beginning of the list, parses almost instantly, while Insert takes forever.
My first thought was to ask whether I could optimize the syntax lists, placing the most commonly used near the front. I went so far as to declare “the command ‘put’ as something new,” then add back in all the “Understand” lines from the library in what I judged to be a better order. This accomplishes nothing, however. The compiler apparently makes it own decisions about the proper order, placing the simplest syntax lines first and working up to the more complicated. With a command like “put,” this is a recipe for inefficiency in many cases – the complicated constructions already take much longer to parse, and then to put them at the end of the collection… A useful addition to future versions of Inform 7 might be some way to prioritize certain “Understand” lines as commonly used or having priority.
But given the situation as it is, it seems there are a few options for improving performance. One (kludgy) one is to try to help the game out by catching problematic inputs at the interpreter level and changing them to something the game can process more efficiently. Say, define “place” as a synonym for the Insert version of “put” (only), then substitute where appropriate in the interpreter. Besides being ugly, this is of course also problematic in that it requires us to do a substantial amount of parsing in the interpreter – exactly the job the parser in the game is supposed to be doing.
Another is to cut down on the number of syntax lines we define for problematic verbs like “put.” Since this also means cutting down on the number of possible inputs we understand from the player, it’s also not ideal.
The last solution is just to fix the damn parser, find some way to make it faster. But man, is it a complicated and opaque piece of code. I think a logical first step is to set up some performance logging in the parser itself, to try to figure out where it’s spending the majority of its time. Then we could perhaps target just that section(s) for optimization – maybe even an accelerated function if it seems manageable. I suspect that there’s some sort of Inform 7 hook in there that is causing a massive slowdown, as the Inform 6 parser never had these problems. I just don’t know where or what it might be.
Or maybe we learn something important from Ron’s ongoing reconstruction of the parser. That would be nice…