1 /* Copyright 2021 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 #ifndef TENSORFLOW_LITE_EXPERIMENTAL_ACCELERATION_MINI_BENCHMARK_RUNNER_H_ 16 #define TENSORFLOW_LITE_EXPERIMENTAL_ACCELERATION_MINI_BENCHMARK_RUNNER_H_ 17 18 #include <string> 19 #include <vector> 20 21 #include "flatbuffers/flatbuffers.h" // from @flatbuffers 22 #include "tensorflow/lite/experimental/acceleration/mini_benchmark/status_codes.h" 23 24 namespace tflite { 25 namespace acceleration { 26 27 // Class that runs a C-main-function -compatible exported symbol in a separate 28 // process on Android. Support all Android 24+ devices and some 23 devices. May 29 // also work on 22- but has not been tested. 30 // 31 // Requirements on the caller: 32 // - The function to be called must reside in the same shared library as this 33 // code and it must be exported (typically by being extern "C" and having a name 34 // that starts with Java). 35 // - The function to be called must have the same signature as C main: 36 // extern "C" int Java_foo(int argc, char** argv) 37 // - The librunner_main.so shared object from this directory must 38 // reside in the same location as the shared object above (typically by 39 // depending on the runner_main_library_for_deps target from this 40 // directory in a java_library or java_binary) 41 // 42 // The return values are meant to be detailed enough for telemetry. 43 // 44 // For reasons behind the above restrictions and requirements, see 45 // implementation notes in runner.cc 46 // 47 // Warning: this class will just run the provided code in-process when compiled 48 // for non-Android. 49 class ProcessRunner { 50 public: 51 // Construct ProcessRunner. 'temporary_path' should be a suitable subdirectory 52 // of the app data path for extracting the helper binary on Android P-. 53 // 54 // Since the function will be called through popen() only return values 55 // between 0 and 127 are well-defined. 56 ProcessRunner(const std::string& temporary_path, 57 const std::string& function_name, 58 int (*function_pointer)(int argc, char** argv)); 59 60 // Initialize runner. 61 MinibenchmarkStatus Init(); 62 63 // Run function in separate process. Returns function's output to stdout and 64 // the shell exitcode. Stderr is discarded. 65 // 66 // The function will be called with argc and argv corresponding to a command 67 // line like: 68 // helper_binary function_name (optional: model path) args 69 // If model is not null, runner will use pipe() to pass the model 70 // to subprocess. Otherwise, args[0] should be a model path. 71 // The args are escaped for running through the shell. 72 // 73 // The 'output' and 'exitcode' and `signal` are set as follows based on the 74 // return value: 75 // kMinibenchmarkUnknownStatus, kMinibenchmarkPreconditionNotMet: undefined 76 // kMinibenchmarkPopenFailed: 77 // *output is an empty string 78 // *exitcode is errno after popen() 79 // *signal is 0 80 // kMinibenchmarkCommandFailed, kMinibenchmarkSuccess: 81 // *output is stdout produced from function 82 // *exitcode is: 83 // - if the process terminated normally: 84 // the return value of the benchmark function or, if function 85 // loading fails one the MinibenchmarkStatus values listed under 86 // 'Runner main status codes' to describe the failure. 87 // - if the process has been terminated by a signal: 0 88 // *signal is: 89 // - if the process has been terminated by a signal: the signal number 90 // - 0 otherwise 91 // 92 // To be considered successful, the function must return 93 // kMinibenchmarkSuccess. This is because some GPU drivers call exit(0) as a 94 // bailout and we don't want to confuse that with a successful run. 95 MinibenchmarkStatus Run(flatbuffers::FlatBufferBuilder* model, 96 const std::vector<std::string>& args, 97 std::string* output, int* exitcode, int* signal); 98 99 ProcessRunner(ProcessRunner&) = delete; 100 ProcessRunner& operator=(const ProcessRunner&) = delete; 101 102 private: 103 #ifndef __ANDROID__ 104 int RunInprocess(flatbuffers::FlatBufferBuilder* model, 105 const std::vector<std::string>& args); 106 #endif // !__ANDROID__ 107 std::string temporary_path_; 108 std::string function_name_; 109 void* function_pointer_; 110 std::string runner_path_; 111 std::string soname_; 112 }; 113 114 } // namespace acceleration 115 } // namespace tflite 116 #endif // TENSORFLOW_LITE_EXPERIMENTAL_ACCELERATION_MINI_BENCHMARK_RUNNER_H_ 117