Groups keyboard shortcuts have been updated
Dismiss
See shortcuts

UPCXX_SERIALIZED_FIELDS serializes member which is not asked for

5 views
Skip to first unread message

Orxan Shibliyev

unread,
Jan 24, 2022, 7:15:28 AM1/24/22
to UPC++

In this code below, I except field j not to be transmitted since I only provided UPCXX_SERIALIZED_FIELDS(i). According to the documentation:

"In UPCXX_SERIALIZED_FIELDS the programmer passes a list of non-static member field names in a class, and the UPC++ library automatically generates the needed serialization logic to transmit those fields (and only those fields) whenever an instance of that class is sent as part of an RPC."


#include <iostream>
#include <upcxx/upcxx.hpp>

using namespace upcxx;

struct MyClass
{
    int i;
    int j;

    MyClass()
    {
        i = rank_me();
        j = rank_me();
    }

    UPCXX_SERIALIZED_FIELDS(i)
};

int main()
{
  init();

  dist_object<global_ptr<MyClass>> myclass(new_<MyClass>());

  if (rank_me() == 0)
  {
      auto fetched = myclass.fetch(1).wait().local();
      std::cout << "my j: " << myclass->local()->j << std::endl;
      std::cout << "fetched j: " << fetched->j << std::endl;
  }

  finalize();
  return 0;
}

Dan Bonachea

unread,
Jan 25, 2022, 5:59:17 PM1/25/22
to Orxan Shibliyev, UPC++
Hi Orxan - Thanks for your question!

The issue here is not Serialization, because the code you supplied does not even invoke the UPCXX_SERIALIZED_FIELDS serializer you've specified, due to a level of pointer indirection.

This code:

  dist_object<global_ptr<MyClass>> myclass(new_<MyClass>());
allocates a MyClass object on the shared heap of each process and creates a distributed object to hold the global pointer to each MyClass.
Then the call by process 0:
  myclass.fetch(1)
fetches the global_ptr<MyClass> from process 1. The RPC underlying fetch trivially serializes the global_ptr, but NOT the referenced MyClass object (which seems to be what you expected). The subsequent call to local() returns a MyClass* pointer into "fetched" (and this call is notably only valid when process 0 and 1 share a local_team(), ie same-node; this call will crash in multi-node runs using codemode debug). The subsequent expression fetched->j is actually a heap access reading the initial/unchanged MyClass object from the shared heap of process 1.

Below is a modified version of your code that removes the level of indirection (that seems to have been unintentional) so the MyClass object is actually serialzed, with the critical changes highlighted.

#include <iostream>
#include <upcxx/upcxx.hpp>

using namespace upcxx;

struct MyClass
{
    int i;
    int j;

    MyClass()
    {
        i = rank_me();
        j = rank_me();
    }

    UPCXX_SERIALIZED_FIELDS(i)
};

int main()
{
  init();

  dist_object<MyClass> do_myclass({});

  if (rank_me() == 0)
  {
      MyClass fetched = do_myclass.fetch(1).wait();
      std::cout << "my j: " << do_myclass->j << std::endl;
      std::cout << "fetched j: " << fetched.j << std::endl;
  }

  finalize();
  return 0;
}


Which should print the expected result:
my j: 0
fetched j: 0


Hope this helps!
-D

--
You received this message because you are subscribed to the Google Groups "UPC++" group.
To unsubscribe from this group and stop receiving emails from it, send an email to upcxx+un...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/upcxx/7589c17d-d6ef-49e2-9913-b26b5b15d964n%40googlegroups.com.
Reply all
Reply to author
Forward
0 new messages