Skip to content

Fix compilation on macOS#189

Merged
shwestrick merged 1 commit into
MPLLang:mainfrom
waterlens:fix-macos-compilation
Jul 1, 2024
Merged

Fix compilation on macOS#189
shwestrick merged 1 commit into
MPLLang:mainfrom
waterlens:fix-macos-compilation

Conversation

@waterlens

Copy link
Copy Markdown
Contributor

I followed the instructions in #181.
The required rand48_r series functions were re-implemented as it is a GNU extension and Linux-only.
The call to getrusage(RUSAGE_THREAD, ...) is also replaced on this platform.

@shwestrick

Copy link
Copy Markdown
Collaborator

This is great! Thank you @waterlens for working on this 🎉

I ran these commands on my Mac (8-core M2, 2022, Monterey 12.5). I was able to compile a few examples and benchmarks with reasonable speedups. As far as I can tell right now, everything seems to be working!

$ brew install make
$ brew install gmp 
$ gmake WITH_GMP_DIR=/opt/homebrew/Cellar/gmp/6.3.0

$ cd examples
$ gmake primes
$ bin/primes @mpl procs 4 --

I've also confirmed that existing compilation (on x86 Ubuntu 20.04) still seems to work fine.

(Something to keep in mind: we'll eventually need to do some more thorough testing on MacOS. The runtime system and scheduler were designed with x86-TSO in mind, and it's possible that there are some unexpected data races lurking under the weaker arm memory model.)

@MatthewFluet, if you have a chance, I'd love to hear your thoughts on this PR. Perhaps all of the MacOS-specific elements should live in runtime/platform/..., with the appropriate wrappers?

@waterlens

Copy link
Copy Markdown
Contributor Author

Glad to know that it works. Yeah, it's interesting to see if the runtime can function with a weaker memory model. Thank you for reminding me about the directory for platform-specfic code. I think we could place the code in runtime/platform/darwin.h?

@shwestrick

Copy link
Copy Markdown
Collaborator

Yes, I think runtime/platform/... is a good place for things like getrusage_thread.h and rand48.h, and these could be loaded by runtime/platform/darwin.h.

By the way, just curious, where does this implementation of rand48 come from? Perhaps there is a standard open-source implementation?

@waterlens

Copy link
Copy Markdown
Contributor Author

As far as I know, the only standard open-source implementation is at glibc. My implementation refers to both glibc and musl.

But I just realized this may involve GPL license related issues. Instead of re-implementing GNU extension for other platforms, I think it would be preferable to switch from drand48_r to another random number generator. What do you think about it?

@MatthewFluet

Copy link
Copy Markdown
Collaborator

A suggestion is to add a (trivial) implementation of rusage_thread to runtime/platform/linux.c (that simply does getrusage (RUSAGE_THREAD, &ru_result);) and avoid the

#ifdef __MACH__
  getrusage_thread (&ru_result);
#else
  getrusage (RUSAGE_THREAD, &ru_result);
#endif

dance whenever the current thread's rusage is requested.

I see the pthread_yield deprecation on my Linux systems (Fedora 39/40), so maybe it suffices to just switch to sched_yield for all platforms, rather than just doing a #define pthread_yield() sched_yield() for MacOS only.

Finally, why the additional function declarations in c-main.h?

@waterlens

waterlens commented Jun 13, 2024

Copy link
Copy Markdown
Contributor Author

The forward declarations are for functions surrounded by MLTON_GC_INTERNAL_FUNCS. I think the mpl compiler attempts to compile the user program without defining this macro, but some of those functions are called in c-main.h. Therefore it always produces compilation error when using mpl. After that, I added it into the c-main.h file as a workaround.

@shwestrick

Copy link
Copy Markdown
Collaborator

I played with this a little and it seems like the only forward declaration that I need is Parallel_run:

diff --git a/include/c-main.h b/include/c-main.h
index 698656c2c..6826e5829 100644
--- a/include/c-main.h
+++ b/include/c-main.h
@@ -14,10 +14,6 @@
 #include "c-common.h"

 void Parallel_run (void);
-int32_t Proc_processorNumber (GC_state s);
-void Proc_waitForInitialization (GC_state s);
-void HH_EBR_enterQuiescentState(GC_state s);
-void relayerLoop(GC_state s);

With the above change everything still seems to work properly.

