Skip to content

Instantly share code, notes, and snippets.

@umurgdk
Created October 1, 2022 16:52
Show Gist options
  • Save umurgdk/f93b75c6478847a38ee008f2d3dd5fc6 to your computer and use it in GitHub Desktop.
Save umurgdk/f93b75c6478847a38ee008f2d3dd5fc6 to your computer and use it in GitHub Desktop.
import Foundation
import Darwin
var logID: Int64 = 0
enum Errors: String, Error {
case couldntOpenFile
case failedToWrite
}
struct BufferedWriter {
let file: OutputStream
let bufferCapacity: Int
var buffer: UnsafeMutableBufferPointer<UInt8>
var bufferSize = 0
init(file: OutputStream, bufferCapacity: Int = 10_024_000) {
self.file = file
self.bufferCapacity = bufferCapacity
self.buffer = .allocate(capacity: bufferCapacity)
self.buffer.initialize(repeating: 0)
}
@inline(__always)
mutating func write(_ string: String) throws -> Int {
let utf8View = string.utf8
let stringLen = utf8View.count
if bufferSize + stringLen >= bufferCapacity {
try flush()
}
let writeAddress = buffer.baseAddress!.advanced(by: bufferSize)
utf8View.withContiguousStorageIfAvailable { bytes in
writeAddress.assign(from: bytes.baseAddress!, count: stringLen)
}
bufferSize += stringLen
return utf8View.count
}
@inline(__always)
mutating func flush() throws {
let writtenBytes = file.write(buffer.baseAddress!, maxLength: bufferSize)
if writtenBytes != bufferSize {
throw Errors.failedToWrite
}
bufferSize = 0
}
}
func main() throws {
guard let file = OutputStream(toFileAtPath: "output.txt", append: false) else {
throw Errors.couldntOpenFile
}
file.open()
var bufferedWriter = BufferedWriter(file: file)
print("Starting to write...")
let beginning = Date()
var totalBytesWritten: Int = 0
let message = "This is a really long log message with the id: \(logID)"
while true {
let bytesWritten = try bufferedWriter.write(message)
totalBytesWritten += bytesWritten
logID += 1
if totalBytesWritten >= 512_000_000 {
break
}
}
try bufferedWriter.flush()
file.close()
let operationDuration = Date().timeIntervalSince(beginning)
let bytesMeasurement = Measurement<UnitInformationStorage>(value: Double(totalBytesWritten), unit: .bytes)
let timeMeasurement = Measurement<UnitDuration>(value: operationDuration, unit: .seconds)
let megabytesPerSecond = bytesMeasurement
print("Written \(bytesMeasurement.converted(to: .megabytes)) bytes in \(timeMeasurement) seconds")
print("Performance: \(bytesMeasurement.converted(to: .megabytes).value / timeMeasurement.value) mb/s")
}
try main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment