My open source app, Beacon, makes extensive use of JSON. It's what the document format is built from. So the topic of JSON is of great interest to me, especially when it comes to LOTS of JSON. Beacon files can get pretty big. I have one here that is 10MB, which is a lot for a block of text. So needless to say, I'm interested in speed.

I recently ran some tests to get a sense of how to squeeze the most performance from Xojo. For my case, I can't use third party plugins because this is an open source project and I want users to be able to just grab the code and go. I parsed that 10MB file on Mac and Windows, then generated the JSON back again in both compact and "pretty" format. And I tested the classic JSONItem, the new Xojo.Data methods, and Kem Tekinay's JSONItem_MTC class using Xojo 2018r3. Both platforms are running 64-bit code with optimization level set to aggressive. Mac hardware is a 3.1GHz 2017 MacBook Pro and Windows hardware is a 3.7GHz Ryzen 2700X.

The results are... not fantastic.

Parsing

Platform JSONItem Xojo.Data.ParseJSON JSONItem_MTC
Mac 9,197ms 235ms 6,440ms
Windows 7,831ms 1,877ms 12,932ms

On both platforms, Xojo.Data.ParseJSON is the clear winner in performance alone, but of course gives you back new framework objects. In the classic framework, news isn't great either. While JSONItem_MTC is faster on Mac, it's much slower on Windows in this case. For parsing, the classic JSONItem is probably the better choice. You'll lose speed on Mac parsing, but Windows users will be a little happier. Interestingly, the Xojo.Data.ParseJSON method is much slower on Windows, but still creams the classic framework options.

Compact Generation

Platform JSONItem Xojo.Data.GenerateJSON JSONItem_MTC
Mac 32,453ms 198ms 5,216ms
Windows 25,932ms 422ms 8,069ms

There is a very clear winner here, and it's the new framework again. So why not just use the new framework? We'll get to that at the end. In the classic framework, JSONItem_MTC has a massive advantage over JSONItem. So remember when I said "classic JSONItem is probably the better choice?" To hell with that unless you're parsing only.

Pretty Generation

Platform JSONItem Xojo.Data.GenerateJSON JSONItem_MTC
Mac 34,826ms 4,542ms 4,873ms
Windows 25,989ms 8,912ms 8,339ms

The new framework has no option to pretty-print JSON, so this was done with a post-processing routine. Obviously, it is very expensive.

In the classic framework side of things, pretty-printing doesn't cost much performance with JSONItem, but since it's so slow to begin with, that's not saying much. JSONItem_MTC is the clear winner overall though. While it's slightly slower than the new framework on Mac, it's slightly faster than the new framework on Windows.

So Why Not Use the New Framework?

The big issue with the new framework options is the use of the Text type. The Text type is absurdly slow on Windows. I previously ran a test using For Each Char As Text In SomeVariable.Characters to iterate over every character in a 3MB block of text. On Mac, the test completed very quickly. Sorry, I don't recall exact numbers. On Windows, I waited 15 minutes before giving up on the test. For Beacon, I had to put out an emergency update last week because doing using Text.ReplaceAll on even a moderate chunk of text - 100KB for example - was causing hangups on Windows.

Text is just too slow to use on Windows. That makes things very awkward with the new framework JSON routines.

The good news is some exchanges work fine. For example:

Dim Dict As Xojo.Core.Dictionary = Xojo.Data.ParseJSON("{""key"": ""value""}")
Dim StringValue As String = Dict.Value("key")
Dict.Value("key") = StringValue
Dim JSON As Text = Xojo.Data.GenerateJSON(Dict)

This code works perfectly fine. Which is a bit confusing because Auto does not automatically convert between Text and String. If key in this dictionary is a Text, why I can pull it out as a String?

Conversely, this code does not work:

Dim StringValue As String = "One"
Dim AutoValue As Auto = StringValue
Dim TextValue As Text = AutoValue

It will fire a TypeMismatchException because the value in AutoValue is a String not a Text.

So using the new framework JSON routines with strings is counterintuitive. And you need your own pretty-print routine, if your app needs that. But the classic framework options are slow in comparison.

Conclusion

The JSON situation with Xojo really exemplifies Xojo's problems as a tool right now. The new framework, now deprecated, does JSON way faster but leaves you with data types that are way slower on a major platform. The situation with JSON is a mess and something needs to be done. I'd be happy if JSONItem got behind-the-scenes tuning to bring it on par with Xojo.Data. Or if we got a replacement for Xojo.Data that returned classic objects and could pretty-print.

For Beacon, I'll be using the new framework routines, converting to String when I need speed, and outputting compressed non-pretty JSON unless the user really wants a format compatible with version control. Some do.