Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2)

Side by Side Diff: third_party/libwebp/dsp/cpu-features.c

Issue 10832153: libwebp: update snapshot to v0.2.0-rc1 (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 /*
2 * Copyright (C) 2010 The Android Open Source Project
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
12 * the documentation and/or other materials provided with the
13 * distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 /* ChangeLog for this library:
30 *
31 * NDK r7c: Fix CPU count computation. The old method only reported the
32 * number of _active_ CPUs when the library was initialized,
33 * which could be less than the real total.
34 *
35 * NDK r5: Handle buggy kernels which report a CPU Architecture number of 7
36 * for an ARMv6 CPU (see below).
37 *
38 * Handle kernels that only report 'neon', and not 'vfpv3'
39 * (VFPv3 is mandated by the ARM architecture is Neon is implemented)
40 *
41 * Handle kernels that only report 'vfpv3d16', and not 'vfpv3'
42 *
43 * Fix x86 compilation. Report ANDROID_CPU_FAMILY_X86 in
44 * android_getCpuFamily().
45 *
46 * NDK r4: Initial release
47 */
48 #include <sys/system_properties.h>
49 #ifdef __arm__
50 #include <machine/cpu-features.h>
51 #endif
52 #include <pthread.h>
53 #include "cpu-features.h"
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <fcntl.h>
57 #include <errno.h>
58
59 static pthread_once_t g_once;
60 static AndroidCpuFamily g_cpuFamily;
61 static uint64_t g_cpuFeatures;
62 static int g_cpuCount;
63
64 static const int android_cpufeatures_debug = 0;
65
66 #ifdef __arm__
67 # define DEFAULT_CPU_FAMILY ANDROID_CPU_FAMILY_ARM
68 #elif defined __i386__
69 # define DEFAULT_CPU_FAMILY ANDROID_CPU_FAMILY_X86
70 #else
71 # define DEFAULT_CPU_FAMILY ANDROID_CPU_FAMILY_UNKNOWN
72 #endif
73
74 #define D(...) \
75 do { \
76 if (android_cpufeatures_debug) { \
77 printf(__VA_ARGS__); fflush(stdout); \
78 } \
79 } while (0)
80
81 #ifdef __i386__
82 static __inline__ void x86_cpuid(int func, int values[4])
83 {
84 int a, b, c, d;
85 /* We need to preserve ebx since we're compiling PIC code */
86 /* this means we can't use "=b" for the second output register */
87 __asm__ __volatile__ ( \
88 "push %%ebx\n"
89 "cpuid\n" \
90 "mov %1, %%ebx\n"
91 "pop %%ebx\n"
92 : "=a" (a), "=r" (b), "=c" (c), "=d" (d) \
93 : "a" (func) \
94 );
95 values[0] = a;
96 values[1] = b;
97 values[2] = c;
98 values[3] = d;
99 }
100 #endif
101
102 /* Read the content of /proc/cpuinfo into a user-provided buffer.
103 * Return the length of the data, or -1 on error. Does *not*
104 * zero-terminate the content. Will not read more
105 * than 'buffsize' bytes.
106 */
107 static int
108 read_file(const char* pathname, char* buffer, size_t buffsize)
109 {
110 int fd, len;
111
112 fd = open(pathname, O_RDONLY);
113 if (fd < 0)
114 return -1;
115
116 do {
117 len = read(fd, buffer, buffsize);
118 } while (len < 0 && errno == EINTR);
119
120 close(fd);
121
122 return len;
123 }
124
125 /* Extract the content of a the first occurence of a given field in
126 * the content of /proc/cpuinfo and return it as a heap-allocated
127 * string that must be freed by the caller.
128 *
129 * Return NULL if not found
130 */
131 static char*
132 extract_cpuinfo_field(char* buffer, int buflen, const char* field)
133 {
134 int fieldlen = strlen(field);
135 char* bufend = buffer + buflen;
136 char* result = NULL;
137 int len, ignore;
138 const char *p, *q;
139
140 /* Look for first field occurence, and ensures it starts the line.
141 */
142 p = buffer;
143 bufend = buffer + buflen;
144 for (;;) {
145 p = memmem(p, bufend-p, field, fieldlen);
146 if (p == NULL)
147 goto EXIT;
148
149 if (p == buffer || p[-1] == '\n')
150 break;
151
152 p += fieldlen;
153 }
154
155 /* Skip to the first column followed by a space */
156 p += fieldlen;
157 p = memchr(p, ':', bufend-p);
158 if (p == NULL || p[1] != ' ')
159 goto EXIT;
160
161 /* Find the end of the line */
162 p += 2;
163 q = memchr(p, '\n', bufend-p);
164 if (q == NULL)
165 q = bufend;
166
167 /* Copy the line into a heap-allocated buffer */
168 len = q-p;
169 result = malloc(len+1);
170 if (result == NULL)
171 goto EXIT;
172
173 memcpy(result, p, len);
174 result[len] = '\0';
175
176 EXIT:
177 return result;
178 }
179
180 /* Like strlen(), but for constant string literals */
181 #define STRLEN_CONST(x) ((sizeof(x)-1)
182
183
184 /* Checks that a space-separated list of items contains one given 'item'.
185 * Returns 1 if found, 0 otherwise.
186 */
187 static int
188 has_list_item(const char* list, const char* item)
189 {
190 const char* p = list;
191 int itemlen = strlen(item);
192
193 if (list == NULL)
194 return 0;
195
196 while (*p) {
197 const char* q;
198
199 /* skip spaces */
200 while (*p == ' ' || *p == '\t')
201 p++;
202
203 /* find end of current list item */
204 q = p;
205 while (*q && *q != ' ' && *q != '\t')
206 q++;
207
208 if (itemlen == q-p && !memcmp(p, item, itemlen))
209 return 1;
210
211 /* skip to next item */
212 p = q;
213 }
214 return 0;
215 }
216
217 /* Parse an decimal integer starting from 'input', but not going further
218 * than 'limit'. Return the value into '*result'.
219 *
220 * NOTE: Does not skip over leading spaces, or deal with sign characters.
221 * NOTE: Ignores overflows.
222 *
223 * The function returns NULL in case of error (bad format), or the new
224 * position after the decimal number in case of success (which will always
225 * be <= 'limit').
226 */
227 static const char*
228 parse_decimal(const char* input, const char* limit, int* result)
229 {
230 const char* p = input;
231 int val = 0;
232 while (p < limit) {
233 int d = (*p - '0');
234 if ((unsigned)d >= 10U)
235 break;
236 val = val*10 + d;
237 p++;
238 }
239 if (p == input)
240 return NULL;
241
242 *result = val;
243 return p;
244 }
245
246 /* This small data type is used to represent a CPU list / mask, as read
247 * from sysfs on Linux. See http://www.kernel.org/doc/Documentation/cputopology. txt
248 *
249 * For now, we don't expect more than 32 cores on mobile devices, so keep
250 * everything simple.
251 */
252 typedef struct {
253 uint32_t mask;
254 } CpuList;
255
256 static __inline__ void
257 cpulist_init(CpuList* list) {
258 list->mask = 0;
259 }
260
261 static __inline__ void
262 cpulist_and(CpuList* list1, CpuList* list2) {
263 list1->mask &= list2->mask;
264 }
265
266 static __inline__ void
267 cpulist_set(CpuList* list, int index) {
268 if ((unsigned)index < 32) {
269 list->mask |= (uint32_t)(1U << index);
270 }
271 }
272
273 static __inline__ int
274 cpulist_count(CpuList* list) {
275 return __builtin_popcount(list->mask);
276 }
277
278 /* Parse a textual list of cpus and store the result inside a CpuList object.
279 * Input format is the following:
280 * - comma-separated list of items (no spaces)
281 * - each item is either a single decimal number (cpu index), or a range made
282 * of two numbers separated by a single dash (-). Ranges are inclusive.
283 *
284 * Examples: 0
285 * 2,4-127,128-143
286 * 0-1
287 */
288 static void
289 cpulist_parse(CpuList* list, const char* line, int line_len)
290 {
291 const char* p = line;
292 const char* end = p + line_len;
293 const char* q;
294
295 /* NOTE: the input line coming from sysfs typically contains a
296 * trailing newline, so take care of it in the code below
297 */
298 while (p < end && *p != '\n')
299 {
300 int val, start_value, end_value;
301
302 /* Find the end of current item, and put it into 'q' */
303 q = memchr(p, ',', end-p);
304 if (q == NULL) {
305 q = end;
306 }
307
308 /* Get first value */
309 p = parse_decimal(p, q, &start_value);
310 if (p == NULL)
311 goto BAD_FORMAT;
312
313 end_value = start_value;
314
315 /* If we're not at the end of the item, expect a dash and
316 * and integer; extract end value.
317 */
318 if (p < q && *p == '-') {
319 p = parse_decimal(p+1, q, &end_value);
320 if (p == NULL)
321 goto BAD_FORMAT;
322 }
323
324 /* Set bits CPU list bits */
325 for (val = start_value; val <= end_value; val++) {
326 cpulist_set(list, val);
327 }
328
329 /* Jump to next item */
330 p = q;
331 if (p < end)
332 p++;
333 }
334
335 BAD_FORMAT:
336 ;
337 }
338
339 /* Read a CPU list from one sysfs file */
340 static void
341 cpulist_read_from(CpuList* list, const char* filename)
342 {
343 char file[64];
344 int filelen;
345
346 cpulist_init(list);
347
348 filelen = read_file(filename, file, sizeof file);
349 if (filelen < 0) {
350 D("Could not read %s: %s\n", filename, strerror(errno));
351 return;
352 }
353
354 cpulist_parse(list, file, filelen);
355 }
356
357 /* Return the number of cpus present on a given device.
358 *
359 * To handle all weird kernel configurations, we need to compute the
360 * intersection of the 'present' and 'possible' CPU lists and count
361 * the result.
362 */
363 static int
364 get_cpu_count(void)
365 {
366 CpuList cpus_present[1];
367 CpuList cpus_possible[1];
368
369 cpulist_read_from(cpus_present, "/sys/devices/system/cpu/present");
370 cpulist_read_from(cpus_possible, "/sys/devices/system/cpu/possible");
371
372 /* Compute the intersection of both sets to get the actual number of
373 * CPU cores that can be used on this device by the kernel.
374 */
375 cpulist_and(cpus_present, cpus_possible);
376
377 return cpulist_count(cpus_present);
378 }
379
380 static void
381 android_cpuInit(void)
382 {
383 char cpuinfo[4096];
384 int cpuinfo_len;
385
386 g_cpuFamily = DEFAULT_CPU_FAMILY;
387 g_cpuFeatures = 0;
388 g_cpuCount = 1;
389
390 cpuinfo_len = read_file("/proc/cpuinfo", cpuinfo, sizeof cpuinfo);
391 D("cpuinfo_len is (%d):\n%.*s\n", cpuinfo_len,
392 cpuinfo_len >= 0 ? cpuinfo_len : 0, cpuinfo);
393
394 if (cpuinfo_len < 0) /* should not happen */ {
395 return;
396 }
397
398 /* Count the CPU cores, the value may be 0 for single-core CPUs */
399 g_cpuCount = get_cpu_count();
400 if (g_cpuCount == 0) {
401 g_cpuCount = 1;
402 }
403
404 D("found cpuCount = %d\n", g_cpuCount);
405
406 #ifdef __ARM_ARCH__
407 {
408 char* features = NULL;
409 char* architecture = NULL;
410
411 /* Extract architecture from the "CPU Architecture" field.
412 * The list is well-known, unlike the the output of
413 * the 'Processor' field which can vary greatly.
414 *
415 * See the definition of the 'proc_arch' array in
416 * $KERNEL/arch/arm/kernel/setup.c and the 'c_show' function in
417 * same file.
418 */
419 char* cpuArch = extract_cpuinfo_field(cpuinfo, cpuinfo_len, "CPU archite cture");
420
421 if (cpuArch != NULL) {
422 char* end;
423 long archNumber;
424 int hasARMv7 = 0;
425
426 D("found cpuArch = '%s'\n", cpuArch);
427
428 /* read the initial decimal number, ignore the rest */
429 archNumber = strtol(cpuArch, &end, 10);
430
431 /* Here we assume that ARMv8 will be upwards compatible with v7
432 * in the future. Unfortunately, there is no 'Features' field to
433 * indicate that Thumb-2 is supported.
434 */
435 if (end > cpuArch && archNumber >= 7) {
436 hasARMv7 = 1;
437 }
438
439 /* Unfortunately, it seems that certain ARMv6-based CPUs
440 * report an incorrect architecture number of 7!
441 *
442 * See http://code.google.com/p/android/issues/detail?id=10812
443 *
444 * We try to correct this by looking at the 'elf_format'
445 * field reported by the 'Processor' field, which is of the
446 * form of "(v7l)" for an ARMv7-based CPU, and "(v6l)" for
447 * an ARMv6-one.
448 */
449 if (hasARMv7) {
450 char* cpuProc = extract_cpuinfo_field(cpuinfo, cpuinfo_len,
451 "Processor");
452 if (cpuProc != NULL) {
453 D("found cpuProc = '%s'\n", cpuProc);
454 if (has_list_item(cpuProc, "(v6l)")) {
455 D("CPU processor and architecture mismatch!!\n");
456 hasARMv7 = 0;
457 }
458 free(cpuProc);
459 }
460 }
461
462 if (hasARMv7) {
463 g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_ARMv7;
464 }
465
466 /* The LDREX / STREX instructions are available from ARMv6 */
467 if (archNumber >= 6) {
468 g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_LDREX_STREX;
469 }
470
471 free(cpuArch);
472 }
473
474 /* Extract the list of CPU features from 'Features' field */
475 char* cpuFeatures = extract_cpuinfo_field(cpuinfo, cpuinfo_len, "Feature s");
476
477 if (cpuFeatures != NULL) {
478
479 D("found cpuFeatures = '%s'\n", cpuFeatures);
480
481 if (has_list_item(cpuFeatures, "vfpv3"))
482 g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFPv3;
483
484 else if (has_list_item(cpuFeatures, "vfpv3d16"))
485 g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFPv3;
486
487 if (has_list_item(cpuFeatures, "neon")) {
488 /* Note: Certain kernels only report neon but not vfpv3
489 * in their features list. However, ARM mandates
490 * that if Neon is implemented, so must be VFPv3
491 * so always set the flag.
492 */
493 g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_NEON |
494 ANDROID_CPU_ARM_FEATURE_VFPv3;
495 }
496 free(cpuFeatures);
497 }
498 }
499 #endif /* __ARM_ARCH__ */
500
501 #ifdef __i386__
502 g_cpuFamily = ANDROID_CPU_FAMILY_X86;
503
504 int regs[4];
505
506 /* According to http://en.wikipedia.org/wiki/CPUID */
507 #define VENDOR_INTEL_b 0x756e6547
508 #define VENDOR_INTEL_c 0x6c65746e
509 #define VENDOR_INTEL_d 0x49656e69
510
511 x86_cpuid(0, regs);
512 int vendorIsIntel = (regs[1] == VENDOR_INTEL_b &&
513 regs[2] == VENDOR_INTEL_c &&
514 regs[3] == VENDOR_INTEL_d);
515
516 x86_cpuid(1, regs);
517 if ((regs[2] & (1 << 9)) != 0) {
518 g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_SSSE3;
519 }
520 if ((regs[2] & (1 << 23)) != 0) {
521 g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_POPCNT;
522 }
523 if (vendorIsIntel && (regs[2] & (1 << 22)) != 0) {
524 g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_MOVBE;
525 }
526 #endif
527
528 #ifdef _MIPS_ARCH
529 g_cpuFamily = ANDROID_CPU_FAMILY_MIPS;
530 #endif /* _MIPS_ARCH */
531 }
532
533
534 AndroidCpuFamily
535 android_getCpuFamily(void)
536 {
537 pthread_once(&g_once, android_cpuInit);
538 return g_cpuFamily;
539 }
540
541
542 uint64_t
543 android_getCpuFeatures(void)
544 {
545 pthread_once(&g_once, android_cpuInit);
546 return g_cpuFeatures;
547 }
548
549
550 int
551 android_getCpuCount(void)
552 {
553 pthread_once(&g_once, android_cpuInit);
554 return g_cpuCount;
555 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698