-
Notifications
You must be signed in to change notification settings - Fork 77
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
There is no convenient interface for object pinning #265
Comments
to support pinning and unpinning multiple objects i implement the following MPS states that a moving GC should not move ambigious pointers do note that this is not gaurenteed to keep the object alive between the object allocation and the object being pinned // object pinning support
// an array is used to keep track of pinned objects
managed_obj_t* pinned;
size_t pinned_used;
size_t pinned_capacity;
mps_root_t pinned_root; state->pinned_used = 0;
state->pinned_capacity = 2;
state->pinned = calloc(sizeof(managed_obj_t), state->pinned_capacity);
if (state->pinned == NULL) managed_obj_error("Couldn't allocate pinned memory");
res = mps_root_create_area_tagged(
&state->pinned_root, state->arena, mps_rank_ambig(),
(mps_rm_t)0, state->pinned, state->pinned+state->pinned_capacity,
mps_scan_area_tagged, sizeof(mps_word_t) - 1, (mps_word_t)0
);
if (res != MPS_RES_OK) managed_obj_error("Couldn't create pinned root"); void managed_obj_pin(ManagedObjState * state, managed_obj_t obj) {
int found = 0;
for (int i = 0; i < state->pinned_capacity; i++) {
if (state->pinned[i] == obj) {
found = 1;
break;
}
}
// dont pin object that has already been pinned
if (found == 1) return;
if (state->pinned_used == state->pinned_capacity) {
// reallocate
int new_capacity = state->pinned_capacity * 2;
managed_obj_t * new_pinned = calloc(sizeof(managed_obj_t), new_capacity);
if (new_pinned == NULL) managed_obj_error("Couldn't allocate pinned memory");
// copy old pinned to new pinned
memcpy(new_pinned, state->pinned, sizeof(managed_obj_t)*state->pinned_capacity);
mps_root_t new_pinned_root = NULL;
mps_res_t res = mps_root_create_area_tagged(
&new_pinned_root, state->arena, mps_rank_ambig(),
(mps_rm_t)0, new_pinned, new_pinned+new_capacity,
mps_scan_area_tagged, sizeof(mps_word_t) - 1, (mps_word_t)0
);
if (res != MPS_RES_OK) managed_obj_error("Couldn't create pinned root");
// both are pinned, we can safely destroy old pin
mps_root_destroy(state->pinned_root);
state->pinned_root = new_pinned_root;
free(state->pinned);
state->pinned = new_pinned;
state->pinned_capacity = new_capacity;
}
for (int i = 0; i < state->pinned_capacity; i++) {
if (state->pinned[i] == NULL) {
state->pinned[i] = obj;
state->pinned_used++;
break;
}
}
}
void managed_obj_unpin(ManagedObjState * state, managed_obj_t obj) {
int found = 0;
int index = 0;
for (int i = 0; i < state->pinned_capacity; i++) {
if (state->pinned[i] == obj) {
found = 1;
index = i;
break;
}
}
// dont unpin object that has not been pinned
if (found == 0) return;
state->pinned[index] = NULL;
state->pinned_used--;
memmove(state->pinned+index, state->pinned+index+1, sizeof(managed_obj_t)*(state->pinned_capacity-(index+1)));
state->pinned[state->pinned_capacity-1] = NULL;
// always keep at least 2 elements
if (state->pinned_capacity > 2 && state->pinned_used == state->pinned_capacity / 2) {
// reallocate
int new_capacity = state->pinned_capacity / 2;
managed_obj_t * new_pinned = malloc(sizeof(managed_obj_t)*new_capacity);
if (new_pinned == NULL) managed_obj_error("Couldn't allocate pinned memory");
// copy old pinned to new pinned
memcpy(new_pinned, state->pinned, sizeof(managed_obj_t)*new_capacity);
mps_root_t new_pinned_root = NULL;
mps_res_t res = mps_root_create_area_tagged(
&new_pinned_root, state->arena, mps_rank_ambig(),
(mps_rm_t)0, new_pinned, new_pinned+new_capacity,
mps_scan_area_tagged, sizeof(mps_word_t) - 1, (mps_word_t)0
);
if (res != MPS_RES_OK) managed_obj_error("Couldn't create pinned root");
// both are pinned, we can safely destroy old pin
mps_root_destroy(state->pinned_root);
state->pinned_root = new_pinned_root;
free(state->pinned);
state->pinned = new_pinned;
state->pinned_capacity = new_capacity;
}
} |
Yes, to pin an object, store a reference to it in an ambiguous root. If you have registered your threads as roots, then any object you can "see" directly from your running code (in a local variable, argument, etc.) is pinned. May I ask why you are pinning objects? It would be very useful to know your requirement. |
In terms of a moving gc, does such prevent the gc from compacting memory ? Tho we can observe objects being forwarded even though the thread is registered as an ambiguous root yet pinning WILL NOT move an object even when explicitly garbage collection triggered, and pinning simply stores the object in an ambiguous root
Completeness i guess, also pinning is useful when passing objects to code not managed by MPS (such as 3rd party libraries, or a |
Yes. If you're using the AMC pool class for example, the pinned objects don't get compacted. They will also reduce the performance. So it's best not to do it if you can avoid it.
The program should not be able to observe this directly. If you e.g. print the addresses of objects, you might notice the changes, but the running program should not be able to observe it. If you can produce an example of this, it would be a bug, and we'd like to know about it. A running program can observe movement if it somehow depends on the actual bit patterns of pointers, e.g. for hashing. In that case, the program must use a location dependency.
If you call a third-party library from the MPS on a thread that is registered as a root then you do not need to pin objects, as long as that library uses the thread stack. This covers most cases. This is a key ability of the MPS and is one of the main reasons for its existence. Dylan, and our commercial clients, want to be able to call foreign code naturally. |
i forgot that i was using custom memory root instead of a registered thread objects indeed do not move if we have a registered thread
it can if you supply a custom fwd function :)
true, tho if compacting memory is implemented (via an exact/semi-exact GC) then object pinning will be required |
also, if the hash table stores strong keys and strong values, is it still possible for such to be collected even if they still exist in the hash table ? eg, if we only store the hash table in a root, and only store a key/value in the hash table and not in a root
then the key and value can be collected unless they are pinned, regardless if the table uses a strong ap (rank exact) or a weak ap (rank weak) even if we explicitly fix the keys/values they still get collected case MANAGED_OBJECT_TYPE_METADATA_HASH_TABLE: { \
size_t i, length; \
printf("scan keys %p\n", obj->metadata_hashtable.keys); \
MANAGED_OBJECT_FIX(obj->metadata_hashtable.keys); \
if (obj->metadata_hashtable.key_is_weak == 0) { \
length = MANAGED_OBJECT_METADATA_UNTAG_COUNT(obj->metadata_hashtable.keys->length); \
for (i = 0; i < length; ++i) { \
MANAGED_OBJECT_FIX(obj->metadata_hashtable.keys->bucket[i]); \
} \
} \
printf("scan values %p\n", obj->metadata_hashtable.values); \
MANAGED_OBJECT_FIX(obj->metadata_hashtable.values); \
if (obj->metadata_hashtable.value_is_weak == 0) { \
length = MANAGED_OBJECT_METADATA_UNTAG_COUNT(obj->metadata_hashtable.values->length); \
for (i = 0; i < length; ++i) { \
MANAGED_OBJECT_FIX(obj->metadata_hashtable.values->bucket[i]); \
} \
} \
base = (char *)base + MANAGED_OBJECT_ALIGN_OBJ(sizeof(managed_obj_metadata_hashtable_s)); \
break; } \ so it seems like the AWL pool will ALWAYS allow its objects to be collected regardless if they are stored as an exact ref or a weak ref (storing such in AWL will never prevent it from being collected) |
That's right. That's why the AMC pool class is our most used and best developed: it allows for compaction but copes well in the case of foreign code on the stack.
Sneaky!
Objects are preserved by anything that is scanned. That includes roots, and other object in pools that may contain references -- i.e. they scan their objects. If your hash table is in such a pool, it will keep everything that it refers to alive. The only except is if you allocate objects with weak references, which do not preserve the objects to which they refer. |
This indicates that you may be allocating your exact table as weak by mistake. |
You need to create two allocation points in AWL: one weak and one exact. Allocate the exact table with the exact AP, etc. Otherwise the exact table will be scanned as weak, and its referents could die. |
There's nothing obviously wrong with your code. Is it possible that we can reproduce this ourselves? Is your project public? Can we run and debug it? If so, please could you file a new issue about non-weak objects dying with reproduction instructions. Thank you. |
the problem was i was storing a copy of the original pointer and assuming the GC would not need to move it when collecting |
so, both weak-key table, weak-value table, and weak table work as expected in regards to finalization (my dumbass was logging inside if(MANAGED_OBJECT_TYPE(obj) == MANAGED_OBJECT_TYPE_EMPTY) {
state->freed_obj_bytes += sizeof(managed_obj_empty_s);
state->freed_aligned_obj_bytes += MANAGED_OBJECT_ALIGN_OBJ(sizeof(managed_obj_empty_s));
printf("object %p is being finalized.\n", obj); instead of printf("object %p is being finalized.\n", obj);
if(MANAGED_OBJECT_TYPE(obj) == MANAGED_OBJECT_TYPE_EMPTY) {
state->freed_obj_bytes += sizeof(managed_obj_empty_s);
state->freed_aligned_obj_bytes += MANAGED_OBJECT_ALIGN_OBJ(sizeof(managed_obj_empty_s)); ) |
anyway, back to the main issue, can this be done more efficiently ?
|
On 2023-10-01 01:36, mgood7123 wrote:
is it possible to have a flag in the object itself that states if it is
pinned or not? so we dont need to consume extra memory (ambig root) to
store pinned object pointers?
I'm interpreting this as you wanting a flag to *control* pinning.
Ambiguity is a property of the reference to an object, not the object
itself. The MPS knows to pin an object because it sorts the references
and scans all ambiguous references before any exact references. The
sort is done on the references, not the objects they refer to.
What you're asking for is subtly different. You could have a property
of an object that told e.g. the AMC pool not to move it, independent of
how it is referenced. Because the MPS does not know the format of
objects, this would involve adding a new format method.
Somewhere around
https://github.com/Ravenbrook/mps/blob/554513b16461ec0bbf82856dfe6b0528518c3658/code/poolamc.c#L1595
you could call this method and if it asked for the object not to move,
apply the same logic as for pinning
https://github.com/Ravenbrook/mps/blob/554513b16461ec0bbf82856dfe6b0528518c3658/code/poolamc.c#L1560-L1578
. That would be the basics of it. We'd have to check whether that broke
any assumptions elsewhere (e.g. that new nailboards don't appear after
the ambiguous phase).
The problem with that is that it adds more logic to the critical path
https://github.com/Ravenbrook/mps/blob/master/design/critical-path.txt
and we're very careful about that. As well as more complexity in general.
It's not clear what you gain. Each ambiguous reference only costs one
word of memory space. You'll need somewhere to store the flag in the
object as well.
|
true if we allocate and pin 10,000 (10 thousand) objects then we end up with a pinned capacity of so, we have 240 KB aligned alloc, plus 80 KB pinned, for 10,000 objects given that, here, 1 object is 4 bytes and 24 aligned bytes, and 1 pinned is 8 bytes if we do the same with 200 thousand objects then we get a pinned capacity of so, we have 4.8 MB aligned alloc (0.8 MB unaligned alloc), plus 1.6 MB pinned (2 MB pinned capacity), for 200,000 objects and for 1 million (1,000,000) we get a pinned capacity of so, we have 24 MB aligned alloc (4 MB unaligned alloc), plus 8 MB pinned (8.3 MB pinned capacity), for 1,000,000 objects (with 1 KB = 1000 Bytes) |
in which allocating 1 million objects takes around 4 seconds
but PINNING 1 million objects takes
|
@thejayps look over this |
Yes, allocation is very fast. It's done inline in only a few instructions. I assume that in this pinning benchmark you're measuring your own code for adding an ambiguous root, since the MPS does not provide an interface. Is there a use case for doing that? If you were e.g. making FFI calls to an external library at a high rate (e.g. a graphics renderer) then you would not need to explicitly pin the objects if you're passing things on the stack. There is no cost to that. If you know at allocation time that your objects need to not move, you could allocate them in a non-moving pool and there would be no need to pin them. The MPS is designed with the assumption that the mutator will not need to explicitly pin and unpin large numbers of objects. If you have a reason to do it, we'd definitely like to hear about it. |
i tried using a hash table/map https://github.com/DavidLeeds/hashmap (modified) but thats even slower
int pinned_map_compare_func(const union managed_obj_u * a, const union managed_obj_u * b) {
return a == b ? 0 : 1;
}
size_t pinned_map_hash_func(const union managed_obj_u * data) {
return managed_object_hashmap_hash_default(data, sizeof(data));
}
void pinned_map_on_realloc_func(void * user_data, void * new_pinned, size_t new_capacity) {
ManagedObjState * state = (ManagedObjState*)user_data;
mps_root_t new_pinned_root = NULL;
if (new_capacity != 0) {
mps_res_t res = mps_root_create_area_tagged(
&new_pinned_root, state->arena, mps_rank_ambig(),
(mps_rm_t)0, new_pinned, new_pinned+new_capacity,
mps_scan_area_tagged, sizeof(mps_word_t) - 1, (mps_word_t)0
);
if (res != MPS_RES_OK) managed_obj_error("Couldn't create pinned root");
}
// both are pinned, we can safely destroy old pin
if (state->pinned_root != NULL)
mps_root_destroy(state->pinned_root);
state->pinned_root = new_pinned_root;
}
void managed_obj_pin(ManagedObjState * state, managed_obj_t obj) {
if (state->pinned.map_base.table_size == 0) {
managed_object_hashmap_init(&state->pinned, pinned_map_hash_func, pinned_map_compare_func);
managed_object_hashmap_set_on_realloc_func(&state->pinned, pinned_map_on_realloc_func);
}
/* Insert a my_value (fails and returns -EEXIST if the key already exists) */
int result = managed_object_hashmap_put(&state->pinned, state, obj, obj);
if (result == -EEXIST) return;
}
void managed_obj_unpin(ManagedObjState * state, managed_obj_t obj) {
if (state->pinned.map_base.table_size != 0) {
if (managed_object_hashmap_remove(&state->pinned, obj) != NULL) {
if (state->pinned.map_base.size == 0) {
managed_object_hashmap_cleanup(&state->pinned, state);
}
}
}
} |
my use case would be a compacting garbage collected language with C interop support currently i intend to transpile down to C/C++ and fall back to interpreted execution if a compiler is unavailable |
basically i seem to have 6 ... design/implementation goals for object pinning
i tried void managed_obj_pin(ManagedObjState * state, managed_obj_t obj) {
if (obj->empty.pinned_root == NULL) {
mps_res_t res = mps_root_create_area_tagged(
&obj->empty.pinned_root, state->arena, mps_rank_ambig(),
(mps_rm_t)0, &obj->empty.pinned, (&obj->empty.pinned)+sizeof(managed_obj_t),
mps_scan_area_tagged, sizeof(mps_word_t) - 1, (mps_word_t)0
);
if (res != MPS_RES_OK) managed_obj_error("Couldn't create pinned root");
obj->empty.pinned = obj;
state->pinned_used++;
}
}
void managed_obj_unpin(ManagedObjState * state, managed_obj_t obj) {
if (obj->empty.pinned_root != NULL) {
obj->empty.pinned = NULL;
mps_root_destroy(obj->empty.pinned_root);
obj->empty.pinned_root = NULL;
state->pinned_used--;
}
} but it seems to page fault while scanning during create root which leads to double lock |
the only way i can see doing this effiecently would be to directly integrate it into the gc amc pool class as a queriable flag |
ok i implemented object pinning directly into the GC and now it is a lot faster
diff --git a/code/config.h b/code/config.h
index 02d335e..5561bec 100644
--- a/code/config.h
+++ b/code/config.h
@@ -353,6 +353,7 @@
#define FMT_SKIP_DEFAULT (&FormatNoSkip)
#define FMT_FWD_DEFAULT (&FormatNoMove)
#define FMT_ISFWD_DEFAULT (&FormatNoIsMoved)
+#define FMT_ISPINNED_DEFAULT (&FormatNoIsPinned)
#define FMT_PAD_DEFAULT (&FormatNoPad)
#define FMT_CLASS_DEFAULT (&FormatDefaultClass)
diff --git a/code/fmtdy.c b/code/fmtdy.c
index 6cfbca6..d43763a 100644
--- a/code/fmtdy.c
+++ b/code/fmtdy.c
@@ -771,6 +771,7 @@ static struct mps_fmt_A_s dylan_fmt_A_s =
dylan_copy,
dylan_fwd,
dylan_isfwd,
+ no_ispinned,
dylan_pad
};
@@ -782,6 +783,7 @@ static struct mps_fmt_B_s dylan_fmt_B_s =
dylan_copy,
dylan_fwd,
dylan_isfwd,
+ no_ispinned,
dylan_pad,
dylan_class
};
@@ -816,6 +818,7 @@ static struct mps_fmt_A_s dylan_fmt_A_weak_s =
no_copy,
no_fwd,
no_isfwd,
+ no_ispinned,
no_pad
};
@@ -827,6 +830,7 @@ static struct mps_fmt_B_s dylan_fmt_B_weak_s =
no_copy,
no_fwd,
no_isfwd,
+ no_ispinned,
no_pad,
dylan_class
};
diff --git a/code/fmthe.c b/code/fmthe.c
index 76f7239..0dfd422 100644
--- a/code/fmthe.c
+++ b/code/fmthe.c
@@ -138,6 +138,7 @@ static struct mps_fmt_auto_header_s HeaderFormat =
dylan_header_skip,
NULL, /* later overwritten by dylan format forward method */
dylan_header_isfwd,
+ no_ispinned,
dylan_header_pad,
(size_t)headerSIZE
};
@@ -152,6 +153,7 @@ static struct mps_fmt_auto_header_s HeaderWeakFormat =
dylan_header_skip,
no_fwd,
no_isfwd,
+ no_ispinned,
no_pad,
(size_t)headerSIZE
};
diff --git a/code/fmtno.c b/code/fmtno.c
index 4854e55..a655d06 100644
--- a/code/fmtno.c
+++ b/code/fmtno.c
@@ -59,6 +59,13 @@ mps_addr_t no_isfwd(mps_addr_t object)
return 0;
}
+mps_bool_t no_ispinned(mps_addr_t object)
+{
+ unused(object);
+ notreached();
+ return FALSE;
+}
+
void no_pad(mps_addr_t addr,
size_t size)
{
@@ -83,6 +90,7 @@ static struct mps_fmt_A_s no_fmt_A_s =
no_copy,
no_fwd,
no_isfwd,
+ no_ispinned,
no_pad
};
@@ -94,6 +102,7 @@ static struct mps_fmt_B_s no_fmt_B_s =
no_copy,
no_fwd,
no_isfwd,
+ no_ispinned,
no_pad,
no_class
};
diff --git a/code/fmtno.h b/code/fmtno.h
index c7afc1d..6e8dcd5 100644
--- a/code/fmtno.h
+++ b/code/fmtno.h
@@ -14,6 +14,7 @@ extern mps_addr_t no_skip(mps_addr_t);
extern void no_copy(mps_addr_t, mps_addr_t);
extern void no_fwd(mps_addr_t, mps_addr_t);
extern mps_addr_t no_isfwd(mps_addr_t);
+extern mps_bool_t no_ispinned(mps_addr_t);
extern void no_pad(mps_addr_t, size_t);
extern mps_addr_t no_class(mps_addr_t);
diff --git a/code/format.c b/code/format.c
index 8d51357..a9515a4 100644
--- a/code/format.c
+++ b/code/format.c
@@ -31,6 +31,7 @@ Bool FormatCheck(Format format)
CHECKL(FUNCHECK(format->skip));
CHECKL(FUNCHECK(format->move));
CHECKL(FUNCHECK(format->isMoved));
+ CHECKL(FUNCHECK(format->isPinned));
CHECKL(FUNCHECK(format->pad));
CHECKL(FUNCHECK(format->klass));
@@ -70,6 +71,13 @@ static mps_addr_t FormatNoIsMoved(mps_addr_t object)
return NULL;
}
+static mps_bool_t FormatNoIsPinned(mps_addr_t object)
+{
+ UNUSED(object);
+ NOTREACHED;
+ return FALSE;
+}
+
static void FormatNoPad(mps_addr_t addr, size_t size)
{
UNUSED(addr);
@@ -92,6 +100,7 @@ ARG_DEFINE_KEY(FMT_SCAN, Fun);
ARG_DEFINE_KEY(FMT_SKIP, Fun);
ARG_DEFINE_KEY(FMT_FWD, Fun);
ARG_DEFINE_KEY(FMT_ISFWD, Fun);
+ARG_DEFINE_KEY(FMT_ISPINNED, Fun);
ARG_DEFINE_KEY(FMT_PAD, Fun);
ARG_DEFINE_KEY(FMT_HEADER_SIZE, Size);
ARG_DEFINE_KEY(FMT_CLASS, Fun);
@@ -108,6 +117,7 @@ Res FormatCreate(Format *formatReturn, Arena arena, ArgList args)
mps_fmt_skip_t fmtSkip = FMT_SKIP_DEFAULT;
mps_fmt_fwd_t fmtFwd = FMT_FWD_DEFAULT;
mps_fmt_isfwd_t fmtIsfwd = FMT_ISFWD_DEFAULT;
+ mps_fmt_ispinned_t fmtIspinned = FMT_ISPINNED_DEFAULT;
mps_fmt_pad_t fmtPad = FMT_PAD_DEFAULT;
mps_fmt_class_t fmtClass = FMT_CLASS_DEFAULT;
@@ -127,6 +137,8 @@ Res FormatCreate(Format *formatReturn, Arena arena, ArgList args)
fmtFwd = arg.val.fmt_fwd;
if (ArgPick(&arg, args, MPS_KEY_FMT_ISFWD))
fmtIsfwd = arg.val.fmt_isfwd;
+ if (ArgPick(&arg, args, MPS_KEY_FMT_ISPINNED))
+ fmtIspinned = arg.val.fmt_ispinned;
if (ArgPick(&arg, args, MPS_KEY_FMT_PAD))
fmtPad = arg.val.fmt_pad;
if (ArgPick(&arg, args, MPS_KEY_FMT_CLASS))
@@ -146,6 +158,7 @@ Res FormatCreate(Format *formatReturn, Arena arena, ArgList args)
format->skip = fmtSkip;
format->move = fmtFwd;
format->isMoved = fmtIsfwd;
+ format->isPinned = fmtIspinned;
format->pad = fmtPad;
format->klass = fmtClass;
@@ -206,6 +219,7 @@ Res FormatDescribe(Format format, mps_lib_FILE *stream, Count depth)
" skip $F\n", (WriteFF)format->skip,
" move $F\n", (WriteFF)format->move,
" isMoved $F\n", (WriteFF)format->isMoved,
+ " isPinned $F\n", (WriteFF)format->isPinned,
" pad $F\n", (WriteFF)format->pad,
" headerSize $W\n", (WriteFW)format->headerSize,
"} Format $P ($U)\n", (WriteFP)format, (WriteFU)format->serial,
diff --git a/code/mpmst.h b/code/mpmst.h
index f5ba00b..4da18f0 100644
--- a/code/mpmst.h
+++ b/code/mpmst.h
@@ -361,6 +361,7 @@ typedef struct mps_fmt_s {
mps_fmt_skip_t skip;
mps_fmt_fwd_t move;
mps_fmt_isfwd_t isMoved;
+ mps_fmt_ispinned_t isPinned;
mps_fmt_pad_t pad;
mps_fmt_class_t klass; /* pointer indicating class */
Size headerSize; /* size of header */
diff --git a/code/mps.h b/code/mps.h
index 700c414..8faadbf 100644
--- a/code/mps.h
+++ b/code/mps.h
@@ -117,6 +117,7 @@ typedef mps_addr_t (*mps_fmt_skip_t)(mps_addr_t);
typedef void (*mps_fmt_copy_t)(mps_addr_t, mps_addr_t);
typedef void (*mps_fmt_fwd_t)(mps_addr_t, mps_addr_t);
typedef mps_addr_t (*mps_fmt_isfwd_t)(mps_addr_t);
+typedef mps_bool_t (*mps_fmt_ispinned_t)(mps_addr_t);
typedef void (*mps_fmt_pad_t)(mps_addr_t, size_t);
typedef mps_addr_t (*mps_fmt_class_t)(mps_addr_t);
@@ -159,6 +160,7 @@ typedef struct mps_arg_s {
mps_fmt_skip_t fmt_skip;
mps_fmt_fwd_t fmt_fwd;
mps_fmt_isfwd_t fmt_isfwd;
+ mps_fmt_ispinned_t fmt_ispinned;
mps_fmt_pad_t fmt_pad;
mps_fmt_class_t fmt_class;
mps_pool_t pool;
@@ -253,6 +255,9 @@ extern const struct mps_key_s _mps_key_FMT_FWD;
extern const struct mps_key_s _mps_key_FMT_ISFWD;
#define MPS_KEY_FMT_ISFWD (&_mps_key_FMT_ISFWD)
#define MPS_KEY_FMT_ISFWD_FIELD fmt_isfwd
+extern const struct mps_key_s _mps_key_FMT_ISPINNED;
+#define MPS_KEY_FMT_ISPINNED (&_mps_key_FMT_ISPINNED)
+#define MPS_KEY_FMT_ISPINNED_FIELD fmt_ispinned
extern const struct mps_key_s _mps_key_FMT_PAD;
#define MPS_KEY_FMT_PAD (&_mps_key_FMT_PAD)
#define MPS_KEY_FMT_PAD_FIELD fmt_pad
@@ -395,6 +400,7 @@ typedef struct mps_fmt_A_s {
mps_fmt_copy_t copy;
mps_fmt_fwd_t fwd;
mps_fmt_isfwd_t isfwd;
+ mps_fmt_ispinned_t ispinned;
mps_fmt_pad_t pad;
} mps_fmt_A_s;
typedef struct mps_fmt_A_s *mps_fmt_A_t;
@@ -407,6 +413,7 @@ typedef struct mps_fmt_B_s {
mps_fmt_copy_t copy;
mps_fmt_fwd_t fwd;
mps_fmt_isfwd_t isfwd;
+ mps_fmt_ispinned_t ispinned;
mps_fmt_pad_t pad;
mps_fmt_class_t mps_class;
} mps_fmt_B_s;
@@ -420,6 +427,7 @@ typedef struct mps_fmt_auto_header_s {
mps_fmt_skip_t skip;
mps_fmt_fwd_t fwd;
mps_fmt_isfwd_t isfwd;
+ mps_fmt_ispinned_t ispinned;
mps_fmt_pad_t pad;
size_t mps_headerSize;
} mps_fmt_auto_header_s;
@@ -430,6 +438,7 @@ typedef struct mps_fmt_fixed_s {
mps_fmt_scan_t scan;
mps_fmt_fwd_t fwd;
mps_fmt_isfwd_t isfwd;
+ mps_fmt_ispinned_t ispinned;
mps_fmt_pad_t pad;
} mps_fmt_fixed_s;
diff --git a/code/mpsi.c b/code/mpsi.c
index eab0deb..0d2ce74 100644
--- a/code/mpsi.c
+++ b/code/mpsi.c
@@ -573,6 +573,7 @@ mps_res_t mps_fmt_create_A(mps_fmt_t *mps_fmt_o,
MPS_ARGS_ADD(args, MPS_KEY_FMT_SKIP, mps_fmt_A->skip);
MPS_ARGS_ADD(args, MPS_KEY_FMT_FWD, mps_fmt_A->fwd);
MPS_ARGS_ADD(args, MPS_KEY_FMT_ISFWD, mps_fmt_A->isfwd);
+ MPS_ARGS_ADD(args, MPS_KEY_FMT_ISPINNED, mps_fmt_A->ispinned);
MPS_ARGS_ADD(args, MPS_KEY_FMT_PAD, mps_fmt_A->pad);
res = FormatCreate(&format, arena, args);
} MPS_ARGS_END(args);
@@ -607,6 +608,7 @@ mps_res_t mps_fmt_create_B(mps_fmt_t *mps_fmt_o,
MPS_ARGS_ADD(args, MPS_KEY_FMT_SKIP, mps_fmt_B->skip);
MPS_ARGS_ADD(args, MPS_KEY_FMT_FWD, mps_fmt_B->fwd);
MPS_ARGS_ADD(args, MPS_KEY_FMT_ISFWD, mps_fmt_B->isfwd);
+ MPS_ARGS_ADD(args, MPS_KEY_FMT_ISPINNED, mps_fmt_B->ispinned);
MPS_ARGS_ADD(args, MPS_KEY_FMT_PAD, mps_fmt_B->pad);
MPS_ARGS_ADD(args, MPS_KEY_FMT_CLASS, mps_fmt_B->mps_class);
res = FormatCreate(&format, arena, args);
@@ -643,6 +645,7 @@ mps_res_t mps_fmt_create_auto_header(mps_fmt_t *mps_fmt_o,
MPS_ARGS_ADD(args, MPS_KEY_FMT_SKIP, mps_fmt->skip);
MPS_ARGS_ADD(args, MPS_KEY_FMT_FWD, mps_fmt->fwd);
MPS_ARGS_ADD(args, MPS_KEY_FMT_ISFWD, mps_fmt->isfwd);
+ MPS_ARGS_ADD(args, MPS_KEY_FMT_ISPINNED, mps_fmt->ispinned);
MPS_ARGS_ADD(args, MPS_KEY_FMT_PAD, mps_fmt->pad);
res = FormatCreate(&format, arena, args);
} MPS_ARGS_END(args);
@@ -676,6 +679,7 @@ mps_res_t mps_fmt_create_fixed(mps_fmt_t *mps_fmt_o,
MPS_ARGS_ADD(args, MPS_KEY_FMT_SCAN, mps_fmt_fixed->scan);
MPS_ARGS_ADD(args, MPS_KEY_FMT_FWD, mps_fmt_fixed->fwd);
MPS_ARGS_ADD(args, MPS_KEY_FMT_ISFWD, mps_fmt_fixed->isfwd);
+ MPS_ARGS_ADD(args, MPS_KEY_FMT_ISPINNED, mps_fmt_fixed->ispinned);
MPS_ARGS_ADD(args, MPS_KEY_FMT_PAD, mps_fmt_fixed->pad);
res = FormatCreate(&format, arena, args);
} MPS_ARGS_END(args);
diff --git a/code/poolamc.c b/code/poolamc.c
index c526c8e..ed14d8a 100644
--- a/code/poolamc.c
+++ b/code/poolamc.c
@@ -1592,6 +1592,29 @@ static Res amcSegFix(Seg seg, ScanState ss, Ref *refIO)
/* .exposed.seg: Statements tagged ".exposed.seg" below require */
/* that "seg" (that is: the 'from' seg) has been ShieldExposed. */
ShieldExpose(arena, seg);
+ /* If the reference is pinned, set up the datastructures for */
+ /* managing a nailed segment. This involves marking the segment */
+ /* as nailed, and setting up a per-word mark table */
+ if ((*format->isPinned)(ref)) {
+ ShieldCover(arena, seg);
+ /* .nail.new: Check to see whether we need a Nailboard for */
+ /* this seg. We use "SegNailed(seg) == TraceSetEMPTY" */
+ /* rather than "!amcSegHasNailboard(seg)" because this avoids */
+ /* setting up a new nailboard when the segment was nailed, but */
+ /* had no nailboard. This must be avoided because otherwise */
+ /* assumptions in amcSegFixEmergency will be wrong (essentially */
+ /* we will lose some pointer fixes because we introduced a */
+ /* nailboard). */
+ if(SegNailed(seg) == TraceSetEMPTY) {
+ res = amcSegCreateNailboard(seg);
+ if(res != ResOK)
+ return res;
+ STATISTIC(++ss->nailCount);
+ SegSetNailed(seg, TraceSetUnion(SegNailed(seg), ss->traces));
+ }
+ amcSegFixInPlace(seg, ss, refIO);
+ return ResOK;
+ }
newRef = (*format->isMoved)(ref); /* .exposed.seg */
if(newRef == (Addr)0) { |
tho it can sometimes complete tho it seems to vary between ~ 10 seconds and ~30 seconds |
using a stack-like approach seems to be a bit slower at the expense of pin/unpin order around ~30 seconds void reroot(ManagedObjState * state, managed_obj_t * new_pinned, int new_capacity) {
mps_root_t new_pinned_root = NULL;
mps_res_t res = mps_root_create_area_tagged(
&new_pinned_root, state->arena, mps_rank_ambig(),
(mps_rm_t)0, new_pinned, new_pinned+new_capacity,
mps_scan_area_tagged, sizeof(mps_word_t) - 1, (mps_word_t)0
);
if (res != MPS_RES_OK) managed_obj_error("Couldn't create pinned root");
// both are pinned, we can safely destroy old pin
mps_root_destroy(state->pinned_root);
state->pinned_root = new_pinned_root;
free(state->pinned);
state->pinned = new_pinned;
state->pinned_capacity = new_capacity;
}
void managed_obj_push_pin(ManagedObjState * state, managed_obj_t obj) {
if (state->pinned_used == state->pinned_capacity) {
// reallocate
int new_capacity = state->pinned_capacity * 2;
managed_obj_t * new_pinned = calloc(sizeof(managed_obj_t), new_capacity);
if (new_pinned == NULL) managed_obj_error("Couldn't allocate pinned memory");
// copy old pinned to new pinned
memcpy(new_pinned, state->pinned, sizeof(managed_obj_t)*state->pinned_capacity);
reroot(state, new_pinned, new_capacity);
}
state->pinned[state->pinned_used++] = obj;
}
void managed_obj_pop_pin(ManagedObjState * state) {
state->pinned[--state->pinned_used] = NULL;
// always keep at least 2 elements
if (state->pinned_capacity > 2 && state->pinned_used == state->pinned_capacity / 2) {
// reallocate
int new_capacity = state->pinned_capacity / 2;
managed_obj_t * new_pinned = malloc(sizeof(managed_obj_t)*new_capacity);
if (new_pinned == NULL) managed_obj_error("Couldn't allocate pinned memory");
// copy old pinned to new pinned
memcpy(new_pinned, state->pinned, sizeof(managed_obj_t)*new_capacity);
reroot(state, new_pinned, new_capacity);
}
} |
both appear to be equally fast, maybe due to cpu caching ? |
tho im running on COOL build, ill try RASH build |
on RASH i seem to get ~8 seconds for 1 million pinned allocs |
Please let us know if you are seeing a significant difference between HOT and RASH. The RASH build only really exists as a comparison, to ensure that HOT is fast enough. We strongly discourage the use of RASH, either in development or production, because heap corruption is extremely hard to debug if left around for any amount of time. |
sorry i was busy, i ended up integrating object pinning directly into the MPS system for usage: MPS_ARGS_ADD(args, MPS_KEY_FMT_ISFWD, managed_obj_isfwd);
MPS_ARGS_ADD(args, MPS_KEY_FMT_ISPINNED, managed_obj_ispinned);
MPS_ARGS_ADD(args, MPS_KEY_FMT_PAD, managed_obj_pad); inline void managed_obj_pin(ManagedObjState * state, managed_obj_t obj) {
obj->type.pinned = TRUE;
state->pinned_used++;
}
inline void managed_obj_unpin(ManagedObjState * state, managed_obj_t obj) {
obj->type.pinned = FALSE;
state->pinned_used--;
} static mps_bool_t managed_obj_ispinned(mps_addr_t addr)
{
managed_obj_t obj = (managed_obj_t)addr;
return obj->type.pinned;
} |
from commit 554513b
diff --git a/mps_raven/code/config.h b/mps_mgood/code/config.h
index 02d335e..5561bec 100644
--- a/mps_raven/code/config.h
+++ b/mps_mgood/code/config.h
@@ -353,6 +353,7 @@
#define FMT_SKIP_DEFAULT (&FormatNoSkip)
#define FMT_FWD_DEFAULT (&FormatNoMove)
#define FMT_ISFWD_DEFAULT (&FormatNoIsMoved)
+#define FMT_ISPINNED_DEFAULT (&FormatNoIsPinned)
#define FMT_PAD_DEFAULT (&FormatNoPad)
#define FMT_CLASS_DEFAULT (&FormatDefaultClass)
diff --git a/mps_raven/code/fmtdy.c b/mps_mgood/code/fmtdy.c
index 6cfbca6..d43763a 100644
--- a/mps_raven/code/fmtdy.c
+++ b/mps_mgood/code/fmtdy.c
@@ -771,6 +771,7 @@ static struct mps_fmt_A_s dylan_fmt_A_s =
dylan_copy,
dylan_fwd,
dylan_isfwd,
+ no_ispinned,
dylan_pad
};
@@ -782,6 +783,7 @@ static struct mps_fmt_B_s dylan_fmt_B_s =
dylan_copy,
dylan_fwd,
dylan_isfwd,
+ no_ispinned,
dylan_pad,
dylan_class
};
@@ -816,6 +818,7 @@ static struct mps_fmt_A_s dylan_fmt_A_weak_s =
no_copy,
no_fwd,
no_isfwd,
+ no_ispinned,
no_pad
};
@@ -827,6 +830,7 @@ static struct mps_fmt_B_s dylan_fmt_B_weak_s =
no_copy,
no_fwd,
no_isfwd,
+ no_ispinned,
no_pad,
dylan_class
};
diff --git a/mps_raven/code/fmthe.c b/mps_mgood/code/fmthe.c
index 76f7239..0dfd422 100644
--- a/mps_raven/code/fmthe.c
+++ b/mps_mgood/code/fmthe.c
@@ -138,6 +138,7 @@ static struct mps_fmt_auto_header_s HeaderFormat =
dylan_header_skip,
NULL, /* later overwritten by dylan format forward method */
dylan_header_isfwd,
+ no_ispinned,
dylan_header_pad,
(size_t)headerSIZE
};
@@ -152,6 +153,7 @@ static struct mps_fmt_auto_header_s HeaderWeakFormat =
dylan_header_skip,
no_fwd,
no_isfwd,
+ no_ispinned,
no_pad,
(size_t)headerSIZE
};
diff --git a/mps_raven/code/fmtno.c b/mps_mgood/code/fmtno.c
index 4854e55..a655d06 100644
--- a/mps_raven/code/fmtno.c
+++ b/mps_mgood/code/fmtno.c
@@ -59,6 +59,13 @@ mps_addr_t no_isfwd(mps_addr_t object)
return 0;
}
+mps_bool_t no_ispinned(mps_addr_t object)
+{
+ unused(object);
+ notreached();
+ return FALSE;
+}
+
void no_pad(mps_addr_t addr,
size_t size)
{
@@ -83,6 +90,7 @@ static struct mps_fmt_A_s no_fmt_A_s =
no_copy,
no_fwd,
no_isfwd,
+ no_ispinned,
no_pad
};
@@ -94,6 +102,7 @@ static struct mps_fmt_B_s no_fmt_B_s =
no_copy,
no_fwd,
no_isfwd,
+ no_ispinned,
no_pad,
no_class
};
diff --git a/mps_raven/code/fmtno.h b/mps_mgood/code/fmtno.h
index c7afc1d..6e8dcd5 100644
--- a/mps_raven/code/fmtno.h
+++ b/mps_mgood/code/fmtno.h
@@ -14,6 +14,7 @@ extern mps_addr_t no_skip(mps_addr_t);
extern void no_copy(mps_addr_t, mps_addr_t);
extern void no_fwd(mps_addr_t, mps_addr_t);
extern mps_addr_t no_isfwd(mps_addr_t);
+extern mps_bool_t no_ispinned(mps_addr_t);
extern void no_pad(mps_addr_t, size_t);
extern mps_addr_t no_class(mps_addr_t);
diff --git a/mps_raven/code/format.c b/mps_mgood/code/format.c
index 8d51357..a9515a4 100644
--- a/mps_raven/code/format.c
+++ b/mps_mgood/code/format.c
@@ -31,6 +31,7 @@ Bool FormatCheck(Format format)
CHECKL(FUNCHECK(format->skip));
CHECKL(FUNCHECK(format->move));
CHECKL(FUNCHECK(format->isMoved));
+ CHECKL(FUNCHECK(format->isPinned));
CHECKL(FUNCHECK(format->pad));
CHECKL(FUNCHECK(format->klass));
@@ -70,6 +71,13 @@ static mps_addr_t FormatNoIsMoved(mps_addr_t object)
return NULL;
}
+static mps_bool_t FormatNoIsPinned(mps_addr_t object)
+{
+ UNUSED(object);
+ NOTREACHED;
+ return FALSE;
+}
+
static void FormatNoPad(mps_addr_t addr, size_t size)
{
UNUSED(addr);
@@ -92,6 +100,7 @@ ARG_DEFINE_KEY(FMT_SCAN, Fun);
ARG_DEFINE_KEY(FMT_SKIP, Fun);
ARG_DEFINE_KEY(FMT_FWD, Fun);
ARG_DEFINE_KEY(FMT_ISFWD, Fun);
+ARG_DEFINE_KEY(FMT_ISPINNED, Fun);
ARG_DEFINE_KEY(FMT_PAD, Fun);
ARG_DEFINE_KEY(FMT_HEADER_SIZE, Size);
ARG_DEFINE_KEY(FMT_CLASS, Fun);
@@ -108,6 +117,7 @@ Res FormatCreate(Format *formatReturn, Arena arena, ArgList args)
mps_fmt_skip_t fmtSkip = FMT_SKIP_DEFAULT;
mps_fmt_fwd_t fmtFwd = FMT_FWD_DEFAULT;
mps_fmt_isfwd_t fmtIsfwd = FMT_ISFWD_DEFAULT;
+ mps_fmt_ispinned_t fmtIspinned = FMT_ISPINNED_DEFAULT;
mps_fmt_pad_t fmtPad = FMT_PAD_DEFAULT;
mps_fmt_class_t fmtClass = FMT_CLASS_DEFAULT;
@@ -127,6 +137,8 @@ Res FormatCreate(Format *formatReturn, Arena arena, ArgList args)
fmtFwd = arg.val.fmt_fwd;
if (ArgPick(&arg, args, MPS_KEY_FMT_ISFWD))
fmtIsfwd = arg.val.fmt_isfwd;
+ if (ArgPick(&arg, args, MPS_KEY_FMT_ISPINNED))
+ fmtIspinned = arg.val.fmt_ispinned;
if (ArgPick(&arg, args, MPS_KEY_FMT_PAD))
fmtPad = arg.val.fmt_pad;
if (ArgPick(&arg, args, MPS_KEY_FMT_CLASS))
@@ -146,6 +158,7 @@ Res FormatCreate(Format *formatReturn, Arena arena, ArgList args)
format->skip = fmtSkip;
format->move = fmtFwd;
format->isMoved = fmtIsfwd;
+ format->isPinned = fmtIspinned;
format->pad = fmtPad;
format->klass = fmtClass;
@@ -206,6 +219,7 @@ Res FormatDescribe(Format format, mps_lib_FILE *stream, Count depth)
" skip $F\n", (WriteFF)format->skip,
" move $F\n", (WriteFF)format->move,
" isMoved $F\n", (WriteFF)format->isMoved,
+ " isPinned $F\n", (WriteFF)format->isPinned,
" pad $F\n", (WriteFF)format->pad,
" headerSize $W\n", (WriteFW)format->headerSize,
"} Format $P ($U)\n", (WriteFP)format, (WriteFU)format->serial,
diff --git a/mps_raven/code/mpmst.h b/mps_mgood/code/mpmst.h
index f5ba00b..4da18f0 100644
--- a/mps_raven/code/mpmst.h
+++ b/mps_mgood/code/mpmst.h
@@ -361,6 +361,7 @@ typedef struct mps_fmt_s {
mps_fmt_skip_t skip;
mps_fmt_fwd_t move;
mps_fmt_isfwd_t isMoved;
+ mps_fmt_ispinned_t isPinned;
mps_fmt_pad_t pad;
mps_fmt_class_t klass; /* pointer indicating class */
Size headerSize; /* size of header */
diff --git a/mps_raven/code/mps.h b/mps_mgood/code/mps.h
index 700c414..8faadbf 100644
--- a/mps_raven/code/mps.h
+++ b/mps_mgood/code/mps.h
@@ -117,6 +117,7 @@ typedef mps_addr_t (*mps_fmt_skip_t)(mps_addr_t);
typedef void (*mps_fmt_copy_t)(mps_addr_t, mps_addr_t);
typedef void (*mps_fmt_fwd_t)(mps_addr_t, mps_addr_t);
typedef mps_addr_t (*mps_fmt_isfwd_t)(mps_addr_t);
+typedef mps_bool_t (*mps_fmt_ispinned_t)(mps_addr_t);
typedef void (*mps_fmt_pad_t)(mps_addr_t, size_t);
typedef mps_addr_t (*mps_fmt_class_t)(mps_addr_t);
@@ -159,6 +160,7 @@ typedef struct mps_arg_s {
mps_fmt_skip_t fmt_skip;
mps_fmt_fwd_t fmt_fwd;
mps_fmt_isfwd_t fmt_isfwd;
+ mps_fmt_ispinned_t fmt_ispinned;
mps_fmt_pad_t fmt_pad;
mps_fmt_class_t fmt_class;
mps_pool_t pool;
@@ -253,6 +255,9 @@ extern const struct mps_key_s _mps_key_FMT_FWD;
extern const struct mps_key_s _mps_key_FMT_ISFWD;
#define MPS_KEY_FMT_ISFWD (&_mps_key_FMT_ISFWD)
#define MPS_KEY_FMT_ISFWD_FIELD fmt_isfwd
+extern const struct mps_key_s _mps_key_FMT_ISPINNED;
+#define MPS_KEY_FMT_ISPINNED (&_mps_key_FMT_ISPINNED)
+#define MPS_KEY_FMT_ISPINNED_FIELD fmt_ispinned
extern const struct mps_key_s _mps_key_FMT_PAD;
#define MPS_KEY_FMT_PAD (&_mps_key_FMT_PAD)
#define MPS_KEY_FMT_PAD_FIELD fmt_pad
@@ -395,6 +400,7 @@ typedef struct mps_fmt_A_s {
mps_fmt_copy_t copy;
mps_fmt_fwd_t fwd;
mps_fmt_isfwd_t isfwd;
+ mps_fmt_ispinned_t ispinned;
mps_fmt_pad_t pad;
} mps_fmt_A_s;
typedef struct mps_fmt_A_s *mps_fmt_A_t;
@@ -407,6 +413,7 @@ typedef struct mps_fmt_B_s {
mps_fmt_copy_t copy;
mps_fmt_fwd_t fwd;
mps_fmt_isfwd_t isfwd;
+ mps_fmt_ispinned_t ispinned;
mps_fmt_pad_t pad;
mps_fmt_class_t mps_class;
} mps_fmt_B_s;
@@ -420,6 +427,7 @@ typedef struct mps_fmt_auto_header_s {
mps_fmt_skip_t skip;
mps_fmt_fwd_t fwd;
mps_fmt_isfwd_t isfwd;
+ mps_fmt_ispinned_t ispinned;
mps_fmt_pad_t pad;
size_t mps_headerSize;
} mps_fmt_auto_header_s;
@@ -430,6 +438,7 @@ typedef struct mps_fmt_fixed_s {
mps_fmt_scan_t scan;
mps_fmt_fwd_t fwd;
mps_fmt_isfwd_t isfwd;
+ mps_fmt_ispinned_t ispinned;
mps_fmt_pad_t pad;
} mps_fmt_fixed_s;
diff --git a/mps_raven/code/mpsi.c b/mps_mgood/code/mpsi.c
index eab0deb..0d2ce74 100644
--- a/mps_raven/code/mpsi.c
+++ b/mps_mgood/code/mpsi.c
@@ -573,6 +573,7 @@ mps_res_t mps_fmt_create_A(mps_fmt_t *mps_fmt_o,
MPS_ARGS_ADD(args, MPS_KEY_FMT_SKIP, mps_fmt_A->skip);
MPS_ARGS_ADD(args, MPS_KEY_FMT_FWD, mps_fmt_A->fwd);
MPS_ARGS_ADD(args, MPS_KEY_FMT_ISFWD, mps_fmt_A->isfwd);
+ MPS_ARGS_ADD(args, MPS_KEY_FMT_ISPINNED, mps_fmt_A->ispinned);
MPS_ARGS_ADD(args, MPS_KEY_FMT_PAD, mps_fmt_A->pad);
res = FormatCreate(&format, arena, args);
} MPS_ARGS_END(args);
@@ -607,6 +608,7 @@ mps_res_t mps_fmt_create_B(mps_fmt_t *mps_fmt_o,
MPS_ARGS_ADD(args, MPS_KEY_FMT_SKIP, mps_fmt_B->skip);
MPS_ARGS_ADD(args, MPS_KEY_FMT_FWD, mps_fmt_B->fwd);
MPS_ARGS_ADD(args, MPS_KEY_FMT_ISFWD, mps_fmt_B->isfwd);
+ MPS_ARGS_ADD(args, MPS_KEY_FMT_ISPINNED, mps_fmt_B->ispinned);
MPS_ARGS_ADD(args, MPS_KEY_FMT_PAD, mps_fmt_B->pad);
MPS_ARGS_ADD(args, MPS_KEY_FMT_CLASS, mps_fmt_B->mps_class);
res = FormatCreate(&format, arena, args);
@@ -643,6 +645,7 @@ mps_res_t mps_fmt_create_auto_header(mps_fmt_t *mps_fmt_o,
MPS_ARGS_ADD(args, MPS_KEY_FMT_SKIP, mps_fmt->skip);
MPS_ARGS_ADD(args, MPS_KEY_FMT_FWD, mps_fmt->fwd);
MPS_ARGS_ADD(args, MPS_KEY_FMT_ISFWD, mps_fmt->isfwd);
+ MPS_ARGS_ADD(args, MPS_KEY_FMT_ISPINNED, mps_fmt->ispinned);
MPS_ARGS_ADD(args, MPS_KEY_FMT_PAD, mps_fmt->pad);
res = FormatCreate(&format, arena, args);
} MPS_ARGS_END(args);
@@ -676,6 +679,7 @@ mps_res_t mps_fmt_create_fixed(mps_fmt_t *mps_fmt_o,
MPS_ARGS_ADD(args, MPS_KEY_FMT_SCAN, mps_fmt_fixed->scan);
MPS_ARGS_ADD(args, MPS_KEY_FMT_FWD, mps_fmt_fixed->fwd);
MPS_ARGS_ADD(args, MPS_KEY_FMT_ISFWD, mps_fmt_fixed->isfwd);
+ MPS_ARGS_ADD(args, MPS_KEY_FMT_ISPINNED, mps_fmt_fixed->ispinned);
MPS_ARGS_ADD(args, MPS_KEY_FMT_PAD, mps_fmt_fixed->pad);
res = FormatCreate(&format, arena, args);
} MPS_ARGS_END(args);
diff --git a/mps_raven/code/poolamc.c b/mps_mgood/code/poolamc.c
index c526c8e..ed14d8a 100644
--- a/mps_raven/code/poolamc.c
+++ b/mps_mgood/code/poolamc.c
@@ -1592,6 +1592,29 @@ static Res amcSegFix(Seg seg, ScanState ss, Ref *refIO)
/* .exposed.seg: Statements tagged ".exposed.seg" below require */
/* that "seg" (that is: the 'from' seg) has been ShieldExposed. */
ShieldExpose(arena, seg);
+ /* If the reference is pinned, set up the datastructures for */
+ /* managing a nailed segment. This involves marking the segment */
+ /* as nailed, and setting up a per-word mark table */
+ if ((*format->isPinned)(ref)) {
+ ShieldCover(arena, seg);
+ /* .nail.new: Check to see whether we need a Nailboard for */
+ /* this seg. We use "SegNailed(seg) == TraceSetEMPTY" */
+ /* rather than "!amcSegHasNailboard(seg)" because this avoids */
+ /* setting up a new nailboard when the segment was nailed, but */
+ /* had no nailboard. This must be avoided because otherwise */
+ /* assumptions in amcSegFixEmergency will be wrong (essentially */
+ /* we will lose some pointer fixes because we introduced a */
+ /* nailboard). */
+ if(SegNailed(seg) == TraceSetEMPTY) {
+ res = amcSegCreateNailboard(seg);
+ if(res != ResOK)
+ return res;
+ STATISTIC(++ss->nailCount);
+ SegSetNailed(seg, TraceSetUnion(SegNailed(seg), ss->traces));
+ }
+ amcSegFixInPlace(seg, ss, refIO);
+ return ResOK;
+ }
newRef = (*format->isMoved)(ref); /* .exposed.seg */
if(newRef == (Addr)0) { |
The idea of pinning objects based on their contents is very interesting! Thanks for telling us about this. Can you explain what the use case for this is? Are you setting a "pin bit" in an object before it's passed through an FFI to an unregistered thread, or in shared memory to another process? |
yes |
any update ? |
by the way, direct integration has almost zero performance impact for actually pinning and unpinning objects since we simply set a boolean value to which is a lot faster than managing a dedicated array/memory/pool for pinned objects |
any thoughts on eventually adding this ? |
it appears that MPS does not provide an interface for easy object pinning (for AMC (
moving gc
))The text was updated successfully, but these errors were encountered: