Benchmark Write To File
From Benchmark Kotlin (JVM) write to File
Go to text ā
About 5-10ms to fully write string of less than 10,000 characters to disk (synced).
About 0.05-0.1 milliseconds to write to OS buffer (un-synced).
About 50-100X difference between RAM and SSD write.
GT-Sandbox-Snapshot: Benchmarked in 2025
Code
package com.glassthought.sandbox
import com.asgard.testTools.benchmarker.BenchMarkerJVM
import java.io.File
import java.io.FileOutputStream
/**
* Benchmark comparing file write performance WITH and WITHOUT disk sync.
*
* CRITICAL DISTINCTION:
* - WITHOUT sync (File.writeText): Writes only to OS cache buffer
* PRO: Order of magnitude faster (e.g., 0.05ms vs 5ms)
* CON: Data NOT guaranteed to survive system crash after writeText completes
*
* - WITH sync (fd.sync()): Forces write to physical disk
* PRO: Data guaranteed to survive power loss/system crash
* CON: Much slower due to physical I/O
*/
suspend fun main(args: Array<String>) {
// Compare with and without sync to see the performance difference
println("\n=== WITH DISK SYNC (guaranteed persistence) ===")
benchmarkFileWrite(500, syncToDisk = true)
benchmarkFileWrite(1000, syncToDisk = true)
benchmarkFileWrite(2000, syncToDisk = true)
benchmarkFileWrite(10000, syncToDisk = true)
println("=== WITHOUT DISK SYNC (OS buffer only) ===")
benchmarkFileWrite(500, syncToDisk = false)
benchmarkFileWrite(1000, syncToDisk = false)
benchmarkFileWrite(2000, syncToDisk = false)
benchmarkFileWrite(10000, syncToDisk = false)
}
fun getRandomChar(): String {
return ('a'..'z').random().toString()
}
private suspend fun benchmarkFileWrite(howManyChars: Int, syncToDisk: Boolean = true) {
val string = (1..howManyChars).joinToString("") { getRandomChar() }
val file = File("/tmp/output-file")
val description = if (syncToDisk) {
"Write [${string.length}] chars WITH disk sync (guaranteed persistence)"
} else {
"Write [${string.length}] chars WITHOUT sync (OS buffer only)"
}
val result = BenchMarkerJVM.benchMark({
if (syncToDisk) {
// WITH SYNC: Data is guaranteed to survive system crash
// CON: Much slower (e.g., 5ms)
FileOutputStream(file).use { fos ->
fos.write(string.toByteArray(Charsets.UTF_8))
fos.flush() // Flush to OS buffer
fos.fd.sync() // Force sync to physical disk - GUARANTEES persistence
}
} else {
// WITHOUT SYNC: Only writes to OS cache buffer
// PRO: Order of magnitude faster (e.g., 0.05ms instead of 5ms)
// CON: Data is NOT guaranteed to survive a system crash after writeText completes
file.writeText(string, Charsets.UTF_8)
}
}, 1000, description = description)
result.printFormattedTable()
}
Command to reproduce:
gt.sandbox.checkout.commit b7ad25225b70a37866b9 \
&& cd "${GT_SANDBOX_REPO}" \
&& cmd.run.announce "./gradlew run --quiet"
Recorded output of command:
=== WITH DISK SYNC (guaranteed persistence) ===
Benchmark: Write [500] chars WITH disk sync (guaranteed persistence)
Metric | (millis) | (millis) |
---|---|---|
Min | 5 | 4.852 |
P50 (Median) | 5 | 5.109 |
P90 | 5 | 5.265 |
P95 | 5 | 5.375 |
P99 | 6 | 5.699 |
P99.9 | 10 | 10.050 |
Max | 10 | 10.050 |
Total | 5,146 | 5146.270 |
Iterations | 1,000 |
Benchmark: Write [1000] chars WITH disk sync (guaranteed persistence)
Metric | (millis) | (millis) |
---|---|---|
Min | 5 | 4.964 |
P50 (Median) | 5 | 5.129 |
P90 | 5 | 5.273 |
P95 | 5 | 5.383 |
P99 | 7 | 7.497 |
P99.9 | 13 | 12.547 |
Max | 13 | 12.547 |
Total | 5,210 | 5210.009 |
Iterations | 1,000 |
Benchmark: Write [2000] chars WITH disk sync (guaranteed persistence)
Metric | (millis) | (millis) |
---|---|---|
Min | 5 | 4.964 |
P50 (Median) | 5 | 5.107 |
P90 | 5 | 5.261 |
P95 | 5 | 5.333 |
P99 | 6 | 5.716 |
P99.9 | 10 | 9.933 |
Max | 10 | 9.933 |
Total | 5,148 | 5148.111 |
Iterations | 1,000 |
Benchmark: Write [10000] chars WITH disk sync (guaranteed persistence)
Metric | (millis) | (millis) |
---|---|---|
Min | 5 | 4.882 |
P50 (Median) | 5 | 5.090 |
P90 | 5 | 5.206 |
P95 | 5 | 5.253 |
P99 | 5 | 5.357 |
P99.9 | 9 | 9.306 |
Max | 9 | 9.306 |
Total | 5,112 | 5111.684 |
Iterations | 1,000 |
=== WITHOUT DISK SYNC (OS buffer only) ===
Benchmark: Write [500] chars WITHOUT sync (OS buffer only)
Metric | (micros) | (millis) |
---|---|---|
Min | 54 | 0.054 |
P50 (Median) | 65 | 0.065 |
P90 | 68 | 0.068 |
P95 | 71 | 0.071 |
P99 | 77 | 0.077 |
P99.9 | 142 | 0.142 |
Max | 142 | 0.142 |
Total | 65,610 | 65.610 |
Iterations | 1,000 |
Benchmark: Write [1000] chars WITHOUT sync (OS buffer only)
Metric | (micros) | (millis) |
---|---|---|
Min | 54 | 0.054 |
P50 (Median) | 64 | 0.064 |
P90 | 73 | 0.073 |
P95 | 77 | 0.077 |
P99 | 91 | 0.091 |
P99.9 | 173 | 0.173 |
Max | 173 | 0.173 |
Total | 65,928 | 65.928 |
Iterations | 1,000 |
Benchmark: Write [2000] chars WITHOUT sync (OS buffer only)
Metric | (micros) | (millis) |
---|---|---|
Min | 52 | 0.052 |
P50 (Median) | 64 | 0.064 |
P90 | 66 | 0.066 |
P95 | 69 | 0.069 |
P99 | 76 | 0.076 |
P99.9 | 119 | 0.119 |
Max | 119 | 0.119 |
Total | 63,527 | 63.527 |
Iterations | 1,000 |
Benchmark: Write [10000] chars WITHOUT sync (OS buffer only)
Metric | (micros) | (millis) |
---|---|---|
Min | 71 | 0.071 |
P50 (Median) | 83 | 0.083 |
P90 | 88 | 0.088 |
P95 | 92 | 0.092 |
P99 | 108 | 0.108 |
P99.9 | 176 | 0.176 |
Max | 176 | 0.176 |
Total | 84,336 | 84.336 |
Iterations | 1,000 |
writeText does NOT auto sync.
Note if we do not explicitly sync to disk with code like
File("/tmp/output-file").writeText(string, Charsets.UTF_8)
We will write to OS cache buffer.
- PRO: Performance will look order of magnitude faster (eg. from 5millis to 1/20th millis).
- CON: Data is NOT guaranteed to survive a system crash, after
writeText
completes.
From Write to Disk in Nodejs
Go to text ā
5-10ms to write to SSD for strings less than 10,000 characters.
(with sync to disk).
GT-Sandbox-Snapshot
Command to reproduce:
gt.sandbox.checkout.commit 90303db14ce95a6df23d \
&& cd "${GT_SANDBOX_REPO}" \
&& cmd.run.announce "./run.sh"
Recorded output of command:
Starting file write benchmarks...
Started [Write a string of [500] characters to file (Node.js)], going to run for [1000]...
#### Benchmark: Write a string of [500] characters to file (Node.js)
| Metric | Time | Value (ns) |
|--------------|------------|--------------:|
| Min | 4.899 ms | 4,899,398 |
| P50 (Median) | 5.186 ms | 5,185,765 |
| P90 | 5.308 ms | 5,307,762 |
| P95 | 5.370 ms | 5,370,353 |
| P99 | 5.686 ms | 5,686,219 |
| P99.9 | 9.962 ms | 9,962,423 |
| Max | 9.962 ms | 9,962,423 |
| Total | 5.200 s | 5,199,505,394 |
| Iterations | 1,000 | |
Started [Write a string of [1000] characters to file (Node.js)], going to run for [1000]...
#### Benchmark: Write a string of [1000] characters to file (Node.js)
| Metric | Time | Value (ns) |
|--------------|------------|--------------:|
| Min | 4.913 ms | 4,913,184 |
| P50 (Median) | 5.124 ms | 5,124,034 |
| P90 | 5.274 ms | 5,274,016 |
| P95 | 5.319 ms | 5,318,924 |
| P99 | 5.802 ms | 5,801,763 |
| P99.9 | 10.144 ms | 10,144,346 |
| Max | 10.144 ms | 10,144,346 |
| Total | 5.166 s | 5,165,946,193 |
| Iterations | 1,000 | |
Started [Write a string of [2000] characters to file (Node.js)], going to run for [1000]...
#### Benchmark: Write a string of [2000] characters to file (Node.js)
| Metric | Time | Value (ns) |
|--------------|------------|--------------:|
| Min | 4.860 ms | 4,860,061 |
| P50 (Median) | 5.112 ms | 5,112,402 |
| P90 | 5.321 ms | 5,321,158 |
| P95 | 5.476 ms | 5,475,930 |
| P99 | 6.214 ms | 6,213,986 |
| P99.9 | 10.127 ms | 10,126,632 |
| Max | 10.127 ms | 10,126,632 |
| Total | 5.190 s | 5,189,873,467 |
| Iterations | 1,000 | |
Started [Write a string of [10000] characters to file (Node.js)], going to run for [1000]...
#### Benchmark: Write a string of [10000] characters to file (Node.js)
| Metric | Time | Value (ns) |
|--------------|------------|--------------:|
| Min | 4.889 ms | 4,888,916 |
| P50 (Median) | 5.100 ms | 5,099,928 |
| P90 | 5.279 ms | 5,278,977 |
| P95 | 5.498 ms | 5,497,842 |
| P99 | 6.359 ms | 6,359,360 |
| P99.9 | 9.896 ms | 9,896,024 |
| Max | 9.896 ms | 9,896,024 |
| Total | 5.166 s | 5,166,243,294 |
| Iterations | 1,000 | |
All benchmarks completed!
Children