aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.7
diff options
context:
space:
mode:
authorGeunsik Lim <geunsik.lim@samsung.com>2013-03-05 21:01:07 +0900
committerGeunsik Lim <geunsik.lim@samsung.com>2013-03-06 10:18:50 +0900
commitb3cd55a4e23e443cc4561424e22c27fe7f05b5c1 (patch)
tree985420293e0e9f151c8267e153008e14897d5075 /gcc-4.7
parent125708b8e3afa6007ce3aa7132165d27b719ccc3 (diff)
downloadtoolchain_gcc-b3cd55a4e23e443cc4561424e22c27fe7f05b5c1.zip
toolchain_gcc-b3cd55a4e23e443cc4561424e22c27fe7f05b5c1.tar.gz
toolchain_gcc-b3cd55a4e23e443cc4561424e22c27fe7f05b5c1.tar.bz2
OpenMP: Better CPU count detection for Linux
.PURPOSE This patch is to improve the detection of total CPU count for OpenMP/Linux. This patch helps that OpenMP recognizes the actual CPUs correctly for the task parallelism. Recent mobile devices dynamically disable or enable CPU cores on demand to optimize battery life. This impacts the output of '/proc/cpuinfo' (which only reports active ones). This patch provides a way to compute the total number of cores by parsing the content of '/sys/devices/system/cpu/' instead. Actual CPUs: total installed CPUs Online's CPUs: CPUs of the turn-on status Offline's CPUs: CPUs of the turn-off status Therefore, We need to enhance the existing approach using procfs like '/proc/cpuinfo/' or '/proc/stat'. This patch is suitable for Linux kernel. This patch is based on GCC 4.7.2. .RELATED LINKS: https://android-review.googlesource.com/#/c/52821/ https://android-review.googlesource.com/#/c/51950/ https://android-review.googlesource.com/#/c/51370/ https://android.googlesource.com/toolchain/gcc/ .UNIT TEST int main (int argc, char *argv[]) { int nthreads, tid; printf("SC_NPROCESSORS_ONLN: %d\n", sysconf (_SC_NPROCESSORS_ONLN)); /* Fork a team of threads giving them their own copies of variables */ { /* Obtain thread number */ tid = omp_get_thread_num(); printf("Hello World from thread = %d\n", tid); /* Only master thread does this */ if (tid == 0) { nthreads = omp_get_num_threads(); printf("Number of threads = %d\n", nthreads); } } /* All threads join master thread and disband */ } .LIMITATION OF SCOPE These functions have to be included in Bionic C library as the resource of sysconf(). Examples: _SC_NPROCESSORS_ONLN /proc/stat (= /sys/devices/system/cpu/online) _SC_NPROCESSORS_CONF /proc/cpuinfo (= /sys/devices/system/cpu/online) _SC_NPROCESSORS_ACTU /sys/devices/system/cpu/present (* Future work) .COST EVALUATION OF SYSCALLS (On 32bit Quad core) ------------------------------------------ time seconds usecs/call calls syscall ------------------------------------------ -nan 0.000000 0 3 read -nan 0.000000 0 9 write -nan 0.000000 0 4 open -nan 0.000000 0 4 close -nan 0.000000 0 1 execve -nan 0.000000 0 1 access -nan 0.000000 0 1 brk -nan 0.000000 0 1 munmap -nan 0.000000 0 2 mprotect -nan 0.000000 0 7 mmap2 -nan 0.000000 0 3 fstat64 -nan 0.000000 0 1 set_thread_area ------------------------------------------ 100 0.000000 0 37 total Change-Id: I2c6e41616f309eee89ee1145e92201ffe73463f4 Signed-off-by: Geunsik Lim <leemgs@gmail.com> Signed-off-by: Geunsik Lim <geunsik.lim@samsung.com> Acked-by: Changwoo Min <multics69@gmail.com> CC: David Turner <digit@android.com> CC: Keith Obenschain <obenschaink@gmail.com> CC: Pavel Chupin <pavel.v.chupin@intel.com> CC: Andrew Hsieh <andrewhsieh@google.com>
Diffstat (limited to 'gcc-4.7')
-rw-r--r--gcc-4.7/libgomp/config/linux/proc.c189
1 files changed, 186 insertions, 3 deletions
diff --git a/gcc-4.7/libgomp/config/linux/proc.c b/gcc-4.7/libgomp/config/linux/proc.c
index 8d9cfb5..5cc389d 100644
--- a/gcc-4.7/libgomp/config/linux/proc.c
+++ b/gcc-4.7/libgomp/config/linux/proc.c
@@ -31,8 +31,11 @@
#endif
#include "libgomp.h"
#include "proc.h"
-#include <stdlib.h>
#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <errno.h>
#ifdef HAVE_GETLOADAVG
# ifdef HAVE_SYS_LOADAVG_H
# include <sys/loadavg.h>
@@ -64,6 +67,186 @@ gomp_cpuset_popcount (cpu_set_t *cpusetp)
}
#endif
+/* Read the content of a file.
+ * Return the length of the data, or -1 on error. Does *not*
+ * zero-terminate the content. Will not read more
+ * than 'buffsize' bytes.
+ */
+static int
+read_file(const char* pathname, char* buffer, size_t buffsize)
+{
+ int fd, len;
+
+ fd = open(pathname, O_RDONLY);
+ if (fd < 0)
+ return -1;
+
+ do {
+ len = read(fd, buffer, buffsize);
+ } while (len < 0 && errno == EINTR);
+
+ close(fd);
+
+ return len;
+}
+
+
+/* Parse a decimal integer starting from 'input', but not going further
+ * than 'limit'. Return the value into '*result'.
+ *
+ * NOTE: Does not skip over leading spaces, or deal with sign characters.
+ * NOTE: Ignores overflows.
+ *
+ * The function returns NULL in case of error (bad format), or the new
+ * position after the decimal number in case of success (which will always
+ * be <= 'limit').
+ */
+static const char*
+parse_decimal(const char* input, const char* limit, int* result)
+{
+ const char* p = input;
+ int val = 0;
+ while (p < limit) {
+ int d = (*p - '0');
+ if ((unsigned)d >= 10U)
+ break;
+ val = val*10 + d;
+ p++;
+ }
+ if (p == input)
+ return NULL;
+
+ *result = val;
+ return p;
+}
+
+
+/* This data type is used to represent a CPU list / mask, as read
+ * from sysfs on Linux. See http://www.kernel.org/doc/Documentation/cputopology.txt
+ */
+typedef struct {
+ int mask;
+} cpuList;
+
+/* Returns Actual CPUs (total installed CPUs) */
+static int
+cpuList_count (cpuList* list) {
+ return list->mask ;
+}
+
+/* Parse a textual list of cpus and store the result inside a cpuList object.
+ * Input format is the following:
+ * - comma-separated list of items (no spaces)
+ * - each item is either a single decimal number (cpu index), or a range made
+ * of two numbers separated by a single dash (-). Ranges are inclusive.
+ * Examples:
+ * 0
+ * 2,4-127,128-143
+ * 0-1
+ */
+static void
+cpuList_parse (cpuList* list, const char* line, int line_len)
+{
+ const char* p = line;
+ const char* end = p + line_len;
+ const char* q;
+
+ /* NOTE: the input line coming from sysfs typically contains a
+ * trailing newline, so take care of it in the code below
+ */
+ while (p < end && *p != '\n')
+ {
+ int val, start_value, end_value;
+
+ /* Find the end of current item, and put it into 'q' */
+ q = memchr(p, ',', end-p);
+ if (q == NULL) {
+ q = end;
+ }
+
+ /* Get first value */
+ p = parse_decimal(p, q, &start_value);
+ if (p == NULL)
+ goto BAD_FORMAT;
+
+ end_value = start_value;
+
+ /* If we're not at the end of the item, expect a dash and
+ * and integer; extract end value.
+ */
+ if (p < q && *p == '-') {
+ p = parse_decimal(p+1, q, &end_value);
+ if (p == NULL)
+ goto BAD_FORMAT;
+ }
+
+ /* Set CPU list */
+ for (val = start_value; val <= end_value; val++) {
+ list->mask++;
+ }
+
+ /* Jump to next item */
+ p = q;
+ if (p < end)
+ p++;
+ }
+
+BAD_FORMAT:
+ ;
+}
+
+
+/* Read a CPU list from one sysfs file
+ * The below is CPU related sys interface by CPU topologoy.
+ */
+static void
+cpuList_read_from (cpuList* list, const char* filename)
+{
+ char file[64];
+ int filelen;
+
+ list->mask = 0;
+
+ filelen = read_file(filename, file, sizeof file);
+ if (filelen < 0) {
+ fprintf(stderr,"Could not read %s: %s\n", filename, strerror(errno));
+ return;
+ }
+
+ cpuList_parse(list, file, filelen);
+}
+
+
+/* Probe the number of actual CPUs on devices (e.g. Android devices) using
+ * CPU-Hotplug and CPU-DVFS to optimize battery life.
+ * Return the number of CPUs present on a given device.
+ * See http://www.kernel.org/doc/Documentation/cputopology.txt
+ */
+static int
+sc_nprocessors_actu ()
+{
+ char buffer[256];
+ int buffer_len;
+ int cpuCount = 1;
+ cpuList cpus_present[1];
+ char file_name[64] = "/sys/devices/system/cpu/present";
+
+ buffer_len = read_file(file_name, buffer, sizeof buffer);
+
+ if (buffer_len < 0) /* should not happen */ {
+ fprintf(stderr,"Could not find %s: %s\n", file_name, strerror(errno));
+ return;
+ }
+
+ /* Count the CPU cores, the value may be 0 for single-core CPUs */
+ cpuList_read_from(cpus_present, file_name);
+ cpuCount = cpuList_count(cpus_present);
+ if (cpuCount == 0) {
+ cpuCount = 1;
+ }
+ return cpuCount;
+}
+
/* At startup, determine the default number of threads. It would seem
this should be related to the number of cpus online. */
@@ -83,7 +266,7 @@ gomp_init_num_threads (void)
}
#endif
#ifdef _SC_NPROCESSORS_ONLN
- gomp_global_icv.nthreads_var = sysconf (_SC_NPROCESSORS_ONLN);
+ gomp_global_icv.nthreads_var = sc_nprocessors_actu ();
#endif
}
@@ -115,7 +298,7 @@ get_num_procs (void)
}
#endif
#ifdef _SC_NPROCESSORS_ONLN
- return sysconf (_SC_NPROCESSORS_ONLN);
+ return sc_nprocessors_actu ();
#else
return gomp_icv (false)->nthreads_var;
#endif