Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Minor cleanup and simplification of readString #376

Merged
merged 2 commits into from
Aug 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion benchmarks/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,13 @@ Currently, the suite includes benchmarks on:
- segment pooling performance.

The suite doesn't include benchmarks for more complex APIs inherited from Okio as these APIs are subject to change.
Such benchmarks will be added later along with corresponding changes in the library.
Such benchmarks will be added later along with corresponding changes in the library.

### Quickstart

For JVM:
```
./gradlew :kotlinx-io-benchmarks:jvmJar
java -jar benchmarks/build/benchmarks/jvm/jars/kotlinx-io-benchmarks-jvm-jmh-0.6.0-SNAPSHOT-JMH.jar ReadStringBenchmark -f 1 -wi 5 -i 5 -tu us -w 1 -r 1
```
42 changes: 42 additions & 0 deletions benchmarks/src/commonMain/kotlin/ReadStringBenchmark.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package kotlinx.io.benchmarks

import kotlinx.benchmark.Benchmark
import kotlinx.benchmark.Param
import kotlinx.benchmark.Scope
import kotlinx.benchmark.Setup
import kotlinx.benchmark.State
import kotlinx.io.Buffer
import kotlinx.io.Source
import kotlinx.io.readCodePointValue
import kotlinx.io.readString
import kotlinx.io.writeCodePointValue
import kotlinx.io.writeString
import kotlin.random.Random


@State(Scope.Benchmark)
open class ReadStringBenchmark() {

@Param("16", "64", "512") // Fits into a single segment, so the benchmark does not measure segment boundaries crossing
var size: Int = 0
fzhinkin marked this conversation as resolved.
Show resolved Hide resolved

val buffer: Buffer = Buffer()

@Setup
fun setup() {
val string = buildString { repeat(size) { append(('a'..'z').random()) } }
buffer.writeString(string)
}


@Benchmark
fun bufferReadString(): String {
return buffer.copy().readString()
}

@Benchmark
fun sourceReadString(): String {
val source: Source = buffer.copy()
return source.readString()
}
}
17 changes: 5 additions & 12 deletions core/common/src/Utf8.kt
Original file line number Diff line number Diff line change
Expand Up @@ -206,10 +206,7 @@ public fun Sink.writeString(chars: CharSequence, startIndex: Int = 0, endIndex:
*/
@OptIn(InternalIoApi::class)
public fun Source.readString(): String {
var req: Long = Segment.SIZE.toLong()
while (request(req)) {
req *= 2
}
request(Long.MAX_VALUE) // Request all data
return buffer.commonReadUtf8(buffer.size)
}

Expand Down Expand Up @@ -607,10 +604,7 @@ private fun Buffer.commonWriteUtf8CodePoint(codePoint: Int) {

@OptIn(UnsafeIoApi::class)
private fun Buffer.commonReadUtf8(byteCount: Long): String {
require(byteCount >= 0 && byteCount <= Int.MAX_VALUE) {
"byteCount ($byteCount) is not within the range [0..${Int.MAX_VALUE})"
}
require(byteCount)
// Invariant: byteCount was request()'ed into this buffer beforehand
if (byteCount == 0L) return ""

UnsafeBufferOperations.iterate(this) { ctx, head ->
Expand All @@ -624,7 +618,6 @@ private fun Buffer.commonReadUtf8(byteCount: Long): String {
}
}
}

// If the string spans multiple segments, delegate to readBytes().
return readByteArray(byteCount.toInt()).commonToUtf8String()
}
// If the string spans multiple segments, delegate to readBytes()
return readByteArray(byteCount.toInt()).commonToUtf8String()
}