Ok, I think I've narrowed down the problem: I put the old db.py file back (the one from the welcome app), then I commented everything. The percentage difference with everything commented out is XML 293% faster. I started uncommenting lines, one by one and running the test with each one. I enabled Mail, Crud, and PluginManager without the number dropping.
The moment I enabled Auth, the percentage dropped to 267%: auth = Auth(db) And telling Auth to define_tables dropped the difference between XML and JSON down to 120%: auth.define_tables(username=True) So something in Auth is preferring XML-RPC over JSON-RPC. Is there some code in Auth that skips over some stuff if the request type is XML or something?