global_ptr guarantees

Issue #32 resolved
Dan Bonachea created an issue

I think the current spec draft may be missing some important guarantees of universality of representation for global pointers.

In particular:

  1. All global pointers that reference any given object in shared space should always compare as equal (and report the same .where()), regardless of how the pointers were constructed. In particular, two different ranks on the same local team that use the "from T*" constructor to construct a global pointer to the same object in shared space (of some local team member) will result in global pointers that compare as equal. This is despite the fact that the T* values passed in by each rank might not be bitwise identical.

  2. Also, the .where() of all global pointers referencing any given object in shared space should be guaranteed to be equal - ie where() is determined by the affinity of the object, and in particular might not correspond to the rank who constructed the pointer. It follows that .is_local() == true does not imply .where() == rank_me().

  3. We should guarantee that the global_ptr representation is rank-independent. In particular, if rank A stores a valid global_ptr in shared memory and (after a proper synchronization) rank B reads that pointer back out, rank B should be guaranteed the result is still a valid global_ptr that points to the same object and returns the same .where().

Comments (15)

  1. Dan Bonachea reporter

    On a closely related note, global_ptr<T>.where() is currently underspecified for null pointers, where there is no referenced object and the concept of affinity is therefore undefined. It either needs a precondition of !this.is_null(), or a defined return value for null pointers (eg 0). UPC takes the latter approach for upc_threadof.

  2. Dan Bonachea reporter

    +Global pointers have the following guarantee with respect to how they
    +are represented internally:
    +\begin{quote}
    +For any memory in any rank's shared space, there is exactly one global
    +pointer representation (internal bit-pattern) which references that
    +memory. Also, there is only one global pointer representation which
    +references no memory, and that is the null value.

    This seems a bit too strong - by main objection it seems to require that global_ptr<T> and an aliased global_ptr<char> (after a reinterpret case) have exactly the same internal representation, and I don't think that's something we need or want to guarantee (for example, in a debug build a valid global ptr rep might store some introspection information about its referent type, to perform extra dynamic type-safety checking).

    Also, because you phrased it in terms of memory and not objects, if an shared object is deallocated and a new allocate command for a different object type happens to land on the same byte, we have the same false guarantee that global_ptr<T>::rep == global_ptr<U>::rep when T != U.

    Finally, I don't think we need or want to nail down the internal representation to be truly bitwise identical - that would imply it's valid to compare global_ptr's for equality using memcmp(). For example, we don't care if the contents of internal structure padding differs, or if they carry additional internal-only state for tracking information we don't expose. All we really need is that they behave as if they are identical via all the supported methods.

    What we need is all global_ptr<T> to a given shared object compare equals(), give the same where(), and reference the same object, regardless of which rank is asking.

  3. Dan Bonachea reporter

    I think property #2 in the original post might be worth clarifying explicitly - ie that all gptrs referencing a given object have equal affinity and .where().

    This is mostly because we currently lack a formal definition of "affinity" (will be better once we have a glossary definition of that term).

  4. Former user Account Deleted

    The fact that where() returns the same value for any two gp's referencing the same object follows from:

    1. object reference equality implies gp equality.
    2. gp equality implies behavioral equivalence (hence .where())

    That's enough right? I'm not going to change it unless its necessary.

  5. Dan Bonachea reporter

    I reworded slightly for clarity, see what you think 9befd39

    The only part that still leaves me slightly uneasy is this wording:

    Global pointers have the following guarantees:
    1. There is only one global pointer which does not reference a valid object, that is the
    null global pointer.

    The basic idea is correct, but the highlander phrasing is not strictly true - technically there's actually one null global pointer (ie global_ptr<T>(nullptr)) for every value of T.

    Also, one might argue that after:

    global_ptr<T> g = allocate(1);
    deallocate(g);
    

    g is also a global pointer that does not reference a valid object, but it is not guaranteed to be null. C++ sec 3.7.4.1 phrasing says that deallocation of an object renders the pointer value itself invalid.

    What do you think about this replacement:

    1. There is only one valid global_ptr<T> which does not reference a valid object, that is the null global pointer.
  6. Dan Bonachea reporter
    • changed status to open

    On further reflection, the current language is still not quite right.

    There are actually many valid non-null global_ptr<T>'s that do not reference a valid object, specifically those that point to one-past the end of any array of objects in shared memory.

  7. Log in to comment