sna_threads.c revision 03b705cf
1/* 2 * Copyright © 2013 Intel Corporation 3 * 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: 10 * 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 13 * Software. 14 * 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 21 * SOFTWARE. 22 * 23 * Authors: 24 * Chris Wilson <chris@chris-wilson.co.uk> 25 * 26 */ 27 28#include "sna.h" 29 30#include <unistd.h> 31#include <pthread.h> 32#include <signal.h> 33 34static int max_threads = -1; 35 36static struct thread { 37 pthread_t thread; 38 pthread_mutex_t mutex; 39 pthread_cond_t cond; 40 41 void (*func)(void *arg); 42 void *arg; 43} *threads; 44 45static void *__run__(void *arg) 46{ 47 struct thread *t = arg; 48 sigset_t signals; 49 50 /* Disable all signals in the slave threads as X uses them for IO */ 51 sigfillset(&signals); 52 pthread_sigmask(SIG_BLOCK, &signals, NULL); 53 54 pthread_mutex_lock(&t->mutex); 55 while (1) { 56 while (t->func == NULL) 57 pthread_cond_wait(&t->cond, &t->mutex); 58 pthread_mutex_unlock(&t->mutex); 59 60 assert(t->func); 61 t->func(t->arg); 62 63 pthread_mutex_lock(&t->mutex); 64 t->func = NULL; 65 pthread_cond_signal(&t->cond); 66 } 67 pthread_mutex_unlock(&t->mutex); 68 69 return NULL; 70} 71 72#if defined(__GNUC__) 73#define popcount(x) __builtin_popcount(x) 74#else 75static int popcount(unsigned int x) 76{ 77 int count = 0; 78 79 while (x) { 80 count += x&1; 81 x >>= 1; 82 } 83 84 return count; 85} 86#endif 87 88static int 89num_cores(void) 90{ 91 FILE *file = fopen("/proc/cpuinfo", "r"); 92 int count = 0; 93 if (file) { 94 size_t len = 0; 95 char *line = NULL; 96 uint32_t processors = 0, cores = 0; 97 while (getline(&line, &len, file) != -1) { 98 int id; 99 if (sscanf(line, "physical id : %d", &id) == 1) { 100 if (id >= 32) 101 return 0; 102 processors |= 1 << id; 103 } else if (sscanf(line, "core id : %d", &id) == 1) { 104 if (id >= 32) 105 return 0; 106 cores |= 1 << id; 107 } 108 } 109 free(line); 110 fclose(file); 111 112 DBG(("%s: processors=0x%08x, cores=0x%08x\n", 113 __FUNCTION__, processors, cores)); 114 115 count = popcount(processors) * popcount(cores); 116 } 117 return count; 118} 119 120void sna_threads_init(void) 121{ 122 int n; 123 124 if (max_threads != -1) 125 return; 126 127 max_threads = num_cores(); 128 if (max_threads == 0) 129 max_threads = sysconf(_SC_NPROCESSORS_ONLN) / 2; 130 if (max_threads <= 1) 131 goto bail; 132 133 DBG(("%s: creating a thread pool of %d threads\n", 134 __func__, max_threads)); 135 136 threads = malloc (sizeof(threads[0])*max_threads); 137 if (threads == NULL) 138 goto bail; 139 140 for (n = 0; n < max_threads; n++) { 141 pthread_mutex_init(&threads[n].mutex, NULL); 142 pthread_cond_init(&threads[n].cond, NULL); 143 144 threads[n].func = NULL; 145 if (pthread_create(&threads[n].thread, NULL, 146 __run__, &threads[n])) 147 goto bail; 148 } 149 150 return; 151 152bail: 153 max_threads = 0; 154} 155 156void sna_threads_run(void (*func)(void *arg), void *arg) 157{ 158 int n; 159 160 assert(max_threads > 0); 161 162 for (n = 0; n < max_threads; n++) { 163 if (threads[n].func) 164 continue; 165 166 pthread_mutex_lock(&threads[n].mutex); 167 if (threads[n].func) { 168 pthread_mutex_unlock(&threads[n].mutex); 169 continue; 170 } 171 172 goto execute; 173 } 174 175 n = rand() % max_threads; 176 pthread_mutex_lock(&threads[n].mutex); 177 while (threads[n].func) 178 pthread_cond_wait(&threads[n].cond, &threads[n].mutex); 179 180execute: 181 threads[n].func = func; 182 threads[n].arg = arg; 183 pthread_cond_signal(&threads[n].cond); 184 pthread_mutex_unlock(&threads[n].mutex); 185} 186 187void sna_threads_wait(void) 188{ 189 int n; 190 191 assert(max_threads > 0); 192 193 for (n = 0; n < max_threads; n++) { 194 if (threads[n].func == NULL) 195 continue; 196 197 pthread_mutex_lock(&threads[n].mutex); 198 while (threads[n].func) 199 pthread_cond_wait(&threads[n].cond, &threads[n].mutex); 200 pthread_mutex_unlock(&threads[n].mutex); 201 } 202} 203 204int sna_use_threads(int width, int height, int threshold) 205{ 206 int num_threads; 207 208 if (max_threads <= 0) 209 return 1; 210 211 if (width < 128) 212 height /= 128/width; 213 214 num_threads = height * max_threads / threshold - 1; 215 if (num_threads <= 0) 216 return 1; 217 218 if (num_threads > max_threads) 219 num_threads = max_threads; 220 return num_threads; 221} 222 223struct thread_composite { 224 pixman_image_t *src, *mask, *dst; 225 pixman_op_t op; 226 int16_t src_x, src_y; 227 int16_t mask_x, mask_y; 228 int16_t dst_x, dst_y; 229 uint16_t width, height; 230}; 231 232static void thread_composite(void *arg) 233{ 234 struct thread_composite *t = arg; 235 pixman_image_composite(t->op, t->src, t->mask, t->dst, 236 t->src_x, t->src_y, 237 t->mask_x, t->mask_y, 238 t->dst_x, t->dst_y, 239 t->width, t->height); 240} 241 242void sna_image_composite(pixman_op_t op, 243 pixman_image_t *src, 244 pixman_image_t *mask, 245 pixman_image_t *dst, 246 int16_t src_x, 247 int16_t src_y, 248 int16_t mask_x, 249 int16_t mask_y, 250 int16_t dst_x, 251 int16_t dst_y, 252 uint16_t width, 253 uint16_t height) 254{ 255 int num_threads; 256 257 num_threads = sna_use_threads(width, height, 32); 258 if (num_threads <= 1) { 259 pixman_image_composite(op, src, mask, dst, 260 src_x, src_y, 261 mask_x, mask_y, 262 dst_x, dst_y, 263 width, height); 264 } else { 265 struct thread_composite data[num_threads]; 266 int y, dy, n; 267 268 DBG(("%s: using %d threads for compositing %dx%d\n", 269 __FUNCTION__, num_threads, width, height)); 270 271 y = dst_y; 272 dy = (height + num_threads - 1) / num_threads; 273 274 data[0].op = op; 275 data[0].src = src; 276 data[0].mask = mask; 277 data[0].dst = dst; 278 data[0].src_x = src_x; 279 data[0].src_y = src_y; 280 data[0].mask_x = mask_x; 281 data[0].mask_y = mask_y; 282 data[0].dst_x = dst_x; 283 data[0].dst_y = y; 284 data[0].width = width; 285 data[0].height = dy; 286 287 for (n = 1; n < num_threads; n++) { 288 data[n] = data[0]; 289 data[n].src_y += y - dst_y; 290 data[n].mask_y += y - dst_y; 291 data[n].dst_y = y; 292 y += dy; 293 294 sna_threads_run(thread_composite, &data[n]); 295 } 296 297 if (y + dy > dst_y + height) 298 dy = dst_y + height - y; 299 300 data[0].src_y += y - dst_y; 301 data[0].mask_y += y - dst_y; 302 data[0].dst_y = y; 303 data[0].height = dy; 304 305 thread_composite(&data[0]); 306 307 sna_threads_wait(); 308 } 309} 310