Can somebody tell me how to cast a CPointer<Byt...
# kotlin-native
t
Can somebody tell me how to cast a CPointer<ByteVar> to a ByteArray? I have a c function that allocates a buffer and returns a pointer to it in the form of CPointer<ByteVar>. I'm not sure how I'm supposed to cast that to something I can copy the bytes into.
a
Does the C function also give you an indication of the length?
t
I'm working with libogg. The length is passed into the function.
val buffer = _ogg_sync_buffer_(syncState, bufferSize)
I tried the supposed
memcpy
and got interessting numbers, huge difference between debug and release:
Copy code
> ./debugExecutable/memcpy-test.kexe
# STDLIB
Stressing with 1000 MiB of memory...
Allocated 1000 MiB in 3.447955416s
AddressOf took 2.375us
Read bytes took 33.738578875s
Array size: 1048576000
First 10 elements: [0 1 2 3 4 5 6 7 8 9]
# MEMCPY
Stressing with 1000 MiB of memory...
Allocated 1000 MiB in 3.466606875s
AddressOf took 2.75us
Read bytes took 779.767958ms
Array size: 1048576000
First 10 elements: [0 1 2 3 4 5 6 7 8 9]

> ./releaseExecutable/memcpy-test.kexe
# STDLIB
Stressing with 1000 MiB of memory...
Allocated 1000 MiB in 580.001167ms
AddressOf took 625ns
Read bytes took 755.114958ms
Array size: 1048576000
First 10 elements: [0 1 2 3 4 5 6 7 8 9]
# MEMCPY
Stressing with 1000 MiB of memory...
Allocated 1000 MiB in 573.892666ms
AddressOf took 750ns
Read bytes took 148.824833ms
Array size: 1048576000
First 10 elements: [0 1 2 3 4 5 6 7 8 9]
Copy code
import kotlinx.cinterop.ExperimentalForeignApi
import kotlinx.cinterop.addressOf
import kotlinx.cinterop.pin
import kotlinx.cinterop.readBytes
import platform.posix.memcpy
import kotlin.time.measureTimedValue

fun main() {
    println("# STDLIB")
    stressStdlib(1000).printFirstBytes(10)

    println("# MEMCPY")
    stressMemcpy(1000).printFirstBytes(10)
}

fun ByteArray.printFirstBytes(count: Int = 10) {
    println("Array size: $size")
    println("First 10 elements: ${take(count).joinToString(separator = " ", prefix = "[", postfix = "]")}")
}


@OptIn(ExperimentalForeignApi::class)
fun stressStdlib(sizeInMegabytes: Int = 100): ByteArray {
    println("Stressing with $sizeInMegabytes MiB of memory...")
    val sizeInBytes = sizeInMegabytes * 1024 * 1024

    val (byteArray, timeByteArray) = measureTimedValue {
        ByteArray(sizeInBytes) { it.toByte() }
    }
    println("Allocated $sizeInMegabytes MiB in $timeByteArray")

    val (addressOf, timeAddressOf) = measureTimedValue { byteArray.pin().addressOf(0) }
    println("AddressOf took $timeAddressOf")

    val (array, timeReadBytes) = measureTimedValue {
        addressOf.readBytes(sizeInBytes)
    }

    println("Read bytes took $timeReadBytes")
    return array
}

@OptIn(ExperimentalForeignApi::class)
fun stressMemcpy(sizeInMegabytes: Int = 100): ByteArray {
    println("Stressing with $sizeInMegabytes MiB of memory...")
    val sizeInBytes = sizeInMegabytes * 1024 * 1024

    val (byteArray, timeByteArray) = measureTimedValue {
        ByteArray(sizeInBytes) { it.toByte() }
    }
    println("Allocated $sizeInMegabytes MiB in $timeByteArray")

    val (addressOf, timeAddressOf) = measureTimedValue { byteArray.pin().addressOf(0) }
    println("AddressOf took $timeAddressOf")

    val (array, timeReadBytes) = measureTimedValue {
        val result = ByteArray(sizeInBytes)
        memcpy(result.pin().addressOf(0), addressOf, sizeInBytes.toULong())
        result
    }

    println("Read bytes took $timeReadBytes")
    return array
}
👍 1
c
Maybe that's because the functions in the standard library copy the elements one by one, and vectorization optimization didn't work.