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. NowNanos()254 virtual uint64 NowNanos() { return envTime->NowNanos(); } 255 256 /// \brief Returns the number of micro-seconds since the Unix epoch. NowMicros()257 virtual uint64 NowMicros() { return envTime->NowMicros(); } 258 259 /// \brief Returns the number of seconds since the Unix epoch. NowSeconds()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 EnvWrapper(Env * t)340 explicit EnvWrapper(Env* t) : target_(t) {} 341 virtual ~EnvWrapper(); 342 343 /// Returns the target to which this Env forwards all calls target()344 Env* target() const { return target_; } 345 GetFileSystemForFile(const string & fname,FileSystem ** result)346 Status GetFileSystemForFile(const string& fname, 347 FileSystem** result) override { 348 return target_->GetFileSystemForFile(fname, result); 349 } 350 GetRegisteredFileSystemSchemes(std::vector<string> * schemes)351 Status GetRegisteredFileSystemSchemes(std::vector<string>* schemes) override { 352 return target_->GetRegisteredFileSystemSchemes(schemes); 353 } 354 RegisterFileSystem(const string & scheme,FileSystemRegistry::Factory factory)355 Status RegisterFileSystem(const string& scheme, 356 FileSystemRegistry::Factory factory) override { 357 return target_->RegisterFileSystem(scheme, factory); 358 } 359 MatchPath(const string & path,const string & pattern)360 bool MatchPath(const string& path, const string& pattern) override { 361 return target_->MatchPath(path, pattern); 362 } 363 NowMicros()364 uint64 NowMicros() override { return target_->NowMicros(); } SleepForMicroseconds(int64 micros)365 void SleepForMicroseconds(int64 micros) override { 366 target_->SleepForMicroseconds(micros); 367 } StartThread(const ThreadOptions & thread_options,const string & name,std::function<void ()> fn)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 } GetCurrentThreadId()372 int32 GetCurrentThreadId() override { return target_->GetCurrentThreadId(); } GetCurrentThreadName(string * name)373 bool GetCurrentThreadName(string* name) override { 374 return target_->GetCurrentThreadName(name); 375 } SchedClosure(std::function<void ()> closure)376 void SchedClosure(std::function<void()> closure) override { 377 target_->SchedClosure(closure); 378 } SchedClosureAfter(int64 micros,std::function<void ()> closure)379 void SchedClosureAfter(int64 micros, std::function<void()> closure) override { 380 target_->SchedClosureAfter(micros, closure); 381 } LoadLibrary(const char * library_filename,void ** handle)382 Status LoadLibrary(const char* library_filename, void** handle) override { 383 return target_->LoadLibrary(library_filename, handle); 384 } GetSymbolFromLibrary(void * handle,const char * symbol_name,void ** symbol)385 Status GetSymbolFromLibrary(void* handle, const char* symbol_name, 386 void** symbol) override { 387 return target_->GetSymbolFromLibrary(handle, symbol_name, symbol); 388 } FormatLibraryFileName(const string & name,const string & version)389 string FormatLibraryFileName(const string& name, 390 const string& version) override { 391 return target_->FormatLibraryFileName(name, version); 392 } 393 GetRunfilesDir()394 string GetRunfilesDir() override { return target_->GetRunfilesDir(); } 395 396 private: GetLocalTempDirectories(std::vector<string> * list)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: Thread()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 { RegisterRegister465 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