Draft of JEP-370 kmath-memory implementation #121
17
.github/workflows/build.yml
vendored
17
.github/workflows/build.yml
vendored
@ -13,16 +13,13 @@ jobs:
|
|||||||
runs-on: ${{matrix.os}}
|
runs-on: ${{matrix.os}}
|
||||||
timeout-minutes: 40
|
timeout-minutes: 40
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout the repo
|
- uses: actions/checkout@v2
|
||||||
uses: actions/checkout@v2
|
- uses: DeLaGuardo/setup-graalvm@4.0
|
||||||
- name: Set up JDK 11
|
|
||||||
uses: DeLaGuardo/setup-graalvm@4.0
|
|
||||||
with:
|
with:
|
||||||
graalvm: 21.2.0
|
graalvm: 21.2.0
|
||||||
java: java11
|
java: java16
|
||||||
arch: amd64
|
arch: amd64
|
||||||
- name: Cache gradle
|
- uses: actions/cache@v2
|
||||||
uses: actions/cache@v2
|
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
~/.gradle/caches
|
~/.gradle/caches
|
||||||
@ -30,12 +27,10 @@ jobs:
|
|||||||
key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }}
|
key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }}
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
${{ runner.os }}-gradle-
|
${{ runner.os }}-gradle-
|
||||||
- name: Cache konan
|
- uses: actions/cache@v2
|
||||||
uses: actions/cache@v2
|
|
||||||
with:
|
with:
|
||||||
path: ~/.konan
|
path: ~/.konan
|
||||||
key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }}
|
key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }}
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
${{ runner.os }}-gradle-
|
${{ runner.os }}-gradle-
|
||||||
- name: Build
|
- run: ./gradlew build --build-cache --no-daemon --stacktrace
|
||||||
run: ./gradlew build --build-cache --no-daemon --stacktrace
|
|
||||||
|
12
.github/workflows/pages.yml
vendored
12
.github/workflows/pages.yml
vendored
@ -13,11 +13,19 @@ jobs:
|
|||||||
- uses: DeLaGuardo/setup-graalvm@4.0
|
- uses: DeLaGuardo/setup-graalvm@4.0
|
||||||
with:
|
with:
|
||||||
graalvm: 21.2.0
|
graalvm: 21.2.0
|
||||||
java: java11
|
java: java16
|
||||||
arch: amd64
|
arch: amd64
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v2
|
||||||
with:
|
with:
|
||||||
path: ~/.gradle/caches
|
path: |
|
||||||
|
~/.gradle/caches
|
||||||
|
~/.gradle/wrapper
|
||||||
|
key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-gradle-
|
||||||
|
- uses: actions/cache@v2
|
||||||
|
with:
|
||||||
|
path: ~/.konan
|
||||||
key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }}
|
key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }}
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
${{ runner.os }}-gradle-
|
${{ runner.os }}-gradle-
|
||||||
|
20
.github/workflows/publish.yml
vendored
20
.github/workflows/publish.yml
vendored
@ -14,16 +14,13 @@ jobs:
|
|||||||
os: [ macOS-latest, windows-latest ]
|
os: [ macOS-latest, windows-latest ]
|
||||||
runs-on: ${{matrix.os}}
|
runs-on: ${{matrix.os}}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout the repo
|
- uses: actions/checkout@v2
|
||||||
uses: actions/checkout@v2
|
- uses: DeLaGuardo/setup-graalvm@4.0
|
||||||
- name: Set up JDK 11
|
|
||||||
uses: DeLaGuardo/setup-graalvm@4.0
|
|
||||||
with:
|
with:
|
||||||
graalvm: 21.2.0
|
graalvm: 21.2.0
|
||||||
java: java11
|
java: java16
|
||||||
arch: amd64
|
arch: amd64
|
||||||
- name: Cache gradle
|
- uses: actions/cache@v2
|
||||||
uses: actions/cache@v2
|
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
~/.gradle/caches
|
~/.gradle/caches
|
||||||
@ -31,22 +28,19 @@ jobs:
|
|||||||
key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }}
|
key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }}
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
${{ runner.os }}-gradle-
|
${{ runner.os }}-gradle-
|
||||||
- name: Cache konan
|
- uses: actions/cache@v2
|
||||||
uses: actions/cache@v2
|
|
||||||
with:
|
with:
|
||||||
path: ~/.konan
|
path: ~/.konan
|
||||||
key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }}
|
key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }}
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
${{ runner.os }}-gradle-
|
${{ runner.os }}-gradle-
|
||||||
- name: Publish Windows Artifacts
|
- if: matrix.os == 'windows-latest'
|
||||||
if: matrix.os == 'windows-latest'
|
|
||||||
shell: cmd
|
shell: cmd
|
||||||
run: >
|
run: >
|
||||||
./gradlew release --no-daemon --build-cache -Ppublishing.enabled=true
|
./gradlew release --no-daemon --build-cache -Ppublishing.enabled=true
|
||||||
-Ppublishing.space.user=${{ secrets.SPACE_APP_ID }}
|
-Ppublishing.space.user=${{ secrets.SPACE_APP_ID }}
|
||||||
-Ppublishing.space.token=${{ secrets.SPACE_APP_SECRET }}
|
-Ppublishing.space.token=${{ secrets.SPACE_APP_SECRET }}
|
||||||
- name: Publish Mac Artifacts
|
- if: matrix.os == 'macOS-latest'
|
||||||
if: matrix.os == 'macOS-latest'
|
|
||||||
run: >
|
run: >
|
||||||
./gradlew release --no-daemon --build-cache -Ppublishing.enabled=true -Ppublishing.platform=macosX64
|
./gradlew release --no-daemon --build-cache -Ppublishing.enabled=true -Ppublishing.platform=macosX64
|
||||||
-Ppublishing.space.user=${{ secrets.SPACE_APP_ID }}
|
-Ppublishing.space.user=${{ secrets.SPACE_APP_ID }}
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
kotlin.code.style=official
|
kotlin.code.style=official
|
||||||
|
kotlin.jupyter.add.scanner=false
|
||||||
kotlin.mpp.enableGranularSourceSetsMetadata=true
|
kotlin.mpp.enableGranularSourceSetsMetadata=true
|
||||||
kotlin.mpp.stability.nowarn=true
|
kotlin.mpp.stability.nowarn=true
|
||||||
kotlin.native.enableDependencyPropagation=false
|
kotlin.native.enableDependencyPropagation=false
|
||||||
|
@ -11,7 +11,6 @@ import kotlinx.html.stream.createHTML
|
|||||||
import kotlinx.html.unsafe
|
import kotlinx.html.unsafe
|
||||||
import org.jetbrains.kotlinx.jupyter.api.DisplayResult
|
import org.jetbrains.kotlinx.jupyter.api.DisplayResult
|
||||||
import org.jetbrains.kotlinx.jupyter.api.HTML
|
import org.jetbrains.kotlinx.jupyter.api.HTML
|
||||||
import org.jetbrains.kotlinx.jupyter.api.annotations.JupyterLibrary
|
|
||||||
import org.jetbrains.kotlinx.jupyter.api.libraries.JupyterIntegration
|
import org.jetbrains.kotlinx.jupyter.api.libraries.JupyterIntegration
|
||||||
import space.kscience.kmath.ast.rendering.FeaturedMathRendererWithPostProcess
|
import space.kscience.kmath.ast.rendering.FeaturedMathRendererWithPostProcess
|
||||||
import space.kscience.kmath.ast.rendering.MathMLSyntaxRenderer
|
import space.kscience.kmath.ast.rendering.MathMLSyntaxRenderer
|
||||||
|
@ -70,3 +70,8 @@ public abstract interface class space/kscience/kmath/memory/MemoryWriter {
|
|||||||
public abstract fun writeShort (IS)V
|
public abstract fun writeShort (IS)V
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final class space/kscience/kmath/memory/foreign/ForeignMemoryKt {
|
||||||
|
public static final fun allocateAsForeign (Lspace/kscience/kmath/memory/Memory$Companion;I)Lspace/kscience/kmath/memory/Memory;
|
||||||
|
public static final fun wrapAsForeign (Lspace/kscience/kmath/memory/Memory$Companion;[B)Lspace/kscience/kmath/memory/Memory;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -10,3 +10,7 @@ readme {
|
|||||||
An API and basic implementation for arranging objects in a continuous memory block.
|
An API and basic implementation for arranging objects in a continuous memory block.
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tasks.jvmTest {
|
||||||
|
jvmArgs("--add-modules", "jdk.incubator.foreign")
|
||||||
|
}
|
||||||
|
@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018-2021 KMath contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package space.kscience.kmath.memory.foreign
|
||||||
|
|
||||||
|
import jdk.incubator.foreign.MemorySegment
|
||||||
|
import space.kscience.kmath.memory.Memory
|
||||||
|
import space.kscience.kmath.memory.MemoryReader
|
||||||
|
import space.kscience.kmath.memory.MemoryWriter
|
||||||
|
import java.lang.ref.Cleaner
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocates memory using JDK Foreign Memory API. It should be even faster than default ByteBuffer memory provided by
|
||||||
|
* [space.kscience.kmath.memory.allocate].
|
||||||
|
*/
|
||||||
|
public fun Memory.Companion.allocateAsForeign(length: Int): Memory =
|
||||||
|
ForeignMemory(MemorySegment.allocateNative(length.toLong()))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wraps a [Memory] around existing [ByteArray]. This operation is unsafe since the array is not copied
|
||||||
|
* and could be mutated independently from the resulting [Memory].
|
||||||
|
*
|
||||||
|
* The memory is wrapped to JDK Foreign Memory segment.
|
||||||
|
*/
|
||||||
|
public fun Memory.Companion.wrapAsForeign(array: ByteArray): Memory = ForeignMemory(MemorySegment.ofArray(array))
|
||||||
|
|
||||||
|
private val cleaner: Cleaner by lazy { Cleaner.create() }
|
||||||
|
|
||||||
|
private fun cleaningRunnable(scope: MemorySegment): Runnable = Runnable { scope.close() }
|
||||||
|
|
||||||
|
internal class ForeignMemory(val scope: MemorySegment) : Memory, AutoCloseable {
|
||||||
|
private val cleanable: Cleaner.Cleanable = cleaner.register(this, cleaningRunnable(scope))
|
||||||
|
|
||||||
|
override val size: Int
|
||||||
|
get() = Math.toIntExact(scope.byteSize())
|
||||||
|
|
||||||
|
private val writer: MemoryWriter = ForeignWriter(this)
|
||||||
|
private val reader: MemoryReader = ForeignReader(this)
|
||||||
|
|
||||||
|
override fun view(offset: Int, length: Int): ForeignMemory =
|
||||||
|
ForeignMemory(scope.asSlice(offset.toLong(), length.toLong()))
|
||||||
|
|
||||||
|
override fun copy(): Memory {
|
||||||
|
val newScope = MemorySegment.allocateNative(scope.byteSize())
|
||||||
|
newScope.copyFrom(scope)
|
||||||
|
return ForeignMemory(newScope)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun reader(): MemoryReader = reader
|
||||||
|
override fun writer(): MemoryWriter = writer
|
||||||
|
override fun close(): Unit = cleanable.clean()
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018-2021 KMath contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package space.kscience.kmath.memory.foreign
|
||||||
|
|
||||||
|
import jdk.incubator.foreign.MemoryAccess
|
||||||
|
import jdk.incubator.foreign.MemorySegment
|
||||||
|
import space.kscience.kmath.memory.MemoryReader
|
||||||
|
|
||||||
|
internal class ForeignReader(override val memory: ForeignMemory) : MemoryReader {
|
||||||
|
private val scope: MemorySegment
|
||||||
|
get() = memory.scope
|
||||||
|
|
||||||
|
override fun readDouble(offset: Int): Double = MemoryAccess.getDoubleAtOffset(scope, offset.toLong())
|
||||||
|
override fun readFloat(offset: Int): Float = MemoryAccess.getFloatAtOffset(scope, offset.toLong())
|
||||||
|
override fun readByte(offset: Int): Byte = MemoryAccess.getByteAtOffset(scope, offset.toLong())
|
||||||
|
override fun readShort(offset: Int): Short = MemoryAccess.getShortAtOffset(scope, offset.toLong())
|
||||||
|
override fun readInt(offset: Int): Int = MemoryAccess.getIntAtOffset(scope, offset.toLong())
|
||||||
|
override fun readLong(offset: Int): Long = MemoryAccess.getLongAtOffset(scope, offset.toLong())
|
||||||
|
override fun release(): Unit = Unit
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018-2021 KMath contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package space.kscience.kmath.memory.foreign
|
||||||
|
|
||||||
|
import jdk.incubator.foreign.MemoryAccess
|
||||||
|
import jdk.incubator.foreign.MemorySegment
|
||||||
|
import space.kscience.kmath.memory.MemoryWriter
|
||||||
|
|
||||||
|
internal class ForeignWriter(override val memory: ForeignMemory) : MemoryWriter {
|
||||||
|
private val scope: MemorySegment
|
||||||
|
get() = memory.scope
|
||||||
|
|
||||||
|
override fun writeDouble(offset: Int, value: Double): Unit =
|
||||||
|
MemoryAccess.setDoubleAtOffset(scope, offset.toLong(), value)
|
||||||
|
|
||||||
|
override fun writeFloat(offset: Int, value: Float): Unit =
|
||||||
|
MemoryAccess.setFloatAtOffset(scope, offset.toLong(), value)
|
||||||
|
|
||||||
|
override fun writeByte(offset: Int, value: Byte): Unit = MemoryAccess.setByteAtOffset(scope, offset.toLong(), value)
|
||||||
|
|
||||||
|
override fun writeShort(offset: Int, value: Short): Unit =
|
||||||
|
MemoryAccess.setShortAtOffset(scope, offset.toLong(), value)
|
||||||
|
|
||||||
|
override fun writeInt(offset: Int, value: Int): Unit = MemoryAccess.setIntAtOffset(scope, offset.toLong(), value)
|
||||||
|
override fun writeLong(offset: Int, value: Long): Unit = MemoryAccess.setLongAtOffset(scope, offset.toLong(), value)
|
||||||
|
override fun release(): Unit = Unit
|
||||||
|
}
|
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018-2021 KMath contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package space.kscience.kmath.memory
|
||||||
|
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
internal class ByteBufferMemoryTest {
|
||||||
|
private fun getMemory(int: Int) = Memory.allocate(int)
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun size() {
|
||||||
|
val mem = getMemory(66666)
|
||||||
|
assertEquals(66666, mem.size)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun view() {
|
||||||
|
val mem = getMemory(4242)
|
||||||
|
val sub = mem.view(10, 10)
|
||||||
|
sub.write { writeInt(0, 1000000) }
|
||||||
|
assertEquals(10, sub.size)
|
||||||
|
assertEquals(1000000, mem.read { readInt(10) })
|
||||||
|
assertEquals(1000000, sub.read { readInt(0) })
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun copy() {
|
||||||
|
val mem = getMemory(8)
|
||||||
|
mem.write { writeDouble(0, 12.0) }
|
||||||
|
val copy = mem.copy()
|
||||||
|
assertEquals(12.0, copy.read { readDouble(0) })
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun reader() {
|
||||||
|
val mem = getMemory(8)
|
||||||
|
val rd = mem.reader()
|
||||||
|
assertEquals(0, rd.readLong(0))
|
||||||
|
rd.release()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun writer() {
|
||||||
|
val mem = getMemory(4)
|
||||||
|
val wr = mem.writer()
|
||||||
|
wr.writeFloat(0, 6f)
|
||||||
|
val rd = mem.reader()
|
||||||
|
assertEquals(6f, rd.readFloat(0))
|
||||||
|
rd.release()
|
||||||
|
wr.release()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018-2021 KMath contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package space.kscience.kmath.memory
|
||||||
|
|
||||||
|
import space.kscience.kmath.memory.foreign.allocateAsForeign
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
internal class ForeignMemoryTest {
|
||||||
|
private fun getMemory(int: Int) = Memory.allocateAsForeign(int)
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun size() {
|
||||||
|
val mem = getMemory(66666)
|
||||||
|
assertEquals(66666, mem.size)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun view() {
|
||||||
|
val mem = getMemory(4242)
|
||||||
|
val sub = mem.view(10, 10)
|
||||||
|
sub.write { writeInt(0, 1000000) }
|
||||||
|
assertEquals(10, sub.size)
|
||||||
|
assertEquals(1000000, mem.read { readInt(10) })
|
||||||
|
assertEquals(1000000, sub.read { readInt(0) })
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun copy() {
|
||||||
|
val mem = getMemory(8)
|
||||||
|
mem.write { writeDouble(0, 12.0) }
|
||||||
|
val copy = mem.copy()
|
||||||
|
assertEquals(12.0, copy.read { readDouble(0) })
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun reader() {
|
||||||
|
val mem = getMemory(8)
|
||||||
|
val rd = mem.reader()
|
||||||
|
assertEquals(0, rd.readLong(0))
|
||||||
|
rd.release()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun writer() {
|
||||||
|
val mem = getMemory(4)
|
||||||
|
val wr = mem.writer()
|
||||||
|
wr.writeFloat(0, 6f)
|
||||||
|
val rd = mem.reader()
|
||||||
|
assertEquals(6f, rd.readFloat(0))
|
||||||
|
rd.release()
|
||||||
|
wr.release()
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user