[cwn] Attn: Development Editor, Latest Caml Weekly News

Alan Schmitt alan.schmitt at polytechnique.org
Tue Mar 15 01:23:43 PST 2005


-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hello,

Here is the latest Caml Weekly News, for the week of 08 to 15 March,  
2005.

1) MinCaml English Documentation
2) GC questions
3) ocamldap 2.1.0
4) 2D maze generator
5) pocengine
6) Ocaml-Expat-0.9.1
7) how to "disable" GC?

========================================================================
1) MinCaml English Documentation
Archive:  
http://caml.inria.fr/pub/ml-archives/caml-list/2005/03/ 
99d07c3f2722cd35b8caeab9c00d5d8a.en.html
- ------------------------------------------------------------------------
** Eijiro Sumii asked and Xavier Leroy answered:

 > In fact, I'm looking for a good (as simple and efficient as
 > possible) algorithm of pattern matching.  Any suggestions, anyone?

There are hard trade-offs between simplicity, execution speed and
size of generated code.  However, the compilation scheme I used in
Caml Light is a reasonable starting point.  It was inspired by
Phil Wadler's chapter in Simon Peyton Jones's book "The implementation  
of
functional programming languages" (out of print, but a scanned version
is available from SPJ's Web page), and described in details in the
"ZINC report", http://pauillac.inria.fr/~xleroy/publi/ZINC.ps.gz

Luc Maranget has some papers describing much more sophisticated
approaches used in the OCaml compiler, if you find so inclined.

** Eijiro Sumii added:

Thanks a lot for the references - and yes, that reminds me what I
forgot to mention:

If anybody is interested in a compiler of the complexity "between"
OCaml and MinCaml (and generating byte code or C), it may be good to
take a look at Caml Light, Camlot, or Bigloo.

   http://caml.inria.fr/distrib-caml-light-eng.html

========================================================================
2) GC questions
Archive:  
http://caml.inria.fr/pub/ml-archives/caml-list/2005/03/ 
c2f161f0d98362e787fa3a553deb34f9.en.html
- ------------------------------------------------------------------------
** Deep in this thread, Daniel Yokomizo asked and Damien Doligez  
answered:

 > AFAIK it doesn't force the GC to respect the dependencies. A object is
 > garbage if it can't be reached from any root references, it doesn't
 > matter
 > if other garbage objects still reference it. So if we have:
 >
 >
 > ROOT -> A -> B -> C
 >
 > D -> E -> F
 >
 > G -> B
 >
 > H -> C
 >
 >
 > the GC can collect any of [D, E, F, G, H], in any order it wants,
 > because
 > they're all garbage. An incremental collector could collect first [F,
 > G, H]
 > because they are (say) large objects, and don't recycle the memory for
 > [D,
 > E] until the next collection.

As far as _collecting_ is concerned, the GC can do it in any order it
wants,
and the current implementation is likely to do it in order of increasing
addresses (i.e. in some unpredictable order).

 > IIUC the current OCaml GC implementation may exhibit such properties
 > (i.e.
 > respect dependencies) but it isn't required to do so.

What I did specify and implement for 3.08 is the following:

If you call Gc.finalise on your values in the same order as they are
allocated, and if you don't introduce new depedencies afterward (with
assignments), then the finalisation functions will be called in the
right order (i.e. D before E before F, etc).

On the other hand, it means that a non-terminating finalisation function
must call Gc.finalise_release in order to let the GC run other
finalisation functions.

========================================================================
3) ocamldap 2.1.0
Archive:  
http://caml.inria.fr/pub/ml-archives/caml-list/2005/03/ 
8e2aab76580bd5f6f367ad1942c5e4f8.en.html
- ------------------------------------------------------------------------
** Eric Stokes announced:

I am pleased to announce the release of ocamldap 2.1.0.  If you ever
have to interact with an ldap server (or you need to write one), you
can do now it in Ocaml in a highly painless way. Note, for those people
who still believe that C is always faster (no one on this list I know,
but I vent my frustration), I am proud to announce that in this release
ocamldap's ldap decoder is faster than the one included with OpenLDAP
2.2.x. Thank you INRIA for making a compiler/runtime that doesn't suck.

http://ocamldap.sourceforge.net/

Because I did not announce the release of 2.0 I will include the
changelog back to 2.0.0.
2.1.0
     * ocaml-ssl is now required
     * BER Decoder
       - Improved decoding performance, 2x speedup. Beats OpenLDAP 2.2's
         decoder by about 5% (tested on PPC Mac OS X, and Intel Linux)
       - Fixed decoding of negative integers
       - Fixed decoding of error codes to comply with rfc2251. Unknown  
