diff --git a/src/Makefile_Eina.am b/src/Makefile_Eina.am index 020052ad28..b442635ccd 100644 --- a/src/Makefile_Eina.am +++ b/src/Makefile_Eina.am @@ -58,6 +58,7 @@ lib/eina/eina_trash.h \ lib/eina/eina_iterator.h \ lib/eina/eina_main.h \ lib/eina/eina_cpu.h \ +lib/eina/eina_cpu_private.h \ lib/eina/eina_inline_cpu.x \ lib/eina/eina_sched.h \ lib/eina/eina_tiler.h \ diff --git a/src/lib/eina/eina_cpu.c b/src/lib/eina/eina_cpu.c index e6b99218a6..fe3986111b 100644 --- a/src/lib/eina/eina_cpu.c +++ b/src/lib/eina/eina_cpu.c @@ -49,12 +49,20 @@ #include "eina_log.h" #include "eina_cpu.h" +#include + +#include "eina_cpu_private.h" + /*============================================================================* * Local * *============================================================================*/ static void _eina_page_size(void); +static int fastest_core_speed = 0; +static int slowest_core_speed = INT_MAX; +static Eina_Hash *cpu_hash = NULL; + /* FIXME this ifdefs should be replaced */ #if defined(__i386__) || defined(__x86_64__) /* We save ebx and restore it to be PIC compatible */ @@ -151,6 +159,9 @@ eina_cpu_init(void) Eina_Bool eina_cpu_shutdown(void) { + eina_hash_free(cpu_hash); + cpu_hash = NULL; + fastest_core_speed = 0; return EINA_TRUE; } @@ -286,3 +297,98 @@ void eina_cpu_count_internal(void) else _cpu_count = _eina_cpu_count_internal(); } + +static void +eina_cpu_map_init(void) +{ + fastest_core_speed = -1; + +#if defined (__linux__) || defined(__GLIBC__) + Eina_Iterator *it; + Eina_Strbuf *fname; + const Eina_File_Direct_Info *f_info; + + it = eina_file_stat_ls("/sys/devices/system/cpu/cpufreq"); + if (!it) return; + + cpu_hash = eina_hash_int32_new(free); + + fname = eina_strbuf_new(); + EINA_ITERATOR_FOREACH(it, f_info) + { + if ((f_info->type == EINA_FILE_DIR) && + eina_str_has_prefix(f_info->path, + "/sys/devices/system/cpu/cpufreq/policy")) + { + FILE *f; + int num, speed; + + eina_strbuf_append_printf(fname, "%s%s", f_info->path, "/cpuinfo_max_freq"); + f = fopen(eina_strbuf_string_get(fname), "r"); + eina_strbuf_reset(fname); + if (!f) goto err; + speed = -1; + num = fscanf(f, "%d", &speed); + fclose(f); + if ((num != 1) || (speed == -1)) goto err; + + slowest_core_speed = MIN(speed, slowest_core_speed); + fastest_core_speed = MAX(speed, fastest_core_speed); + + eina_strbuf_append_printf(fname, "%s%s", f_info->path, "/affected_cpus"); + f = fopen(eina_strbuf_string_get(fname), "r"); + eina_strbuf_reset(fname); + if (!f) goto err; + do + { + int core; + uint64_t *corelist; + num = fscanf(f, "%d", &core); + if ((num == EOF) || (core > 63)) break; + + corelist = eina_hash_find(cpu_hash, &speed); + if (!corelist) + { + corelist = malloc(sizeof(*corelist)); + if (!corelist) goto err; + *corelist = 1 << core; + eina_hash_add(cpu_hash, &speed, corelist); + } + *corelist |= 1 << core; + } while (num != EOF); + fclose(f); + } + } +err: + eina_strbuf_free(fname); + eina_iterator_free(it); +#endif +} + +EAPI int +_eina_cpu_fast_core_get(void) +{ +#if defined (__linux__) || defined(__GLIBC__) + uint64_t *corelist; + uint64_t cores; + int bit, place = 0; + + if (fastest_core_speed == -1) return -1; + + if (fastest_core_speed == 0) eina_cpu_map_init(); + + corelist = eina_hash_find(cpu_hash, &fastest_core_speed); + cores = *corelist; + bit = rand() % __builtin_popcount(cores); + while (bit || !(cores & 1)) + { + if (cores & 1) bit--; + cores = cores >> 1; + place++; + } + + return place; +#else + return 0; +#endif +} diff --git a/src/lib/eina/eina_cpu_private.h b/src/lib/eina/eina_cpu_private.h new file mode 100644 index 0000000000..667f0a7ed3 --- /dev/null +++ b/src/lib/eina/eina_cpu_private.h @@ -0,0 +1,35 @@ +#ifndef EINA_CPU_PRIVATE_H_ +#define EINA_CPU_PRIVATE_H_ + +#ifdef EAPI +# undef EAPI +#endif + +#ifdef _WIN32 +# ifdef EFL_ECORE_BUILD +# ifdef DLL_EXPORT +# define EAPI __declspec(dllexport) +# else +# define EAPI +# endif /* ! DLL_EXPORT */ +# else +# define EAPI __declspec(dllimport) +# endif /* ! EFL_ECORE_BUILD */ +#else +# ifdef __GNUC__ +# if __GNUC__ >= 4 +# define EAPI __attribute__ ((visibility("default"))) +# else +# define EAPI +# endif +# else +# define EAPI +# endif +#endif /* ! _WIN32 */ + +EAPI int _eina_cpu_fast_core_get(void); + +#undef EAPI +#define EAPI + +#endif