Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Alternate GC hooking into Julia GC. #2092

Merged
merged 1 commit into from
Aug 2, 2018
Merged

Conversation

rbehrends
Copy link
Contributor

@rbehrends rbehrends commented Jan 17, 2018

This is the GAP side aspects of the work for making the Julia GC work with GAP.

The modified version of Julia with conservative stack scanning lives in the rb/gc-extensions branch at https://github.com/rbehrends/julia and is tracked via this pull request.

To do list for the integration:

Checklist

  • Write generic alternate GC implementation.
  • Modify build system to allow for enabling it from configure.
  • Support conservative stackscanning in Julia.
  • Make that GC suitable for inclusion in Julia.
    Subgoals:
    • Refactor API.
    • Separate out code into separate files, with only hooks remaining.
    • Rewrite treaps for pointers to live outside bigval_t struct.
    • bigval_t allocation hooks.
    • Allow hooking custom root scanners.
    • Support (conservative) tracing of task stacks.
    • Public interface for custom mark/sweep functions.
    • Export necessary functionality from Julia's src/gc.{h,c}.
    • Option: support a jl_value_from_interior_ptr(void *p) directly?
    • Performance regression tests: ensure Julia is not affected.
    • Functionality regression tests: ensure Julia changes don't break
      the API.
  • Fix remaining bugs and add missing functionality in GC/Julia interop.
    Subgoals:
    • Non-hackish mark routines to support tracing GAP objects.
    • Under rare circumstances, small blocks aren't identified properly
      through interior pointers.
    • Look into write barrier implementation (jl_gc_wb() vs.
      jl_gc_wb_back()).
    • Add support for GAP finalizers (used by various packages)
    • Implement jl_task_root_scanner_hook
    • Add HPC-GAP support (e.g. move some globals into GAPState; possibly get rid of JuliaTLS; ...)
  • Complete hooking the Julia GC into GAP.

Building the system:

