/* * pfmlib_os.c: set of functions OS dependent functions * * Copyright (c) 2003-2006 Hewlett-Packard Development Company, L.P. * Contributed by Stephane Eranian * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef _GNU_SOURCE #define _GNU_SOURCE /* for getline */ #endif #include #include #include #include #include #include #include #include #include #include #include #include "pfmlib_priv.h" int _pfmlib_sys_base; /* syscall base */ int _pfmlib_major_version; /* kernel perfmon major version */ int _pfmlib_minor_version; /* kernel perfmon minor version */ /* * helper function to retrieve one value from /proc/cpuinfo * for internal libpfm use only * attr: the attribute (line) to look for * ret_buf: a buffer to store the value of the attribute (as a string) * maxlen : number of bytes of capacity in ret_buf * * ret_buf is null terminated. * * Return: * 0 : attribute found, ret_buf populated * -1: attribute not found */ int __pfm_getcpuinfo_attr(const char *attr, char *ret_buf, size_t maxlen) { FILE *fp = NULL; int ret = -1; size_t attr_len, buf_len = 0; char *p, *value = NULL; char *buffer = NULL; if (attr == NULL || ret_buf == NULL || maxlen < 1) return -1; attr_len = strlen(attr); fp = fopen("/proc/cpuinfo", "r"); if (fp == NULL) return -1; while(getline(&buffer, &buf_len, fp) != -1){ /* skip blank lines */ if (*buffer == '\n') continue; p = strchr(buffer, ':'); if (p == NULL) goto error; /* * p+2: +1 = space, +2= firt character * strlen()-1 gets rid of \n */ *p = '\0'; value = p+2; value[strlen(value)-1] = '\0'; if (!strncmp(attr, buffer, attr_len)) break; } strncpy(ret_buf, value, maxlen-1); ret_buf[maxlen-1] = '\0'; ret = 0; error: free(buffer); fclose(fp); return ret; } #if defined(__x86_64__) static void adjust__pfmlib_sys_base(int version) { #ifdef CONFIG_PFMLIB_ARCH_CRAYXT _pfmlib_sys_base = 273; #else switch(version) { case 29: case 28: case 27: _pfmlib_sys_base = 295; break; case 26: case 25: _pfmlib_sys_base = 288; break; case 24: default: /* 2.6.24 as default */ _pfmlib_sys_base = 286; } #endif } #elif defined(__i386__) static void adjust__pfmlib_sys_base(int version) { switch(version) { case 29: case 28: case 27: _pfmlib_sys_base = 333; break; case 26: case 25: _pfmlib_sys_base = 327; break; case 24: default: /* 2.6.24 as default */ _pfmlib_sys_base = 325; } } #elif defined(__mips__) #if (_MIPS_SIM == _ABIN32) || (_MIPS_SIM == _MIPS_SIM_NABI32) static void adjust__pfmlib_sys_base(int version) { _pfmlib_sys_base = 6000; #ifdef CONFIG_PFMLIB_ARCH_SICORTEX _pfmlib_sys_base += 279; #else switch(version) { case 29: case 28: case 27: _pfmlib_sys_base += 293; break; case 26: case 25: _pfmlib_sys_base += 287; break; case 24: default: /* 2.6.24 as default */ _pfmlib_sys_base += 284; } #endif } #elif (_MIPS_SIM == _ABIO32) || (_MIPS_SIM == _MIPS_SIM_ABI32) static void adjust__pfmlib_sys_base(int version) { _pfmlib_sys_base = 4000; #ifdef CONFIG_PFMLIB_ARCH_SICORTEX _pfmlib_sys_base += 316; #else switch(version) { case 29: case 28: case 27: _pfmlib_sys_base += 330; break; case 26: case 25: _pfmlib_sys_base += 324; break; case 24: default: /* 2.6.24 as default */ _pfmlib_sys_base += 321; } #endif } #elif (_MIPS_SIM == _ABI64) || (_MIPS_SIM == _MIPS_SIM_ABI64) static void adjust__pfmlib_sys_base(int version) { _pfmlib_sys_base = 5000; #ifdef CONFIG_PFMLIB_ARCH_SICORTEX _pfmlib_sys_base += 275; #else switch(version) { case 29: case 28: case 27: _pfmlib_sys_base += 289; break; case 26: case 25: _pfmlib_sys_base += 283; break; case 24: default: /* 2.6.24 as default */ _pfmlib_sys_base += 280; } #endif } #endif #elif defined(__ia64__) static void adjust__pfmlib_sys_base(int version) { switch(version) { case 29: case 28: case 27: _pfmlib_sys_base = 1319; break; case 26: case 25: _pfmlib_sys_base = 1313; break; case 24: default: /* 2.6.24 as default */ _pfmlib_sys_base = 1310; } } #elif defined(__powerpc__) static void adjust__pfmlib_sys_base(int version) { switch(version) { case 29: case 28: case 27: _pfmlib_sys_base = 319; break; case 26: case 25: _pfmlib_sys_base = 313; break; case 24: default: /* 2.6.24 as default */ _pfmlib_sys_base = 310; } } #elif defined(__sparc__) static void adjust__pfmlib_sys_base(int version) { switch(version) { case 28: _pfmlib_sys_base = 324; break; case 27: _pfmlib_sys_base = 323; break; case 26: case 25: _pfmlib_sys_base = 317; break; case 24: default: /* 2.6.24 as default */ _pfmlib_sys_base = 310; } } #elif defined(__crayx2) static inline void adjust__pfmlib_sys_base(int version) { _pfmlib_sys_base = 294; } #else static inline void adjust__pfmlib_sys_base(int version) {} #endif static void pfm_init_syscalls_hardcoded(void) { struct utsname b; char *p, *s; int ret, v; /* * get version information */ ret = uname(&b); if (ret == -1) return; /* * expect major number 2 */ s= b.release; p = strchr(s, '.'); if (!p) return; *p = '\0'; v = atoi(s); if (v != 2) return; /* * expect 2.6 */ s = ++p; p = strchr(s, '.'); if (!p) return; *p = '\0'; v = atoi(s); if (v != 6) return; s = ++p; while (*p >= '0' && *p <= '9') p++; *p = '\0'; /* v is subversion: 23, 24 25 */ v = atoi(s); adjust__pfmlib_sys_base(v); } static int pfm_init_syscalls_sysfs(void) { FILE *fp; int ret; fp = fopen("/sys/kernel/perfmon/syscall", "r"); if (!fp) return -1; ret = fscanf(fp, "%d", &_pfmlib_sys_base); fclose(fp); return ret == 1 ? 0 : -1; } static int pfm_init_version_sysfs(void) { FILE *fp; char *p; char v[8]; int ret; fp = fopen("/sys/kernel/perfmon/version", "r"); if (!fp) return -1; ret = fscanf(fp, "%s", v); if (ret != 1) goto skip; p = strchr(v, '.'); if (p) { *p++ = '\0'; _pfmlib_major_version = atoi(v); _pfmlib_minor_version = atoi(p); } skip: fclose(fp); return ret == 1 ? 0 : -1; } void pfm_init_syscalls(void) { int ret; /* * first try via sysfs */ ret = pfm_init_syscalls_sysfs(); if (ret) pfm_init_syscalls_hardcoded(); ret = pfm_init_version_sysfs(); if (ret) { _pfmlib_major_version = 3; _pfmlib_minor_version = 0; } __pfm_vbprintf("sycall base %d\n", _pfmlib_sys_base); __pfm_vbprintf("major version %d\nminor version %d\n", _pfmlib_major_version, _pfmlib_minor_version); }