6
votes

I have a large C project which must be compiled with gcc. So I link the main executable with a file like this:

#include <HsFFI.h>

static void my_enter(void) __attribute__((constructor));
static void my_enter(void) {
  static char *argv[] = { "Pointer.exe", 0 };
  //static char *argv[] = { "Pointer.exe", "+RTS", "-N", "-p", "-s", "-h", "-i0.1", "-RTS", 0 };
  static char **argv_ = argv;
  static int argc = 1; // 8 for profiling
  hs_init(&argc, &argv_);
  //hs_init_with_rtsopts(&argc, &argv_);
}

static void my_exit(void) __attribute__((destructor));
static void my_exit(void) { hs_exit(); }

which works as expected - the GHC runtime system gets initialized and I'm able to use the FFI to call Haskell code from C.

I then attempt to enable profiling (mainly for stack traces with Debug.Trace) and code coverage (HPC) using the "+RTS", "-N", "-p", "-s", "-h", "-i0.1", "-RTS" flags on the line commented out above. However I get error messages about threading and profiling during initialization:

Pointer.exe: the flag -N requires the program to be built with -threaded
Pointer.exe: the flag -p requires the program to be built with -prof
Pointer.exe: Most RTS options are disabled. Use hs_init_with_rtsopts() to enable them.
Pointer.exe: newBoundTask: RTS is not initialised; call hs_init() first

I configured the cabal package with:

"--enable-library-profiling"
"--enable-executable-profiling"
"--enable-shared"
"--enable-tests"
"--enable-coverage"

which has properly given me stack traces and code coverage when running executables compiled as part of the cabal project.

If I try to use hs_init_with_rtsopts as recommended by the error message, I get a SIGSEGV during the GHC rts initialization:

Using host libthread_db library "/usr/lib/libthread_db.so.1".

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff6a2d0ca in strlen () from /usr/lib/libc.so.6
(gdb) bt
#0  0x00007ffff6a2d0ca in strlen () from /usr/lib/libc.so.6
#1  0x00007ffff798c5f6 in copyArg (
    arg=0x657372615062696c <error: Cannot access memory at address 0x657372615062696c>) at rts/RtsFlags.c:1684
#2  0x00007ffff798c679 in copyArgv (argc=8, argv=0x555555554cee) at rts/RtsFlags.c:1696
#3  0x00007ffff798dbe2 in setFullProgArgv (argc=<optimized out>, argv=<optimized out>) at rts/RtsFlags.c:1780
#4  0x00007ffff798e773 in hs_init_ghc (argc=0x555555756090 <argc>, argv=0x5555557560a0 <argv>, rts_config=...)
    at rts/RtsStartup.c:162
#5  0x00007ffff798e7cc in hs_init_with_rtsopts (argc=<optimized out>, argv=<optimized out>)
    at rts/RtsStartup.c:121
#6  0x0000555555554c7d in __libc_csu_init ()
#7  0x00007ffff69cc59f in __libc_start_main () from /usr/lib/libc.so.6
#8  0x0000555555554b29 in _start ()

So how can I enable runtime profiling from a program compiled with gcc?

1
Is the C code copy&pasted from your real program? In particular are you really sure you included both the & and _ around argv in hs_init_with_rtsopts(&argc, &argv_)? It looks incompatible with your gdb output.Reid Barton
For threading and profiling, you will need to link against the threaded and profiled version of the RTS (HSrts_thr_p).Reid Barton
I was linking with -lHSrts-ghc7.10.2. I'll try using HSrts_thr_p now.cronburg
You're right - I was missing the _ when the SIGSEGV happens.cronburg

1 Answers

1
votes

So the segfault was due to a typo which was not included in the question. Sneaky!

To enable threading and profiling and so on you must link your final program against the appropriate RTS flavor. This is one effect of GHC's -prof flag, and the only effect of its -threaded flag, and various other flags like -debug.

The RTS flavors are in different libraries with names of the form

libHSrts.a           libHSrts-ghc7.8.4.so        (vanilla)
libHSrts_debug.a     libHSrts_debug-ghc7.8.4.so  (debug)
libHSrts_thr.a       libHSrts_thr-ghc7.8.4.so    (threaded)
libHSrts_p.a         -                           (profiling)
libHSrts_thr_p.a     -                           (threaded+profiling)
libHSrts_l.a         libHSrts_l-ghc7.8.4.so      (eventlog)
...

On the left are static libraries; on the right are dynamic libraries, whose library names include the GHC version to make it easier for the runtime dynamic loader to find the correct version if you have multiple versions of GHC installed. You can see the full list for your GHC installation under "RTS ways" in ghc --info.

There are no dynamic profiling libraries installed by default but I think there is no fundamental problem with having them and you can configure the GHC build system to build them. (They are not especially useful now because ghci does not support profiling, though that is hopefully changing very soon.)