Bugs in OCaml interface

Hello there,
I've been using the PPL OCaml interface to carry out some program analysis within a compiler. It's been working pretty well, but I've come across a number of bugs.
--------------------------------------------------------------------------------
1. The OCaml 'unit' type has only a single value, denoted (); this is represented internally by a pointer to a single preallocated value. However, many of the functions in the PPL interface return the wrong value.
Here's an example from an OCaml top level built with PPL
$ ocamlppl Objective Caml version 3.11.0
# let p = Ppl_ocaml.ppl_new_C_Polyhedron_from_constraints [];; val p : Ppl_ocaml.polyhedron = <abstr>
# let u = Ppl_ocaml.ppl_Polyhedron_add_constraints p [];; val u : unit = <unknown constructor>
# u = ();; - : bool = false #
The <unknown constructor> thing is something you should never see.
Here's the defintion of the ppl_Polyhedron_add_constraints function from interfaces/OCaml/ppl_ocaml_Polyhedron.cc:
extern "C" void ppl_Polyhedron_add_constraints(value ph, value cs) try { CAMLparam2(ph, cs); Polyhedron& pph = *p_Polyhedron_val(ph); Constraint_System pcs = build_ppl_Constraint_System(cs); pph.add_constraints(pcs); CAMLreturn0; } CATCH_ALL
This has void return type, but should actually return a pointer to the preallocated unit value. I think the correct code should look like
extern "C" CAMLprim value ppl_Polyhedron_add_constraints(value ph, value cs) try { CAMLparam2(ph, cs); Polyhedron& pph = *p_Polyhedron_val(ph); Constraint_System pcs = build_ppl_Constraint_System(cs); pph.add_constraints(pcs); CAMLreturn(Val_unit); } CATCH_ALL
Every function returning a unit value (it looks like there are 509 of them) should look like this. I don't think this bug is very harmful unless one uses unit values in unusual ways.
----------------------------------------------------------------------
2. Certain functions can lead to segmentation errors. Here's a program which creates a polyhedron and then loops round adding constraints one by one. The call to ppl_Polyhedron_get_constraints sometimes causes a segmentation fault; if you remove it then the program runs OK. (Presumably it eventually runs out of memory, but I've run it for a very long time (millions of iterations) without this happening.)
$ cat tst.ml
open Ppl_ocaml
let itoz = Gmp.Z.of_int
let f n = (* Generate a constraint nx + (n+1)y <= n+2 *) Less_Or_Equal (Plus (Times (itoz n, Variable 0), Times (itoz (n+1), Variable 1)), Coefficient (itoz (n+2)))
let p = ppl_new_C_Polyhedron_from_space_dimension 2 Universe
let rec g n = let () = ppl_Polyhedron_add_constraint p (f n) in let l = ppl_Polyhedron_get_constraints p in let () = Printf.printf "%d\n" n in let () = flush stdout in g (n+1)
let _ = g 0
Here's what happens when you run it:
$ ocamlppl # #use "tst.ml";; val itoz : int -> Gmp.Z.t = <fun> val f : int -> Ppl_ocaml.linear_constraint = <fun> val p : Ppl_ocaml.polyhedron = <abstr> File "tst.ml", line 12, characters 9-10: Warning Y: unused variable l. val g : int -> 'a = <fun> 0 1 2 3 . . <output deleted> . 1654 1655 1656 Segmentation fault
I think that the problem here is in the function build_ocaml_constraint_system in interfaces/OCaml/ppl_ocaml_common.cc:
value build_ocaml_constraint_system(const Constraint_System& ppl_cs) { // This code builds a list of constraints starting from bottom to // top. A list on OCaml must be built like a sequence of Cons and Tail. // The first element is the Nil list (the Val_int(0)). value result = Val_int(0); for (Constraint_System::const_iterator v_begin = ppl_cs.begin(), v_end = ppl_cs.end(); v_begin != v_end; ++v_begin) { value new_tail = caml_alloc_tuple(2); Field(new_tail, 0) = build_ocaml_constraint(*v_begin); Field(new_tail, 1) = result; result = new_tail; } return result; }
The problem is in the way that allocation in the ocaml heap is handled. The function loops round allocating list cells in the heap, but the ocaml garbage collector doesn't know what's going on. Eventually caml_alloc_tuple is called when there isn't enough free space: this triggers garbage collection, and the memory occupied by the partially built list is reclaimed; the loop then continues, allocating a new list cell whose tail points to some garbage-collected memory which will later be occupied by something else allocated in the heap. The function finally returns a malformed list to the ocaml system, eventually leading to a crash. To overcome this the CAMLlocal macro should be used to tell the ocaml garbage collector to leave the partially-allocated list alone:
CAMLprim value build_ocaml_constraint_system(const Constraint_System& ppl_cs) { // This code builds a list of constraints starting from bottom to // top. A list on OCaml must be built like a sequence of Cons and Tail. // The first element is the Nil list (the Val_int(0)). CAMLlocal2 (result, new_tail); result = Val_emptylist; // Synonymous with Val_int(0); for (Constraint_System::const_iterator v_begin = ppl_cs.begin(), v_end = ppl_cs.end(); v_begin != v_end; ++v_begin) { new_tail = caml_alloc_tuple(2); Field(new_tail, 0) = build_ocaml_constraint(*v_begin); Field(new_tail, 1) = result; result = new_tail; } CAMLreturn (result); }
I haven't actually tested this since it would require too much rebuilding, but I've written similar code which worked OK. I'm not sure whether "CAMLprim" is in fact necessary, but I don't think it does any harm.
Again, there are a number of functions which should be amended in a similar way: I think that in any C function which uses a caml_alloc* function, every local variable which may point to a value allocated in the ocaml heap should be protected by a CAMLlocal* macro.
--------------------------------------------------------------------------------
3. I've also had problems with ppl_Polyhedron_BHRZ03_widening_assign. Occasionally my compiler locks up with a lot of CPU usage when ppl_Polyhedron_BHRZ03_widening_assign is called. I didn't have any probelms using the H79 widening instead. I'm not sure what's causing this: ppl_Polyhedron_BHRZ03_widening_assign does have the problem with units mentioned in (1) above, but I don't think that should do any damage. It's possible that I have some malformed data structures from (2) which are causing problems.
--------------------------------------------------------------------------------
4. While looking at the code for ppl_Polyhedron_BHRZ03_widening_assign I noticed a bug in ppl_Polyhedron_BHRZ03_widening_assign_with_tokens, which is repeated in all the widening-with-tokens functions:
CAMLprim value ppl_Polyhedron_BHRZ03_widening_assign_with_tokens (value ph1, value ph2, value integer) try { CAMLparam3(ph1, ph2, integer); Polyhedron& pph1 = *p_Polyhedron_val(ph1); Polyhedron& pph2 = *p_Polyhedron_val(ph2); int cpp_int = Val_int(integer); check_int_is_unsigned(cpp_int); unsigned int unsigned_value = cpp_int; pph1.BHRZ03_widening_assign(pph2, &unsigned_value); CAMLreturn(Int_val(unsigned_value)); }
Val_int and Int_val should be interchanged here. The current version will calculate the number of remaining tokens incorrectly.
--------------------------------------------------------------------------------
5. It's not really a bug, but I'm a little confused by the way the code is divided into modules. Ppl_ocaml_globals contains the type definitions for various datatypes, but why does it also contain all the MIP functions? I see that the OCamldoc-generated documentation only contains information about Ppl_ocaml_globals, but Ppl_ocaml is missing, so there's no information available about the types of the polyhedron functions and other things in Ppl_ocaml.
Also, the documentation for the OCaml interface (for example, at
http://www.cs.unipr.it/ppl/Documentation/user/ppl-user-ocaml-interface-0.10-... )
refers to a number of functions such as ppl_reset_timeout which don't actually occur in the interface.
--------------------------------------------------------------------------------
Best wishes,
Kenneth MacKenzie

Kenneth MacKenzie wrote:
I've been using the PPL OCaml interface to carry out some program analysis within a compiler. It's been working pretty well, but I've come across a number of bugs.
Hi Kenneth,
thanks a lot for your detailed report. We will look into these issues in the next few days. We will release PPL 0.10.1 in one week or so: would you like to test a release snapshot to make sure all the problems you reported have been solved? All the best,
Roberto

Kenneth MacKenzie wrote:
I've been using the PPL OCaml interface to carry out some program analysis within a compiler. It's been working pretty well, but I've come across a number of bugs.
- The OCaml 'unit' type has only a single value, denoted (); this is
represented internally by a pointer to a single preallocated value. However, many of the functions in the PPL interface return the wrong value.
[...]
Every function returning a unit value (it looks like there are 509 of them) should look like this. I don't think this bug is very harmful unless one uses unit values in unusual ways.
Kenneth,
can you please let us know how you configured the PPL? The reason is that we obtain a different number of occurrences. This depends on the configure command used, as well as the characteristics of the host machine (i.e., the kind of available floating point support). If you can send your config.log file, this would give us all the information we need. All the best,
Roberto

Kenneth MacKenzie wrote:
Hello there,
I've been using the PPL OCaml interface to carry out some program analysis within a compiler. It's been working pretty well, but I've come across a number of bugs.
Hi Kenneth.
The snapshot with the corrections is now ready: ftp://ftp.cs.unipr.it/pub/ppl/snapshots/ or http://www.cs.unipr.it/ppl/Download/ftp/snapshots/
We would really appreciate if you could download and test it to see if any of the issues you were reporting (or even brand new ones) is still there. Please do not hesitate to come back to us if you see anything suspicious. Here below I briefly comment on the points you reported.
- The OCaml 'unit' type has only a single value, denoted (); this is
represented internally by a pointer to a single preallocated value. However, many of the functions in the PPL interface return the wrong value.
[...]
Every function returning a unit value (it looks like there are 509 of them) should look like this. I don't think this bug is very harmful unless one uses unit values in unusual ways.
This should be fixed now (I counted and corrected 520 occurrences, if I remember well.)
- Certain functions can lead to segmentation errors. Here's a
program which creates a polyhedron and then loops round adding constraints one by one.
This should be fixed too: we are now almost systematic in registering values to the GC ... even when there is no actual need (up to my understanding).
- I've also had problems with ppl_Polyhedron_BHRZ03_widening_assign.
Occasionally my compiler locks up with a lot of CPU usage when ppl_Polyhedron_BHRZ03_widening_assign is called. I didn't have any probelms using the H79 widening instead. I'm not sure what's causing this: ppl_Polyhedron_BHRZ03_widening_assign does have the problem with units mentioned in (1) above, but I don't think that should do any damage. It's possible that I have some malformed data structures from (2) which are causing problems.
In this case I am not sure it was a problem of the OCaml interface.
Depending on the input polyhedra (hence, not easily predictable), the BHRZ03 widening might bump into an exponential computation that is avoided by the H79 widening: it that is the case, you could observe wild variations on the overall computation times. Note that even the opposite case is possible (even though it should occur much less often), since a chain of widening computations does not respect the usual monotonicity properties, so that a more precise widening could result in a less precise final post-fixpoint and computation times become quite unpredictable.
Now that we also have the timeout functions available, I can suggest the following approach:
1) copy the polyhedron ph to be widened to ph_copy; 2) set a timeout; 3) try using the BHRZ03 widening on ph; 4) if the computation stops before the timeout expires, reset the timeout and get rid of the previous copy (now useless); 5) otherwise, if the timeout expires, you will obtain a PPL_timeout_exception; you can then replace the polyhedron ph with the copy you saved in step 1 and re-try using the H79 widening.
We tried this (in C++) and in our context was working fairly well.
The code for using the timeout is similar to the following (apologies for the awfully looking and untested OCaml code ... I never coded in OCaml before):
print_string "Set timeout and use BHRZ03\n"; ppl_set_timeout 100; (* 100 hsec *) try compute_something_using_BHRZ03 ph; ppl_reset_timeout (); print_string "BHRZ03 computation succeeded\n" with | PPL_timeout_exception -> ppl_reset_timeout (); print_string "Timeout expired: retrying using H79\n"; ppl_Polyhedron_swap ph, ph_copy; compute_something_using_H79 ph | _ -> print_string "Unexpected exception\n"
Also see PPL test file interfaces/OCaml/tests/test1.ml, looking for the code below the comment (* Testing timeouts *).
- While looking at the code for
ppl_Polyhedron_BHRZ03_widening_assign I noticed a bug in ppl_Polyhedron_BHRZ03_widening_assign_with_tokens, which is repeated in all the widening-with-tokens functions:
Should be fixed (thanks a lot for the detailed explanation).
- It's not really a bug, but I'm a little confused by the way
the code is divided into modules. Ppl_ocaml_globals contains the type definitions for various datatypes, but why does it also contain all the MIP functions? I see that the OCamldoc-generated documentation only contains information about Ppl_ocaml_globals, but Ppl_ocaml is missing, so there's no information available about the types of the polyhedron functions and other things in Ppl_ocaml.
I have added a note to the manual in this respect. Briefly, since we do not want to force people to install the OCaml tools, we have two manuals: a configuration dependent and a configuration independent one. In the configuration independent one we only list those features that are available no matter what domain instances are selected (when the Ocaml interface is enabled): this also includes MIP_Problem. Hence, I suggest you look to the configuration dependent manual. In order to build it, you should cd into the ppl/doc directory and issue
make ppl-user-configured-ocaml-interface-0.10.1pre10-html
Also note that the Ppl_ocaml_globals module is automatically included in module Ppl_ocaml.
Also, the documentation for the OCaml interface (for example, at
http://www.cs.unipr.it/ppl/Documentation/user/ppl-user-ocaml-interface-0.10-... )
refers to a number of functions such as ppl_reset_timeout which don't actually occur in the interface.
You are right, these were missing. We now have added them (together with a few others).
Let us know how it goes.
Cheers, Enea.
Best wishes,
Kenneth MacKenzie

Enea Zaffanella writes:
The snapshot with the corrections is now ready: ftp://ftp.cs.unipr.it/pub/ppl/snapshots/
Hi Enea,
The problems with the OCaml interface have now gone away (thanks!), and I can confirm that my problem with the ppl_Polyhedron_BHRZ03_widening_assign function has nothing to do with the OCaml interface. I extracted the polyhedra that were causing problems (they have 60 and 81 constraints) and fed them to the C++ version of the widening function. It's now been running for 14 hours without terminating. However, your suggestion of using a timer to escape and use the H79 widening instead seems to work well.
I did have a couple of problems with the snapshot. I changed to the ppl/doc directory and tried
[5~ make ppl-user-configured-ocaml-interface-0.10.1pre10-html
but it failed because it couldn't find something it needed from gmp. This is due to the fact that I had to install gmp in a subdirectory of my home directory, but the makefile was looking in one of the standard directories:
OCAMLDOC_HTML_OPTIONS = \ -I +gmp -I $(top_builddir)/interfaces/OCaml -html
OCAMLDOC_LATEX_OPTIONS = \ -I +gmp -I $(top_builddir)/interfaces/OCaml \ -latex -noheader -notrailer -notoc
I changed the +gmp to the location of my version of gmp and it worked properly. I had other problems for the same reason a while ago and someone added --with-libgmp and --with-libgmpxx-prefix options to the top-level configure script, so presumably these should also be used here.
I also ran "make check", and it failed after 4 hours with
make check-TESTS make[6]: Entering directory `/disk/scratch/ppl-0.10.1pre10/interfaces/OCaml/tests' ./test1: error while loading shared libraries: libgmpxx.so.4: cannot open shared object file: No such file or directory FAIL: test1 ./ppl_ocaml_generated_test: error while loading shared libraries: libgmpxx.so.4: cannot open shared object file: No such file or directory FAIL: ppl_ocaml_generated_test ./test1_opt: error while loading shared libraries: libgmpxx.so.4: cannot open shared object file: No such file or directory FAIL: test1_opt ./ppl_ocaml_generated_test_opt: error while loading shared libraries: libgmpxx.so.4: cannot open shared object file: No such file or directory FAIL: ppl_ocaml_generated_test_opt ====================================== 4 of 4 tests failed Please report to ppl-devel@cs.unipr.it ====================================== make[6]: *** [check-TESTS] Error 1 make[6]: Leaving directory `/disk/scratch/ppl-0.10.1pre10/interfaces/OCaml/tests' make[5]: *** [check-am] Error 2 make[5]: Leaving directory `/disk/scratch/ppl-0.10.1pre10/interfaces/OCaml/tests' make[4]: *** [check-recursive] Error 1 make[4]: Leaving directory `/disk/scratch/ppl-0.10.1pre10/interfaces/OCaml' make[3]: *** [check] Error 2 make[3]: Leaving directory `/disk/scratch/ppl-0.10.1pre10/interfaces/OCaml' make[2]: *** [check-recursive] Error 1 make[2]: Leaving directory `/disk/scratch/ppl-0.10.1pre10/interfaces' make[1]: *** [check] Error 2 make[1]: Leaving directory `/disk/scratch/ppl-0.10.1pre10/interfaces' make: *** [check-recursive] Error 1
Again, it appears that it's not looking in the right place.
Here's my config.log if you need it:

Kenneth MacKenzie wrote:
Enea Zaffanella writes:
The snapshot with the corrections is now ready: ftp://ftp.cs.unipr.it/pub/ppl/snapshots/
Hi Enea,
The problems with the OCaml interface have now gone away (thanks!), and I can confirm that my problem with the ppl_Polyhedron_BHRZ03_widening_assign function has nothing to do with the OCaml interface. I extracted the polyhedra that were causing problems (they have 60 and 81 constraints) and fed them to the C++ version of the widening function. It's now been running for 14 hours without terminating. However, your suggestion of using a timer to escape and use the H79 widening instead seems to work well.
This is good news.
I did have a couple of problems with the snapshot. I changed to the ppl/doc directory and tried
[5~ make ppl-user-configured-ocaml-interface-0.10.1pre10-html
but it failed because it couldn't find something it needed from gmp. This is due to the fact that I had to install gmp in a subdirectory of my home directory, but the makefile was looking in one of the standard directories:
OCAMLDOC_HTML_OPTIONS = \ -I +gmp -I $(top_builddir)/interfaces/OCaml -html
OCAMLDOC_LATEX_OPTIONS = \ -I +gmp -I $(top_builddir)/interfaces/OCaml \ -latex -noheader -notrailer -notoc
I changed the +gmp to the location of my version of gmp and it worked properly. I had other problems for the same reason a while ago and someone added --with-libgmp and --with-libgmpxx-prefix options to the top-level configure script, so presumably these should also be used here.
You are right: we should have used -I @mlgmp_dir@ This is already corrected in the git master branch.
The commit info is available at: http://www.cs.unipr.it/git/gitweb.cgi?p=ppl/ppl.git;a=commit;h=3b959163da9e9...
I also ran "make check", and it failed after 4 hours with
make check-TESTS make[6]: Entering directory `/disk/scratch/ppl-0.10.1pre10/interfaces/OCaml/tests' ./test1: error while loading shared libraries: libgmpxx.so.4: cannot open shared object file: No such file or directory FAIL: test1 ./ppl_ocaml_generated_test: error while loading shared libraries: libgmpxx.so.4: cannot open shared object file: No such file or directory FAIL: ppl_ocaml_generated_test ./test1_opt: error while loading shared libraries: libgmpxx.so.4: cannot open shared object file: No such file or directory FAIL: test1_opt ./ppl_ocaml_generated_test_opt: error while loading shared libraries: libgmpxx.so.4: cannot open shared object file: No such file or directory FAIL: ppl_ocaml_generated_test_opt ====================================== 4 of 4 tests failed Please report to ppl-devel@cs.unipr.it ====================================== make[6]: *** [check-TESTS] Error 1 make[6]: Leaving directory `/disk/scratch/ppl-0.10.1pre10/interfaces/OCaml/tests' make[5]: *** [check-am] Error 2 make[5]: Leaving directory `/disk/scratch/ppl-0.10.1pre10/interfaces/OCaml/tests' make[4]: *** [check-recursive] Error 1 make[4]: Leaving directory `/disk/scratch/ppl-0.10.1pre10/interfaces/OCaml' make[3]: *** [check] Error 2 make[3]: Leaving directory `/disk/scratch/ppl-0.10.1pre10/interfaces/OCaml' make[2]: *** [check-recursive] Error 1 make[2]: Leaving directory `/disk/scratch/ppl-0.10.1pre10/interfaces' make[1]: *** [check] Error 2 make[1]: Leaving directory `/disk/scratch/ppl-0.10.1pre10/interfaces' make: *** [check-recursive] Error 1
Again, it appears that it's not looking in the right place.
This looks strange to me: the message seems to suggest that the system finds the OCaml mlgmp wrapper, but it does not find the C++ wrapper libgmpxx.
I am definitely not an expert of OCaml related builds, but I think that I have read somewhere that OCaml native library wrappers were encoding in their inside the right link options, so that one should not need to issue them each time.
I will need to investigate further, but for the immediate I can imagine two possible explanations :
a) Maybe you did something wrong when compiling the mlgmp wrapper. As said in file interfaces/Ocaml/README.ocaml: =========== In order to install MLGMP you should make sure that GMP_INCLUDES and GMP_LIBDIR are correctly set (these variables are defined at the beginning of Makefile in the MLGMP's root directory). =========== Could it be the case that you did something wrong here?
b) What is the output of the command echo $LD_LIBRARY_PATH on your machine? Does it include the path to your installation place, that is /afs/inf.ed.ac.uk/user/k/kwxm/libraries/lib ?
Let us know if either a) or b) solves the problem.
Cheers, Enea.
Here's my config.log if you need it:
Best wishes,
Kenneth

