Re: libcruft/sysconf_cpus.c patch
Bela Lubkin <[email protected]> Tue, 23 Nov 2010 17:58:05 -0800
| Newsgroups | gmane.linux.lib.dietlibc |
|---|---|
| Message-ID | <[email protected]> |
Indan Zupancic wrote:
> (Bela forgot to CC the list.)
Actually I completely missed my aim, intended to send only to the list
and you'd get your list copy.
> > It'll also be wrong if you were exec'd by someone who used
> > sched_setaffinity() to restrict your horizons.
>
> Not really. The manpage says:
>
> - _SC_NPROCESSORS_CONF
> The number of processors configured.
>
> - _SC_NPROCESSORS_ONLN
> The number of processors currently online (available).
>
> I'd argue that for ONLN returning the number of available cpus is the
> correct thing to do.
Hmmm. _SC_NPROCESSORS_ONLN is a non-POSIX extension. glibc doc at
<http://www.gnu.org/s/libc/manual/html_node/Processor-Resources.html>
says:
" But it might be possible for the operating system to disable individual
" processors and so the call
"
" sysconf (_SC_NPROCESSORS_ONLN)
"
" returns the number of processors which are currently inline (i.e.,
" available).
There are at least 3 numbers one *could* want to know: (1) # CPUs in the
hardware, (2) # CPUs activated by the system (e.g. if the OS has CPU
licenses, or detected some are broken), and (3) # CPUs *this* process is
allowed to access. The doc says (to me) #2.
Anyway, the number returned should be the same as glibc on the same
platform. FWIW, glibc counts "cpu%d" subdirectories in
/sys/devices/system/cpu for _SC_NPROCESSORS_CONF, and "^cpu%d" lines in
/proc/stat for _SC_NPROCESSORS_ONLN. Is /proc/stat format at least as
stable as (not-very-stable) /proc/cpuinfo across Linux arches &
releases? Nothing in dietlibc uses /sys/... yet; I don't think that's a
good bridge to cross even though current Linux conveniently provides
/sys/devices/system/cpu/present (#1) and online (#2). Added in 2008-12
according to linux/Documentation/ABI/testing/sysfs-devices-system-cpu
and Documentationlinux//cputopology.txt.
> Anyway, if you don't want that, and also want to support CONF you can
> save the original mask, then figure out the number of cpus with
> sched_setaffinity(), before restoring the original. Though that is
> more bother than really worth it.
You're assuming the kernel get/set implementation will clear bits above
the actual # CPUs in the system. It could just as reasonably let you
set as many bits as you want, knowing the scheduler will only pay
attention to the ones that count.
> > Anyway, I haven't noticed sched_[gs]etaffinity() support in dietlibc!
>
> The kernel supports it, it's a system call, so adding it to dietlibc
> is trivial.
The stuff in glibc is uhhhgly, feel free...
> > Writing a fully working /proc version isn't hard... stand by.
I came up with this. It compiles to 51 bytes more than the old one for
me (gcc 4.4.5/x86 32-bit), but that's the price for working 100%. Also,
it assumes strlen("constant string") is evaluated at compile time -- I'm
not sure if that's true for all compilers dietlibc might see. If not,
NR_CPUS_LEN should be defined in each lobe of that #ifdef.
Retained existing style; changed `i' -> `idx', `n' -> `nb' for better
greppability; tested with smaller buffers to make sure the algorithm was
stable. Changed (buf[m]=='x' && memcmp(buf+m,"xyz",n)) to just memcmp()
since it's only one per input line and memcmp() returns on 1st mismatch
anyway.
So, new libcruft/sysconf_cpus.c (and it should definitely be mentioned
in PORTING):
========================================================================
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include "dietfeatures.h"
/*
* by Olaf Dreesen
* rewritten by Bela Lubkin to handle buffer wrap
*
* arm NO SMP ?!? (return 1)
* undef SLASH_PROC_OK NO METHOD! (return 1)
*
* alpha -> cpus detected\t\t: <nr>\n
* sparc -> ncpus active\t: <nr>\n
*
* default -> processor\t: <cpunr>\n (one per cpu)
*/
#if !defined(SLASH_PROC_OK) || defined(__arm__)
int __sc_nr_cpus() {
return 1; /* kludge kludge ;-) */
}
#else
#if defined(__alpha__)
#define NR_CPUS_STR "cpus detected"
#define NR_CPUS_OFF 17
#elif defined(__sparc__)
#define NR_CPUS_STR "ncpus active"
#define NR_CPUS_OFF 15
#else
#define NR_CPUS_STR "processor"
#define NR_CPUS_OFF 0 /* count instances of ^NR_CPUS_STR */
#endif
#define NR_CPUS_LEN (strlen(NR_CPUS_STR))
int __sc_nr_cpus(void);
int __sc_nr_cpus() {
#if NR_CPUS_OFF == 0
int nr=0;
#endif
char buf[1024]; /* holds ~2 cpuinfos */
register int nb;
int wrap=0;
int fd=open("/proc/cpuinfo", O_RDONLY);
if (fd==-1) return 1; /* fallback if no proc-fs mounted */
while((nb=read(fd,buf+wrap,sizeof(buf)-wrap))>0 || wrap) {
register int idx=0;
if (nb<0) nb=0; /* wrapped buffer after err */
nb+=wrap;
wrap=0;
while (idx<nb) {
if (idx+256>=sizeof(buf)) { /* avoid split-line parsing */
memcpy(buf,buf+idx,(wrap=nb-idx)); /* save tail of full buf */
break;
}
if (!memcmp(buf+idx,NR_CPUS_STR,NR_CPUS_LEN)) {
#if NR_CPUS_OFF == 0
++nr;
#else
close(fd);
return atoi(buf+idx+NR_CPUS_OFF);
#endif
}
while(idx<nb && buf[idx++]!='\n'); /* skip rest of line */
}
}
#if NR_CPUS_OFF == 0
close(fd);
return nr;
#endif
}
#endif
========================================================================
>Bela<