Build Julia from the rb/gc-extensions branch as usual, say in directory /julia/root/dir. Then build GAP from this PR (resp. the alt-gc branch) as follows (don't forget the final usr in the path passed to --with-julia):

./configure --with-gc=julia --with-julia=/julia/root/dir/usr
make

Now you should be able to start GAP. Be warned, garbage collections are currently suppressed, and if one happens anyway, it'll crash. This is now being worked on.

@fingolfin
Copy link
Member

Thanks @rbehrends ! Would you please consider rebasing this PR, to get rid of those merges? That'd make it a tad easier to look at this on a per-commit level.

@rbehrends
Copy link
Contributor Author

I can do that. There's a certain irony to the fact that I had used merges to add structure to the changes, but I agree that as GitHub does not deal with merges well, that may have inadvertently resulted in the opposite effect.

@fingolfin
Copy link
Member

To be honest, I don't see how the two merges in your PR add structure in a meaningful way... Anyway, so far this PR is pretty small, I think we are fine rebasing it.

@markuspf markuspf added the do not merge PRs which are not yet ready to be merged (e.g. submitted for discussion, or test results) label Jan 17, 2018
@codecov
Copy link

codecov bot commented Jan 18, 2018

Codecov Report

Merging #2092 into master will decrease coverage by <.01%.
The diff coverage is n/a.

@@            Coverage Diff             @@
##           master    #2092      +/-   ##
==========================================
- Coverage   75.41%   75.41%   -0.01%     
==========================================
  Files         478      478              
  Lines      241578   241578              
==========================================
- Hits       182192   182190       -2     
- Misses      59386    59388       +2
Impacted Files Coverage Δ
src/gasman.h 94.87% <ø> (ø) ⬆️
src/weakptr.c 97.04% <ø> (ø) ⬆️
hpcgap/lib/hpc/stdtasks.g 63.93% <0%> (-0.52%) ⬇️

@fingolfin
Copy link
Member

Rebased and squashed version is here: https://github.com/fingolfin/gap/tree/mh/alt-gc

src/alt_gc.c Outdated
@@ -0,0 +1,329 @@
/****************************************************************************
**
*W boehm_gc.c
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be alt_gc.c

Though I don't quite see why we need the file alt_c.c in the first place?

src/julia_gc.c Outdated
@@ -0,0 +1,641 @@
/****************************************************************************
**
*W boehm_gc.c
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be julia_gc.c; and the next few lines should be adjusted, too.

src/julia_gc.c Outdated

enum {
NTYPES = 256
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps we should resurrect #1700 to get this constant (but with a better name) into a header file, so all GCs can share it.

src/julia_gc.c Outdated
NTYPES = 256
};

TNumInfoBags InfoBags [ NTYPES ];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

InfoBags is another function which all GCs will share, so this, too, is something we can perhaps move into a shared header. I've thought about calling that bags.h, and moving a considerable part of gasman.h into that. Thoughts?

src/julia_gc.c Outdated
void InitFreeFuncBag(UInt type, TNumFreeFuncBags finalizer_func)
{
TabFreeFuncBags[type] = finalizer_func;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TabFreeFuncBags and InitFreeFuncBag is also something that perhaps all GCs want to share (in theory, some memory manager might want to customize it; but if that happens, we can still think about a scheme to make it possible; no need to duplicate code until then, I'd say...)

src/julia_gc.c Outdated
InfoBags[old_type].sizeAll -= size;
InfoBags[new_type].sizeAll += size;
}
#endif
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note to self: factor out the above statistics code, too

src/julia_gc.c Outdated
// Master pointers require one word of memory.
void *result = (void *) jl_gc_alloc(JuliaTLS,
sizeof(void *), datatype_mptr);
return result;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was wondering whether it would make more sense for Boehm and Julia GC to store at lest the type and flags (but possibly also the size) inside the master point instead? This way, querying the type of an object requires on indirection less.

src/julia_gc.c Outdated
*/
if (size == 0)
alloc_size++;
/* While we use the Boehm GC without the "all interior pointers"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment seems to be Boehm GC specific...

src/julia_gc.c Outdated
/* get type and old size of the bag */
type = header->type;
flags = header->flags;
old_size = header->size;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does Julia GC offer a function similar to GC_size? If no, perhaps one could/should add one? (Small allocations seem to come from pools, where the allocation size should thus be known; big allocations seem to store the size in struct bigval_t -- but of course I only scratched the surface of that code, so what I just said may very well be just nonsense)

src/julia_gc.c Outdated

/*****************************************************************************
** The following functions are not required respectively supported, so empty
** implementations are provided
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's just no true ... :-)

src/julia_gc.c Outdated
@@ -456,6 +456,7 @@ UInt CollectBags (
UInt full )
{
// HOOK: perform a full collection
jl_gc_collect(1);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not jl_gc_collect(full);?

@fingolfin
Copy link
Member

FYI, we just updated this PR branch with a force push, so if anybody here was/is using that, you may need to take care when updating that branch. News: it was rebased, history was squashed, src/alt_gc.c removed, and clang-format run on the code. More actual work will follow.

@fingolfin fingolfin force-pushed the alt-gc branch 2 times, most recently from cddeeeb to 912be10 Compare May 11, 2018 13:14
src/boehm_gc.c Outdated
}
else if (new_size < old_size) {
memset(DATA(header) + new_size, 0, old_size - new_size);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a tiny improvement for Boehm which we could port over to master right away.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, see PR #2455

src/julia_gc.c Outdated
#include "julia.h"
#include "gcext.h"

extern jl_value_t *(jl_gc_alloc)(jl_ptls_t ptls, size_t sz, void * ty);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is from julia_internal.h -- if this is internal, it probably is so for a good reason. So I guess we must ask them to make it public; or add a gcext specific wrapper for it; or find a way to avoid it?

src/julia_gc.c Outdated
bagContents2 = ((char *)bagContents) + sizeof(BagHeader);
bag = (Bag)&bagContents2;
TabFreeFuncBags[TNUM_BAG(bag)](bag);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function is not used. Are there plans to do so?

src/julia_gc.c Outdated
**
** Allocate memory for a new bag.
**
** 'AllocateBagMemory' is an auxiliary routine for the Boehm GC that
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should replace or remove Boehm GC here.

src/julia_gc.c Outdated
** Allocate memory for a new bag.
**
** 'AllocateBagMemory' is an auxiliary routine for the Boehm GC that
** allocates memory from the appropriate pool. 'gc_type' is -1 if all words
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

gc_type == type? Uhh, but below, it seems to actually be a TNUM?!

src/julia_gc.c Outdated
static void * JCache;
static void * JSp;
static size_t max_pool_obj_size;
static size_t bigval_startoffset;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please consistently use CamelCase for global vars, as that makes it easier to recognize them at a glance .

src/julia_gc.c Outdated

// copy data and update the masterpointer
src = PTR_BAG(bag);
memcpy(DATA(header), src, old_size < new_size ? old_size : new_size);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

even simpler would be to copy *everything, including the BagHeader, and then only update header->size

src/julia_gc.c Outdated
// Master pointers require one word of memory.
void * result =
(void *)jl_gc_alloc(JuliaTLS, sizeof(void *), datatype_mptr);
memset(result, 0, sizeof(void *));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This memset call is not necessary here. And at this point, perhaps we should just merge this function into `NewBag?

src/julia_gc.c Outdated
UInt CollectBags(UInt size, UInt full)
{
// HOOK: perform a full collection
jl_gc_collect(1);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not jl_gc_collect(full);?

src/julia_gc.c Outdated
datatype_bag = jl_new_foreign_type(jl_symbol("BagInner"), Module,
jl_any_type, JMarkBag, NULL, 1, 0);
datatype_largebag = jl_new_foreign_type(
jl_symbol("BagInner"), Module, jl_any_type, JMarkBag, NULL, 1, 1);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, so two datatypes both use BagInner as their name. Perhaps this second one should be BagLargeInner?

Or perhaps it should be MasterPointer (or MPtr), Bag, LargeBag, matching the C variable names?

@fingolfin
Copy link
Member

I recently wondered why we need the treap code, and it seems we don't: rbehrends#9 removes it, and seems to work just fine (at least in the GAP test suite). If you know of reasons why having it is beneficial, let's discuss it on that PR.

@fingolfin
Copy link
Member

During a video conference call today, we seemed to agree that we this could be merged right away (and apparently, doing so would be helpful for @frankluebeck and @ThomasBreuer).

I am fine with this, although I'd like to rebase and squash this one last time before that, i.e.: I would like to perform the merge. However, in the meantime, perhaps those people who want this in can at least formally "approve" this PR; and all others could at least briefly have a look at it, to make sure there is nothing immediately upsetting in this PR.

@fingolfin fingolfin self-assigned this Jul 30, 2018
@fingolfin fingolfin removed the do not merge PRs which are not yet ready to be merged (e.g. submitted for discussion, or test results) label Jul 30, 2018
@fingolfin fingolfin changed the title WIP (Do not merge): Alternate GC hooking into Julia GC. Alternate GC hooking into Julia GC. Jul 30, 2018
@fingolfin
Copy link
Member

BTW, right now, the Julia GC is not supported together with HPC-GAP. But this could be changed -- it just wasn't a priority for now. I think it would be useful to work towards that, but first, we should wait for the Julia changes to land there; then adapt our code here to match; and only afterwards, start looking more into HPC-GAP integration.

src/weakptr.c Outdated
len = LoadUInt();
STORE_LEN_WPOBJ(wpobj, len);
for (i = 1; i <= len; i++)
{
#ifdef USE_JULIA_GC
SET_ELM_WPOBJ(wpobj, i, LoadSubObj());
#else
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very minor suggestion, I think we could just use the Julia codepath here -- it would be valid for GASMAN (I'm 99% sure). It might be slightly less efficient, but would save code seperation.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fine by me, will change it.

@ChrisJefferson
Copy link
Contributor

ChrisJefferson commented Jul 30, 2018

This is not a suggested change for this PR.

Reading the weak pointer file, the main difference between the Julia and GASMAN implementation seems to be GASMAN has to handle DEAD_WEAK_BAGS.

I think if we made GASMAN's ELM_WPOBJ return 0 if a bag for DEAD_WEAK_BAGs (and most code in weakptr.c doesn't care about the difference between 0 and a DEAD_WEAK_BAG), then I think the Julia weakpointer code (which uses cfunction calls rather than reading through bags with raw C pointers) could be used for both gasman and JuliaGC removing the code differences and cleaning things up.

@frankluebeck
Copy link
Member

frankluebeck commented Jul 30, 2018

I have merged this branch into the master branch some days ago. Together with @rbehrends' corresponding branch of julia this seemed to work without problems on the GAP side.

Merging this into the master branch now would simplify the task to install a combination of GAP/Julia that can be used for further development.

I cannot see any problem for people who want to use GAP but not the new feature provided by this pull request.

@@ -868,6 +960,9 @@ static Int InitKernel (
InitMarkFuncBags ( T_WPOBJ +COPYING, MarkWeakPointerObj );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Completely unrelated stupid question (which does not need to be addressed for merging): why is it possible to have USE_GASMAN and USE_THREADSAFE_COPYING?

#define MARK_HASH(x) (FibHash((x), MARK_CACHE_BITS))

// #define STAT_MARK_CACHE

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will this become a compile-time option?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question. It's also not clear to me how useful that cache really is. Which reminds me: I asked @rbehrends before to add more comments to this file, I'll prod him again about it once this is merged, and/or add some more comments myself.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, I also just discovered that MarkCache doesn't actually seem to do anything! I.e. we never use it to prevent any computation. @rbehrends did we loose some code there, or what?

Use `--with-gc=julia` to switch to this alternative garbage
collector. There is also a new `--with-julia=` option which
can be used to point GAP at the correct Julia version (which
currently still needs some patches to add APIs we need).

The main work is in the new file src/julia_gc.c
@fingolfin fingolfin merged commit 8dcd909 into gap-system:master Aug 2, 2018
@fingolfin fingolfin added the release notes: to be added PRs introducing changes that should be (but have not yet been) mentioned in the release notes label Aug 9, 2018
@fingolfin fingolfin added release notes: added PRs introducing changes that have since been mentioned in the release notes and removed release notes: to be added PRs introducing changes that should be (but have not yet been) mentioned in the release notes labels Sep 12, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
release notes: added PRs introducing changes that have since been mentioned in the release notes topic: kernel
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants