Version française
Home     About     Download     Resources     Contact us    
Browse thread
[Caml-list] [PATCH] Dynamic freeing of dynamically loaded code
[ Home ] [ Index: by date | by threads ]
[ Search: ]

[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
Date: -- (:)
From: Nuutti Kotivuori <naked+caml@n...>
Subject: [Caml-list] [PATCH] Dynamic freeing of dynamically loaded code
* NOTE * NOTE * NOTE * NOTE * NOTE * NOTE * NOTE * NOTE * NOTE * NOTE *

  This is a preliminary release of this patch and contains requires
  still a lot of tweaking to be decently usable. Feel free to play
  around with it, but don't expect it to work or solve your problems.

* NOTE * NOTE * NOTE * NOTE * NOTE * NOTE * NOTE * NOTE * NOTE * NOTE *

Yuletime tidings!

So, as the questions on the list on how to make dynamically loaded
code garbage collectable evolved into implementation plans, now the
implementation plans evolved into actual code.

I'll outline really briefly what the implementation consists of:

 - Staticalloc module to have static_alloc'd blocks that are freed on
 finalization.

 - Modification to byterun - on CLOSURE and CLOSUREREC instructions,
 if nvars is below zero, negate it before using and append the last
 element of current env into the created closure.

   - Explanation: making two new bytecode instructions, CLOSUREDYN and
   CLOSURERECDYN, proved to be more difficult than I assumed, so I
   went the trivial way for now.

 - Implement reify_bytecode_with_ref - do as reify_bytecode, but go
 through the codeblock and negate all nvars parameters to CLOSURE and
 CLOSUREDYN and append given ref to the closure generated.

 - Make Dynlink use all this.

 - Fix utils/consistbl.ml to only store last crc given for an
 interface name. Should not affect functionality at all, but prevents
 memory bloat. (In the process of finding this I also noticed that
 Hashtbl resizing will use a non-tail-recursive function to reallocate
 a single bucket - and if that bucket is large enough: stack
 overflow. I filed a bug report on this already.)

What is the result now then:

 - Running Dynlink.loadfile "test.cmo";; on a file 1,000,000 times
 results a memory image rougly 12Mb when finished. Even 50,000 times
 used to make it 40Mb and crash on a stack overflow. Since the memory
 image of ocamlrun at start seems to be around 4Mb, a conservative
 estimate for the amount of memory taken by the loading would be 8Mb -
 that is, roughly 8 bytes per load. And atleast four bytes will
 necessarily go to the allocation of a new global on each time around.

 - Performance impacts of this on either normal bytecode, or
 dynamically loaded code, were totally unnoticeable. Somebody should
 run a much longer tests and prepare them better though. The impact of
 the code should be that executing CLOSURE and CLOSUREDYN instructions
 is a tiny bit more expensive, and each closure created from
 dynamically loaded code takes one word more memory.

What are the limitations then:

 - If the module defines any toplevel functions, it cannot ever be
 freed, because the closures are referenced from the global
 table. This is true even for loadfile_private. Eg. code that defines
 functions will still not be garbage collected.

 - If the module has any literals, the literals will not be freed and
 will be reallocated on each time it is loaded.

 - The global_data table will bloat for each load and the space will
 not be reclaimed.

 - Toploop doesn't use this yet.

What next:

 - Removing the limitations as much as possible - some might be
 unavoidable, but the cost shouldn't be higher than what it is now -
 and 8 bytes per loaded file is quite acceptable in all but the
 stringest environments.

So, in summary:

SUCCESS!

There is still a lot to do, though, and I will keep on working on the
implementation. Any review on the code anyone might wish to do would
be welcome indeed - as well as general comments on the subject.

I fear to attach the diff here as I don't know the policy of this list
on them, so I will put it online. If it's okay to post patches here, I
will do so in future revisions of this code. Also I wonder how I might
supply this patch when it's finished to the OCaml maintainers - they
will probably wish to do several things differently though - or if
just having it here on the mailing list is enough.

The patch should be applied on top of a current cvs checkout of
ocaml. Making it compile is a bit tricky though. I include hand hacked
Makefile and .depend changes in it to make it easier - yet I didn't
wish to supply a new ocamlc binary or anything. When starting to use
the code, first run 'make world' - this will break at some point
because the primitives are different - after that do 'make bootstrap',
which should complete gracefully. After that you can do whatever, like
'make clean', 'make world.opt' and 'make install' - everything should
work.

So, here's the link:

  http://www.iki.fi/naked/ocaml-dynlink-free.diff

Thanks for listening, and have a nice holiday everyone!
-- Naked

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners