mirror of
https://github.com/anrieff/libcpuid
synced 2025-07-02 14:04:15 +00:00
* Support for stdin/stdout for (de)serializing cpu_raw_data_t;
* set_warn_function renamed to cpuid_set_warn_function; * Updated Doxygen documentation: added manpage output, generic mainpage intro, default module named correctly; * Updated doxy libcpuid.h documentation, fixed some bugs; * Warnings are now printed to stderr by default, not stdout; * Some constants in AMD code did not reflected their meaning well, fixed; * The cpuid_tool utility thoroughly redesigned; now a multiple-function program, perhaps close to the finalized state. git-svn-id: https://svn.code.sf.net/p/libcpuid/code/HEAD/libcpuid@19 3b4be424-7ac5-41d7-8526-f4ddcb85d872
This commit is contained in:
parent
5c348fd6bd
commit
c5c0539372
7 changed files with 638 additions and 99 deletions
|
@ -1,47 +1,562 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2008 Veselin Georgiev,
|
||||||
|
* anrieffNOSPAM @ mgail_DOT.com (convert to gmail)
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @File cpuid_tool.c
|
||||||
|
* @Date 2008-11-19
|
||||||
|
* @Author Veselin Georgiev
|
||||||
|
* @Brief Command line interface to libcpuid
|
||||||
|
*
|
||||||
|
* This file is provides a direct interface to libcpuid. See the usage()
|
||||||
|
* function (or just run the program with the `--help' switch) for a short
|
||||||
|
* command line options reference.
|
||||||
|
*
|
||||||
|
* This file has several purposes:
|
||||||
|
*
|
||||||
|
* 1) When started with no arguments, the program outputs the RAW and decoded
|
||||||
|
* CPU data to files (`raw.txt' and `report.txt', respectively) - this is
|
||||||
|
* intended to be a dumb, doubleclicky tool for non-developer
|
||||||
|
* users, that can provide debug info about unrecognized processors to
|
||||||
|
* libcpuid developers.
|
||||||
|
* 2) When operated from the terminal with the `--report' option, it is a
|
||||||
|
* generic CPU-info utility.
|
||||||
|
* 3) Can be used in shell scripts, e.g. to get the name of the CPU, cache
|
||||||
|
* sizes, features, with query options like `--cache', `--brandstr', etc.
|
||||||
|
* 4) Finally, it serves to self-document libcpiud itself :)
|
||||||
|
*/
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include "libcpuid.h"
|
#include "libcpuid.h"
|
||||||
|
|
||||||
int main(void)
|
/* Globals: */
|
||||||
|
char raw_data_file[256] = "";
|
||||||
|
char out_file[256] = "";
|
||||||
|
typedef enum {
|
||||||
|
NEED_CPUID_PRESENT,
|
||||||
|
NEED_VENDOR_STR,
|
||||||
|
NEED_VENDOR_ID,
|
||||||
|
NEED_BRAND_STRING,
|
||||||
|
NEED_FAMILY,
|
||||||
|
NEED_MODEL,
|
||||||
|
NEED_STEPPING,
|
||||||
|
NEED_EXT_FAMILY,
|
||||||
|
NEED_EXT_MODEL,
|
||||||
|
NEED_NUM_CORES,
|
||||||
|
NEED_NUM_LOGICAL,
|
||||||
|
NEED_TOTAL_CPUS,
|
||||||
|
NEED_L1D_SIZE,
|
||||||
|
NEED_L1I_SIZE,
|
||||||
|
NEED_L2_SIZE,
|
||||||
|
NEED_L3_SIZE,
|
||||||
|
NEED_L1D_ASSOC,
|
||||||
|
NEED_L2_ASSOC,
|
||||||
|
NEED_L3_ASSOC,
|
||||||
|
NEED_L1D_CACHELINE,
|
||||||
|
NEED_L2_CACHELINE,
|
||||||
|
NEED_L3_CACHELINE,
|
||||||
|
NEED_CODENAME,
|
||||||
|
NEED_FEATURES,
|
||||||
|
NEED_CLOCK,
|
||||||
|
NEED_CLOCK_RDTSC,
|
||||||
|
} output_data_switch;
|
||||||
|
|
||||||
|
int need_input = 0,
|
||||||
|
need_output = 0,
|
||||||
|
need_quiet = 0,
|
||||||
|
need_report = 0,
|
||||||
|
need_clockreport = 0,
|
||||||
|
need_timed_clockreport = 0,
|
||||||
|
need_verbose = 0,
|
||||||
|
need_version = 0;
|
||||||
|
|
||||||
|
#define MAX_REQUESTS 32
|
||||||
|
int num_requests = 0;
|
||||||
|
output_data_switch requests[MAX_REQUESTS];
|
||||||
|
|
||||||
|
FILE *fout;
|
||||||
|
|
||||||
|
|
||||||
|
const struct { output_data_switch sw; const char* synopsis; int ident_required; }
|
||||||
|
matchtable[] = {
|
||||||
|
{ NEED_CPUID_PRESENT, "--cpuid" , 0},
|
||||||
|
{ NEED_VENDOR_STR , "--vendorstr" , 1},
|
||||||
|
{ NEED_VENDOR_ID , "--vendorid" , 1},
|
||||||
|
{ NEED_BRAND_STRING , "--brandstr" , 1},
|
||||||
|
{ NEED_FAMILY , "--family" , 1},
|
||||||
|
{ NEED_MODEL , "--model" , 1},
|
||||||
|
{ NEED_STEPPING , "--stepping" , 1},
|
||||||
|
{ NEED_EXT_FAMILY , "--extfamily" , 1},
|
||||||
|
{ NEED_EXT_MODEL , "--extmodel" , 1},
|
||||||
|
{ NEED_NUM_CORES , "--cores" , 1},
|
||||||
|
{ NEED_NUM_LOGICAL , "--logical" , 1},
|
||||||
|
{ NEED_TOTAL_CPUS , "--total-cpus" , 1},
|
||||||
|
{ NEED_L1D_SIZE , "--l1d-cache" , 1},
|
||||||
|
{ NEED_L1I_SIZE , "--l1i-cache" , 1},
|
||||||
|
{ NEED_L2_SIZE , "--cache" , 1},
|
||||||
|
{ NEED_L2_SIZE , "--l2-cache" , 1},
|
||||||
|
{ NEED_L3_SIZE , "--l3-cache" , 1},
|
||||||
|
{ NEED_L1D_ASSOC , "--l1d-assoc" , 1},
|
||||||
|
{ NEED_L2_ASSOC , "--l2-assoc" , 1},
|
||||||
|
{ NEED_L3_ASSOC , "--l3-assoc" , 1},
|
||||||
|
{ NEED_L1D_CACHELINE, "--l1d-cacheline", 1},
|
||||||
|
{ NEED_L2_CACHELINE , "--l2-cacheline" , 1},
|
||||||
|
{ NEED_L3_CACHELINE , "--l3-cacheline" , 1},
|
||||||
|
{ NEED_CODENAME , "--codename" , 1},
|
||||||
|
{ NEED_FEATURES , "--flags" , 1},
|
||||||
|
{ NEED_CLOCK , "--clock" , 0},
|
||||||
|
{ NEED_CLOCK_RDTSC , "--clock-rdtsc" , 1},
|
||||||
|
};
|
||||||
|
|
||||||
|
const int sz_match = (sizeof(matchtable) / sizeof(matchtable[0]));
|
||||||
|
|
||||||
|
/* functions */
|
||||||
|
|
||||||
|
static void usage(void)
|
||||||
{
|
{
|
||||||
if (!cpuid_present()) {
|
printf("Usage: cpuid_tool [options]\n\n");
|
||||||
printf("No CPUID on this CPU, sorry!\n");
|
printf("Options:\n");
|
||||||
return -1;
|
printf(" -h,--help - Show this help\n");
|
||||||
}
|
printf(" --load=<file> - Load RAW CPUID data from file\n");
|
||||||
printf("CPUID is present\n");
|
printf(" --save=<file> - Aquire RAW CPUID data and write it to file\n");
|
||||||
struct cpu_raw_data_t raw;
|
printf(" --report,--all - Report all decoded CPU info (w/o clock)\n");
|
||||||
struct cpu_id_t data;
|
printf(" --clock - in conjunction to --report: print CPU clock as well\n");
|
||||||
if (cpuid_get_raw_data(&raw) < 0)
|
printf(" --clock-rdtsc - same as --clock, but use RDTSC for clock detection\n");
|
||||||
printf("Error obtaining raw data: %s\n", cpuid_error());
|
printf(" --quiet - disable warnings\n");
|
||||||
if (cpu_identify(&raw, &data) < 0)
|
printf(" --outfile=<file> - redirect all output to this file, instead of stdout\n");
|
||||||
printf("Error identifying the CPU: %s\n", cpuid_error());
|
printf(" --verbose - be extra verbose\n");
|
||||||
printf("CPU Info:\n------------------\n");
|
printf(" --version - print library version\n");
|
||||||
printf(" vendor_str : `%s'\n", data.vendor_str);
|
|
||||||
printf(" vendor id : %d\n", (int) data.vendor);
|
|
||||||
printf(" brand_str : `%s'\n", data.brand_str);
|
|
||||||
printf(" family : %d\n", data.family);
|
|
||||||
printf(" model : %d\n", data.model);
|
|
||||||
printf(" stepping : %d\n", data.stepping);
|
|
||||||
printf(" ext_family : %d\n", data.ext_family);
|
|
||||||
printf(" ext_model : %d\n", data.ext_model);
|
|
||||||
printf(" num_cores : %d\n", data.num_cores);
|
|
||||||
printf(" num_logical: %d\n", data.num_logical_cpus);
|
|
||||||
printf(" total_cpus : %d\n", data.total_cpus);
|
|
||||||
printf(" L1 D cache : %d KB\n", data.l1_data_cache);
|
|
||||||
printf(" L1 I cache : %d KB\n", data.l1_instruction_cache);
|
|
||||||
printf(" L2 cache : %d KB\n", data.l2_cache);
|
|
||||||
printf(" L3 cache : %d KB\n", data.l3_cache);
|
|
||||||
printf(" L1D assoc. : %d-way\n", data.l1_assoc);
|
|
||||||
printf(" L2 assoc. : %d-way\n", data.l2_assoc);
|
|
||||||
printf(" L3 assoc. : %d-way\n", data.l3_assoc);
|
|
||||||
printf(" L1D line sz: %d bytes\n", data.l1_cacheline);
|
|
||||||
printf(" L2 line sz : %d bytes\n", data.l2_cacheline);
|
|
||||||
printf(" L3 line sz : %d bytes\n", data.l3_cacheline);
|
|
||||||
printf(" code name : `%s'\n", data.cpu_codename);
|
|
||||||
printf(" features :");
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < NUM_CPU_FEATURES; i++)
|
|
||||||
if (data.flags[i])
|
|
||||||
printf(" %s", cpu_feature_str(i));
|
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
printf("Query switches (generate 1 line of ouput per switch; in order of appearance):");
|
||||||
|
|
||||||
|
int line_fill = 80, l, i;
|
||||||
|
for (i = 0; i < sz_match; i++) {
|
||||||
|
l = (int) strlen(matchtable[i].synopsis);
|
||||||
|
if (line_fill + l > 76) {
|
||||||
|
line_fill = 2;
|
||||||
|
printf("\n ");
|
||||||
|
}
|
||||||
|
printf("%s", matchtable[i].synopsis);
|
||||||
|
if (i < sz_match - 1) {
|
||||||
|
line_fill += l + 2;
|
||||||
|
printf(", ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("\n\n");
|
||||||
|
printf("If `-' is used for <file>, then stdin/stdout will be used instead of files.\n");
|
||||||
|
printf("When no options are present, the program behaves as if it was invoked with\n");
|
||||||
|
printf(" cpuid_tool \"--save=raw.txt --outfile=report.txt --report --verbose\"\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parse_cmdline(int argc, char** argv)
|
||||||
|
{
|
||||||
|
#define xerror(msg)\
|
||||||
|
fprintf(stderr, "Error: %s\n\n", msg); \
|
||||||
|
fprintf(stderr, "Use -h to get a list of supported options\n"); \
|
||||||
|
return -1;
|
||||||
|
if (argc == 1) {
|
||||||
|
/* Default command line options */
|
||||||
|
need_output = 1;
|
||||||
|
strcpy(raw_data_file, "raw.txt");
|
||||||
|
strcpy(out_file, "report.txt");
|
||||||
|
need_report = 1;
|
||||||
|
need_verbose = 1;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
int i, j, recog;
|
||||||
|
for (i = 1; i < argc; i++) {
|
||||||
|
char *arg = argv[i];
|
||||||
|
recog = 0;
|
||||||
|
if (!strcmp(arg, "-h") || !strcmp(arg, "--help")) {
|
||||||
|
usage();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (!strncmp(arg, "--load=", 7)) {
|
||||||
|
if (need_input) {
|
||||||
|
xerror("Too many `--load' options!");
|
||||||
|
}
|
||||||
|
if (need_output) {
|
||||||
|
xerror("Cannot have both `--load' and `--save' options!");
|
||||||
|
}
|
||||||
|
if (strlen(arg) <= 7) {
|
||||||
|
xerror("--load: bad file specification!");
|
||||||
|
}
|
||||||
|
need_input = 1;
|
||||||
|
strcpy(raw_data_file, arg + 7);
|
||||||
|
recog = 1;
|
||||||
|
}
|
||||||
|
if (!strncmp(arg, "--save=", 7)) {
|
||||||
|
if (need_output) {
|
||||||
|
xerror("Too many `--save' options!");
|
||||||
|
}
|
||||||
|
if (need_input) {
|
||||||
|
xerror("Cannot have both `--load' and `--save' options!");
|
||||||
|
}
|
||||||
|
if (strlen(arg) <= 7) {
|
||||||
|
xerror("--save: bad file specification!");
|
||||||
|
}
|
||||||
|
need_output = 1;
|
||||||
|
strcpy(raw_data_file, arg + 7);
|
||||||
|
recog = 1;
|
||||||
|
}
|
||||||
|
if (!strncmp(arg, "--outfile=", 10)) {
|
||||||
|
if (strlen(arg) <= 10) {
|
||||||
|
xerror("--output: bad file specification!");
|
||||||
|
}
|
||||||
|
strcpy(out_file, arg + 10);
|
||||||
|
recog = 1;
|
||||||
|
}
|
||||||
|
if (!strcmp(arg, "--report") || !strcmp(arg, "--all")) {
|
||||||
|
need_report = 1;
|
||||||
|
recog = 1;
|
||||||
|
}
|
||||||
|
if (!strcmp(arg, "--clock")) {
|
||||||
|
need_clockreport = 1;
|
||||||
|
recog = 1;
|
||||||
|
}
|
||||||
|
if (!strcmp(arg, "--clock-rdtsc")) {
|
||||||
|
need_timed_clockreport = 1;
|
||||||
|
recog = 1;
|
||||||
|
}
|
||||||
|
if (!strcmp(arg, "--quiet")) {
|
||||||
|
need_quiet = 1;
|
||||||
|
recog = 1;
|
||||||
|
}
|
||||||
|
if (!strcmp(arg, "--verbose")) {
|
||||||
|
need_verbose = 1;
|
||||||
|
recog = 1;
|
||||||
|
}
|
||||||
|
if (!strcmp(arg, "--version")) {
|
||||||
|
need_version = 1;
|
||||||
|
recog = 1;
|
||||||
|
}
|
||||||
|
for (j = 0; j < sz_match; j++)
|
||||||
|
if (!strcmp(arg, matchtable[j].synopsis)) {
|
||||||
|
if (num_requests >= MAX_REQUESTS) {
|
||||||
|
xerror("Too many requests!");
|
||||||
|
}
|
||||||
|
requests[num_requests++] = matchtable[j].sw;
|
||||||
|
recog = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!recog) {
|
||||||
|
fprintf(stderr, "Unrecognized option: `%s'\n\n", arg);
|
||||||
|
fprintf(stderr, "Use -h to get a list of supported options\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void close_out(void)
|
||||||
|
{
|
||||||
|
fclose(fout);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int check_need_raw_data(void)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
if (need_output || need_report) return 1;
|
||||||
|
for (i = 0; i < num_requests; i++) {
|
||||||
|
for (j = 0; j < sz_match; j++)
|
||||||
|
if (requests[i] == matchtable[j].sw &&
|
||||||
|
matchtable[j].ident_required) return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_info(output_data_switch query, struct cpu_raw_data_t* raw,
|
||||||
|
struct cpu_id_t* data)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
switch (query) {
|
||||||
|
case NEED_CPUID_PRESENT:
|
||||||
|
fprintf(fout, "%d\n", cpuid_present());
|
||||||
|
break;
|
||||||
|
case NEED_VENDOR_STR:
|
||||||
|
fprintf(fout, "%s\n", data->vendor_str);
|
||||||
|
break;
|
||||||
|
case NEED_VENDOR_ID:
|
||||||
|
fprintf(fout, "%d\n", data->vendor);
|
||||||
|
break;
|
||||||
|
case NEED_BRAND_STRING:
|
||||||
|
fprintf(fout, "%s\n", data->brand_str);
|
||||||
|
break;
|
||||||
|
case NEED_FAMILY:
|
||||||
|
fprintf(fout, "%d\n", data->family);
|
||||||
|
break;
|
||||||
|
case NEED_MODEL:
|
||||||
|
fprintf(fout, "%d\n", data->model);
|
||||||
|
break;
|
||||||
|
case NEED_STEPPING:
|
||||||
|
fprintf(fout, "%d\n", data->stepping);
|
||||||
|
break;
|
||||||
|
case NEED_EXT_FAMILY:
|
||||||
|
fprintf(fout, "%d\n", data->ext_family);
|
||||||
|
break;
|
||||||
|
case NEED_EXT_MODEL:
|
||||||
|
fprintf(fout, "%d\n", data->ext_model);
|
||||||
|
break;
|
||||||
|
case NEED_NUM_CORES:
|
||||||
|
fprintf(fout, "%d\n", data->num_cores);
|
||||||
|
break;
|
||||||
|
case NEED_NUM_LOGICAL:
|
||||||
|
fprintf(fout, "%d\n", data->num_logical_cpus);
|
||||||
|
break;
|
||||||
|
case NEED_TOTAL_CPUS:
|
||||||
|
fprintf(fout, "%d\n", data->total_cpus);
|
||||||
|
break;
|
||||||
|
case NEED_L1D_SIZE:
|
||||||
|
fprintf(fout, "%d\n", data->l1_data_cache);
|
||||||
|
break;
|
||||||
|
case NEED_L1I_SIZE:
|
||||||
|
fprintf(fout, "%d\n", data->l1_instruction_cache);
|
||||||
|
break;
|
||||||
|
case NEED_L2_SIZE:
|
||||||
|
fprintf(fout, "%d\n", data->l2_cache);
|
||||||
|
break;
|
||||||
|
case NEED_L3_SIZE:
|
||||||
|
fprintf(fout, "%d\n", data->l3_cache);
|
||||||
|
break;
|
||||||
|
case NEED_L1D_ASSOC:
|
||||||
|
fprintf(fout, "%d\n", data->l1_assoc);
|
||||||
|
break;
|
||||||
|
case NEED_L2_ASSOC:
|
||||||
|
fprintf(fout, "%d\n", data->l2_assoc);
|
||||||
|
break;
|
||||||
|
case NEED_L3_ASSOC:
|
||||||
|
fprintf(fout, "%d\n", data->l3_assoc);
|
||||||
|
break;
|
||||||
|
case NEED_L1D_CACHELINE:
|
||||||
|
fprintf(fout, "%d\n", data->l1_cacheline);
|
||||||
|
break;
|
||||||
|
case NEED_L2_CACHELINE:
|
||||||
|
fprintf(fout, "%d\n", data->l2_cacheline);
|
||||||
|
break;
|
||||||
|
case NEED_L3_CACHELINE:
|
||||||
|
fprintf(fout, "%d\n", data->l3_cacheline);
|
||||||
|
break;
|
||||||
|
case NEED_CODENAME:
|
||||||
|
fprintf(fout, "%s\n", data->cpu_codename);
|
||||||
|
break;
|
||||||
|
case NEED_FEATURES:
|
||||||
|
{
|
||||||
|
for (i = 0; i < NUM_CPU_FEATURES; i++)
|
||||||
|
if (data->flags[i])
|
||||||
|
fprintf(fout, " %s", cpu_feature_str(i));
|
||||||
|
fprintf(fout, "\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case NEED_CLOCK:
|
||||||
|
fprintf(fout, "%d\n", cpu_clock());
|
||||||
|
break;
|
||||||
|
case NEED_CLOCK_RDTSC:
|
||||||
|
fprintf(fout, "%d\n", cpu_clock_measure(400, 1));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(fout, "How did you get here?!?\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
int parseres = parse_cmdline(argc, argv);
|
||||||
|
int i, readres, writeres;
|
||||||
|
int only_clock_queries;
|
||||||
|
if (parseres != 1)
|
||||||
|
return parseres;
|
||||||
|
struct cpu_raw_data_t raw;
|
||||||
|
struct cpu_id_t data;
|
||||||
|
|
||||||
|
/* In quiet mode, disable libcpuid warning messages: */
|
||||||
|
if (need_quiet)
|
||||||
|
cpuid_set_warn_function(NULL);
|
||||||
|
|
||||||
|
/* Redirect output, if necessary: */
|
||||||
|
if (strcmp(out_file, "") && strcmp(out_file, "-")) {
|
||||||
|
fout = fopen(out_file, "wt");
|
||||||
|
if (!fout) {
|
||||||
|
if (!need_quiet)
|
||||||
|
fprintf(stderr, "Cannot open `%s' for writing!\n", out_file);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
atexit(close_out);
|
||||||
|
} else {
|
||||||
|
fout = stdout;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If requested, print library version: */
|
||||||
|
if (need_version)
|
||||||
|
fprintf(fout, "%s\n", cpuid_lib_version());
|
||||||
|
|
||||||
|
if (need_input) {
|
||||||
|
/* We have a request to input raw CPUID data from file: */
|
||||||
|
if (!strcmp(raw_data_file, "-"))
|
||||||
|
/* Input from stdin */
|
||||||
|
readres = cpuid_deserialize_raw_data(&raw, "");
|
||||||
|
else
|
||||||
|
/* Input from file */
|
||||||
|
readres = cpuid_deserialize_raw_data(&raw, raw_data_file);
|
||||||
|
if (readres < 0) {
|
||||||
|
if (!need_quiet) {
|
||||||
|
fprintf(stderr, "Cannot deserialize raw data from ");
|
||||||
|
if (!strcmp(raw_data_file, "-"))
|
||||||
|
fprintf(stderr, "stdin\n");
|
||||||
|
else
|
||||||
|
fprintf(stderr, "file `%s'\n", raw_data_file);
|
||||||
|
/* Print the error message */
|
||||||
|
fprintf(stderr, "Error: %s\n", cpuid_error());
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (check_need_raw_data()) {
|
||||||
|
/* Try to obtain raw CPUID data from the CPU: */
|
||||||
|
readres = cpuid_get_raw_data(&raw);
|
||||||
|
if (readres < 0) {
|
||||||
|
if (!need_quiet) {
|
||||||
|
fprintf(stderr, "Cannot obtain raw CPU data!\n");
|
||||||
|
fprintf(stderr, "Error: %s\n", cpuid_error());
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Need to dump raw CPUID data to file: */
|
||||||
|
if (need_output) {
|
||||||
|
if (need_verbose)
|
||||||
|
printf("Writing raw CPUID dump to `%s'\n", raw_data_file);
|
||||||
|
if (!strcmp(raw_data_file, "-"))
|
||||||
|
/* Serialize to stdout */
|
||||||
|
writeres = cpuid_serialize_raw_data(&raw, "");
|
||||||
|
else
|
||||||
|
/* Serialize to file */
|
||||||
|
writeres = cpuid_serialize_raw_data(&raw, raw_data_file);
|
||||||
|
if (writeres < 0) {
|
||||||
|
if (!need_quiet) {
|
||||||
|
fprintf(stderr, "Cannot serialize raw data to ");
|
||||||
|
if (!strcmp(raw_data_file, "-"))
|
||||||
|
fprintf(stderr, "stdout\n");
|
||||||
|
else
|
||||||
|
fprintf(stderr, "file `%s'\n", raw_data_file);
|
||||||
|
/* Print the error message */
|
||||||
|
fprintf(stderr, "Error: %s\n", cpuid_error());
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (need_report) {
|
||||||
|
if (need_verbose) {
|
||||||
|
printf("Writing decoded CPU report to `%s'\n", out_file);
|
||||||
|
}
|
||||||
|
/* Write a thorough report of cpu_id_t structure to output (usually stdout) */
|
||||||
|
fprintf(fout, "CPUID is present\n");
|
||||||
|
/*
|
||||||
|
* Try CPU identification
|
||||||
|
* (this fill the `data' structure with decoded CPU features)
|
||||||
|
*/
|
||||||
|
if (cpu_identify(&raw, &data) < 0)
|
||||||
|
fprintf(fout, "Error identifying the CPU: %s\n", cpuid_error());
|
||||||
|
|
||||||
|
/* OK, now write what we have in `data'...: */
|
||||||
|
fprintf(fout, "CPU Info:\n------------------\n");
|
||||||
|
fprintf(fout, " vendor_str : `%s'\n", data.vendor_str);
|
||||||
|
fprintf(fout, " vendor id : %d\n", (int) data.vendor);
|
||||||
|
fprintf(fout, " brand_str : `%s'\n", data.brand_str);
|
||||||
|
fprintf(fout, " family : %d\n", data.family);
|
||||||
|
fprintf(fout, " model : %d\n", data.model);
|
||||||
|
fprintf(fout, " stepping : %d\n", data.stepping);
|
||||||
|
fprintf(fout, " ext_family : %d\n", data.ext_family);
|
||||||
|
fprintf(fout, " ext_model : %d\n", data.ext_model);
|
||||||
|
fprintf(fout, " num_cores : %d\n", data.num_cores);
|
||||||
|
fprintf(fout, " num_logical: %d\n", data.num_logical_cpus);
|
||||||
|
fprintf(fout, " total_cpus : %d\n", data.total_cpus);
|
||||||
|
fprintf(fout, " L1 D cache : %d KB\n", data.l1_data_cache);
|
||||||
|
fprintf(fout, " L1 I cache : %d KB\n", data.l1_instruction_cache);
|
||||||
|
fprintf(fout, " L2 cache : %d KB\n", data.l2_cache);
|
||||||
|
fprintf(fout, " L3 cache : %d KB\n", data.l3_cache);
|
||||||
|
fprintf(fout, " L1D assoc. : %d-way\n", data.l1_assoc);
|
||||||
|
fprintf(fout, " L2 assoc. : %d-way\n", data.l2_assoc);
|
||||||
|
fprintf(fout, " L3 assoc. : %d-way\n", data.l3_assoc);
|
||||||
|
fprintf(fout, " L1D line sz: %d bytes\n", data.l1_cacheline);
|
||||||
|
fprintf(fout, " L2 line sz : %d bytes\n", data.l2_cacheline);
|
||||||
|
fprintf(fout, " L3 line sz : %d bytes\n", data.l3_cacheline);
|
||||||
|
fprintf(fout, " code name : `%s'\n", data.cpu_codename);
|
||||||
|
fprintf(fout, " features :");
|
||||||
|
/*
|
||||||
|
* Here we enumerate all CPU feature bits, and when a feature
|
||||||
|
* is present output its name:
|
||||||
|
*/
|
||||||
|
for (i = 0; i < NUM_CPU_FEATURES; i++)
|
||||||
|
if (data.flags[i])
|
||||||
|
fprintf(fout, " %s", cpu_feature_str(i));
|
||||||
|
fprintf(fout, "\n");
|
||||||
|
|
||||||
|
/* Is CPU clock info requested? */
|
||||||
|
if (need_clockreport) {
|
||||||
|
if (need_timed_clockreport) {
|
||||||
|
/* Here we use the RDTSC-based routine */
|
||||||
|
fprintf(fout, " cpu clock : %d MHz\n",
|
||||||
|
cpu_clock_measure(400, 1));
|
||||||
|
} else {
|
||||||
|
/* Here we use the OS-provided info */
|
||||||
|
fprintf(fout, " cpu clock : %d MHz\n",
|
||||||
|
cpu_clock());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Check if we have any queries to process.
|
||||||
|
* We have to handle the case when `--clock' or `--clock-rdtsc' options
|
||||||
|
* are present.
|
||||||
|
* If in report mode, this will generate spurious output after the
|
||||||
|
* report, if not handled explicitly.
|
||||||
|
*/
|
||||||
|
only_clock_queries = 1;
|
||||||
|
for (i = 0; i < num_requests; i++)
|
||||||
|
if (requests[i] != NEED_CLOCK && requests[i] != NEED_CLOCK_RDTSC) {
|
||||||
|
only_clock_queries = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* OK, process all queries. */
|
||||||
|
if ((!need_report || !only_clock_queries) && num_requests > 0) {
|
||||||
|
if (cpu_identify(&raw, &data) < 0) {
|
||||||
|
if (!need_quiet)
|
||||||
|
fprintf(stderr,
|
||||||
|
"Error identifying the CPU: %s\n",
|
||||||
|
cpuid_error());
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
for (i = 0; i < num_requests; i++)
|
||||||
|
print_info(requests[i], &raw, &data);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -862,7 +862,7 @@ RTF_EXTENSIONS_FILE =
|
||||||
# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
|
# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
|
||||||
# generate man pages
|
# generate man pages
|
||||||
|
|
||||||
GENERATE_MAN = NO
|
GENERATE_MAN = YES
|
||||||
|
|
||||||
# The MAN_OUTPUT tag is used to specify where the man pages will be put.
|
# The MAN_OUTPUT tag is used to specify where the man pages will be put.
|
||||||
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
|
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
|
||||||
|
|
|
@ -38,7 +38,7 @@
|
||||||
|
|
||||||
static int _libcpiud_errno = ERR_OK;
|
static int _libcpiud_errno = ERR_OK;
|
||||||
|
|
||||||
static int set_error(cpuid_error_t err)
|
static int set_error(cpu_error_t err)
|
||||||
{
|
{
|
||||||
_libcpiud_errno = (int) err;
|
_libcpiud_errno = (int) err;
|
||||||
return (int) err;
|
return (int) err;
|
||||||
|
@ -291,6 +291,9 @@ int cpuid_serialize_raw_data(struct cpu_raw_data_t* data, const char* filename)
|
||||||
int i;
|
int i;
|
||||||
FILE *f;
|
FILE *f;
|
||||||
|
|
||||||
|
if (!strcmp(filename, ""))
|
||||||
|
f = stdout;
|
||||||
|
else
|
||||||
f = fopen(filename, "wt");
|
f = fopen(filename, "wt");
|
||||||
if (!f) return set_error(ERR_OPEN);
|
if (!f) return set_error(ERR_OPEN);
|
||||||
|
|
||||||
|
@ -308,6 +311,7 @@ int cpuid_serialize_raw_data(struct cpu_raw_data_t* data, const char* filename)
|
||||||
data->intel_fn4[i][0], data->intel_fn4[i][1],
|
data->intel_fn4[i][0], data->intel_fn4[i][1],
|
||||||
data->intel_fn4[i][2], data->intel_fn4[i][3]);
|
data->intel_fn4[i][2], data->intel_fn4[i][3]);
|
||||||
|
|
||||||
|
if (strcmp(filename, ""))
|
||||||
fclose(f);
|
fclose(f);
|
||||||
return set_error(ERR_OK);
|
return set_error(ERR_OK);
|
||||||
}
|
}
|
||||||
|
@ -325,6 +329,9 @@ int cpuid_deserialize_raw_data(struct cpu_raw_data_t* data, const char* filename
|
||||||
|
|
||||||
raw_data_t_constructor(data);
|
raw_data_t_constructor(data);
|
||||||
|
|
||||||
|
if (!strcmp(filename, ""))
|
||||||
|
f = stdin;
|
||||||
|
else
|
||||||
f = fopen(filename, "rt");
|
f = fopen(filename, "rt");
|
||||||
if (!f) return set_error(ERR_OPEN);
|
if (!f) return set_error(ERR_OPEN);
|
||||||
while (fgets(line, sizeof(line), f)) {
|
while (fgets(line, sizeof(line), f)) {
|
||||||
|
@ -360,6 +367,7 @@ int cpuid_deserialize_raw_data(struct cpu_raw_data_t* data, const char* filename
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (strcmp(filename, ""))
|
||||||
fclose(f);
|
fclose(f);
|
||||||
return set_error(ERR_OK);
|
return set_error(ERR_OK);
|
||||||
}
|
}
|
||||||
|
@ -489,7 +497,7 @@ const char* cpu_feature_str(cpu_feature_t feature)
|
||||||
|
|
||||||
const char* cpuid_error(void)
|
const char* cpuid_error(void)
|
||||||
{
|
{
|
||||||
const struct { cpuid_error_t error; const char *description; }
|
const struct { cpu_error_t error; const char *description; }
|
||||||
matchtable[] = {
|
matchtable[] = {
|
||||||
{ ERR_OK , "No error"},
|
{ ERR_OK , "No error"},
|
||||||
{ ERR_NO_CPUID , "CPUID instruction is not supported"},
|
{ ERR_NO_CPUID , "CPUID instruction is not supported"},
|
||||||
|
@ -513,7 +521,7 @@ const char* cpuid_lib_version(void)
|
||||||
return VERSION;
|
return VERSION;
|
||||||
}
|
}
|
||||||
|
|
||||||
libcpuid_warn_fn_t set_warn_function(libcpuid_warn_fn_t new_fn)
|
libcpuid_warn_fn_t cpuid_set_warn_function(libcpuid_warn_fn_t new_fn)
|
||||||
{
|
{
|
||||||
libcpuid_warn_fn_t ret = _warn_fun;
|
libcpuid_warn_fn_t ret = _warn_fun;
|
||||||
_warn_fun = new_fn;
|
_warn_fun = new_fn;
|
||||||
|
|
|
@ -23,6 +23,8 @@
|
||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
#ifndef __LIBCPUID_H__
|
||||||
|
#define __LIBCPUID_H__
|
||||||
/**
|
/**
|
||||||
* @File libcpuid.h
|
* @File libcpuid.h
|
||||||
* @Author Veselin Georgiev
|
* @Author Veselin Georgiev
|
||||||
|
@ -34,9 +36,21 @@
|
||||||
* 0.1.0 (2008-10-15): initial adaptation from wxfractgui sources
|
* 0.1.0 (2008-10-15): initial adaptation from wxfractgui sources
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @defgroup libcpuid @{ */
|
/** @mainpage A simple libcpuid introduction
|
||||||
#ifndef __LIBCPUID_H__
|
*
|
||||||
#define __LIBCPUID_H__
|
* LibCPUID provides CPU identification and access to the CPUID and RDTSC
|
||||||
|
* instructions on the x86.
|
||||||
|
* <p>
|
||||||
|
* To execute CPUID, use \ref cpu_exec_cpuid <br>
|
||||||
|
* To execute RDTSC, use \ref cpu_rdtsc <br>
|
||||||
|
* To fetch the CPUID info needed for CPU identification, use
|
||||||
|
* \ref cpuid_get_raw_data <br>
|
||||||
|
* To make sense of that data (decode, extract features), use \ref cpu_identify <br>
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @defgroup libcpuid LibCPUID
|
||||||
|
@{ */
|
||||||
|
|
||||||
/* Include some integer type specifications: */
|
/* Include some integer type specifications: */
|
||||||
#include "libcpuid_types.h"
|
#include "libcpuid_types.h"
|
||||||
|
@ -51,23 +65,22 @@ extern "C" {
|
||||||
/**
|
/**
|
||||||
* @brief CPU vendor, as guessed from the Vendor String.
|
* @brief CPU vendor, as guessed from the Vendor String.
|
||||||
*/
|
*/
|
||||||
enum _cpu_vendor_t {
|
typedef enum {
|
||||||
VENDOR_INTEL = 0,
|
VENDOR_INTEL = 0, /*!< Intel CPU */
|
||||||
VENDOR_AMD,
|
VENDOR_AMD, /*!< AMD CPU */
|
||||||
VENDOR_CYRIX,
|
VENDOR_CYRIX, /*!< Cyrix CPU */
|
||||||
VENDOR_NEXGEN,
|
VENDOR_NEXGEN, /*!< NexGen CPU */
|
||||||
VENDOR_TRANSMETA,
|
VENDOR_TRANSMETA, /*!< Transmeta CPU */
|
||||||
VENDOR_UMC,
|
VENDOR_UMC, /*!< x86 CPU by UMC */
|
||||||
VENDOR_CENTAUR,
|
VENDOR_CENTAUR, /*!< x86 CPU by IDT */
|
||||||
VENDOR_RISE,
|
VENDOR_RISE, /*!< x86 CPU by Rise Technology */
|
||||||
VENDOR_SIS,
|
VENDOR_SIS, /*!< x86 CPU by SiS */
|
||||||
VENDOR_NSC,
|
VENDOR_NSC, /*!< x86 CPU by National Semiconductor */
|
||||||
|
|
||||||
NUM_CPU_VENDORS,
|
NUM_CPU_VENDORS, /*!< Valid CPU vendor ids: 0..NUM_CPU_VENDORS - 1 */
|
||||||
VENDOR_UNKNOWN = -1,
|
VENDOR_UNKNOWN = -1,
|
||||||
};
|
} cpu_vendor_t;
|
||||||
#define NUM_CPU_VENDORS NUM_CPU_VENDORS
|
#define NUM_CPU_VENDORS NUM_CPU_VENDORS
|
||||||
typedef enum _cpu_vendor_t cpu_vendor_t;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Contains just the raw CPUID data.
|
* @brief Contains just the raw CPUID data.
|
||||||
|
@ -209,7 +222,7 @@ struct cpu_id_t {
|
||||||
* ...
|
* ...
|
||||||
* struct cpu_raw_data_t raw;
|
* struct cpu_raw_data_t raw;
|
||||||
* struct cpu_id_t id;
|
* struct cpu_id_t id;
|
||||||
* if (cpuid_get_raw_data(&raw) == 0 && cpu_identify(&raw, &id)) {
|
* if (cpuid_get_raw_data(&raw) == 0 && cpu_identify(&raw, &id) == 0) {
|
||||||
* if (id.flags[CPU_FEATURE_SSE2]) {
|
* if (id.flags[CPU_FEATURE_SSE2]) {
|
||||||
* // The CPU has SSE2...
|
* // The CPU has SSE2...
|
||||||
* ...
|
* ...
|
||||||
|
@ -221,7 +234,7 @@ struct cpu_id_t {
|
||||||
* }
|
* }
|
||||||
* @endcode
|
* @endcode
|
||||||
*/
|
*/
|
||||||
enum _cpu_feature_t {
|
typedef enum {
|
||||||
CPU_FEATURE_FPU = 0, /*!< Floating point unit */
|
CPU_FEATURE_FPU = 0, /*!< Floating point unit */
|
||||||
CPU_FEATURE_VME, /*!< Virtual mode extension */
|
CPU_FEATURE_VME, /*!< Virtual mode extension */
|
||||||
CPU_FEATURE_DE, /*!< Debugging extension */
|
CPU_FEATURE_DE, /*!< Debugging extension */
|
||||||
|
@ -307,13 +320,12 @@ enum _cpu_feature_t {
|
||||||
CPU_FEATURE_CONSTANT_TSC, /*!< TSC ticks at constant rate */
|
CPU_FEATURE_CONSTANT_TSC, /*!< TSC ticks at constant rate */
|
||||||
// termination:
|
// termination:
|
||||||
NUM_CPU_FEATURES,
|
NUM_CPU_FEATURES,
|
||||||
};
|
} cpu_feature_t;
|
||||||
typedef enum _cpu_feature_t cpu_feature_t;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Describes common library error codes
|
* @brief Describes common library error codes
|
||||||
*/
|
*/
|
||||||
enum _cpuid_error_t {
|
typedef enum {
|
||||||
ERR_OK = 0, /*!< "No error" */
|
ERR_OK = 0, /*!< "No error" */
|
||||||
ERR_NO_CPUID = -1, /*!< "CPUID instruction is not supported" */
|
ERR_NO_CPUID = -1, /*!< "CPUID instruction is not supported" */
|
||||||
ERR_NO_RDTSC = -2, /*!< "RDTSC instruction is not supported" */
|
ERR_NO_RDTSC = -2, /*!< "RDTSC instruction is not supported" */
|
||||||
|
@ -322,8 +334,7 @@ enum _cpuid_error_t {
|
||||||
ERR_BADFMT = -5, /*!< "Bad file format" */
|
ERR_BADFMT = -5, /*!< "Bad file format" */
|
||||||
ERR_NOT_IMP = -6, /*!< "Not implemented" */
|
ERR_NOT_IMP = -6, /*!< "Not implemented" */
|
||||||
ERR_CPU_UNKN = -7, /*!< "Unsupported processor" */
|
ERR_CPU_UNKN = -7, /*!< "Unsupported processor" */
|
||||||
};
|
} cpu_error_t;
|
||||||
typedef enum _cpuid_error_t cpuid_error_t;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Internal structure, used in cpu_tsc_mark, cpu_tsc_unmark and
|
* @brief Internal structure, used in cpu_tsc_mark, cpu_tsc_unmark and
|
||||||
|
@ -363,8 +374,9 @@ void cpu_exec_cpuid_ext(uint32_t* regs);
|
||||||
/**
|
/**
|
||||||
* @brief Obtains the raw CPUID data
|
* @brief Obtains the raw CPUID data
|
||||||
* @param data - a pointer to cpu_raw_data_t structure
|
* @param data - a pointer to cpu_raw_data_t structure
|
||||||
* @returns zero if successful, and some negative number on error (@see cpuid_error_t)
|
* @returns zero if successful, and some negative number on error.
|
||||||
* The error message can be obtained by calling cpuid_error
|
* The error message can be obtained by calling \ref cpuid_error.
|
||||||
|
* @see cpu_error_t
|
||||||
*/
|
*/
|
||||||
int cpuid_get_raw_data(struct cpu_raw_data_t* data);
|
int cpuid_get_raw_data(struct cpu_raw_data_t* data);
|
||||||
|
|
||||||
|
@ -372,7 +384,7 @@ int cpuid_get_raw_data(struct cpu_raw_data_t* data);
|
||||||
* @brief Writes the raw CPUID data to a text file
|
* @brief Writes the raw CPUID data to a text file
|
||||||
* @param data - a pointer to cpu_raw_data_t structure
|
* @param data - a pointer to cpu_raw_data_t structure
|
||||||
* @param filename - the path of the file, where the serialized data should be
|
* @param filename - the path of the file, where the serialized data should be
|
||||||
* written
|
* written. If empty, stdout will be used.
|
||||||
* @note This is intended primarily for debugging. On some processor, which is
|
* @note This is intended primarily for debugging. On some processor, which is
|
||||||
* not currently supported or not completely recognized by cpu_identify,
|
* not currently supported or not completely recognized by cpu_identify,
|
||||||
* one can still successfully get the raw data and write it to a file.
|
* one can still successfully get the raw data and write it to a file.
|
||||||
|
@ -381,8 +393,9 @@ int cpuid_get_raw_data(struct cpu_raw_data_t* data);
|
||||||
* The file is simple text format of "something=value" pairs. Version info
|
* The file is simple text format of "something=value" pairs. Version info
|
||||||
* is also written, but the format is not intended to be neither backward-
|
* is also written, but the format is not intended to be neither backward-
|
||||||
* nor forward compatible.
|
* nor forward compatible.
|
||||||
* @returns zero if successful, and some negative number on error (@see cpuid_error_t)
|
* @returns zero if successful, and some negative number on error.
|
||||||
* The error message can be obtained by calling cpuid_error
|
* The error message can be obtained by calling \ref cpuid_error.
|
||||||
|
* @see cpu_error_t
|
||||||
*/
|
*/
|
||||||
int cpuid_serialize_raw_data(struct cpu_raw_data_t* data, const char* filename);
|
int cpuid_serialize_raw_data(struct cpu_raw_data_t* data, const char* filename);
|
||||||
|
|
||||||
|
@ -391,10 +404,12 @@ int cpuid_serialize_raw_data(struct cpu_raw_data_t* data, const char* filename);
|
||||||
* @param data - a pointer to cpu_raw_data_t structure. The deserialized data will
|
* @param data - a pointer to cpu_raw_data_t structure. The deserialized data will
|
||||||
* be written here.
|
* be written here.
|
||||||
* @param filename - the path of the file, containing the serialized raw data.
|
* @param filename - the path of the file, containing the serialized raw data.
|
||||||
|
* If empty, stdin will be used.
|
||||||
* @note This function may fail, if the file is created by different version of
|
* @note This function may fail, if the file is created by different version of
|
||||||
* the library. Also, see the notes on cpuid_serialize_raw_data.
|
* the library. Also, see the notes on cpuid_serialize_raw_data.
|
||||||
* @returns zero if successful, and some negative number on error (@see cpuid_error_t)
|
* @returns zero if successful, and some negative number on error.
|
||||||
* The error message can be obtained by calling cpuid_error
|
* The error message can be obtained by calling \ref cpuid_error.
|
||||||
|
* @see cpu_error_t
|
||||||
*/
|
*/
|
||||||
int cpuid_deserialize_raw_data(struct cpu_raw_data_t* data, const char* filename);
|
int cpuid_deserialize_raw_data(struct cpu_raw_data_t* data, const char* filename);
|
||||||
|
|
||||||
|
@ -417,8 +432,9 @@ int cpuid_deserialize_raw_data(struct cpu_raw_data_t* data, const char* filename
|
||||||
* performance significantly. Specifically, avoid writing "cpu feature
|
* performance significantly. Specifically, avoid writing "cpu feature
|
||||||
* checker" wrapping function, which calls cpu_identify and returns the
|
* checker" wrapping function, which calls cpu_identify and returns the
|
||||||
* value of some flag, if that function is going to be called frequently.
|
* value of some flag, if that function is going to be called frequently.
|
||||||
* @returns zero if successful, and some negative number on error (@see cpuid_error_t)
|
* @returns zero if successful, and some negative number on error.
|
||||||
* The error message can be obtained by calling cpuid_error
|
* The error message can be obtained by calling \ref cpuid_error.
|
||||||
|
* @see cpu_error_t
|
||||||
*/
|
*/
|
||||||
int cpu_identify(struct cpu_raw_data_t* raw, struct cpu_id_t* data);
|
int cpu_identify(struct cpu_raw_data_t* raw, struct cpu_id_t* data);
|
||||||
|
|
||||||
|
@ -437,6 +453,7 @@ const char* cpu_feature_str(cpu_feature_t feature);
|
||||||
* libcpuid stores an `errno'-style error status, whose description
|
* libcpuid stores an `errno'-style error status, whose description
|
||||||
* can be obtained with this function.
|
* can be obtained with this function.
|
||||||
* @note This function is not thread-safe
|
* @note This function is not thread-safe
|
||||||
|
* @see cpu_error_t
|
||||||
*/
|
*/
|
||||||
const char* cpuid_error(void);
|
const char* cpuid_error(void);
|
||||||
|
|
||||||
|
@ -469,11 +486,12 @@ void cpu_rdtsc(uint64_t* result);
|
||||||
/**
|
/**
|
||||||
* @brief Store TSC and timing info
|
* @brief Store TSC and timing info
|
||||||
*
|
*
|
||||||
* This function stores the current TSC value (@see cpu_rdtsc) and current
|
* This function stores the current TSC value and current
|
||||||
* time info from a precise OS-specific clock source in the cpu_mark_t
|
* time info from a precise OS-specific clock source in the cpu_mark_t
|
||||||
* structure. The sys_clock field contains time with microsecond resolution.
|
* structure. The sys_clock field contains time with microsecond resolution.
|
||||||
* The values can later be used to measure time intervals, number of clocks,
|
* The values can later be used to measure time intervals, number of clocks,
|
||||||
* FPU frequency, etc.
|
* FPU frequency, etc.
|
||||||
|
* @see cpu_rdtsc
|
||||||
*
|
*
|
||||||
* @param mark [out] - a pointer to a cpu_mark_t structure
|
* @param mark [out] - a pointer to a cpu_mark_t structure
|
||||||
*/
|
*/
|
||||||
|
@ -526,10 +544,10 @@ int cpu_clock_by_mark(struct cpu_mark_t* mark);
|
||||||
* @brief Returns the CPU clock, as reported by the OS
|
* @brief Returns the CPU clock, as reported by the OS
|
||||||
*
|
*
|
||||||
* This function uses OS-specific functions to obtain the CPU clock. It may
|
* This function uses OS-specific functions to obtain the CPU clock. It may
|
||||||
* differ from the true clock for several reasons:
|
* differ from the true clock for several reasons:<br><br>
|
||||||
*
|
*
|
||||||
* i) The CPU might be in some power saving state, while the OS reports its
|
* i) The CPU might be in some power saving state, while the OS reports its
|
||||||
* full-power frequency, or vice-versa.
|
* full-power frequency, or vice-versa.<br>
|
||||||
* ii) In some cases you can raise or lower the CPU frequency with overclocking
|
* ii) In some cases you can raise or lower the CPU frequency with overclocking
|
||||||
* utilities and the OS will not notice.
|
* utilities and the OS will not notice.
|
||||||
*
|
*
|
||||||
|
@ -552,18 +570,18 @@ int cpu_clock_by_os(void);
|
||||||
* but 100ms should be enough for most purposes.
|
* but 100ms should be enough for most purposes.
|
||||||
*
|
*
|
||||||
* While this will calculate the CPU frequency correctly in most cases, there are
|
* While this will calculate the CPU frequency correctly in most cases, there are
|
||||||
* several reasons why it might be incorrect:
|
* several reasons why it might be incorrect:<br>
|
||||||
*
|
*
|
||||||
* i) RDTSC doesn't guarantee it will run at the same clock as the CPU.
|
* i) RDTSC doesn't guarantee it will run at the same clock as the CPU.
|
||||||
* Apparently there aren't CPUs at the moment, but still, there's no
|
* Apparently there aren't CPUs at the moment, but still, there's no
|
||||||
* guarantee.
|
* guarantee.<br>
|
||||||
* ii) The CPU might be in a low-frequency power saving mode, and the CPU
|
* ii) The CPU might be in a low-frequency power saving mode, and the CPU
|
||||||
* might be switched to higher frequency at any time. If this happens
|
* might be switched to higher frequency at any time. If this happens
|
||||||
* during the measurement, the result can be anywhere between the
|
* during the measurement, the result can be anywhere between the
|
||||||
* low and high frequencies. Also, if you're interested in the
|
* low and high frequencies. Also, if you're interested in the
|
||||||
* high frequency value only, this function might return the low one
|
* high frequency value only, this function might return the low one
|
||||||
* instead.
|
* instead.<br>
|
||||||
* iii) On SMP systems exhibiting TSC drift (@see cpu_rdtsc)
|
* iii) On SMP systems exhibiting TSC drift (see \ref cpu_rdtsc)
|
||||||
*
|
*
|
||||||
* the quad_check option will run four consecutive measurements and
|
* the quad_check option will run four consecutive measurements and
|
||||||
* then return the average of the two most-consistent results. The total
|
* then return the average of the two most-consistent results. The total
|
||||||
|
@ -606,7 +624,7 @@ typedef void (*libcpuid_warn_fn_t) (const char *msg);
|
||||||
* @brief Sets the warning print function
|
* @brief Sets the warning print function
|
||||||
*
|
*
|
||||||
* In some cases, the internal libcpuid machinery would like to emit useful
|
* In some cases, the internal libcpuid machinery would like to emit useful
|
||||||
* debug warnings. By default, these warnings are written to stdout. However,
|
* debug warnings. By default, these warnings are written to stderr. However,
|
||||||
* you can set a custom function that will receive those warnings.
|
* you can set a custom function that will receive those warnings.
|
||||||
*
|
*
|
||||||
* @param warn_fun - the warning function you want to set. If NULL, warnings
|
* @param warn_fun - the warning function you want to set. If NULL, warnings
|
||||||
|
@ -615,7 +633,7 @@ typedef void (*libcpuid_warn_fn_t) (const char *msg);
|
||||||
* @returns the current warning function. You can use the return value to
|
* @returns the current warning function. You can use the return value to
|
||||||
* keep the previous warning function and restore it at your discretion.
|
* keep the previous warning function and restore it at your discretion.
|
||||||
*/
|
*/
|
||||||
libcpuid_warn_fn_t set_warn_function(libcpuid_warn_fn_t warn_fun);
|
libcpuid_warn_fn_t cpuid_set_warn_function(libcpuid_warn_fn_t warn_fun);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}; // extern "C"
|
}; // extern "C"
|
||||||
|
|
|
@ -15,3 +15,4 @@ cpu_clock_by_os
|
||||||
cpu_clock_measure
|
cpu_clock_measure
|
||||||
cpu_clock
|
cpu_clock
|
||||||
cpuid_lib_version
|
cpuid_lib_version
|
||||||
|
cpuid_set_warn_function
|
||||||
|
|
|
@ -41,7 +41,7 @@ void match_features(const struct feature_map_t* matchtable, int count, uint32_t
|
||||||
|
|
||||||
static void default_warn(const char *msg)
|
static void default_warn(const char *msg)
|
||||||
{
|
{
|
||||||
printf("%s", msg);
|
fprintf(stderr, "%s", msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
libcpuid_warn_fn_t _warn_fun = default_warn;
|
libcpuid_warn_fn_t _warn_fun = default_warn;
|
||||||
|
|
|
@ -39,8 +39,7 @@ enum _amd_code_t {
|
||||||
ATHLON_XP_BARTON,
|
ATHLON_XP_BARTON,
|
||||||
ATHLON_XP_M,
|
ATHLON_XP_M,
|
||||||
ATHLON_XP_M_LV,
|
ATHLON_XP_M_LV,
|
||||||
ATHLON_64,
|
ATHLON,
|
||||||
ATHLON_64_MANCHESTER,
|
|
||||||
ATHLON_MP,
|
ATHLON_MP,
|
||||||
MOBILE_ATHLON64,
|
MOBILE_ATHLON64,
|
||||||
ATHLON_FX,
|
ATHLON_FX,
|
||||||
|
@ -102,7 +101,7 @@ const struct match_entry_t cpudb_amd[] = {
|
||||||
{ 6, 4, -1, -1, -1, NO_CODE, "Athlon (ThunderBird)" },
|
{ 6, 4, -1, -1, -1, NO_CODE, "Athlon (ThunderBird)" },
|
||||||
|
|
||||||
{ 6, 6, -1, -1, -1, NO_CODE, "Unknown Athlon" },
|
{ 6, 6, -1, -1, -1, NO_CODE, "Unknown Athlon" },
|
||||||
{ 6, 6, -1, -1, -1, ATHLON_64, "Athlon (Palomino)" },
|
{ 6, 6, -1, -1, -1, ATHLON, "Athlon (Palomino)" },
|
||||||
{ 6, 6, -1, -1, -1, ATHLON_MP, "Athlon MP (Palomino)" },
|
{ 6, 6, -1, -1, -1, ATHLON_MP, "Athlon MP (Palomino)" },
|
||||||
{ 6, 6, -1, -1, -1, DURON, "Duron (Palomino)" },
|
{ 6, 6, -1, -1, -1, DURON, "Duron (Palomino)" },
|
||||||
{ 6, 6, -1, -1, -1, ATHLON_XP, "Athlon XP" },
|
{ 6, 6, -1, -1, -1, ATHLON_XP, "Athlon XP" },
|
||||||
|
@ -111,7 +110,7 @@ const struct match_entry_t cpudb_amd[] = {
|
||||||
{ 6, 7, -1, -1, -1, DURON, "Duron (Morgan)" },
|
{ 6, 7, -1, -1, -1, DURON, "Duron (Morgan)" },
|
||||||
|
|
||||||
{ 6, 8, -1, -1, -1, NO_CODE, "Athlon XP" },
|
{ 6, 8, -1, -1, -1, NO_CODE, "Athlon XP" },
|
||||||
{ 6, 8, -1, -1, -1, ATHLON_64, "Athlon XP" },
|
{ 6, 8, -1, -1, -1, ATHLON, "Athlon XP" },
|
||||||
{ 6, 8, -1, -1, -1, ATHLON_XP, "Athlon XP" },
|
{ 6, 8, -1, -1, -1, ATHLON_XP, "Athlon XP" },
|
||||||
{ 6, 8, -1, -1, -1, DURON, "Duron (Applebred)" },
|
{ 6, 8, -1, -1, -1, DURON, "Duron (Applebred)" },
|
||||||
{ 6, 8, -1, -1, -1, SEMPRON, "Sempron (Thoroughbred)" },
|
{ 6, 8, -1, -1, -1, SEMPRON, "Sempron (Thoroughbred)" },
|
||||||
|
@ -122,7 +121,7 @@ const struct match_entry_t cpudb_amd[] = {
|
||||||
{ 6, 8, -1, -1, -1, ATHLON_XP_M_LV, "Mobile Athlon (Thoroughbred)" },
|
{ 6, 8, -1, -1, -1, ATHLON_XP_M_LV, "Mobile Athlon (Thoroughbred)" },
|
||||||
|
|
||||||
{ 6, 10, -1, -1, -1, NO_CODE, "Athlon XP (Barton)" },
|
{ 6, 10, -1, -1, -1, NO_CODE, "Athlon XP (Barton)" },
|
||||||
{ 6, 10, -1, -1, -1, ATHLON_64, "Athlon XP (Barton)" },
|
{ 6, 10, -1, -1, -1, ATHLON, "Athlon XP (Barton)" },
|
||||||
{ 6, 10, -1, -1, -1, ATHLON_XP_BARTON, "Athlon XP (Barton)" },
|
{ 6, 10, -1, -1, -1, ATHLON_XP_BARTON, "Athlon XP (Barton)" },
|
||||||
{ 6, 10, -1, -1, -1, SEMPRON, "Sempron (Barton)" },
|
{ 6, 10, -1, -1, -1, SEMPRON, "Sempron (Barton)" },
|
||||||
{ 6, 10, -1, -1, -1, SEMPRON_64_256K, "Sempron (Barton)" },
|
{ 6, 10, -1, -1, -1, SEMPRON_64_256K, "Sempron (Barton)" },
|
||||||
|
@ -280,7 +279,7 @@ static amd_code_t decode_amd_codename_part1(const char *bs)
|
||||||
if (strstr(bs, "Athlon(tm) XP")) return ATHLON_XP;
|
if (strstr(bs, "Athlon(tm) XP")) return ATHLON_XP;
|
||||||
if (strstr(bs, "Athlon(tm) MP")) return ATHLON_MP;
|
if (strstr(bs, "Athlon(tm) MP")) return ATHLON_MP;
|
||||||
if (strstr(bs, "Duron")) return DURON;
|
if (strstr(bs, "Duron")) return DURON;
|
||||||
if (strstr(bs, "Athlon")) return ATHLON_64;
|
if (strstr(bs, "Athlon")) return ATHLON;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NO_CODE;
|
return NO_CODE;
|
||||||
|
@ -290,8 +289,6 @@ static void decode_amd_codename(struct cpu_raw_data_t* raw, struct cpu_id_t* dat
|
||||||
{
|
{
|
||||||
amd_code_t code = decode_amd_codename_part1(data->brand_str);
|
amd_code_t code = decode_amd_codename_part1(data->brand_str);
|
||||||
|
|
||||||
if (code == ATHLON_64 && data->l2_cache == 512)
|
|
||||||
code = ATHLON_64_MANCHESTER;
|
|
||||||
if (code == ATHLON_XP && data->l2_cache == 512)
|
if (code == ATHLON_XP && data->l2_cache == 512)
|
||||||
code = ATHLON_XP_BARTON;
|
code = ATHLON_XP_BARTON;
|
||||||
if (code == ATHLON_64_512K && data->l2_cache > 512)
|
if (code == ATHLON_64_512K && data->l2_cache > 512)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue