Thank you dear multiplatform developers, best comm...
# multiplatform
p
Thank you dear multiplatform developers, best commit of the year ❤️
🔥 8
👍 4
🌡️ 7
K 3
🎉 14
m
How's the performance going so far? Did you have a chance to benchmark it against the old memory model?
p
From the subjective feeling not worse. From the bit of benchmarking we did at the most performance critical path (querying thousands of recipes in the database, filtering, sorting in code) the performance went up by 2.5x
m
So "up" is "better", right?
p
Yes
m
Wow, that's cool!
I thought the new GC was somewhat slower
p
It is in some cases in others it’s not
👍 2
m
Nice
p
Current benchmark does not back this assumption ~Another interesting insight we had is that having expect actual classes is bad for performance in some cases. Our recipes had a
UUID
which was a
NSUUID
. By moving that to a regular data class the performance went up by 2x. I assume it’s something to do with overhead on calling into platform classes~
👀 3
That UUID was used transitively by equals / hashCode when using things like
find
and
distinct
m
Were you using https://github.com/benasher44/uuid by any chance?
p
Nope just a regular expect-actual
Our uuid is pretty straight forward:
Copy code
package com.yazio.shared.uuid

import platform.Foundation.NSUUID

public actual data class UUID(val uuid: String) {

  override fun toString(): String = uuid
}

public actual fun uuid(value: String): UUID {
  return requireNotNull(value.asUUIDorNull()) {
    "Could not parse $value"
  }
}

public actual val UUID.value: String get() = uuid

public actual fun randomUUID(): UUID {
  return NSUUID().toUUID()
}

public actual fun String.asUUIDorNull(): UUID? {
  return try {
    NSUUID(this)
  } catch (e: NullPointerException) {
    // Kotlin does not support optional initializers.
    null
  }?.toUUID()
}

private fun NSUUID.toUUID(): UUID {
  return UUID(UUIDString.lowercase())
}
👍 1
Ah yes and that optional initializer thing was also interesting, see the catch NPE 😜
👀 1
m
Thanks for sharing this, this is super exciting 🙂
(not the NPE part though :P)
😅 1
k
The expect/actual thing is interesting, but I'd want to isolate that before generalizing on just that. I'd always assumed that was a compile time thing, which in theory wouldn't impact performance on its own. My assumption, of course, could be wrong. Never tried comparing that with anything
p
No, I don’t think that it affects performance at all. I think what’s affecting performance is calling into platform functions. ~ edit: BENCHMARK IS WRONG Lets take this “benchmark”: https://gist.github.com/PaulWoitaschek/a46415746f9154885cff13a11196c507 It prints on kotlin 1.6.21
Copy code
kotlin took 1.959us
ns took 4.122052778s
~
i
@Paul Woitaschek it looks like you're accumulating nsTime and reassigning kotlinTime in each iteration. No wonder the results differ that much after a million iterations.
1
d
Whoops, missing a
+
☝️ 🤦 Would be interested to see the result again using Kotlin 1.7.0 Beta, which 'headlines' with Native Memory Manager performance improvements 💪
👍 1
x
i must be one of the luck few who never had to manually freeze anything - and hopefully will never have to in the future. 🤞
p
Ah yes I am! Turns out with correct code the data class path is actually 2x slower. Now I’m asking myself why that switch improved the performance so much. I don’t know if it’s something that’s changed in 1.6 or if my original observation was simply wrong 🤔
d
...any chance to try in 1.7.0 Beta, @Paul Woitaschek? Contains unspecified 'performance improvements' to K/N MM.
r
The data class path is creating twice as many objects, because it has to build an
NSUUID
to get a
UUIDString
to pass to the
UUID
constructor. I wonder if that accounts for the 2x difference.