Enea Zaffanella writes:
[About make check].
This looks strange to me: the message seems to suggest that the system finds the OCaml mlgmp wrapper, but it does not find the C++ wrapper libgmpxx.
I am definitely not an expert of OCaml related builds, but I think that I have read somewhere that OCaml native library wrappers were encoding in their inside the right link options, so that one should not need to issue them each time.
I will need to investigate further, but for the immediate I can imagine two possible explanations :
a) Maybe you did something wrong when compiling the mlgmp wrapper. As said in file interfaces/Ocaml/README.ocaml: =========== In order to install MLGMP you should make sure that GMP_INCLUDES and GMP_LIBDIR are correctly set (these variables are defined at the beginning of Makefile in the MLGMP's root directory). =========== Could it be the case that you did something wrong here?
No, MLGMP's OK.
b) What is the output of the command echo $LD_LIBRARY_PATH on your machine? Does it include the path to your installation place, that is /afs/inf.ed.ac.uk/user/k/kwxm/libraries/lib ?
Let us know if either a) or b) solves the problem.
I have to admit that I'm very confused by this. I don't have LD_LIBRARY_PATH set, and you're correct in suggesting that if I set it to point to the location of my libraries then the test works OK. However, I've been able to compile and link my own programs without the use of LD_LIBRARY_PATH with no problems, and I can also compile your test program without using it. Here are the commands which interfaces/OCcaml/tests/Makefile executes when it's compiling test1:
OCAMLRUNPARAM='l=1M' ocamlc -o test1.cmo -c -I /home/kwxm/libraries/lib -I .. -ccopt -g test1.ml OCAMLRUNPARAM='l=1M' ocamlc -o test1 \ -cc "g++" -I /home/kwxm/libraries/lib -I .. -ccopt -g \ -cclib ../../../src/.libs/libppl.so -cclib ../../../Watchdog/src/.libs/libpwl.so -cclib -lmlgmp -cclib -lmpfr `echo " -lm -L/home/kwxm/libraries/lib -lgmpxx -L/home/kwxm/libraries/lib -lgmp -R/home/kwxm/libraries/lib -R/home/kwxm/libraries/lib " | /bin/sed -e "s/ -R[^ ]*//g" -e "s/ -/ -cclib -/g"` \ ppl_ocaml.cma test1.cmo
Note that the second command, which does the linking, explicitly mentions things like libppl.so and -lgmpxx.
If you run the above commands and then use ldd, you get the following:
ldd test1 linux-gate.so.1 => (0xb7fc4000) libgmpxx.so.4 => not found libgmp.so.3 => /usr/lib/libgmp.so.3 (0xb7f4e000) libppl.so.7 => not found libpwl.so.4 => not found libmpfr.so.1 => /usr/lib/libmpfr.so.1 (0xb7f0b000) ...
So in spite of all the options, it still doesn't know where to find libgmpxx.so. It turns out that if you make a directory containing only libgmpxx.so.4 and point LD_LIBRARY_PATH to it, then test1 still fails because it can't find libppl.so.7, and similarly for libpwl.so.4. Once it's got all of these it works OK though.
I spent some time experimenting and found that I could do the compilation with much simpler commands. To avoid the danger of interacting with my own previously-compiled version of PPL and other libraries, I made a directory called ~/gmp containing libgmp.a and libgmp.so*, together with the files gmp.a, gmp.cma and gmp.cmxa from mlgmp. I can compile test1.ml by saying
ocamlc -c -o test1.cmo -I ~/gmp -I .. test1.ml
This is pretty much the same as what's in the makefile. I think that at this stage it just needs to be able to find the .cma files for the OCaml modules used by test1.
After this, I can link test1 with
ocamlc -o test1 ../ppl_ocaml.cma ~/gmp/gmp.cma test1.cmo \ -cclib -lppl -cclib -lpwl
(instead of using ../ppl_ocaml.cma you can also say -I .. ppl_ocaml.cma, and similarly for gmp)
After this test1 runs successfully.
Note that I don't have to refer to -lgmp or any of the other libraries (but you can't leave out -lppl or -lpwl). If you type "strings ../ppl_ocaml.cma" then at the very end you see some strings which mention stuff like -L/home/kwxm/libraries/lib and -lgmpxx, so I think the ocaml compiler records some of the information that's necessary for the final linking.
[Some time later...]
Ah, now I see that what makes the difference is including gmp.cma in the linking command. If you insert it just after libppl.so in the makefile then everything works OK, and I think most of the other options are unnecessary. I still don't understand exactly what's going on though. :(
Kenneth
PS: my problematic BHRZ03 widening just finished, after 31 hours and 40 minutes. The result was the same as that of the H79 widening.

Kenneth MacKenzie wrote:
Enea Zaffanella writes:
[...snip...]
b) What is the output of the command echo $LD_LIBRARY_PATH on your machine? Does it include the path to your installation place, that is /afs/inf.ed.ac.uk/user/k/kwxm/libraries/lib ?
Let us know if either a) or b) solves the problem.
I have to admit that I'm very confused by this. I don't have LD_LIBRARY_PATH set, and you're correct in suggesting that if I set it to point to the location of my libraries then the test works OK.
Good.
However, I've been able to compile and link my own programs without the use of LD_LIBRARY_PATH with no problems, and I can also compile your test program without using it.
The LD_LIBRARY_PATH environment variable has not much to do with compilation and (compile-time) linking. Rather, it comes into play when you run your program and it needs to link dynamically to a shared library.
Here are the commands which interfaces/OCcaml/tests/Makefile executes when it's compiling test1:
OCAMLRUNPARAM='l=1M' ocamlc -o test1.cmo -c -I /home/kwxm/libraries/lib -I .. -ccopt -g test1.ml OCAMLRUNPARAM='l=1M' ocamlc -o test1 \ -cc "g++" -I /home/kwxm/libraries/lib -I .. -ccopt -g \ -cclib ../../../src/.libs/libppl.so -cclib ../../../Watchdog/src/.libs/libpwl.so -cclib -lmlgmp -cclib -lmpfr `echo " -lm -L/home/kwxm/libraries/lib -lgmpxx -L/home/kwxm/libraries/lib -lgmp -R/home/kwxm/libraries/lib -R/home/kwxm/libraries/lib " | /bin/sed -e "s/ -R[^ ]*//g" -e "s/ -/ -cclib -/g"` \ ppl_ocaml.cma test1.cmo
Note that the second command, which does the linking, explicitly mentions things like libppl.so and -lgmpxx.
If you run the above commands and then use ldd, you get the following:
ldd test1 linux-gate.so.1 => (0xb7fc4000) libgmpxx.so.4 => not found libgmp.so.3 => /usr/lib/libgmp.so.3 (0xb7f4e000) libppl.so.7 => not found libpwl.so.4 => not found libmpfr.so.1 => /usr/lib/libmpfr.so.1 (0xb7f0b000) ...
That is ok : it can't find libgmpxx.so.4 because the corresponding directory is not listed in LD_LIBRARY_PATH.
On the other hand, it can't find the ppl and pwl .so files because these libraries have not been installed yet (and they too are in a directory which is not listed in LD_LIBRARY_PATH).
In fact, when we *run* the OCaml tests, the command that gets actually executed looks like the following (to be run from path interfaces/Ocaml/tests):
../../../libtool --mode=execute -dlopen ../../../src/libppl.la -dlopen ../../../Watchdog/src/libpwl.la ./test1
Note that here we are dlopen-ing the just built ppl and pwl libraries, because we want to link with *THESE* libraries and not any other previously installed ppl library (which might be a different version).
On the other hand, we do not dl-open libgmpxx, because this is the library which is installed in your system ... i.e., this is the one that should be normally accessible using ld and LD_LIBRARY_PATH.
So in spite of all the options, it still doesn't know where to find libgmpxx.so. It turns out that if you make a directory containing only libgmpxx.so.4 and point LD_LIBRARY_PATH to it, then test1 still fails because it can't find libppl.so.7, and similarly for libpwl.so.4. Once it's got all of these it works OK though.
I spent some time experimenting and found that I could do the compilation with much simpler commands. To avoid the danger of interacting with my own previously-compiled version of PPL and other libraries, I made a directory called ~/gmp containing libgmp.a and libgmp.so*, together with the files gmp.a, gmp.cma and gmp.cmxa from mlgmp. I can compile test1.ml by saying
ocamlc -c -o test1.cmo -I ~/gmp -I .. test1.ml
This is pretty much the same as what's in the makefile. I think that at this stage it just needs to be able to find the .cma files for the OCaml modules used by test1.
After this, I can link test1 with
ocamlc -o test1 ../ppl_ocaml.cma ~/gmp/gmp.cma test1.cmo \ -cclib -lppl -cclib -lpwl
(instead of using ../ppl_ocaml.cma you can also say -I .. ppl_ocaml.cma, and similarly for gmp)
After this test1 runs successfully.
Note that I don't have to refer to -lgmp or any of the other libraries (but you can't leave out -lppl or -lpwl). If you type "strings ../ppl_ocaml.cma" then at the very end you see some strings which mention stuff like -L/home/kwxm/libraries/lib and -lgmpxx, so I think the ocaml compiler records some of the information that's necessary for the final linking.
[Some time later...]
Ah, now I see that what makes the difference is including gmp.cma in the linking command. If you insert it just after libppl.so in the makefile then everything works OK, and I think most of the other options are unnecessary. I still don't understand exactly what's going on though. :(
That is interesting info. However, since you are not definitely sure that the thing above will always work and given that we are near to the release of ppl-0.10.1, I prefer to leave things as they are (having more link options than strictly needed should make no arm).
Kenneth
PS: my problematic BHRZ03 widening just finished, after 31 hours and 40 minutes. The result was the same as that of the H79 widening.
There is nothing really surprising ... that's life.
The BHRZ03 widening is meant to try and apply a whole range of heuristics to improve the precision of the H79 widening. It might fail to achieve such an improvement, in which case it falls back to the H79 widening.
As far as efficiency is concerned, as said earlier, whenever convex polyhedra come into play you need to keep an eye on the possibility of bumping into exponential behavior. Fortunately, the PPL library provides you with the tools (timeout and exception safety) needed to first identify the problem and then let the application skip to an alternative plan.
Cheers, Enea.
participants (3)
-
Enea Zaffanella
-
Kenneth MacKenzie
-
Roberto Bagnara