2
* Copyright © 2013 Intel Corporation
4
* Permission is hereby granted, free of charge, to any person obtaining a
5
* copy of this software and associated documentation files (the "Software"),
6
* to deal in the Software without restriction, including without limitation
7
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
8
* and/or sell copies of the Software, and to permit persons to whom the
9
* Software is furnished to do so, subject to the following conditions:
11
* The above copyright notice and this permission notice (including the next
12
* paragraph) shall be included in all copies or substantial portions of the
15
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24
* Chris Wilson <chris@chris-wilson.co.uk>
40
static inline bool valgrind_active(void) { return RUNNING_ON_VALGRIND; }
42
static inline bool valgrind_active(void) { return false; }
45
static int max_threads = -1;
47
static struct thread {
49
pthread_mutex_t mutex;
52
void (*func)(void *arg);
56
static void *__run__(void *arg)
58
struct thread *t = arg;
61
/* Disable all signals in the slave threads as X uses them for IO */
63
sigdelset(&signals, SIGBUS);
64
sigdelset(&signals, SIGSEGV);
65
pthread_sigmask(SIG_SETMASK, &signals, NULL);
67
pthread_mutex_lock(&t->mutex);
69
while (t->func == NULL)
70
pthread_cond_wait(&t->cond, &t->mutex);
71
pthread_mutex_unlock(&t->mutex);
76
pthread_mutex_lock(&t->mutex);
79
pthread_cond_signal(&t->cond);
81
pthread_mutex_unlock(&t->mutex);
87
#define popcount(x) __builtin_popcount(x)
89
static int popcount(unsigned int x)
105
FILE *file = fopen("/proc/cpuinfo", "r");
110
uint32_t processors = 0, cores = 0;
111
while (getline(&line, &len, file) != -1) {
113
if (sscanf(line, "physical id : %d", &id) == 1) {
116
processors |= 1 << id;
117
} else if (sscanf(line, "core id : %d", &id) == 1) {
126
DBG(("%s: processors=0x%08x, cores=0x%08x\n",
127
__FUNCTION__, processors, cores));
129
count = popcount(processors) * popcount(cores);
134
void sna_threads_init(void)
138
if (max_threads != -1)
141
if (valgrind_active())
144
max_threads = num_cores();
145
if (max_threads == 0)
146
max_threads = sysconf(_SC_NPROCESSORS_ONLN) / 2;
147
if (max_threads <= 1)
150
DBG(("%s: creating a thread pool of %d threads\n",
151
__func__, max_threads));
153
threads = malloc (sizeof(threads[0])*max_threads);
157
for (n = 1; n < max_threads; n++) {
158
pthread_mutex_init(&threads[n].mutex, NULL);
159
pthread_cond_init(&threads[n].cond, NULL);
161
threads[n].func = NULL;
162
threads[n].arg = NULL;
163
if (pthread_create(&threads[n].thread, NULL,
164
__run__, &threads[n]))
168
threads[0].thread = pthread_self();
175
void sna_threads_run(int id, void (*func)(void *arg), void *arg)
177
assert(max_threads > 0);
178
assert(pthread_self() == threads[0].thread);
179
assert(id > 0 && id < max_threads);
181
assert(threads[id].func == NULL);
183
pthread_mutex_lock(&threads[id].mutex);
184
threads[id].func = func;
185
threads[id].arg = arg;
186
pthread_cond_signal(&threads[id].cond);
187
pthread_mutex_unlock(&threads[id].mutex);
190
void sna_threads_trap(int sig)
192
pthread_t t = pthread_self();
195
if (max_threads == 0)
198
if (t == threads[0].thread)
201
for (n = 1; threads[n].thread != t; n++)
204
ERR(("%s: thread[%d] caught signal %d\n", __func__, n, sig));
206
pthread_mutex_lock(&threads[n].mutex);
207
threads[n].arg = (void *)(intptr_t)sig;
208
threads[n].func = NULL;
209
pthread_cond_signal(&threads[n].cond);
210
pthread_mutex_unlock(&threads[n].mutex);
215
void sna_threads_wait(void)
219
assert(max_threads > 0);
220
assert(pthread_self() == threads[0].thread);
222
for (n = 1; n < max_threads; n++) {
223
if (threads[n].func != NULL) {
224
pthread_mutex_lock(&threads[n].mutex);
225
while (threads[n].func)
226
pthread_cond_wait(&threads[n].cond, &threads[n].mutex);
227
pthread_mutex_unlock(&threads[n].mutex);
230
if (threads[n].arg != NULL) {
231
DBG(("%s: thread[%d] died from signal %d\n", __func__, n, (int)(intptr_t)threads[n].arg));
238
void sna_threads_kill(void)
242
ERR(("%s: kill %d threads\n", __func__, max_threads));
243
assert(max_threads > 0);
244
assert(pthread_self() == threads[0].thread);
246
for (n = 1; n < max_threads; n++)
247
pthread_cancel(threads[n].thread);
249
for (n = 1; n < max_threads; n++)
250
pthread_join(threads[n].thread, NULL);
255
int sna_use_threads(int width, int height, int threshold)
259
if (max_threads <= 0)
268
num_threads = height * max_threads / threshold - 1;
269
if (num_threads <= 0)
272
if (num_threads > max_threads)
273
num_threads = max_threads;
274
if (num_threads > height)
275
num_threads = height;
280
struct thread_composite {
281
pixman_image_t *src, *mask, *dst;
283
int16_t src_x, src_y;
284
int16_t mask_x, mask_y;
285
int16_t dst_x, dst_y;
286
uint16_t width, height;
289
static void thread_composite(void *arg)
291
struct thread_composite *t = arg;
292
pixman_image_composite(t->op, t->src, t->mask, t->dst,
294
t->mask_x, t->mask_y,
296
t->width, t->height);
299
void sna_image_composite(pixman_op_t op,
301
pixman_image_t *mask,
314
num_threads = sna_use_threads(width, height, 32);
315
if (num_threads <= 1) {
316
if (sigtrap_get() == 0) {
317
pixman_image_composite(op, src, mask, dst,
325
struct thread_composite data[num_threads];
328
DBG(("%s: using %d threads for compositing %dx%d\n",
329
__FUNCTION__, num_threads, width, height));
332
dy = (height + num_threads - 1) / num_threads;
333
num_threads -= (num_threads-1) * dy >= height;
339
data[0].src_x = src_x;
340
data[0].src_y = src_y;
341
data[0].mask_x = mask_x;
342
data[0].mask_y = mask_y;
343
data[0].dst_x = dst_x;
345
data[0].width = width;
348
if (sigtrap_get() == 0) {
349
for (n = 1; n < num_threads; n++) {
351
data[n].src_y += y - dst_y;
352
data[n].mask_y += y - dst_y;
356
sna_threads_run(n, thread_composite, &data[n]);
359
assert(y < dst_y + height);
360
if (y + dy > dst_y + height)
361
dy = dst_y + height - y;
363
data[0].src_y += y - dst_y;
364
data[0].mask_y += y - dst_y;
368
thread_composite(&data[0]);