From 9cf8005f3aa82704c155e72e4bf6b765dc3c4a50 Mon Sep 17 00:00:00 2001 From: Veselin Georgiev Date: Fri, 21 Nov 2008 18:48:11 +0000 Subject: [PATCH] Removed C++ style comments; added CPU clock measuring code git-svn-id: https://svn.code.sf.net/p/libcpuid/code/HEAD/libcpuid@29 3b4be424-7ac5-41d7-8526-f4ddcb85d872 --- cpuid_tool/cpuid_tool.c | 1 + libcpuid/asm-bits.c | 16 ++-- libcpuid/asm-bits.h | 2 +- libcpuid/cpuid_main.c | 8 +- libcpuid/libcpuid.h | 6 +- libcpuid/libcpuid_constants.h | 2 +- libcpuid/libcpuid_types.h | 4 +- libcpuid/libcpuid_util.h | 2 +- libcpuid/rdtsc.c | 158 ++++++++++++++++++++++++++++++++-- libcpuid/recog_amd.h | 2 +- libcpuid/recog_intel.c | 6 +- libcpuid/recog_intel.h | 2 +- 12 files changed, 179 insertions(+), 30 deletions(-) diff --git a/cpuid_tool/cpuid_tool.c b/cpuid_tool/cpuid_tool.c index 45c55de..794dfa1 100644 --- a/cpuid_tool/cpuid_tool.c +++ b/cpuid_tool/cpuid_tool.c @@ -240,6 +240,7 @@ static int parse_cmdline(int argc, char** argv) recog = 1; } if (!strcmp(arg, "--clock-rdtsc")) { + need_clockreport = 1; need_timed_clockreport = 1; recog = 1; } diff --git a/libcpuid/asm-bits.c b/libcpuid/asm-bits.c index ce073fe..09a84d7 100644 --- a/libcpuid/asm-bits.c +++ b/libcpuid/asm-bits.c @@ -30,7 +30,7 @@ int cpuid_exists_by_eflags(void) { #ifdef __x86_64__ - return 1; // CPUID is always present on the x86_64 + return 1; /* CPUID is always present on the x86_64 */ #else # ifdef __GNUC__ int result; @@ -70,9 +70,9 @@ int cpuid_exists_by_eflags(void) return (result != 0); # else # error "Unsupported compiler" -# endif // _MSC_VER -# endif // __GNUC__ -#endif // __x86_64__ +# endif /* _MSC_VER */ +# endif /* __GNUC__ */ +#endif /* __x86_64__ */ } void exec_cpiud(uint32_t *regs) @@ -133,7 +133,7 @@ void exec_cpiud(uint32_t *regs) :"m"(regs) :"memory", "eax" ); -# endif // __x86_64__ +# endif /* __x86_64__ */ #else # ifdef _MSC_VER __asm { @@ -162,7 +162,7 @@ void exec_cpiud(uint32_t *regs) } # else # error "Unsupported compiler" -# endif // _MSC_VER +# endif /* _MSC_VER */ #endif } @@ -186,7 +186,7 @@ void cpu_rdtsc(uint64_t* result) }; # else # error "Unsupported compiler" -# endif // _MSC_VER -#endif // __GNUC__ +# endif /* _MSC_VER */ +#endif /* __GNUC__ */ *result = (uint64_t)low_part + (((uint64_t) hi_part) << 32); } diff --git a/libcpuid/asm-bits.h b/libcpuid/asm-bits.h index f286e49..e486f56 100644 --- a/libcpuid/asm-bits.h +++ b/libcpuid/asm-bits.h @@ -30,4 +30,4 @@ int cpuid_exists_by_eflags(void); void exec_cpiud(uint32_t *regs); -#endif // __ASM_BITS_H__ +#endif /* __ASM_BITS_H__ */ diff --git a/libcpuid/cpuid_main.c b/libcpuid/cpuid_main.c index 783fb03..3d15560 100644 --- a/libcpuid/cpuid_main.c +++ b/libcpuid/cpuid_main.c @@ -64,8 +64,8 @@ static int parse_token(const char* expected_token, const char *token, int veax, vebx, vecx, vedx; int index; - if (*recognized) return 1; // already recognized - if (strncmp(token, expected_token, strlen(expected_token))) return 1; // not what we search for + if (*recognized) return 1; /* already recognized */ + if (strncmp(token, expected_token, strlen(expected_token))) return 1; /* not what we search for */ sprintf(format, "%s[%%d]", expected_token); *recognized = 1; if (1 == sscanf(token, format, &index) && index >=0 && index < limit) { @@ -134,7 +134,7 @@ static int get_total_cpus(void) } return 1; } -#endif // GET_TOTAL_CPUS_DEFINED +#endif /* GET_TOTAL_CPUS_DEFINED */ static void load_features_common(struct cpu_raw_data_t* raw, struct cpu_id_t* data) @@ -353,7 +353,7 @@ int cpuid_deserialize_raw_data(struct cpu_raw_data_t* data, const char* filename strncpy(token, line, i); token[i] = '\0'; value = &line[i + 1]; - // try to recognize the line + /* try to recognize the line */ recognized = 0; if (!strcmp(token, "version")) { recognized = 1; diff --git a/libcpuid/libcpuid.h b/libcpuid/libcpuid.h index 70cf422..10409c5 100644 --- a/libcpuid/libcpuid.h +++ b/libcpuid/libcpuid.h @@ -318,7 +318,7 @@ typedef enum { CPU_FEATURE_100MHZSTEPS,/*!< 100 MHz multiplier control */ CPU_FEATURE_HWPSTATE, /*!< Hardware P-state control */ CPU_FEATURE_CONSTANT_TSC, /*!< TSC ticks at constant rate */ - // termination: + /* termination: */ NUM_CPU_FEATURES, } cpu_feature_t; @@ -636,10 +636,10 @@ typedef void (*libcpuid_warn_fn_t) (const char *msg); libcpuid_warn_fn_t cpuid_set_warn_function(libcpuid_warn_fn_t warn_fun); #ifdef __cplusplus -}; // extern "C" +}; /* extern "C" */ #endif /** @} */ -#endif // __LIBCPUID_H__ +#endif /* __LIBCPUID_H__ */ diff --git a/libcpuid/libcpuid_constants.h b/libcpuid/libcpuid_constants.h index 0495da2..336f3fc 100644 --- a/libcpuid/libcpuid_constants.h +++ b/libcpuid/libcpuid_constants.h @@ -39,4 +39,4 @@ #define MAX_EXT_CPUID_LEVEL 32 #define MAX_INTELFN4_LEVEL 4 -#endif // __LIBCPUID_CONSTANTS_H__ +#endif /* __LIBCPUID_CONSTANTS_H__ */ diff --git a/libcpuid/libcpuid_types.h b/libcpuid/libcpuid_types.h index d396b7a..a5b3be4 100644 --- a/libcpuid/libcpuid_types.h +++ b/libcpuid/libcpuid_types.h @@ -35,7 +35,7 @@ #if defined(HAVE_STDINT_H) # include #else -// we have to provide our own: +/* we have to provide our own: */ # if !defined(HAVE_INT32_T) && !defined(__int32_t_defined) typedef int int32_t; # endif @@ -53,4 +53,4 @@ typedef unsigned long long uint64_t; #endif -#endif // __LIBCPUID_TYPES_H__ +#endif /* __LIBCPUID_TYPES_H__ */ diff --git a/libcpuid/libcpuid_util.h b/libcpuid/libcpuid_util.h index 4914df1..f6b8eed 100644 --- a/libcpuid/libcpuid_util.h +++ b/libcpuid/libcpuid_util.h @@ -53,4 +53,4 @@ __attribute__((format(printf, 1, 2))) extern libcpuid_warn_fn_t _warn_fun; -#endif // __LIBCPUID_UTIL_H__ +#endif /* __LIBCPUID_UTIL_H__ */ diff --git a/libcpuid/rdtsc.c b/libcpuid/rdtsc.c index 89beaa6..cf5fc0e 100644 --- a/libcpuid/rdtsc.c +++ b/libcpuid/rdtsc.c @@ -23,33 +23,181 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include +#include #include "libcpuid.h" +#ifdef _WIN32 +#include +static void sys_precise_clock(uint64_t *result) +{ + LARGE_INTEGER freq, counter; + QueryPerformanceCounter(&counter); + QueryPerformanceFrequency(&freq); + double c = counter.QuadPart; + double f = freq.QuadPart; + result = (uint64_t) ( c * 1000000.0 / f ); +} +#else +/* assuming Linux, Mac OS or other POSIX */ +#include +static void sys_precise_clock(uint64_t *result) +{ + struct timeval tv; + gettimeofday(&tv, NULL); + *result = (uint64_t) tv.tv_sec * (uint64_t) 1000000 + + (uint64_t) tv.tv_usec; +} +#endif /* _WIN32 */ + +/* out = a - b */ +static void mark_t_subtract(struct cpu_mark_t* a, struct cpu_mark_t* b, struct cpu_mark_t *out) +{ + out->tsc = a->tsc - b->tsc; + out->sys_clock = a->sys_clock - b->sys_clock; +} + void cpu_tsc_mark(struct cpu_mark_t* mark) { + cpu_rdtsc(&mark->tsc); + sys_precise_clock(&mark->sys_clock); } void cpu_tsc_unmark(struct cpu_mark_t* mark) { + struct cpu_mark_t temp; + cpu_tsc_mark(&temp); + mark_t_subtract(&temp, mark, mark); } int cpu_clock_by_mark(struct cpu_mark_t* mark) { - return 1400; // FIXME + uint64_t result; + + /* Check if some subtraction resulted in a negative number: */ + if ((mark->tsc >> 63) != 0 || (mark->sys_clock >> 63) != 0) return -1; + + /* Divide-by-zero check: */ + if (mark->sys_clock == 0) return -1; + + /* Check if the result fits in 32bits */ + result = mark->tsc / mark->sys_clock; + if (result > (uint64_t) 0x7fffffff) return -1; + return (int) result; } +#ifdef _WIN32 +int cpu_clock_by_os(void) +{ + HKEY key; + char buff[20]; + DWORD size = 20; + int result; + + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0\\~MHz", 0, KEY_READ, &key) != ERROR_SUCCESS) + return -1; + + if (RegQueryValueEx(key, "~MHz", NULL, NULL, (LPBYTE) buff, (LPDWORD) &size) != ERROR_SUCCESS) { + RegCloseKey(key); + return -1; + } + buff[size] = 0; + RegCloseKey(key); + + if (1 != sscanf(buff, "%d", &result)) + return -1; + return result; +} +#else +/* Assuming Linux with /proc/cpuinfo */ int cpu_clock_by_os(void) { - return 1400; // FIXME + FILE *f; + char line[1024], *s; + int result; + + f = fopen("/proc/cpuinfo", "rt"); + if (!f) return -1; + + while (fgets(line, sizeof(line), f)) { + if (!strncmp(line, "cpu MHz", 7)) { + s = strchr(line, ':'); + if (s && 1 == sscanf(s, ":%d.", &result)) { + fclose(f); + return result; + } + } + } + fclose(f); + return -1; +} +#endif /* _WIN32 */ + +/* Emulate doing useful CPU intensive work */ +static int busy_loop(int amount) +{ + int i, j, k, s = 0; + static volatile int data[42] = {32, 12, -1, 5, 23, 0 }; + for (i = 0; i < amount; i++) + for (j = 0; j < 65536; j++) + for (k = 0; k < 42; k++) + s += data[k]; + return s; } -int cpu_clock_measure(int millis, int triple_check) +int cpu_clock_measure(int millis, int quad_check) { - return 1400; // FIXME + struct cpu_mark_t begin[4], end[4], temp, temp2; + int results[4], cycles, n, k, i, j, bi, bj, mdiff, diff, _zero = 0; + uint64_t tl; + + if (millis < 1) return -1; + tl = millis * (uint64_t) 1000; + if (quad_check) + tl /= 4; + n = quad_check ? 4 : 1; + cycles = 1; + for (k = 0; k < n; k++) { + cpu_tsc_mark(&begin[k]); + end[k] = begin[k]; + do { + /* Run busy loop, and fool the compiler that we USE the garbishy + value it calculates */ + _zero |= (1 & busy_loop(cycles)); + cpu_tsc_mark(&temp); + mark_t_subtract(&temp, &end[k], &temp2); + /* If busy loop is too short, increase it */ + if (temp2.sys_clock < tl / 8) + cycles *= 2; + end[k] = temp; + } while (end[k].sys_clock - begin[k].sys_clock < tl); + mark_t_subtract(&end[k], &begin[k], &temp); + results[k] = cpu_clock_by_mark(&temp); + } + if (n == 1) return results[k]; + mdiff = 0x7fffffff; + bi = bj = -1; + for (i = 0; i < 4; i++) { + for (j = i + 1; j < 4; j++) { + diff = results[i] - results[j]; + if (diff < 0) diff = -diff; + if (diff < mdiff) { + mdiff = diff; + bi = i; + bj = j; + } + } + } + if (results[bi] == -1) return -1; + return (results[bi] + results[bj] + _zero) / 2; } int cpu_clock(void) { - return 1400; // FIXME + int result; + result = cpu_clock_by_os(); + if (result <= 0) + result = cpu_clock_measure(200, 1); + return result; } diff --git a/libcpuid/recog_amd.h b/libcpuid/recog_amd.h index 24bcc5c..e5d3ccf 100644 --- a/libcpuid/recog_amd.h +++ b/libcpuid/recog_amd.h @@ -28,4 +28,4 @@ int cpuid_identify_amd(struct cpu_raw_data_t* raw, struct cpu_id_t* data); -#endif // __RECOG_AMD_H__ +#endif /* __RECOG_AMD_H__ */ diff --git a/libcpuid/recog_intel.c b/libcpuid/recog_intel.c index 8cd1c40..9a57079 100644 --- a/libcpuid/recog_intel.c +++ b/libcpuid/recog_intel.c @@ -108,7 +108,7 @@ const struct match_entry_t cpudb_intel[] = { { 6, 5, -1, -1, -1, CELERON , "P-II Celeron (no L2)" }, { 6, 6, -1, -1, -1, CELERON , "P-II Celeron (128K)" }, - /* ////////////////////////////////////////////////// */ + /* -------------------------------------------------- */ { 6, 7, -1, -1, -1, NO_CODE , "Pentium III (Katmai)" }, { 6, 8, -1, -1, -1, NO_CODE , "Pentium III (Coppermine)"}, @@ -125,7 +125,7 @@ const struct match_entry_t cpudb_intel[] = { { 6, 10, -1, -1, -1, CELERON , "P-III Celeron" }, { 6, 11, -1, -1, -1, CELERON , "P-III Celeron" }, - /* ////////////////////////////////////////////////// */ + /* -------------------------------------------------- */ { 6, 9, -1, -1, -1, NO_CODE , "Unknown Pentium M" }, { 6, 9, -1, -1, -1, MOBILE_PENTIUM_M , "Unknown Pentium M" }, @@ -139,7 +139,7 @@ const struct match_entry_t cpudb_intel[] = { { 6, 12, -1, -1, -1, ATOM_DUALCORE , "Atom (Dual Core)" }, { 6, 12, -1, -1, -1, ATOM_SILVERTHORNE , "Atom (Silverthorne)" }, - /* ////////////////////////////////////////////////// */ + /* -------------------------------------------------- */ { 6, 14, -1, -1, -1, NO_CODE , "Unknown Yonah" }, { 6, 14, -1, -1, -1, CORE_SOLO , "Yonah (Core Solo)" }, diff --git a/libcpuid/recog_intel.h b/libcpuid/recog_intel.h index a412019..dbb8841 100644 --- a/libcpuid/recog_intel.h +++ b/libcpuid/recog_intel.h @@ -28,4 +28,4 @@ int cpuid_identify_intel(struct cpu_raw_data_t* raw, struct cpu_id_t* data); -#endif //__RECOG_INTEL_H__ +#endif /*__RECOG_INTEL_H__*/