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