If I remove the Parallel_run forward declaration from c-main.h, then I get the following error when trying to compile fib.dbg from examples/

bin/fib.dbg.1.c:4502:13: error: conflicting types for 'Parallel_run'
PUBLIC void Parallel_run () {
            ^
bin/fib.dbg.1.c:4498:1: note: previous implicit declaration is here
MLtonMain (8, (Word32)(0x2554275Aull), 536, FALSE, PROFILE_NONE, FALSE, /* initGlobals_0 */ 1539)
^
/Users/shwestrick/proj/mpl/macos/build/lib/mlton/include/c-main.h:125:3: note: expanded from macro 'MLtonMain'
  MLtonThreadFunc(ml)                                                   \
  ^
/Users/shwestrick/proj/mpl/macos/build/lib/mlton/include/c-main.h:119:5: note: expanded from macro 'MLtonThreadFunc'
    Parallel_run ();                                                    \
    ^

Perhaps this is due to a difference between gcc and clang? I'm guessing here, but it seems like Parallel_run has always been an implicit declaration within MLtonMain, and perhaps gcc (on Linux) has silently agreed to it but clang (on Mac) isn't happy.

@shwestrick

shwestrick commented Jun 13, 2024

Copy link
Copy Markdown
Collaborator

Confirmed: on main branch of MPL (62504e0), if I set CC := clang (and AR := ar and RANLIB := ranlib) and compile on x86 Ubuntu, then I get the same error for Parallel_run.

So, it does appear to be a difference between gcc and clang. I think previously we were just lucky that gcc decided not to complain.

TLDR: I think the forward declaration of Parallel_run in c-main.h is fine, but we don't seem to need the other forward declarations. I'd recommend this:

diff --git a/include/c-main.h b/include/c-main.h
index 698656c2c..6826e5829 100644
--- a/include/c-main.h
+++ b/include/c-main.h
@@ -14,10 +14,6 @@
 #include "c-common.h"

 void Parallel_run (void);
-int32_t Proc_processorNumber (GC_state s);
-void Proc_waitForInitialization (GC_state s);
-void HH_EBR_enterQuiescentState(GC_state s);
-void relayerLoop(GC_state s);

@waterlens

waterlens commented Jun 14, 2024

Copy link
Copy Markdown
Contributor Author

The inconsistency looks weird.

If I understand correctly, the only file included in the generated C source is c-main.h, and it has such an including relation

/* c-main.h */
#define MLTON_GC_INTERNAL_TYPES
#define MLTON_GC_INTERNAL_BASIS
#include "platform.h"

/* platform.h */
#include "gc.h"

/* gc.h */
#include "gc/processor.h"

/* gc/processor.h */
#if (defined (MLTON_GC_INTERNAL_FUNCS))
int32_t Proc_processorNumber (GC_state s);
void Proc_waitForInitialization (GC_state s);
void Proc_signalInitialization (GC_state s);
bool Proc_isInitialized (GC_state s);
#endif /* (defined (MLTON_GC_INTERNAL_FUNCS)) */

It looks like the declarations of called functions are not visible when mpl is invoking the C compiler because the reason I mentioned above.
I manually checked the preprocessed source file, using the commands provided by mpl -verbose 1 ..., and confirmed that there are no necessary declarations of those functions in the file passed to clang.

And that seems to explain why I got the following errors

MLton [mpl] 20240612.030853-g1c34035f1-dirty starting
   Compile SML starting
   Compile SML finished in 1.66 + 0.76 (31% GC)
   Compile and Assemble starting
   Compile and Assemble finished in 0.00 + 0.00 (0% GC)
   clang -c -DDETECT_ENTANGLEMENT=1 \
       -I/Users/waterlens/Projects/mpl/build/lib/mlton/targets/self/include \
       -std=gnu11 -fno-common -O1 -fno-strict-aliasing \
       -foptimize-sibling-calls -w \
       -I/Users/waterlens/Projects/mpl/build/lib/mlton/include \
       -I/opt/homebrew//include -arch arm64 -o \
       /var/folders/8t/vs_sxd5j4ydb0723h38z_r680000gn/T/file5Asu77.o \
       /var/folders/8t/vs_sxd5j4ydb0723h38z_r680000gn/T/filedRg6AT.1.c
/var/folders/8t/vs_sxd5j4ydb0723h38z_r680000gn/T/filedRg6AT.1.c:4498:1: error: call to undeclared function 'Proc_processorNumber'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
MLtonMain (8, (Word32)(0x25B34459ull), 536, FALSE, PROFILE_NONE, FALSE, /* initGlobals_0 */ 1539)
^
/Users/waterlens/Projects/mpl/build/lib/mlton/include/c-main.h:129:3: note: expanded from macro 'MLtonMain'
  MLtonThreadFunc(ml)                                                   \
  ^
/Users/waterlens/Projects/mpl/build/lib/mlton/include/c-main.h:86:22: note: expanded from macro 'MLtonThreadFunc'
      uint32_t num = Proc_processorNumber (s)                           \
                     ^
/var/folders/8t/vs_sxd5j4ydb0723h38z_r680000gn/T/filedRg6AT.1.c:4498:1: note: did you mean 'Parallel_processorNumber'?
/Users/waterlens/Projects/mpl/build/lib/mlton/include/c-main.h:129:3: note: expanded from macro 'MLtonMain'
  MLtonThreadFunc(ml)                                                   \
  ^
/Users/waterlens/Projects/mpl/build/lib/mlton/include/c-main.h:86:22: note: expanded from macro 'MLtonThreadFunc'
      uint32_t num = Proc_processorNumber (s)                           \
                     ^
/Users/waterlens/Projects/mpl/build/lib/mlton/include/gc/parallel.h:13:16: note: 'Parallel_processorNumber' declared here
PRIVATE Word32 Parallel_processorNumber (void);
               ^
/var/folders/8t/vs_sxd5j4ydb0723h38z_r680000gn/T/filedRg6AT.1.c:4498:1: error: call to undeclared function 'Proc_processorNumber'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
MLtonMain (8, (Word32)(0x25B34459ull), 536, FALSE, PROFILE_NONE, FALSE, /* initGlobals_0 */ 1539)
^
/Users/waterlens/Projects/mpl/build/lib/mlton/include/c-main.h:129:3: note: expanded from macro 'MLtonMain'
  MLtonThreadFunc(ml)                                                   \
  ^
/Users/waterlens/Projects/mpl/build/lib/mlton/include/c-main.h:106:7: note: expanded from macro 'MLtonThreadFunc'
  if (Proc_processorNumber (s) == 0) {                                  \
      ^
/var/folders/8t/vs_sxd5j4ydb0723h38z_r680000gn/T/filedRg6AT.1.c:4498:1: error: call to undeclared function 'Proc_waitForInitialization'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
/Users/waterlens/Projects/mpl/build/lib/mlton/include/c-main.h:129:3: note: expanded from macro 'MLtonMain'
  MLtonThreadFunc(ml)                                                   \
  ^
/Users/waterlens/Projects/mpl/build/lib/mlton/include/c-main.h:115:5: note: expanded from macro 'MLtonThreadFunc'
    Proc_waitForInitialization(s);                                      \
    ^
/var/folders/8t/vs_sxd5j4ydb0723h38z_r680000gn/T/filedRg6AT.1.c:4498:1: error: call to undeclared function 'HH_EBR_enterQuiescentState'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
/Users/waterlens/Projects/mpl/build/lib/mlton/include/c-main.h:129:3: note: expanded from macro 'MLtonMain'
  MLtonThreadFunc(ml)                                                   \
  ^
/Users/waterlens/Projects/mpl/build/lib/mlton/include/c-main.h:116:5: note: expanded from macro 'MLtonThreadFunc'
    HH_EBR_enterQuiescentState(s);                                      \
    ^
/var/folders/8t/vs_sxd5j4ydb0723h38z_r680000gn/T/filedRg6AT.1.c:4498:1: error: call to undeclared function 'relayerLoop'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
/Users/waterlens/Projects/mpl/build/lib/mlton/include/c-main.h:129:3: note: expanded from macro 'MLtonMain'
  MLtonThreadFunc(ml)                                                   \
  ^
/Users/waterlens/Projects/mpl/build/lib/mlton/include/c-main.h:117:5: note: expanded from macro 'MLtonThreadFunc'
    relayerLoop(s);                                                     \
    ^
/var/folders/8t/vs_sxd5j4ydb0723h38z_r680000gn/T/filedRg6AT.1.c:4498:1: error: call to undeclared function 'Proc_waitForInitialization'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
/Users/waterlens/Projects/mpl/build/lib/mlton/include/c-main.h:129:3: note: expanded from macro 'MLtonMain'
  MLtonThreadFunc(ml)                                                   \
  ^
/Users/waterlens/Projects/mpl/build/lib/mlton/include/c-main.h:120:5: note: expanded from macro 'MLtonThreadFunc'
    Proc_waitForInitialization (s);                                     \
    ^
6 errors generated.
   MLton [mpl] 20240612.030853-g1c34035f1-dirty raised: Fail: Process.waits: child 11047 failed with exit status 1
MLton [mpl] 20240612.030853-g1c34035f1-dirty raised in 1.73 + 0.76 (30% GC)

I tried it in a clean docker image and got the similar errors.

@MatthewFluet

Copy link
Copy Markdown
Collaborator

I'm also now getting the undeclared function errors on Linux with gcc. I certainly wasn't a couple of weeks ago when I submitted #185 and #188. Something that has changed in that time is that I upgraded my machines from Fedora 39 (gcc 13.3.1) to Fedora 40 (gcc 14.1.1); and from https://gcc.gnu.org/gcc-14/porting_to.html#implicit-function-declaration, we see that it is now an error to call a function that has not been declared.

I think that the right thing to do would be to properly expose those functions in gc.h (i.e., not guard them with a #if (defined (MLTON_GC_INTERNAL_FUNCS))).

@shwestrick

Copy link
Copy Markdown
Collaborator

Aha! Nice catch Matthew. I was having trouble reproducing, but after updating clang I also was able to reproduce these errors on mac.

shwestrick added a commit that referenced this pull request Jun 18, 2024
This is a relic of an old lock-based synchronization strategy for
hierarchical heaps which was deprecated a few years ago (deprecated
since 2019; see e.g. e0404a7).

IIRC, the deprecated strategy associated a rwlock with each
hierarchical heap, and used a randomized backoff algorithm to reduce
contention. The randomization came from `s->tlsObjects.drand48_data`
and `drand48_r(...)` which are no longer used.

One benefit of removing these now is that #189 is easier. The best
portability is no code at all.
@shwestrick shwestrick mentioned this pull request Jun 18, 2024
@shwestrick

Copy link
Copy Markdown
Collaborator

But I just realized this may involve GPL license related issues. Instead of re-implementing GNU extension for other platforms, I think it would be preferable to switch from drand48_r to another random number generator. What do you think about it?

@waterlens I looked into this and noticed that drand48 can be removed entirely. See #191. IMO removing it is the best option because we're not using it anyway! If you'd like, we could incorporate the changes of #191 into this PR. Or, I'm happy to merge #191 into main and then you could rebase on top of it. Let me know which you prefer.

I think that the right thing to do would be to properly expose those functions in gc.h (i.e., not guard them with a #if (defined (MLTON_GC_INTERNAL_FUNCS))).

I agree with Matthew. This can be done in the appropriate .h files (processor.h, hierarchical-heap-ebr.h, and handler.h)

@waterlens

Copy link
Copy Markdown
Contributor Author

I prefer to merge the changes in #191 first, then I will edit this PR, removing the rand48 stuff and making the functions used in c-main.h visible :)

@shwestrick

Copy link
Copy Markdown
Collaborator

Sounds good! Just merged #191.

@waterlens waterlens force-pushed the fix-macos-compilation branch from 1c34035 to ec5d271 Compare June 24, 2024 11:27
@waterlens

Copy link
Copy Markdown
Contributor Author

I edited some files to change the guard from looking at MLTON_GC_INTERNAL_FUNCS to checking MLTON_GC_INTERNAL_BASIS. I'm not sure if it would satisfy the original purpose of that macro, so welcome to give me more suggestions on it.

Or maybe these guards should just be removed? It will look like a bit of inconsistent for me because most functions in other files are put in such guards.

@shwestrick

Copy link
Copy Markdown
Collaborator

Looking it over, the usage of these guards throughout the runtime codebase is definitely inconsistent. I think it's about time we do some cleanup of the runtime system, but for this PR I say: let's not worry about it. Putting these under MLTON_GC_INTERNAL_BASIS seems okay to me for now.

I'll do some final testing but then I think we're probably good to merge.

@shwestrick shwestrick merged commit a54ea0e into MPLLang:main Jul 1, 2024
@shwestrick shwestrick mentioned this pull request Jul 1, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants