From: Florent M. <fmo...@li...> - 2008-06-10 16:03:32
|
... > > Hi, > > this hairy version is as fast as the one with the external oneliner C, > > here are the elapsed times (from Sys.time) for 3_000_000 floats written > > to /dev/null: > > > > 0.51 sec. -- with extern oneliner C > > 0.50 sec. -- the hairy one wins, well done! > > That's to be expected. Obj.magic is just the %identity compiler > primitive, which the compiler optimizes away completely, so the only > overhead is (maybe) the function call and (maybe) the boxing up of the > float argument. yes Obj.magic / %identity just allow to go through the type inference, but do not produce any assembly. the one with the extern C should be much slower because there is a call to memcpy (while there's no copy in the hairy one), and moreover there is a C function call that cannot be inlined. why the difference is so thin, I think, is that the hairy one makes 8 char outputs, while the C oneliner makes a single string output. I don't see any other reason why it's so close, this point seems to balance. ... So, I've just tryed to hack it to make a single string output, the hack is to use an unsafe_output just as the previous hairy one used String.unsafe_get. The function unsafe_output is defined in Pervasives, but is not exposed in the .mli file ; however it is still possible to use it from any file if one copy its definition: external unsafe_output: out_channel -> string -> int -> int -> unit = "caml_ml_output" this one avoids the call to string_length that will crash with the fake string there's a significant gain: 0.50 sec. -- rich's hairy one 0.35 sec. -- with the single unsafe ouput 1.34 sec. -- (for recall) the one from current extLib ___________________________ to make it included in the extLib.IO I have added the unsafe output in the type "output": type 'a output = { mutable out_write : char -> unit; mutable out_output : string -> int -> int -> int; mutable out_output_unsafe : string -> int -> int -> int; mutable out_close : unit -> 'a; mutable out_flush : unit -> unit; } let output_channel ch = { out_write = (fun c -> output_char ch c); out_output = (fun s p l -> Pervasives.output ch s p l; l); out_output_unsafe = (fun s p l -> unsafe_output ch s p l; l); out_close = (fun () -> Pervasives.close_out ch); out_flush = (fun () -> Pervasives.flush ch); } (* in other places I've just copy-pasted out_output to out_output_unsafe *) let output_unsafe o s p l = o.out_output_unsafe s p l let write_double_once ch (d : float) = ignore(output_unsafe ch (Obj.magic d : string) 0 8) maybe there could be a more elegant way... -- With Regards Florent |