Re: ocaml limitations

From: John Carol Langford (jcl@gs176.sp.cs.cmu.edu)
Date: Wed Dec 15 1999 - 04:06:41 MET


Message-Id: <199912150306.WAA17480@gs176.sp.cs.cmu.edu>
To: Xavier Leroy <Xavier.Leroy@inria.fr>, caml-list@inria.fr,
Subject: Re: ocaml limitations
In-Reply-To: Your message of "Tue, 14 Dec 1999 13:31:14 +0100."
             <19991214133114.35181@pauillac.inria.fr>
Date: Tue, 14 Dec 1999 22:06:41 -0500
From: John Carol Langford <jcl@gs176.sp.cs.cmu.edu>

I grabbed David McClain's code, figured out how to use it, then
stripped it down to the minimal set necessary for what I want to do.
Here are the timings for a little benchmark I made: (P-120, linux)

Time when redirecting to a c short array: ~40 seconds

Time when "arena"ing a c long array and playing masking games to get
simulated shorts: 25.68 seconds

Time to simulate the long array and play masking games in pure ocaml:
54.90 seconds

Time for native C: 7.13 seconds

'arena' was a big win. Without the need to play shift & mask games
'arena' will get you down to 14 seconds or so. The remaining
factor of 2 is probably loop optimizations in the C compiler.

-John

The benchmark in ocaml with 'arena' and short simulation:
let max = 1 lsl 23

let big = General_array.foreign_unsafe_create max

let set arr loc valu =
  let real_loc = loc / 2 in
  let mixed_val = Array.unsafe_get arr real_loc in
  let final_val =
    if loc mod 2 = 1 then (mixed_val land 4294901760) lor valu
    else (mixed_val land 65535) lor (valu lsl 16) in
  Array.unsafe_set arr real_loc final_val

let get arr loc =
  let ret = Array.unsafe_get arr (loc/2) in
  let real_ret =
    if loc mod 2 = 1 then ret
    else ret lsr 16 in
  real_ret land 65535
    
let _ =
  let accum =ref 0 in
  let ml_big = General_array.arena big in
  for i = 0 to max -1 do
    set ml_big i i
  done;
  for j = 0 to 9 do
    for i = 0 to max -1 do
      accum := get ml_big i
    done;
  done;
  print_int !accum; print_newline()

The benchmark in c:
int main(void)
{
  int i,j;
  int max = 1 << 23;
  int accum = 0;
  short int *big = (short int *)malloc(sizeof(short) *max);
  
  for(i=0;i<max-1;i++)
    big[i] = (short)i;
  for(j=0; j<10; j++)
    for(i=0;i<max-1;i++)
      accum = big[i];
  printf("%i\n",accum);
  return 0;
}

The support code:
// foreign_array.c -- Implementation of foreign array objects
// hacked to specialize by jcl@cs.cmu.edu
// DM/MCFA 01/99
// ---------------------------------------------------------------

#include <stdlib.h>
#include <stdio.h>

#include "mlvalues.h"
#include "memory.h"
#include "alloc.h"
#include "fail.h"
#include <assert.h>

// ----------------------------------------------------------------------

inline long int *pdata(value arr)
{
        return (long *)Field(arr,1);
}

inline void foreign_array_delete(value arr)
{
        free(pdata(arr));
}

inline value foreign_array_unsafe_get(value arr, value ix)
{
  // printf("get %i = %i\n",Long_val(ix), pdata(arr)[Long_val(ix)]);
        return pdata(arr)[Long_val(ix)];
}

inline value foreign_array_unsafe_set(value arr, value ix, value val)
{
  // printf("set %i to %i\n",Long_val(ix), Long_val(val));
        pdata(arr)[Long_val(ix)] = (long)val;
        return Val_unit;
}

inline value foreign_arena(value arr)
{
  return pdata(arr);
}

value foreign_array_unsafe_create(value vlen)
{
        CAMLparam1(vlen);
        CAMLlocal1(res);

        long int *p;

        long len = Long_val(vlen);

        res = alloc_final(2, foreign_array_delete,1,1);
        p = (long int *)malloc(sizeof(long) *len);

        Store_field(res,1,(value)p);
        CAMLreturn res;
}

general_array.ml:
(* general_array.ml -- Implementation of (essentially) unlimited size arrays *)
(* hacked by jcl@cs.cmu.edu *)
(* DM/MCFA 01/99 *)

type foreign_array (* opaque foreign array object pointer *)
type raw_ptr (* opaque raw pointer to foreign array data *)
      
external foreign_array_length :
  foreign_array -> int
  = "foreign_array_length"

(* unsafe_get_double and unsafe_set_double are provided to allow *)
(* an array to respond to OCAML without requiring that it be an *)
(* array of doubles. *)
external foreign_unsafe_get :
  foreign_array -> int -> int
  = "foreign_array_unsafe_get"
      
external foreign_unsafe_set :
  foreign_array -> int -> int -> unit
  = "foreign_array_unsafe_set"
      
external foreign_unsafe_create :
  int -> foreign_array
  = "foreign_array_unsafe_create"

external foreign_arena :
   foreign_array -> raw_ptr = "foreign_arena"

let arena f = ((Obj.magic (foreign_arena f)): int array)



This archive was generated by hypermail 2b29 : Sun Jan 02 2000 - 11:58:29 MET