Home | History | Annotate | Download | only in stream_executor
      1 /* Copyright 2015 The TensorFlow Authors. All Rights Reserved.
      2 
      3 Licensed under the Apache License, Version 2.0 (the "License");
      4 you may not use this file except in compliance with the License.
      5 You may obtain a copy of the License at
      6 
      7     http://www.apache.org/licenses/LICENSE-2.0
      8 
      9 Unless required by applicable law or agreed to in writing, software
     10 distributed under the License is distributed on an "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 See the License for the specific language governing permissions and
     13 limitations under the License.
     14 ==============================================================================*/
     15 
     16 // This is a registration-oriented interface for multiple platforms. It will
     17 // replace the MachineManager singleton interface, as MachineManager does not
     18 // currently support simultaneous use of multiple platforms.
     19 //
     20 // Usage:
     21 //
     22 // In your BUILD rule, add a dependency on a platform plugin that you'd like
     23 // to use, such as:
     24 //
     25 //   //perftools/gputools/executor/cuda:cuda_platform
     26 //   //perftools/gputools/executor/opencl:opencl_platform
     27 //
     28 // This will register platform plugins that can be discovered via this
     29 // interface. Sample API usage:
     30 //
     31 //   port::StatusOr<Platform*> platform_status =
     32 //      gpu::MultiPlatformManager::PlatformWithName("OpenCL");
     33 //   if (!platform_status.ok()) { ... }
     34 //   Platform* platform = platform_status.ValueOrDie();
     35 //   LOG(INFO) << platform->VisibleDeviceCount() << " devices visible";
     36 //   if (platform->VisibleDeviceCount() <= 0) { return; }
     37 //
     38 //   for (int i = 0; i < platform->VisibleDeviceCount(); ++i) {
     39 //     port::StatusOr<StreamExecutor*> executor_status =
     40 //        platform->ExecutorForDevice(i);
     41 //     if (!executor_status.ok()) {
     42 //       LOG(INFO) << "could not retrieve executor for device ordinal " << i
     43 //                 << ": " << executor_status.status();
     44 //       continue;
     45 //     }
     46 //     LOG(INFO) << "found usable executor: " << executor_status.ValueOrDie();
     47 //   }
     48 //
     49 // A few things to note:
     50 //  - There is no standard formatting/practice for identifying the name of a
     51 //    platform. Ideally, a platform will list its registered name in its header
     52 //    or in other associated documentation.
     53 //  - Platform name lookup is case-insensitive. "OpenCL" or "opencl" (or even
     54 //    ("OpEnCl") would work correctly in the above example.
     55 //
     56 // And similarly, for standard interfaces (BLAS, RNG, etc.) you can add
     57 // dependencies on support libraries, e.g.:
     58 //
     59 //    //perftools/gputools/executor/cuda:pluton_blas_plugin
     60 //    //perftools/gputools/executor/cuda:cudnn_plugin
     61 //    //perftools/gputools/executor/cuda:cublas_plugin
     62 //    //perftools/gputools/executor/cuda:curand_plugin
     63 
     64 #ifndef TENSORFLOW_STREAM_EXECUTOR_MULTI_PLATFORM_MANAGER_H_
     65 #define TENSORFLOW_STREAM_EXECUTOR_MULTI_PLATFORM_MANAGER_H_
     66 
     67 #include <functional>
     68 #include <map>
     69 #include <memory>
     70 #include "tensorflow/stream_executor/platform/port.h"
     71 
     72 #include "tensorflow/stream_executor/lib/status.h"
     73 #include "tensorflow/stream_executor/lib/statusor.h"
     74 #include "tensorflow/stream_executor/platform.h"
     75 #include "tensorflow/stream_executor/platform/mutex.h"
     76 #include "tensorflow/stream_executor/platform/port.h"
     77 
     78 namespace perftools {
     79 namespace gputools {
     80 
     81 // Manages multiple platforms that may be present on the current machine.
     82 class MultiPlatformManager {
     83  public:
     84   // Registers a platform object, returns an error status if the platform is
     85   // already registered. The associated listener, if not null, will be used to
     86   // trace events for ALL executors for that platform.
     87   // Takes ownership of listener.
     88   static port::Status RegisterPlatform(std::unique_ptr<Platform> platform);
     89 
     90   // Retrieves the platform registered with the given platform name; e.g.
     91   // "CUDA", "OpenCL", ...
     92   //
     93   // If the requested platform is not registered, an error status is returned.
     94   // Ownership of the platform is NOT transferred to the caller --
     95   // the MultiPlatformManager owns the platforms in a singleton-like fashion.
     96   static port::StatusOr<Platform*> PlatformWithName(const string& target);
     97 
     98   // Retrieves the platform registered with the given platform ID, which
     99   // is an opaque (but comparable) value.
    100   //
    101   // If the requested platform is not registered, an error status is returned.
    102   // Ownership of the platform is NOT transferred to the caller --
    103   // the MultiPlatformManager owns the platforms in a singleton-like fashion.
    104   static port::StatusOr<Platform*> PlatformWithId(const Platform::Id& id);
    105 
    106   // Clears the set of registered platforms, primarily used for testing.
    107   static void ClearPlatformRegistry();
    108 
    109   // Although the MultiPlatformManager "owns" its platforms, it holds them as
    110   // undecorated pointers to prevent races during program exit (between this
    111   // object's data and the underlying platforms (e.g., CUDA, OpenCL).
    112   // Because certain platforms have unpredictable deinitialization
    113   // times/sequences, it is not possible to strucure a safe deinitialization
    114   // sequence. Thus, we intentionally "leak" allocated platforms to defer
    115   // cleanup to the OS. This should be acceptable, as these are one-time
    116   // allocations per program invocation.
    117   // The MultiPlatformManager should be considered the owner
    118   // of any platforms registered with it, and leak checking should be disabled
    119   // during allocation of such Platforms, to avoid spurious reporting at program
    120   // exit.
    121   using PlatformMap = std::map<string, Platform*>;
    122 
    123   // Provides access to the available set of platforms under a lock.
    124   static port::Status WithPlatforms(
    125       std::function<port::Status(PlatformMap*)> callback) {
    126     mutex_lock lock(GetPlatformsMutex());
    127     return callback(GetPlatformMap());
    128   }
    129 
    130  private:
    131   // mutex that guards the platform map.
    132   static mutex& GetPlatformsMutex() {
    133     static mutex* platforms_mutex = new mutex;
    134     return *platforms_mutex;
    135   }
    136 
    137   // TODO(b/22689637): Clean up these two maps; make sure they coexist nicely.
    138   // TODO(b/22689637): Move this (whatever the final/"official" map is) to
    139   // plugin_regstry.h, along with the associated functionality.
    140   // Platform-name-to-object mapping. These platforms are registered via module
    141   // initializers, and linkage determines which platforms are available to a
    142   // given target.
    143   static PlatformMap* GetPlatformMap() {
    144     static PlatformMap* instance = new PlatformMap;
    145     return instance;
    146   }
    147 
    148   // Holds a Platform::Id-to-object mapping.
    149   // Unlike platforms_ above, this map does not own its contents.
    150   static std::map<Platform::Id, Platform*>* GetPlatformByIdMap() {
    151     using PlatformIdMap = std::map<Platform::Id, Platform*>;
    152     static PlatformIdMap* instance = new PlatformIdMap;
    153     return instance;
    154   }
    155 
    156   SE_DISALLOW_COPY_AND_ASSIGN(MultiPlatformManager);
    157 };
    158 
    159 }  // namespace gputools
    160 }  // namespace perftools
    161 
    162 #endif  // TENSORFLOW_STREAM_EXECUTOR_MULTI_PLATFORM_MANAGER_H_
    163