data_parallel.h (4338B)
1 // Copyright (c) the JPEG XL Project Authors. All rights reserved. 2 // 3 // Use of this source code is governed by a BSD-style 4 // license that can be found in the LICENSE file. 5 6 #ifndef LIB_JXL_BASE_DATA_PARALLEL_H_ 7 #define LIB_JXL_BASE_DATA_PARALLEL_H_ 8 9 // Portable, low-overhead C++11 ThreadPool alternative to OpenMP for 10 // data-parallel computations. 11 12 #include <jxl/parallel_runner.h> 13 #include <stddef.h> 14 #include <stdint.h> 15 16 #include "lib/jxl/base/compiler_specific.h" 17 #include "lib/jxl/base/status.h" 18 #if JXL_COMPILER_MSVC 19 // suppress warnings about the const & applied to function types 20 #pragma warning(disable : 4180) 21 #endif 22 23 namespace jxl { 24 25 class ThreadPool { 26 public: 27 ThreadPool(JxlParallelRunner runner, void* runner_opaque) 28 : runner_(runner), 29 runner_opaque_(runner ? runner_opaque : static_cast<void*>(this)) {} 30 31 ThreadPool(const ThreadPool&) = delete; 32 ThreadPool& operator&(const ThreadPool&) = delete; 33 34 JxlParallelRunner runner() const { return runner_; } 35 void* runner_opaque() const { return runner_opaque_; } 36 37 // Runs init_func(num_threads) followed by data_func(task, thread) on worker 38 // thread(s) for every task in [begin, end). init_func() must return a Status 39 // indicating whether the initialization succeeded. 40 // "thread" is an integer smaller than num_threads. 41 // Not thread-safe - no two calls to Run may overlap. 42 // Subsequent calls will reuse the same threads. 43 // 44 // Precondition: begin <= end. 45 template <class InitFunc, class DataFunc> 46 Status Run(uint32_t begin, uint32_t end, const InitFunc& init_func, 47 const DataFunc& data_func, const char* caller = "") { 48 JXL_ASSERT(begin <= end); 49 if (begin == end) return true; 50 RunCallState<InitFunc, DataFunc> call_state(init_func, data_func); 51 // The runner_ uses the C convention and returns 0 in case of error, so we 52 // convert it to a Status. 53 if (!runner_) { 54 void* jpegxl_opaque = static_cast<void*>(&call_state); 55 if (call_state.CallInitFunc(jpegxl_opaque, 1) != 0) { 56 return JXL_FAILURE("Failed to initialize thread"); 57 } 58 for (uint32_t i = begin; i < end; i++) { 59 call_state.CallDataFunc(jpegxl_opaque, i, 0); 60 } 61 return true; 62 } 63 return (*runner_)(runner_opaque_, static_cast<void*>(&call_state), 64 &call_state.CallInitFunc, &call_state.CallDataFunc, begin, 65 end) == 0; 66 } 67 68 // Use this as init_func when no initialization is needed. 69 static Status NoInit(size_t num_threads) { return true; } 70 71 private: 72 // class holding the state of a Run() call to pass to the runner_ as an 73 // opaque_jpegxl pointer. 74 template <class InitFunc, class DataFunc> 75 class RunCallState final { 76 public: 77 RunCallState(const InitFunc& init_func, const DataFunc& data_func) 78 : init_func_(init_func), data_func_(data_func) {} 79 80 // JxlParallelRunInit interface. 81 static int CallInitFunc(void* jpegxl_opaque, size_t num_threads) { 82 const auto* self = 83 static_cast<RunCallState<InitFunc, DataFunc>*>(jpegxl_opaque); 84 // Returns -1 when the internal init function returns false Status to 85 // indicate an error. 86 return self->init_func_(num_threads) ? 0 : -1; 87 } 88 89 // JxlParallelRunFunction interface. 90 static void CallDataFunc(void* jpegxl_opaque, uint32_t value, 91 size_t thread_id) { 92 const auto* self = 93 static_cast<RunCallState<InitFunc, DataFunc>*>(jpegxl_opaque); 94 return self->data_func_(value, thread_id); 95 } 96 97 private: 98 const InitFunc& init_func_; 99 const DataFunc& data_func_; 100 }; 101 102 // The caller supplied runner function and its opaque void*. 103 const JxlParallelRunner runner_; 104 void* const runner_opaque_; 105 }; 106 107 template <class InitFunc, class DataFunc> 108 Status RunOnPool(ThreadPool* pool, const uint32_t begin, const uint32_t end, 109 const InitFunc& init_func, const DataFunc& data_func, 110 const char* caller) { 111 if (pool == nullptr) { 112 ThreadPool default_pool(nullptr, nullptr); 113 return default_pool.Run(begin, end, init_func, data_func, caller); 114 } else { 115 return pool->Run(begin, end, init_func, data_func, caller); 116 } 117 } 118 119 } // namespace jxl 120 #if JXL_COMPILER_MSVC 121 #pragma warning(default : 4180) 122 #endif 123 124 #endif // LIB_JXL_BASE_DATA_PARALLEL_H_