Back to index

glibc  2.9
get_clockfreq.c
Go to the documentation of this file.
00001 /* Get frequency of the system processor.  powerpc/Linux version.
00002    Copyright (C) 2000, 2001, 2005 Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004 
00005    The GNU C Library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009 
00010    The GNU C Library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014 
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with the GNU C Library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00018    02111-1307 USA.  */
00019 
00020 #include <ctype.h>
00021 #include <fcntl.h>
00022 #include <string.h>
00023 #include <unistd.h>
00024 #include <libc-internal.h>
00025 #include <sysdep.h>
00026 #include <bits/libc-vdso.h>
00027 
00028 hp_timing_t
00029 __get_clockfreq (void)
00030 {
00031   /* We read the information from the /proc filesystem.  /proc/cpuinfo
00032      contains at least one line like:
00033      timebase        : 33333333
00034      We search for this line and convert the number into an integer.  */
00035   static hp_timing_t timebase_freq;
00036   hp_timing_t result = 0L;
00037 
00038   /* If this function was called before, we know the result.  */
00039   if (timebase_freq != 0)
00040     return timebase_freq;
00041 
00042   /* If we can use the vDSO to obtain the timebase even better.  */
00043 #ifdef SHARED
00044   INTERNAL_SYSCALL_DECL (err);
00045   timebase_freq = INTERNAL_VSYSCALL_NO_SYSCALL_FALLBACK (get_tbfreq, err, 0);
00046   if (INTERNAL_SYSCALL_ERROR_P (timebase_freq, err)
00047       && INTERNAL_SYSCALL_ERRNO (timebase_freq, err) == ENOSYS)
00048 #endif
00049     {
00050       int fd = open ("/proc/cpuinfo", O_RDONLY);
00051 
00052       if (__builtin_expect (fd != -1, 1))
00053        {
00054          /* The timebase will be in the 1st 1024 bytes for systems with up
00055             to 8 processors.  If the first read returns less then 1024
00056             bytes read,  we have the whole cpuinfo and can start the scan.
00057             Otherwise we will have to read more to insure we have the
00058             timebase value in the scan.  */
00059          char buf[1024];
00060          ssize_t n;
00061 
00062          n = read (fd, buf, sizeof (buf));
00063          if (n == sizeof (buf))
00064            {
00065              /* We are here because the 1st read returned exactly sizeof
00066                 (buf) bytes.  This implies that we are not at EOF and may
00067                 not have read the timebase value yet.  So we need to read
00068                 more bytes until we know we have EOF.  We copy the lower
00069                 half of buf to the upper half and read sizeof (buf)/2
00070                 bytes into the lower half of buf and repeat until we
00071                 reach EOF.  We can assume that the timebase will be in
00072                 the last 512 bytes of cpuinfo, so two 512 byte half_bufs
00073                 will be sufficient to contain the timebase and will
00074                 handle the case where the timebase spans the half_buf
00075                 boundry.  */
00076              const ssize_t half_buf = sizeof (buf) / 2;
00077              while (n >= half_buf)
00078               {
00079                 memcpy (buf, buf + half_buf, half_buf);
00080                 n = read (fd, buf + half_buf, half_buf);
00081               }
00082              if (n >= 0)
00083               n += half_buf;
00084            }
00085 
00086          if (__builtin_expect (n, 1) > 0)
00087            {
00088              char *mhz = memmem (buf, n, "timebase", 7);
00089 
00090              if (__builtin_expect (mhz != NULL, 1))
00091               {
00092                 char *endp = buf + n;
00093 
00094                 /* Search for the beginning of the string.  */
00095                 while (mhz < endp && (*mhz < '0' || *mhz > '9')
00096                       && *mhz != '\n')
00097                   ++mhz;
00098 
00099                 while (mhz < endp && *mhz != '\n')
00100                   {
00101                     if (*mhz >= '0' && *mhz <= '9')
00102                      {
00103                        result *= 10;
00104                        result += *mhz - '0';
00105                      }
00106 
00107                     ++mhz;
00108                   }
00109               }
00110              timebase_freq = result;
00111            }
00112          close (fd);
00113        }
00114     }
00115 
00116   return timebase_freq;
00117 }