2009-01-26 08:27:00 -08:00
/* EINA - EFL data type library
* Copyright ( C ) 2007 - 2008 Jorge Luis Zapata Muga
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
* version 2.1 of the License , or ( at your option ) any later version .
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library ;
* if not , see < http : //www.gnu.org/licenses/>.
*/
2009-01-27 08:44:45 -08:00
2009-01-26 11:35:12 -08:00
# ifdef HAVE_CONFIG_H
# include "config.h"
# endif
2009-07-30 09:45:15 -07:00
# ifdef EFL_HAVE_PTHREAD
2009-08-11 07:11:36 -07:00
# ifdef _WIN32
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
2010-01-04 13:50:31 -08:00
# elif defined (__SUNPRO_C) || defined(__GNU__)
2009-08-11 07:11:36 -07:00
# include <unistd.h>
2009-11-09 01:07:10 -08:00
# elif defined (__FreeBSD__) || defined (__OpenBSD__) || defined (__NetBSD__) || defined (__DragonFly__) || defined (__MacOSX__) || ( defined (__MACH__) && defined (__APPLE__))
2009-08-11 07:11:36 -07:00
# include <unistd.h>
2009-11-07 11:44:39 -08:00
# include <sys / param.h>
2009-08-29 09:39:59 -07:00
# include <sys / sysctl.h>
2009-12-20 02:02:41 -08:00
# elif defined (__linux__) || defined(__GLIBC__)
2009-08-11 07:11:36 -07:00
# define _GNU_SOURCE
# include <sched.h>
# endif
2009-07-30 09:45:15 -07:00
# include <pthread.h>
# define TH_MAX 8
# endif
2009-08-11 07:11:36 -07:00
# include <stdio.h>
# include <string.h>
# include <errno.h>
2009-01-26 08:27:00 -08:00
# include "eina_cpu.h"
2009-01-27 08:44:45 -08:00
2009-01-26 08:27:00 -08:00
/*============================================================================*
* Local *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
2009-01-27 08:44:45 -08:00
2009-01-26 08:27:00 -08:00
/* FIXME this ifdefs should be replaced */
# if defined(__i386__) || defined(__x86_64__)
/* We save ebx and restore it to be PIC compatible */
static inline void _x86_cpuid ( int op , int * a , int * b , int * c , int * d )
{
asm volatile (
2009-01-26 11:35:12 -08:00
# if defined(__x86_64__)
" pushq %%rbx \n \t " /* save %ebx */
# else
2009-01-26 08:27:00 -08:00
" pushl %%ebx \n \t " /* save %ebx */
2009-01-26 11:35:12 -08:00
# endif
2009-01-26 08:27:00 -08:00
" cpuid \n \t "
" movl %%ebx, %1 \n \t " /* save what cpuid just put in %ebx */
2009-01-26 11:35:12 -08:00
# if defined(__x86_64__)
" popq %%rbx \n \t " /* restore the old %ebx */
# else
2009-01-26 08:27:00 -08:00
" popl %%ebx \n \t " /* restore the old %ebx */
2009-01-26 11:35:12 -08:00
# endif
2009-01-26 08:27:00 -08:00
: " =a " ( * a ) , " =r " ( * b ) , " =c " ( * c ) , " =d " ( * d )
: " a " ( op )
: " cc " ) ;
}
2010-01-23 11:53:27 -08:00
static
2009-01-26 08:27:00 -08:00
void _x86_simd ( Eina_Cpu_Features * features )
{
int a , b , c , d ;
_x86_cpuid ( 1 , & a , & b , & c , & d ) ;
/*
* edx
* 18 = PN ( Processor Number )
* 19 = CLFlush ( Cache Line Flush )
* 23 = MMX
* 25 = SSE
* 26 = SSE2
* 28 = HTT ( Hyper Threading )
* ecx
* 0 = SSE3
*/
if ( ( d > > 23 ) & 1 )
* features | = EINA_CPU_MMX ;
if ( ( d > > 25 ) & 1 )
* features | = EINA_CPU_SSE ;
if ( ( d > > 26 ) & 1 )
* features | = EINA_CPU_SSE2 ;
if ( c & 1 )
* features | = EINA_CPU_SSE3 ;
}
# endif
2009-01-27 08:44:45 -08:00
2009-01-26 08:27:00 -08:00
/*============================================================================*
* Global *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
2009-01-27 08:44:45 -08:00
2009-01-26 08:27:00 -08:00
/*============================================================================*
* API *
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
2009-01-27 08:44:45 -08:00
2009-01-26 08:27:00 -08:00
/* FIXME the features checks should be called when this function is called?
* or make it static by doing eina_cpu_init ( ) and return a local var
*/
/**
*
* @ return
*/
EAPI Eina_Cpu_Features eina_cpu_features_get ( void )
{
Eina_Cpu_Features ecf = 0 ;
# if defined(__i386__) || defined(__x86_64__)
_x86_simd ( & ecf ) ;
# endif
return ecf ;
}
2009-07-30 09:45:15 -07:00
EAPI int eina_cpu_count ( void )
{
# ifdef EFL_HAVE_PTHREAD
2009-08-11 07:11:36 -07:00
# if defined (_WIN32)
SYSTEM_INFO sysinfo ;
GetSystemInfo ( & sysinfo ) ;
return sysinfo . dwNumberOfProcessors ;
2010-01-04 13:50:31 -08:00
# elif defined (__SUNPRO_C) || defined(__GNU__)
2009-08-28 05:03:34 -07:00
/*
* _SC_NPROCESSORS_ONLN : number of processors that are online , that
is available when sysconf is called . The number
of cpu can change by admins .
* _SC_NPROCESSORS_CONF : maximum number of processors that are available
to the current OS instance . That number can be
change after a reboot .
* _SC_NPROCESSORS_MAX : maximum number of processors that are on the
motherboard .
*/
2009-08-11 07:11:36 -07:00
return sysconf ( _SC_NPROCESSORS_ONLN ) ;
2009-11-09 01:07:10 -08:00
# elif defined (__FreeBSD__) || defined (__OpenBSD__) || defined (__NetBSD__) || defined (__DragonFly__) || defined (__MacOSX__) || ( defined (__MACH__) && defined (__APPLE__))
2009-08-11 07:11:36 -07:00
int mib [ 4 ] ;
int cpus ;
2009-11-09 02:39:49 -08:00
size_t len = sizeof ( cpus ) ;
2009-08-11 07:11:36 -07:00
mib [ 0 ] = CTL_HW ;
2009-08-29 12:59:26 -07:00
# ifdef HW_AVAILCPU
mib [ 1 ] = HW_AVAILCPU ;
# else
2009-08-29 12:29:30 -07:00
mib [ 1 ] = HW_NCPU ;
2009-08-29 13:53:12 -07:00
# endif
2009-08-11 07:11:36 -07:00
sysctl ( mib , 2 , & cpus , & len , NULL , 0 ) ;
if ( cpus < 1 )
2009-08-29 12:59:26 -07:00
cpus = 1 ;
2009-08-11 07:11:36 -07:00
return cpus ;
2009-12-20 02:02:41 -08:00
# elif defined (__linux__) || defined(__GLIBC__)
2009-07-30 09:45:15 -07:00
cpu_set_t cpu ;
int i ;
static int cpus = 0 ;
if ( cpus ! = 0 ) return cpus ;
CPU_ZERO ( & cpu ) ;
if ( sched_getaffinity ( 0 , sizeof ( cpu ) , & cpu ) ! = 0 )
2009-08-11 07:11:36 -07:00
{
fprintf ( stderr , " [Eina] could not get cpu affinity: %s \n " , strerror ( errno ) ) ;
return 1 ;
}
2009-07-30 09:45:15 -07:00
for ( i = 0 ; i < TH_MAX ; i + + )
{
if ( CPU_ISSET ( i , & cpu ) ) cpus = i + 1 ;
else break ;
}
return cpus ;
2009-08-11 07:11:36 -07:00
# else
# error "eina_cpu_count() error: Platform not supported"
# endif
2009-07-30 09:45:15 -07:00
# else
return 1 ;
# endif
}