error
         codes will now be returned as `UNKNOWN_ERROR of int according  
to the rfc.
       - Fixed buggy decoding of ldap controls. They were not well tested
         until now, and several misinterpertations of the standard  
existed.
       - Fixed a bug which only happens when controls are asserted, some
         operations with optional values at the end would fail to decode
         when the control was present because of improper boundry  
setting.
         Boundries are now set at the end of each operation.
     * BER Encoder
       - Fixed several bugs in the encoding of two's complement integers
         where the sign bit was not being handled correctly. This never
         effected ldap clients, but severly limited the functionality of  
ldap
         servers. They would be unable to respond to requests with  
message id
         128, which would cause most clients to hang
       - Fixed discrepancies between the ldap_errorcode variant type,  
and the
         type recognized by encode_ldapresultcode. They are now the same  
type,
         and no exception can be raised, the compiler will now prove  
that client
         code doesn't send a variant which cannot be recognized.
     * ldap_funclient
       - Studied OpenLDAP's client library in depth, and adapted msgid
         allocation to look exactly like theirs. This will expose fewer
         bugs in ldap servers.
       - Changed the msgid type to an int32 (this should not be a visible
         change, it is an opaque type).
       - Refactored readbyte implementations, moved them to lber.ml, and
         tightened their exception handling.
     * ldap_ooclient
       - connect_timeout is now available as an optional argument to
         ldapcon.
       - added a method called "diff" to the ldapentry higharchy. It
         takes an entry and returns a list of differences between itself
         and the specified entry in the form of a modify record.
     * ldap_funserver
       - Deal with protocol errors according to rfc2251
       - Use the new readbyte implementations in lber.ml instead of a
         custom one
       - Implemented a logging harness. You pass in a function  
(optional) to
         init which takes a log level, and a string. The server will  
send your
         function log lines which exactly match the log format of  
OpenLDAP.
         The default function does nothing with the log lines. A parser  
for
         this log format is in the works and will be released as a  
seperate
         library.
     * LDIF Parser improvements
       - Improved the performance of write_entry, and to_string in  
Ldif_oo
       - Fixed a bug in the LDIF parser which could cause it to return
         the wrong line count when it finds a syntax error.
     * RFC 2252 schema parser/lexer
       - Fixed a typo in the lexer which would cause it
         not to correctly lex non numeric OIDs
       - Fixed bad lexing of X- attributes. There was an error in
         the definition of qdstring which would cause the lexer to eat
         all of the X- attributes in one pass. Tested fix
         with Active Directory 2003, OpenLDAP, and Novell eDirectory.
       - Changed the type of the attribute length field in the attribute
         record of the schema parser to be an Int64. The standard
         does not define the numeric range, and vendors
         (Novell) use huge numbers.
     * Schema Checker
       - Handled the case where the entry being checked does not have the
         objectclass attribute. Objectclass: top will be now be added in
         this case.
       - Fixed a bug in the "of_entry" method. It did not do a full  
schema
         check after importing the entry, so after calling of_entry the
         scldapentry was not proven to be valid.
     * Url Parser
       - Fixed a bug which could cause the url parser to return the wrong
         hostname if the hostname specified contained illegal characters.
     * Error Handling
       - moved err2string to a new module Ldap_error, which will contain
         functions for doing various things with LDAP_Failure exceptions.
         This WILL break existing applications which use err2string,
         however it is a simple matter of opening Ldap_error to fix them.
       - Implemented ldap_perror, and ldap_strerror functions, which
         either print, or return nicely formatted strings describing an
         LDAP_Failure exception.
2.0.3
     * Handle additional Unix_error exceptions as reconnection events,
       including EPIPE, ECONNRESET, and ECONNABORTED. Not handling these
       exceptions caused the library not to autoreconnect when the  
connection
       was dropped under certian circumstances.
2.0.2
     * Fixed a bug in the way delete was encoded which prevented it from  
working
2.0.1
     * Fixed a major bug in async calls.
2.0
     * Complete reimplementation of the low levels.
       - Pure Ocaml lber, and ldap protocol implementation. Ocamldap is
         no longer a C binding.
       - Server side as well as client side encoding/decoding
         functions. You can now make ldap servers with Ocamldap,
         as well as be a client!
       - No code optimization has been done yet, however the decoding
         performance is within 50% of the C library on the same hardware!
         Encoding performance has not been tested yet.
     * Some api changes to support additional error information,  
referrals
       and enhanced client side reliability. Minimal OO api changes,
       fairly significant lower level api changes
     * Module name reorganization. Painful, but it can only get worse
       if we let it stay the way it was. These two changes are the main
       reason for the 2.0 stamp.
     * Greatly simplified build system
     * All portions of the library are now covered by the LGPL license

========================================================================
4) 2D maze generator
Archive:  
http://caml.inria.fr/pub/ml-archives/caml-list/2005/03/ 
7ae599360e1c47901e580017be59124b.en.html
- ------------------------------------------------------------------------
** Jon Harrop announced:

For anyone who is interested: following a post on comp.lang.functional  
asking
for a 2D maze generator, I wrote a little OCaml program to generate  
random 2D
mazes, render them using OpenGL and generate PostScript output. The  
program
is available here:

   http://www.ffconsultancy.com/free/maze/

Hopefully this will serve as an intermediate between the ackermann  
function
and min-caml for people wanting to learn OCaml. ;-)

========================================================================
5) pocengine
Archive:  
http://caml.inria.fr/pub/ml-archives/caml-list/2005/03/ 
a6d8327f4976ef14a6453df1bcf9dab7.en.html
- ------------------------------------------------------------------------
** Julien Boulnois announced:

After having developped the game Battle For Rashitoul  
(http://rashitoul.net),
I started to write a game engine to help us creating more games more  
easily.
The engine is written mainly in Ocaml with some XML and LUA.
After some years of work, a first working version has been released
with a sample game: duck hunt. For more information, here is the link:
http://williamkramps.rashitoul.net/pocengine
(the website is only in French for now but the code is in English)
Feedback is most welcome!

** Christian Lindig asked and Julien Boulnois answered:

 > I am just curious. Are you using the C implementation of Lua? There is
 > also an OCaml of Lua, albeit only for Lua 2.5. I am using it for my  
own
 > projects.
 >
 > http://www.cminusminus.org/code.html#luaml

I'm using the very good OCaml implementation, because interaction with  
lua data
is easier and Lua 2.5 is suffisant for our needs

========================================================================
6) Ocaml-Expat-0.9.1
Archive:  
http://caml.inria.fr/pub/ml-archives/caml-list/2005/03/ 
49c43fbb933075e4183e4314f3209d95.en.html
- ------------------------------------------------------------------------
** Maas-Maarten Zeeman announced:

I'd like to announce Ocaml-Expat-0.9.1, Ocaml bindings for the Expat XML
Parser.

http://www.xs4all.nl/~mmzeeman/ocaml/

Support was added for XML_SetBase, XML_GetBase and
XML_ExternalEntityParserCreate.

========================================================================
7) how to "disable" GC?
Archive:  
http://caml.inria.fr/pub/ml-archives/caml-list/2005/03/ 
eaca75b29d80b5dd3d3ed34cbf7e7afe.en.html
- ------------------------------------------------------------------------
** Eijiro Sumii asked:

I'm trying some very unfair:-) comparisons between OCaml and MinCaml
(min-caml.sf.net), and wondering how to _disable_ GC in OCaml (on
SPARC).  I've tried

   setenv OCAMLRUNPARAM 's=1000000000,v=0x1ff'

and its variants, but none of them seem to stop GC from happening -
and once it happens, it's MUCH slower of course!  By the way, the
machine has 8GB main memory.

So, my questions are:

1. How does the GC happen at all when the minor heap is so huge?  The
    programs don't seem to use so much memory anyway...

2. Some programs get much slower for larger heaps, even though they
    don't seem to trigger any GC.  An example is such programs is given
    below.  Why is this?  (There also exist programs that are not
    affected at all, so this is not because of the initialization
    overhead of the runtime system.)

(**********************************************************************)
let rec tak x y z =
   if y >= x then z else
   tak (tak (x -. 1.0) y z) (tak (y -. 1.0) z x) (tak (z -. 1.0) x y) in
let n = 10.0 in
print_int (int_of_float (1000000.0 *. tak (n *. 3.0) (n *. 2.0) (n *.  
1.0)));
print_newline ()
(**********************************************************************)

** Thomas Fischbacher answered:

Quite in general, Cache hierarchy may be an issue here. The CPU can only
hold a small amount of data in its L1 cache, which is quite fast. Next,
there are L2 and then L3 caches (should you have that), but if you have  
to
do a lot of real memory access, that usually will kill you. Especially  
if
your address space is so badly scrambled that the CPU constantly needs  
to
re-load its address translation cache (called translation lookaside  
buffer
for x86). Worst case situation on a 3-level MMU system is that you will
have to do four memory reads for one word of data.

So, as a quite general rule when doing computationally challenging
algebraic stuff in a functional language: try hard to design your data
representation in such a way that you minimize RAM access. If you can
e.g. encode short lists of small integers into a fixnum-integer, then do
so. A few shift and masking operations do not matter much for many
pipelined processors, provided the code can be held in the cache. Memory
access does. One can overdo it, though: if you need ten times more code  
to
get rid of a simple memory access, you're on the wrong track. Code also
has to be transported to the CPU core.

** Eijiro Sumii then asked:

 > Quite in general, Cache hierarchy may be an issue here.

This is right, but let me clarify my question: Why is _anything_
heap-allocated, for example in the program below (given in my previous
message)?  According to the assembly and intermediate code in
ocamlopt, there is indeed something heap-allocated in the else-clause
of tak, but I don't know what this is for...  Are floting-point
numbers heap-allocated in ocamlopt on sparc??

|  
(**********************************************************************)
| let rec tak x y z =
|   if y >= x then z else
|   tak (tak (x -. 1.0) y z) (tak (y -. 1.0) z x) (tak (z -. 1.0) x y)  
in
| let n = 10.0 in
| print_int (int_of_float (1000000.0 *. tak (n *. 3.0) (n *. 2.0) (n *.  
1.0)));
| print_newline ()
|  
(**********************************************************************)

 > setenv OCAMLRUNPARAM 's=1000'
 > time ./tak.ocamlopt
11000000
3.54u 0.01s 0:03.56 99.7%
 > setenv OCAMLRUNPARAM 's=1000000000'
 > time ./tak.ocamlopt
11000000
6.83u 1.50s 0:08.80 94.6%

** Kurt Welgehausen answered and Eijiro Sumii said:

 > > Are floting-point numbers heap-allocated in ocamlopt on sparc?
 >
 > Yes, I believe FP values are boxed on all platforms. You could
 > try keeping your values in an array, and see if that makes any
 > difference.
 >
 > Also, see http://caml.inria.fr/archives/200501/msg00125.html
 > and related messages.

I see - so it seems to me that FP numbers are heap-allocated at least
when they are passed or returned as function arguments or results (to
support polymorphism, I suppose).  This explains well the behaviors of
ocamlopt (and its GC) that I've been experiencing.  Thanks for the
information!

** Damien Doligez answered the OP:


 >   setenv OCAMLRUNPARAM 's=1000000000,v=0x1ff'
 >
 > and its variants, but none of them seem to stop GC from happening -
 > and once it happens, it's MUCH slower of course!  By the way, the
 > machine has 8GB main memory.
 >
 > So, my questions are:
 >
 > 1. How does the GC happen at all when the minor heap is so huge?  The
 >    programs don't seem to use so much memory anyway...

Look for "caml_check_urgent_gc" in the runtime sources and you'll see
that minor collections can be triggered even if the minor heap is not
full if needed, in order to do a slice of major GC.

So if you allocate some things that go directly into the major heap
(for example reasonably large arrays or strings) you need a big major
heap as well as a big minor heap:

    setenv OCAMLRUNPARAM 's=500M,h=500M,v=0x1ff'

========================================================================
Using folding to read the cwn in vim 6+
- ------------------------------------------------------------------------
Here is a quick trick to help you read this CWN if you are viewing it  
using
vim (version 6 or greater).

:set foldmethod=expr
:set foldexpr=getline(v:lnum)=~'^=\\{78}$'?'<1':1
zM
If you know of a better way, please let me know.

========================================================================
Old cwn
- ------------------------------------------------------------------------

If you happen to miss a CWN, you can send me a message
(alan.schmitt at polytechnique.org) and I'll mail it to you, or go take a  
look at
the archive (http://sardes.inrialpes.fr/~aschmitt/cwn/) or the RSS feed  
of the
archives (http://sardes.inrialpes.fr/~aschmitt/cwn/cwn.rss). If you  
also wish
to receive it every week by mail, you may subscribe online at
http://lists.idyll.org/listinfo/caml-news-weekly/ .

========================================================================

Alan Schmitt, http://sardes.inrialpes.fr/~aschmitt/
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.4 (Darwin)

iD8DBQFCNqmpNIAqM4hFUWgRAlN5AJ9v8bKRLF9SwvN/9HlRLNe6lPqEvwCeIE5A
E9oo4k0dV1bAMSOIOfL1AL4=
=uYs/
-----END PGP SIGNATURE-----




More information about the caml-news-weekly mailing list