Xavier Leroy on the right:
Dinner the evening before:
| Reqs/sec | Mem usage | |
|---|---|---|
| Rails with mongrel, 1 process | 260 | 49MB |
| Rails with mongrel via nginx (rev proxy), 1 proc | 220 | ~51MB |
| Rails with mongrel, 4 processes via nginx | 430 | ~200MB |
| OCaml ocsigen (1 process) | 5800 | 4.5MB |
| lighttpd with FastCGI app in C, 20 procs | 9300 | 4.5MB |
"I have *never* seen it being used since. To my mind they both belong in the category 'interesting, but pointless'."and
"The point is that there's nothing those languages can do that can't be done, often more easily, with the current crop of popular languages. Elegance cannot beat convenience in the workplace, or in most at any rate."and so on.
if (..) { field1 = htonl (field1); ... }. OK so that's a bit hard. Let's say you want to parse a 6 bit length field 'n' followed by an n+1 bit data field (as a 1-64 bit int). Go and write it in C now.
let bits = Bitstring.bitstring_of_file "input.data" in
bitmatch bits with
| { n : 6;
data : n+1 } -> data
set_word_size because you try to call get_word?In a followup, I gave some example code:
OCaml cannot just directly access C globals. At best you'd need to have a function that returns the address of the C global, _and_ the C global would need to be in a form that OCaml code could understand although that is pretty easy to arrange.
------------------------------------------------------------ test_c.c
/* Variable shared between C and OCaml. */
#include <caml/mlvalues.h>
/* On the OCaml side, this will be made to look like a structure
* containing a single int (well, provided you don't look *too*
* closely at it).
*/
value shared_var = Val_int (0);
value
get_struct_addr (value unitv)
{
/* Return the address of the 'structure'. */
return ((value) &shared_var);
}
/* Increment the shared variable. */
value
increment_it (value unitv)
{
int i = Int_val (shared_var);
i++;
shared_var = Val_int (i);
return (Val_unit);
}
----------------------------------------------------------------------
------------------------------------------------------------ test.ml
(* Variable shared between C and OCaml. *)
type var = {
shared_var : int;
}
external get_struct_addr : unit -> var = "get_struct_addr" "noalloc"
external increment_it : unit -> unit = "increment_it" "noalloc"
let var = get_struct_addr () ;;
while true do
Printf.printf "value of the variable now is %d\n%!" var.shared_var;
increment_it ();
(* OCaml isn't expecting that increment_it modifies a variable, so
* there is no guarantee that we will see the changed value next
* time around.
*)
Unix.sleep 1;
done
----------------------------------------------------------------------
$ gcc -I /usr/lib/ocaml -c test_c.c
$ ocamlopt -c test.ml
$ ocamlopt unix.cmxa test_c.o test.cmx -o test
$ ./test
value of the variable now is 0
value of the variable now is 1
value of the variable now is 2
value of the variable now is 3
value of the variable now is 4
[etc.]
then just using
external call_1 : float -> float = "call_1"
call_1. However these calls are not direct. They go via an OCaml runtime function called caml_c_call. This is a tiny bit of assembler, so the overhead isn't large, but it does use a computed jump which on many processors is quite slow.
external call_2 : float -> float = "call_2" "noalloc"
Normal "noalloc"
pushl %eax pushl %eax
movl $call_1, %eax call call_2
call caml_c_call addl $4, %esp
addl $4, %esp
...
caml_c_call:
movl (%esp), %edx
movl %edx, G(caml_last_return_address)
leal 4(%esp), %edx
movl %edx, G(caml_bottom_of_stack)
jmp *%eax
ocamlopt takes the code literally, and
let n = 100_000
let fib = Array.make n 1 ;;
for i = 2 to n-1 do
let a, b = fib.(i-2), fib.(i-1) in
fib.(i) <- a + b
done
let a, b = ... allocates a tuple (a, b) before discarding it. Simply rewriting the problematic statement as: makes the whole loop run in half the time.
let a = fib.(i-2) and b = fib.(i-1) in
fib.(i), the compiler has to emit code to calculate fib + i*sizeof(int), and unlike C, ocamlopt doesn't use code motion to simplify and share the repeated references. Overall these two simple optimizations reduce the total running time of this loop more than three-fold.
let a = ref 1 and b = ref 1 in
for i = 2 to n-1 do
let c = !a + !b in
a := !b; b := c; fib.(i) <- c
done