Home | History | Annotate | Download | only in platform
      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 #ifndef TENSORFLOW_CORE_PLATFORM_ENV_H_
     17 #define TENSORFLOW_CORE_PLATFORM_ENV_H_
     18 
     19 #include <stdint.h>
     20 #include <memory>
     21 #include <string>
     22 #include <unordered_map>
     23 #include <vector>
     24 #include "tensorflow/core/lib/core/errors.h"
     25 #include "tensorflow/core/lib/core/status.h"
     26 #include "tensorflow/core/lib/core/stringpiece.h"
     27 #include "tensorflow/core/platform/env_time.h"
     28 #include "tensorflow/core/platform/file_system.h"
     29 #include "tensorflow/core/platform/macros.h"
     30 #include "tensorflow/core/platform/mutex.h"
     31 #include "tensorflow/core/platform/numa.h"
     32 #include "tensorflow/core/platform/protobuf.h"
     33 #include "tensorflow/core/platform/types.h"
     34 
     35 namespace tensorflow {
     36 
     37 class Thread;
     38 struct ThreadOptions;
     39 
     40 /// \brief An interface used by the tensorflow implementation to
     41 /// access operating system functionality like the filesystem etc.
     42 ///
     43 /// Callers may wish to provide a custom Env object to get fine grain
     44 /// control.
     45 ///
     46 /// All Env implementations are safe for concurrent access from
     47 /// multiple threads without any external synchronization.
     48 class Env {
     49  public:
     50   Env();
     51   virtual ~Env() = default;
     52 
     53   /// \brief Returns a default environment suitable for the current operating
     54   /// system.
     55   ///
     56   /// Sophisticated users may wish to provide their own Env
     57   /// implementation instead of relying on this default environment.
     58   ///
     59   /// The result of Default() belongs to this library and must never be deleted.
     60   static Env* Default();
     61 
     62   /// \brief Returns the FileSystem object to handle operations on the file
     63   /// specified by 'fname'. The FileSystem object is used as the implementation
     64   /// for the file system related (non-virtual) functions that follow.
     65   /// Returned FileSystem object is still owned by the Env object and will
     66   // (might) be destroyed when the environment is destroyed.
     67   virtual Status GetFileSystemForFile(const string& fname, FileSystem** result);
     68 
     69   /// \brief Returns the file system schemes registered for this Env.
     70   virtual Status GetRegisteredFileSystemSchemes(std::vector<string>* schemes);
     71 
     72   /// \brief Register a file system for a scheme.
     73   virtual Status RegisterFileSystem(const string& scheme,
     74                                     FileSystemRegistry::Factory factory);
     75 
     76   /// \brief Flush filesystem caches for all registered filesystems.
     77   Status FlushFileSystemCaches();
     78 
     79   /// \brief Creates a brand new random access read-only file with the
     80   /// specified name.
     81 
     82   /// On success, stores a pointer to the new file in
     83   /// *result and returns OK.  On failure stores NULL in *result and
     84   /// returns non-OK.  If the file does not exist, returns a non-OK
     85   /// status.
     86   ///
     87   /// The returned file may be concurrently accessed by multiple threads.
     88   ///
     89   /// The ownership of the returned RandomAccessFile is passed to the caller
     90   /// and the object should be deleted when is not used. The file object
     91   /// shouldn't live longer than the Env object.
     92   Status NewRandomAccessFile(const string& fname,
     93                              std::unique_ptr<RandomAccessFile>* result);
     94 
     95   /// \brief Creates an object that writes to a new file with the specified
     96   /// name.
     97   ///
     98   /// Deletes any existing file with the same name and creates a
     99   /// new file.  On success, stores a pointer to the new file in
    100   /// *result and returns OK.  On failure stores NULL in *result and
    101   /// returns non-OK.
    102   ///
    103   /// The returned file will only be accessed by one thread at a time.
    104   ///
    105   /// The ownership of the returned WritableFile is passed to the caller
    106   /// and the object should be deleted when is not used. The file object
    107   /// shouldn't live longer than the Env object.
    108   Status NewWritableFile(const string& fname,
    109                          std::unique_ptr<WritableFile>* result);
    110 
    111   /// \brief Creates an object that either appends to an existing file, or
    112   /// writes to a new file (if the file does not exist to begin with).
    113   ///
    114   /// On success, stores a pointer to the new file in *result and
    115   /// returns OK.  On failure stores NULL in *result and returns
    116   /// non-OK.
    117   ///
    118   /// The returned file will only be accessed by one thread at a time.
    119   ///
    120   /// The ownership of the returned WritableFile is passed to the caller
    121   /// and the object should be deleted when is not used. The file object
    122   /// shouldn't live longer than the Env object.
    123   Status NewAppendableFile(const string& fname,
    124                            std::unique_ptr<WritableFile>* result);
    125 
    126   /// \brief Creates a readonly region of memory with the file context.
    127   ///
    128   /// On success, it returns a pointer to read-only memory region
    129   /// from the content of file fname. The ownership of the region is passed to
    130   /// the caller. On failure stores nullptr in *result and returns non-OK.
    131   ///
    132   /// The returned memory region can be accessed from many threads in parallel.
    133   ///
    134   /// The ownership of the returned ReadOnlyMemoryRegion is passed to the caller
    135   /// and the object should be deleted when is not used. The memory region
    136   /// object shouldn't live longer than the Env object.
    137   Status NewReadOnlyMemoryRegionFromFile(
    138       const string& fname, std::unique_ptr<ReadOnlyMemoryRegion>* result);
    139 
    140   /// Returns OK if the named path exists and NOT_FOUND otherwise.
    141   Status FileExists(const string& fname);
    142 
    143   /// Returns true if all the listed files exist, false otherwise.
    144   /// if status is not null, populate the vector with a detailed status
    145   /// for each file.
    146   bool FilesExist(const std::vector<string>& files,
    147                   std::vector<Status>* status);
    148 
    149   /// \brief Stores in *result the names of the children of the specified
    150   /// directory. The names are relative to "dir".
    151   ///
    152   /// Original contents of *results are dropped.
    153   Status GetChildren(const string& dir, std::vector<string>* result);
    154 
    155   /// \brief Returns true if the path matches the given pattern. The wildcards
    156   /// allowed in pattern are described in FileSystem::GetMatchingPaths.
    157   virtual bool MatchPath(const string& path, const string& pattern) = 0;
    158 
    159   /// \brief Given a pattern, stores in *results the set of paths that matches
    160   /// that pattern. *results is cleared.
    161   ///
    162   /// More details about `pattern` in FileSystem::GetMatchingPaths.
    163   virtual Status GetMatchingPaths(const string& pattern,
    164                                   std::vector<string>* results);
    165 
    166   /// Deletes the named file.
    167   Status DeleteFile(const string& fname);
    168 
    169   /// \brief Deletes the specified directory and all subdirectories and files
    170   /// underneath it. This is accomplished by traversing the directory tree
    171   /// rooted at dirname and deleting entries as they are encountered.
    172   ///
    173   /// If dirname itself is not readable or does not exist, *undeleted_dir_count
    174   /// is set to 1, *undeleted_file_count is set to 0 and an appropriate status
    175   /// (e.g. NOT_FOUND) is returned.
    176   ///
    177   /// If dirname and all its descendants were successfully deleted, TF_OK is
    178   /// returned and both error counters are set to zero.
    179   ///
    180   /// Otherwise, while traversing the tree, undeleted_file_count and
    181   /// undeleted_dir_count are updated if an entry of the corresponding type
    182   /// could not be deleted. The returned error status represents the reason that
    183   /// any one of these entries could not be deleted.
    184   ///
    185   /// REQUIRES: undeleted_files, undeleted_dirs to be not null.
    186   ///
    187   /// Typical return codes:
    188   ///  * OK - dirname exists and we were able to delete everything underneath.
    189   ///  * NOT_FOUND - dirname doesn't exist
    190   ///  * PERMISSION_DENIED - dirname or some descendant is not writable
    191   ///  * UNIMPLEMENTED - Some underlying functions (like Delete) are not
    192   ///                    implemented
    193   Status DeleteRecursively(const string& dirname, int64* undeleted_files,
    194                            int64* undeleted_dirs);
    195 
    196   /// \brief Creates the specified directory and all the necessary
    197   /// subdirectories. Typical return codes.
    198   ///  * OK - successfully created the directory and sub directories, even if
    199   ///         they were already created.
    200   ///  * PERMISSION_DENIED - dirname or some subdirectory is not writable.
    201   Status RecursivelyCreateDir(const string& dirname);
    202 
    203   /// \brief Creates the specified directory. Typical return codes
    204   ///  * OK - successfully created the directory.
    205   ///  * ALREADY_EXISTS - directory already exists.
    206   ///  * PERMISSION_DENIED - dirname is not writable.
    207   Status CreateDir(const string& dirname);
    208 
    209   /// Deletes the specified directory.
    210   Status DeleteDir(const string& dirname);
    211 
    212   /// Obtains statistics for the given path.
    213   Status Stat(const string& fname, FileStatistics* stat);
    214 
    215   /// \brief Returns whether the given path is a directory or not.
    216   /// Typical return codes (not guaranteed exhaustive):
    217   ///  * OK - The path exists and is a directory.
    218   ///  * FAILED_PRECONDITION - The path exists and is not a directory.
    219   ///  * NOT_FOUND - The path entry does not exist.
    220   ///  * PERMISSION_DENIED - Insufficient permissions.
    221   ///  * UNIMPLEMENTED - The file factory doesn't support directories.
    222   Status IsDirectory(const string& fname);
    223 
    224   /// Stores the size of `fname` in `*file_size`.
    225   Status GetFileSize(const string& fname, uint64* file_size);
    226 
    227   /// \brief Renames file src to target. If target already exists, it will be
    228   /// replaced.
    229   Status RenameFile(const string& src, const string& target);
    230 
    231   /// \brief Copy the src to target.
    232   Status CopyFile(const string& src, const string& target);
    233 
    234   /// \brief Returns the absolute path of the current executable. It resolves
    235   /// symlinks if there is any.
    236   string GetExecutablePath();
    237 
    238   /// Creates a local unique temporary file name. Returns true if success.
    239   bool LocalTempFilename(string* filename);
    240 
    241   /// Creates a local unique file name that starts with |prefix| and ends with
    242   /// |suffix|. Returns true if success.
    243   bool CreateUniqueFileName(string* prefix, const string& suffix);
    244 
    245   /// \brief Return the runfiles directory if running under bazel. Returns
    246   /// the directory the executable is located in if not running under bazel.
    247   virtual string GetRunfilesDir() = 0;
    248 
    249   // TODO(jeff,sanjay): Add back thread/thread-pool support if needed.
    250   // TODO(jeff,sanjay): if needed, tighten spec so relative to epoch, or
    251   // provide a routine to get the absolute time.
    252 
    253   /// \brief Returns the number of nano-seconds since the Unix epoch.
    254   virtual uint64 NowNanos() { return envTime->NowNanos(); }
    255 
    256   /// \brief Returns the number of micro-seconds since the Unix epoch.
    257   virtual uint64 NowMicros() { return envTime->NowMicros(); }
    258 
    259   /// \brief Returns the number of seconds since the Unix epoch.
    260   virtual uint64 NowSeconds() { return envTime->NowSeconds(); }
    261 
    262   /// Sleeps/delays the thread for the prescribed number of micro-seconds.
    263   virtual void SleepForMicroseconds(int64 micros) = 0;
    264 
    265   /// \brief Returns a new thread that is running fn() and is identified
    266   /// (for debugging/performance-analysis) by "name".
    267   ///
    268   /// Caller takes ownership of the result and must delete it eventually
    269   /// (the deletion will block until fn() stops running).
    270   virtual Thread* StartThread(const ThreadOptions& thread_options,
    271                               const string& name,
    272                               std::function<void()> fn) TF_MUST_USE_RESULT = 0;
    273 
    274   // Returns the thread id of calling thread.
    275   // Posix: Returns pthread id which is only guaranteed to be unique within a
    276   //        process.
    277   // Windows: Returns thread id which is unique.
    278   virtual int32 GetCurrentThreadId() = 0;
    279 
    280   // Copies current thread name to "name". Returns true if success.
    281   virtual bool GetCurrentThreadName(string* name) = 0;
    282 
    283   // \brief Schedules the given closure on a thread-pool.
    284   //
    285   // NOTE(mrry): This closure may block.
    286   virtual void SchedClosure(std::function<void()> closure) = 0;
    287 
    288   // \brief Schedules the given closure on a thread-pool after the given number
    289   // of microseconds.
    290   //
    291   // NOTE(mrry): This closure must not block.
    292   virtual void SchedClosureAfter(int64 micros,
    293                                  std::function<void()> closure) = 0;
    294 
    295   // \brief Load a dynamic library.
    296   //
    297   // Pass "library_filename" to a platform-specific mechanism for dynamically
    298   // loading a library.  The rules for determining the exact location of the
    299   // library are platform-specific and are not documented here.
    300   //
    301   // On success, returns a handle to the library in "*handle" and returns
    302   // OK from the function.
    303   // Otherwise returns nullptr in "*handle" and an error status from the
    304   // function.
    305   virtual Status LoadLibrary(const char* library_filename, void** handle) = 0;
    306 
    307   // \brief Get a pointer to a symbol from a dynamic library.
    308   //
    309   // "handle" should be a pointer returned from a previous call to LoadLibrary.
    310   // On success, store a pointer to the located symbol in "*symbol" and return
    311   // OK from the function. Otherwise, returns nullptr in "*symbol" and an error
    312   // status from the function.
    313   virtual Status GetSymbolFromLibrary(void* handle, const char* symbol_name,
    314                                       void** symbol) = 0;
    315 
    316   // \brief build the name of dynamic library.
    317   //
    318   // "name" should be name of the library.
    319   // "version" should be the version of the library or NULL
    320   // returns the name that LoadLibrary() can use
    321   virtual string FormatLibraryFileName(const string& name,
    322                                        const string& version) = 0;
    323 
    324   // Returns a possible list of local temporary directories.
    325   virtual void GetLocalTempDirectories(std::vector<string>* list) = 0;
    326 
    327  private:
    328   std::unique_ptr<FileSystemRegistry> file_system_registry_;
    329   TF_DISALLOW_COPY_AND_ASSIGN(Env);
    330   EnvTime* envTime = EnvTime::Default();
    331 };
    332 
    333 /// \brief An implementation of Env that forwards all calls to another Env.
    334 ///
    335 /// May be useful to clients who wish to override just part of the
    336 /// functionality of another Env.
    337 class EnvWrapper : public Env {
    338  public:
    339   /// Initializes an EnvWrapper that delegates all calls to *t
    340   explicit EnvWrapper(Env* t) : target_(t) {}
    341   virtual ~EnvWrapper();
    342 
    343   /// Returns the target to which this Env forwards all calls
    344   Env* target() const { return target_; }
    345 
    346   Status GetFileSystemForFile(const string& fname,
    347                               FileSystem** result) override {
    348     return target_->GetFileSystemForFile(fname, result);
    349   }
    350 
    351   Status GetRegisteredFileSystemSchemes(std::vector<string>* schemes) override {
    352     return target_->GetRegisteredFileSystemSchemes(schemes);
    353   }
    354 
    355   Status RegisterFileSystem(const string& scheme,
    356                             FileSystemRegistry::Factory factory) override {
    357     return target_->RegisterFileSystem(scheme, factory);
    358   }
    359 
    360   bool MatchPath(const string& path, const string& pattern) override {
    361     return target_->MatchPath(path, pattern);
    362   }
    363 
    364   uint64 NowMicros() override { return target_->NowMicros(); }
    365   void SleepForMicroseconds(int64 micros) override {
    366     target_->SleepForMicroseconds(micros);
    367   }
    368   Thread* StartThread(const ThreadOptions& thread_options, const string& name,
    369                       std::function<void()> fn) override {
    370     return target_->StartThread(thread_options, name, fn);
    371   }
    372   int32 GetCurrentThreadId() override { return target_->GetCurrentThreadId(); }
    373   bool GetCurrentThreadName(string* name) override {
    374     return target_->GetCurrentThreadName(name);
    375   }
    376   void SchedClosure(std::function<void()> closure) override {
    377     target_->SchedClosure(closure);
    378   }
    379   void SchedClosureAfter(int64 micros, std::function<void()> closure) override {
    380     target_->SchedClosureAfter(micros, closure);
    381   }
    382   Status LoadLibrary(const char* library_filename, void** handle) override {
    383     return target_->LoadLibrary(library_filename, handle);
    384   }
    385   Status GetSymbolFromLibrary(void* handle, const char* symbol_name,
    386                               void** symbol) override {
    387     return target_->GetSymbolFromLibrary(handle, symbol_name, symbol);
    388   }
    389   string FormatLibraryFileName(const string& name,
    390                                const string& version) override {
    391     return target_->FormatLibraryFileName(name, version);
    392   }
    393 
    394   string GetRunfilesDir() override { return target_->GetRunfilesDir(); }
    395 
    396  private:
    397   void GetLocalTempDirectories(std::vector<string>* list) override {
    398     target_->GetLocalTempDirectories(list);
    399   }
    400 
    401   Env* target_;
    402 };
    403 
    404 /// Represents a thread used to run a Tensorflow function.
    405 class Thread {
    406  public:
    407   Thread() {}
    408 
    409   /// Blocks until the thread of control stops running.
    410   virtual ~Thread();
    411 
    412  private:
    413   TF_DISALLOW_COPY_AND_ASSIGN(Thread);
    414 };
    415 
    416 /// \brief Options to configure a Thread.
    417 ///
    418 /// Note that the options are all hints, and the
    419 /// underlying implementation may choose to ignore it.
    420 struct ThreadOptions {
    421   /// Thread stack size to use (in bytes).
    422   size_t stack_size = 0;  // 0: use system default value
    423   /// Guard area size to use near thread stacks to use (in bytes)
    424   size_t guard_size = 0;  // 0: use system default value
    425   int numa_node = port::kNUMANoAffinity;
    426 };
    427 
    428 /// A utility routine: copy contents of `src` in file system `src_fs`
    429 /// to `target` in file system `target_fs`.
    430 Status FileSystemCopyFile(FileSystem* src_fs, const string& src,
    431                           FileSystem* target_fs, const string& target);
    432 
    433 /// A utility routine: reads contents of named file into `*data`
    434 Status ReadFileToString(Env* env, const string& fname, string* data);
    435 
    436 /// A utility routine: write contents of `data` to file named `fname`
    437 /// (overwriting existing contents, if any).
    438 Status WriteStringToFile(Env* env, const string& fname,
    439                          const StringPiece& data);
    440 
    441 /// Write binary representation of "proto" to the named file.
    442 Status WriteBinaryProto(Env* env, const string& fname,
    443                         const ::tensorflow::protobuf::MessageLite& proto);
    444 
    445 /// Reads contents of named file and parse as binary encoded proto data
    446 /// and store into `*proto`.
    447 Status ReadBinaryProto(Env* env, const string& fname,
    448                        ::tensorflow::protobuf::MessageLite* proto);
    449 
    450 /// Write the text representation of "proto" to the named file.
    451 Status WriteTextProto(Env* env, const string& fname,
    452                       const ::tensorflow::protobuf::Message& proto);
    453 
    454 /// Read contents of named file and parse as text encoded proto data
    455 /// and store into `*proto`.
    456 Status ReadTextProto(Env* env, const string& fname,
    457                      ::tensorflow::protobuf::Message* proto);
    458 
    459 // START_SKIP_DOXYGEN
    460 
    461 namespace register_file_system {
    462 
    463 template <typename Factory>
    464 struct Register {
    465   Register(Env* env, const string& scheme) {
    466     // TODO(b/32704451): Don't just ignore the ::tensorflow::Status object!
    467     env->RegisterFileSystem(scheme, []() -> FileSystem* { return new Factory; })
    468         .IgnoreError();
    469   }
    470 };
    471 
    472 }  // namespace register_file_system
    473 
    474 // END_SKIP_DOXYGEN
    475 
    476 }  // namespace tensorflow
    477 
    478 // Register a FileSystem implementation for a scheme. Files with names that have
    479 // "scheme://" prefixes are routed to use this implementation.
    480 #define REGISTER_FILE_SYSTEM_ENV(env, scheme, factory) \
    481   REGISTER_FILE_SYSTEM_UNIQ_HELPER(__COUNTER__, env, scheme, factory)
    482 #define REGISTER_FILE_SYSTEM_UNIQ_HELPER(ctr, env, scheme, factory) \
    483   REGISTER_FILE_SYSTEM_UNIQ(ctr, env, scheme, factory)
    484 #define REGISTER_FILE_SYSTEM_UNIQ(ctr, env, scheme, factory)   \
    485   static ::tensorflow::register_file_system::Register<factory> \
    486       register_ff##ctr TF_ATTRIBUTE_UNUSED =                   \
    487           ::tensorflow::register_file_system::Register<factory>(env, scheme)
    488 
    489 #define REGISTER_FILE_SYSTEM(scheme, factory) \
    490   REGISTER_FILE_SYSTEM_ENV(::tensorflow::Env::Default(), scheme, factory);
    491 
    492 #endif  // TENSORFLOW_CORE_PLATFORM_ENV_H_
    493