I ran across this: http://kjpgit.github.io/posts/testing-rust-io.html
Was curious how nim did. naive version below took 18 seconds vs the "C" fputc_unlocked version at 2.3 seconds and plain fputc at 7 seconds. How do we get the C speed? (compiled with -d:release)
from strutils import parseInt
import os
proc main =
var x: int
if getenv("test_rounds") != "":
x = parseInt(getenv("test_rounds"))
else:
x = 1_000_000_000
for i in countup(1, x):
stdout.write "."
main()
How do we get the C speed?
By not caring about pointless and utterly non representative micro benchmarks? Outputting one char after the other already was a bad idea in the 20ies when the oh so efficient C IO libraries (interpreting format strings at runtime. Seriously?!) were designed.
joe: How do we get the C speed?
proc putc_unlocked(c: cint, fp: File) {.importc, header: "<stdio.h>".}
Note that fputc_unlocked() is not part of the POSIX standard, while putc_unlocked() is.
Also, as Araq points out, this is really a classical case of premature [1] optimization. Nim provides pretty straightforward access to ANSI C file I/O, with all its warts. If you have an application where you are in need of optimizing character-wise writing to a sequential file, you'll probably use a library optimized for that use case, probably by writing to a buffer and then using writeBuffer, e.g.:
from strutils import parseInt
import os
const bufferSize = 8192
type Buffer =
object
size: int
file: File
data: array[bufferSize, char]
proc init(buf: var Buffer, file: File) =
buf.size = 0
buf.file = file
proc flush(buf: var Buffer) =
# Being really lazy here, but this is just a quick example.
# Normally, you should check the return value.
discard writeBuffer(buf.file, addr(buf.data), buf.size)
buf.size = 0
proc write(buf: var Buffer, ch: char) =
buf.data[buf.size] = ch
inc buf.size
if buf.size == bufferSize:
flush(buf)
proc main =
var x: int
var buf: Buffer
if getenv("test_rounds") != "":
x = parseInt(getenv("test_rounds"))
else:
x = 1_000_000_000
init(buf, stdout)
for i in countup(1, x):
write(buf, '.')
flush(buf)
main()
[1] Premature because any tuned I/O library will likely have to be customized in ways that you can't predict at the time you're writing the initial code.
Thanks so much Jehan!
putc_unlocked castcint, stdout
is now a the same speed as C. awesome!
and your buffered version runs in about 1 second. ~1 GBps speed! amazing!
Araq: gotta throw us speedfreaks a bone now and then, thanks for creating a great language.
Oh yes, and regarding: "interpreting format strings at runtime." This might be interesting: http://blog.kazuhooku.com/2014/10/announcing-qrintf-and-qrintf-gcc.html
The whole of h2o web server looks interesting actually, esp as related to HTTP/2.