-
-
Notifications
You must be signed in to change notification settings - Fork 411
Implement a monitor system for the GC #2052
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -37,6 +37,10 @@ struct Range | |
|
|
||
| interface GC | ||
| { | ||
| /// Provided for implementation's convenience, not intended for public usage | ||
| protected alias CollectionStartHook = void delegate() nothrow @nogc; | ||
| /// Ditto | ||
| protected alias CollectionEndHook = void delegate(size_t, size_t) nothrow @nogc; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think that's necessary for |
||
|
|
||
| /* | ||
| * | ||
|
|
@@ -148,6 +152,13 @@ interface GC | |
| */ | ||
| core.memory.GC.Stats stats() nothrow; | ||
|
|
||
| /** | ||
| * Track beginning and end of allocation | ||
| * Useful for debugging and tuning. | ||
| */ | ||
| void monitor (CollectionStartHook on_start, CollectionEndHook on_end) | ||
| nothrow @nogc; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That makes sense.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, I know it would be extremely unlikely, but this is a good example for what
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think |
||
|
|
||
| /** | ||
| * add p to list of roots | ||
| */ | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -255,6 +255,10 @@ class ConservativeGC : GC | |
| __gshared size_t line; | ||
| __gshared char* file; | ||
|
|
||
| /// Hook used for debugging application-side | ||
| __gshared CollectionStartHook on_collect_start; | ||
| __gshared CollectionEndHook on_collect_end; | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. One point raised by @mihails-strasuns-sociomantic is that having
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well, from pure theoretical PoV it should require |
||
|
|
||
| Gcx *gcx; // implementation | ||
|
|
||
| import core.internal.spinlock; | ||
|
|
@@ -1200,6 +1204,16 @@ class ConservativeGC : GC | |
| return ret; | ||
| } | ||
|
|
||
| override void monitor (CollectionStartHook on_start, CollectionEndHook on_end) | ||
| nothrow @nogc | ||
| { | ||
| static void store (CollectionStartHook start, CollectionEndHook end) | ||
| { | ||
| on_collect_start = start; | ||
| on_collect_end = end; | ||
| } | ||
| runLocked!(store)(on_start, on_end); | ||
| } | ||
|
|
||
| // | ||
| // | ||
|
|
@@ -2392,6 +2406,8 @@ struct Gcx | |
| } | ||
|
|
||
| debug(COLLECT_PRINTF) printf("Gcx.fullcollect()\n"); | ||
| if (ConservativeGC.on_collect_start !is null) | ||
| ConservativeGC.on_collect_start(); | ||
| //printf("\tpool address range = %p .. %p\n", minAddr, maxAddr); | ||
|
|
||
| { | ||
|
|
@@ -2456,6 +2472,8 @@ struct Gcx | |
|
|
||
| updateCollectThresholds(); | ||
|
|
||
| if (ConservativeGC.on_collect_end !is null) | ||
| ConservativeGC.on_collect_end(freedLargePages, freedSmallPages); | ||
| return freedLargePages + freedSmallPages; | ||
| } | ||
|
|
||
|
|
@@ -3443,4 +3461,3 @@ unittest | |
| GC.free(z); | ||
| GC.minimize(); // release huge pool | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mihails-strasuns-sociomantic mentioned that this could be two instances of the
GC.Statsstruct.However, those are not so cheap to get, since we iterate over the pools (unless I misunderstood something).
Given the use cases for those hooks, I think having a no-cost approach is quite mandatory.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It still has to hold GC lock which immediately makes it pretty far from no-cost.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think acquiring a lock (specially in single threaded environments, where is basically an atomic op usually) is considered no-cost compared to traverse the whole pool set. Also, there seems to be no reason to do it when the user can get the stats anyway with just one extra call, if needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have two unrelated concerns about it:
It is not cheap in multi-threaded environments and while single-threaded optimization is indeed most suitable to our needs, druntime version should be more uniformly useful.
To avoid calculating exact stats this PR right now exposes
freedLargePagesandfreedSmallPagesas monitored values and I would argue those alone have rather limited usefulness.What would be really cool is to accept different types of callback delegates and provide required stats based on what is desired by callback. Not sure if it can fit into API elegantly though.