Benchmark Write To File

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)
Min54.852
P50 (Median)55.109
P9055.265
P9555.375
P9965.699
P99.91010.050
Max1010.050
Total5,1465146.270
Iterations1,000

Benchmark: Write [1000] chars WITH disk sync (guaranteed persistence)

Metric(millis)(millis)
Min54.964
P50 (Median)55.129
P9055.273
P9555.383
P9977.497
P99.91312.547
Max1312.547
Total5,2105210.009
Iterations1,000

Benchmark: Write [2000] chars WITH disk sync (guaranteed persistence)

Metric(millis)(millis)
Min54.964
P50 (Median)55.107
P9055.261
P9555.333
P9965.716
P99.9109.933
Max109.933
Total5,1485148.111
Iterations1,000

Benchmark: Write [10000] chars WITH disk sync (guaranteed persistence)

Metric(millis)(millis)
Min54.882
P50 (Median)55.090
P9055.206
P9555.253
P9955.357
P99.999.306
Max99.306
Total5,1125111.684
Iterations1,000

=== WITHOUT DISK SYNC (OS buffer only) ===

Benchmark: Write [500] chars WITHOUT sync (OS buffer only)

Metric(micros)(millis)
Min540.054
P50 (Median)650.065
P90680.068
P95710.071
P99770.077
P99.91420.142
Max1420.142
Total65,61065.610
Iterations1,000

Benchmark: Write [1000] chars WITHOUT sync (OS buffer only)

Metric(micros)(millis)
Min540.054
P50 (Median)640.064
P90730.073
P95770.077
P99910.091
P99.91730.173
Max1730.173
Total65,92865.928
Iterations1,000

Benchmark: Write [2000] chars WITHOUT sync (OS buffer only)

Metric(micros)(millis)
Min520.052
P50 (Median)640.064
P90660.066
P95690.069
P99760.076
P99.91190.119
Max1190.119
Total63,52763.527
Iterations1,000

Benchmark: Write [10000] chars WITHOUT sync (OS buffer only)

Metric(micros)(millis)
Min710.071
P50 (Median)830.083
P90880.088
P95920.092
P991080.108
P99.91760.176
Max1760.176
Total84,33684.336
Iterations1,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.

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
  1. Benchmark Kotlin (JVM) write to File
  2. Write to Disk in Nodejs