bricklore
bricklore

Reputation: 4165

iterating over a doubly linked list from device

I need to create a doubly linked list on a cuda device.
I have the host code:

class Foo
{
public:
    int my_index;
    static int count;
    static int index;
    static Foo* first;
    static Foo* last;
    Foo* next;
    Foo* prev;

    Foo(); //adds object to list
    ~Foo(); //deletes object from list
}

Foo* Foo::first = 0;
Foo* Foo::last = 0;
int Foo::count = 0;
int Foo::index = 0;

when i want to iterate through it:

for (Foo* pr = Foo::first; pr; pr = pr->next)
{
    //do something
}

My first problem is:
there are several other classes that inherit from Foo
and they have differrent sizes, so how can I:

I dont have to access the data from Foo on the host,
I need it only on the device.

My second problem:
I have multiple CUDA devices (3 CUDA capable graphic cards)
how could i access the device doubly linked list on both devices?

Upvotes: 0

Views: 192

Answers (2)

Ben S.
Ben S.

Reputation: 1143

I'm not familiar with CUDA, but it sounds you need to transform each object into some form so that it can be transferred to the device, and the problem is that the objects are different sizes and have different contents. If so, you should be able to solve the problem with a virtual function that transforms each object into a form that can be transferred according to its type. For example, if you were transferring data as binary using a void * buffer, it might look like:

class Foo
{
public:
    // ... Everything else ...

    virtual void *add_transfer_data(void *buffer)
    {
        // Copy whatever makes sense for a Foo object into the buffer.
        memcpy(buffer, [something], n);

        return reinterpret_cast<unsigned char *>(buffer) + n;
    }
};

class Bar: public Foo
{
public:
    // ... Everything else ...

    virtual void *add_transfer_data(void *buffer)
    {
        // First, take care of the Foo part of the object.
        buffer = Foo::add_transfer_data(buffer, buffer_size);

        // Now copy whatever else a Bar object needs into the buffer.
        memcpy(buffer, [something], m);

        return reinterpret_cast<unsigned char *>(buffer) + m;
    }
};

void transfer_data(void *buffer)
{
    void *next_location = buffer;
    for (Foo* pr = Foo::first; pr; pr = pr->next)
    {
        next_location = pr->add_transfer_data(next_location);
    }

    // Send the contents of buffer to the device somehow.
}

Of course, your versions of add_transfer_data might be very different depending on the details of how the transfer works and what the objects look like. There might be nothing to write for just a plain Foo object, for example. Hopefully, though, this illustrates the central idea.

Upvotes: 1

user2533092
user2533092

Reputation:

I don't know anything about CUDA, so there is likely a better answer.

If your problem is determining the size of an instance of Foo, then why not give the class a virtual size method?

// In Foo:
virtual size_t size() const;

// In class T, a derivation of Foo:
size_t size() const override { return sizeof(T); }

Upvotes: -3

Related Questions