touchlab/SQLiter

Optimize C string to Kotlin String conversion

andersio opened this issue · 3 comments

I did some synthetic benchmarking in this area recently, and discovered that toKStringFromUtf8() is quite underwhelming, especially in debug builds. Imagine in debug builds, 100 rows of 2KB worth of strings take a whopping 18ms — more than a frame at 60fps.

The results were filed in this issue: https://youtrack.jetbrains.com/issue/KT-44357.

Since toKStringFromUtf8() is a hot path for getting strings out of SQLite, it might be valuable for SQLiter to drop toKStringFromUtf8() for the alternatives listed, until improvements were made to the stdlib. Most importantly, these alternatives have a way less drastic debug-release performance gap, so developer experience is improved too.

TL;DR of the options:

  • Given the known size via sqlite3_column_bytes(), memcpy() the C string to a ByteArray, and then use ByteArray.decodeToString().

  • Convert the C string first to NSString, and then to KString via toString() or as String.

    This is the fastest option, though it is exclusive to Darwin targets.

Take a look. I didn't run your benchmarks, but I'm not super surprised with the outcome. I think we're likely to find this kind of thing in places.

The pre-cinterop version of this library probably had better performance as it was pretty much calling c++ to directly create a utf16 from utf8, and returning that as a Kotlin string. Anyway...

columnGetString and columnName both call into bytesToString, which is an expect/actual.

expect inline fun bytesToString(bv:CPointer<ByteVar>):String

Currently the only actual targets are apple-related and windows. For apple targets, this is the implementation:

actual inline fun bytesToString(bv:CPointer<ByteVar>):String = NSString.create(bv).toString()

I didn't try so hard on windows, however.

actual inline fun bytesToString(bv:CPointer<ByteVar>):String = bv.toKStringFromUtf8()

We can try the other option you presented if somebody wants to give that a run on windows. I'm also going to take a look at toKStringFromUtf8 itself as I've spent some time in the native compiler in the past.

Pushing a PR. Take a look if you get a chance.

BTW, looked at the code for toKStringFromUtf8 and the comment right on top of it is pretty great.

// TODO: optimize

Added back in Jan. Just entering use now with Sqldelight 1.5+.