Skip to content

Make sure all backends are thread safe #907

Closed

Description

@munnybearz

Hi team,

Currently I'm saturating my GPU, which is cool. But on the same server I can have more GPU's - eg. an Amazon g2.8xlarge instance has 4 Nvidia K520's. I want to be able to use them too.

I want to be able to launch 4 threads and allocate each one a GPU for them to work on. I was reading the documentation for cudaSetDevice() and I believe it is possible to do this, but I think it requires some work on the ArrayFire memory manager and device manager. I really want to be able to do something like this:

Main thread
(launch # of gpu's of std::threads, eg. 4 threads)

Worker thread
af::setDevice(threadID);       // threadID is 0-3, passed in as a parameter by the main thread

Then the rest of the worker thread uses the GPU for the device id it set.

The traditional solution of a cluster of GPU hosts would be ideal, but I'm processing huge amounts of data very fast and distributing the work to multiple hosts adds too much latency. There's just too much data to serialise, transfer and deserialise to make the calculation worthwhile on a cluster. So it needs to be done on the same server.

Currently my only alternative is creating multiple processes o the server each having their dedicated GPU and having 1 coordinator process managing the work and shared memory for the data structures. It can be massively simplified if ArrayFire could support multiple GPU's used through dedicated threads.

Please could you add this to the library?

Activity

  1. pavanky commented on Jul 14, 2015

    @pavanky
    Member

    @munnybearz We are trying to make the library thread safe. Once this is done, we'll have an example demonstrating what you request.

  2. munnybearz commented on Jul 14, 2015

    @munnybearz
    ContributorAuthor

    Awesome I'm really looking forward to that then!!

  3. changed the title [-]Add support for processing on multiple GPU's simultaneously[/-] [+]Make sure all backends are thread safe[/+] on Aug 3, 2015
  4. added this to the 3.2.0 milestone on Aug 3, 2015
  5. assigned and unassigned on Aug 3, 2015
  6. modified the milestones: 3.2.0, 3.3.0 on Nov 10, 2015
  7. 15 remaining items

  8. vakopian commented on Nov 23, 2016

    @vakopian
    Contributor

    @pavanky So if I'm not mistaken the queue, async_queue and the related code is basically trying to implement a thread pool, right? If that's indeed the case, perhaps this (single header) ThreadPool library could be used instead? I think it's the same ideas and even similar implementation, but in a cleaner and more self-contained class.

    Another thing I wanted to note here (since you mentioned static variables), I just learned recently that the scoped static variables are actually thread-safe in C++11 (as opposed to older versions of the standard). AF has lots of those in many places, but if we compile with C++11, those don't need to be fixed anymore.

  9. pavanky commented on Nov 23, 2016

    @pavanky
    Member

    @umar456 is in charge of the threadpool. Umar any thoughts ?

    @vakopian
    The idea was to have a multi threaded cpu backend eventually. But for now it is single threaded.

    As for scoped static variables being thread safe, that will make things a lot easier. However I think we still have a couple of places which use global statics. Though these can be moved into a function that returns the static variable.

    @arrayfire/core-devel What are your thoughts on moving all backends to C++-11 (including CUDA). I think CUDA supports C++11 since CUDA 7.0 which makes things easier. Alternatively we can have it so just the .cpp files have the static variables and just compile the .cpp files with C++11 (like we do right now).

  10. pavanky commented on Nov 23, 2016

    @pavanky
    Member
  11. pavanky commented on Nov 23, 2016

    @pavanky
    Member

    btw VS 2013 does not support this feature: https://msdn.microsoft.com/en-us/library/hh567368(v=vs.120).aspx. Look under the section called "magic static".

    GCC and CLANG (unless Apple dropped it) seem to support it.
    VS 2015 also supports it: https://msdn.microsoft.com/en-us/library/hh409293.aspx

    Also this seems useful: http://en.cppreference.com/w/cpp/compiler_support

  12. umar456 commented on Nov 23, 2016

    @umar456
    Member

    The C++11 standard says that the initialization of magic statics are thread safe. The access and modifications are not.

    I fail to see the advantages of the ThreadPool library over the async_queue class. It seems to be a reimplementation of the std::async class. Just like std::async the ThreadPool returns std::futures every time something is queued. This would mean that we will need to keep track of these futures otherwise the operation will be synchronous. If we are keeping track of these futures then we will have another singleton container that will need to be locked every time something is enqueued. Also it looks like it is processing each command on the first available thread. This would mean that we would have to implement a method to define dependencies between operations.

    The async_queue class was created to mimic the behavior of command queues in OpenCL and streams in CUDA. We can add concurrency by creating multiple async_queues and queueing tasks based on the thread_id or some other mechanism.

    This is also a difficult problem because ArrayFire is essentially a parallelism library meaning that we want all of the CPU resources to be working on one task then another; similar to the OpenCL and CUDA backends. Users using ArrayFire in concurrent threads may hurt performance because each task assumes it has full control of the hardware.

    We need ArrayFire to be thread safe in that you should be able to access the arrays from multiple threads. Users should not try to use threads in their code to improve performance by running the same operation on two threads. Tasks should be parallelized to use all of the compute resources of the CPU to speed computations. I have some ideas on how to do something like this but that is not related to this issue.

  13. WilliamTambellini commented on Nov 24, 2016

    @WilliamTambellini
    Contributor

    Good morning gentlemen,
    Is this issue/item likely to be in 3.4.2 or is it really for 3.5 ?
    Kindly

  14. pavanky commented on Nov 24, 2016

    @pavanky
    Member

    @WilliamTambellini I am not sure if this is possible in the timeframe of 3.4.2

  15. vakopian commented on Dec 6, 2016

    @vakopian
    Contributor

    Users should not try to use threads in their code to improve performance by running the same operation on two threads.

    I understand what motivates the statement above, but I think it might be missing 2 important scenarios:

    1. Hybrid applications that are very "parallelizable". By "hybrid", I mean applications that do lots of CPU calculations, then lots of GPU (ArrayFire), then more CPU, then more GPU, etc. And by "parallelizable", I mean it can benefit from concurrency not just from GPU, but at CPU level as well. A simple example would be an image processing algorithm that can easily be parallelized by splitting it into tiles and each tile needs both CPU and GPU processing. For such an application, not using threads means not taking advantage of the CPU for some tiles while the GPU is busy processing the other tiles.

    2. Machines with multiple GPU devices. If the application is not designed to be multi-threaded, it would have no way of taking advantage of multiple GPUs.

    @umar456, do you agree that for these use cases it's important to write the application as multi-threaded. And if so, shouldn't we make sure that ArrayFire does not prevent, nor create unnecessary bottlenecks for, such usage?

  16. pavanky commented on Dec 6, 2016

    @pavanky
    Member

    @vakopian

    FYI

    1. Should not require multi threading support in individual backends if you are using only one thread per backend. We may need to fix the stuff in src/api/unified.

    2. ArrayFire is asynchronous (for the most part).You can hand off function 1 to GPU 1, function 2 to GPU 2, function 3 to GPU 3 in a for loop before function 1 is completed. Granted this is a bit ugly but what you are requesting for can be mostly achieved using existing functionality.

  17. pavanky commented on Dec 6, 2016

    @pavanky
    Member

    Having said that, thread safety is still a very important feature to have.

  18. vakopian commented on Dec 7, 2016

    @vakopian
    Contributor

    @pavanky I'm not sure if there is a recommendation in your (1). I was just trying to say that @umar456's recommendation of "not relying on threads to improve performance" is not really viable in some important scenarios. The way I understood that recommendation was this:

    "since the GPU operations are pushed into a single queue anyway, there is no benefit nor need for multiple threads, and so designing the application as if it's a single threaded program is the recommended way to go".

    Is this understanding correct? Do you really recommend making the application quasi-single-threaded? If yes, then I still think that following this recommendation would result in a sub-optimal application for the 2 scenarios I described.

  19. pavanky commented on Dec 7, 2016

    @pavanky
    Member

    @vakopian No I don't mean that at all :)

    I was just letting you know the workarounds for now if this is a blocking feature on your end.

  20. WilliamTambellini commented on Feb 20, 2017

    @WilliamTambellini
    Contributor

    Good morning,
    What is the current status of this one: still early WIP ? halfly done ? mostly done ready for 3.5 ? done ?
    Kind

  21. pavanky commented on Feb 20, 2017

    @pavanky
    Member

    @WilliamTambellini check #1706 for the progress being made.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions