util-linux/sys-utils/lscpu-cputype.c

339 lines
7.6 KiB
C
Raw Normal View History

#include "lscpu-api.h"
UL_DEBUG_DEFINE_MASK(lscpu);
UL_DEBUG_DEFINE_MASKNAMES(lscpu) = UL_DEBUG_EMPTY_MASKNAMES;
static void lscpu_init_debug(void)
{
__UL_INIT_DEBUG_FROM_ENV(lscpu, LSCPU_DEBUG_, 0, LSCPU_DEBUG);
}
static void context_init_paths(struct lscpu_cxt *cxt)
{
DBG(MISC, ul_debugobj(cxt, "initialize paths"));
ul_path_init_debug();
/* /sys/devices/system/cpu */
cxt->syscpu = ul_new_path(_PATH_SYS_CPU);
if (!cxt->syscpu)
err(EXIT_FAILURE, _("failed to initialize CPUs sysfs handler"));
if (cxt->prefix)
ul_path_set_prefix(cxt->syscpu, cxt->prefix);
/* /proc */
cxt->procfs = ul_new_path("/proc");
if (!cxt->procfs)
err(EXIT_FAILURE, _("failed to initialize procfs handler"));
if (cxt->prefix)
ul_path_set_prefix(cxt->procfs, cxt->prefix);
}
struct lscpu_cputype *lscpu_new_cputype(void)
{
struct lscpu_cputype *ct;
ct = xcalloc(1, sizeof(struct lscpu_cputype));
ct->refcount = 1;
DBG(TYPE, ul_debugobj(ct, "alloc"));
return ct;
}
void lscpu_ref_cputype(struct lscpu_cputype *ct)
{
if (ct)
ct->refcount++;
}
void lscpu_unref_cputype(struct lscpu_cputype *ct)
{
if (!ct)
return;
if (--ct->refcount <= 0) {
DBG(TYPE, ul_debugobj(ct, " freeing"));
free(ct);
}
}
/* Describes /proc/cpuinfo fields */
struct cpuinfo_pattern {
int id; /* field ID */
const char *pattern; /* field name as used in /proc/cpuinfo */
size_t offset; /* offset in lscpu_cputype or lscpu_cpu struct */
};
/* field identifiers (field name may be different on different archs) */
enum {
PAT_ADDRESS_SIZES,
PAT_BOGOMIPS,
PAT_CPU,
PAT_FAMILY,
PAT_FEATURES,
PAT_FLAGS,
PAT_IMPLEMENTER,
PAT_MAX_THREAD_ID,
PAT_MHZ,
PAT_MHZ_DYNAMIC,
PAT_MHZ_STATIC,
PAT_MODEL,
PAT_MODEL_NAME,
PAT_PART,
PAT_PROCESSOR,
PAT_REVISION,
PAT_STEPPING,
PAT_TYPE,
PAT_VARIANT,
PAT_VENDOR,
};
/*
* /proc/cpuinfo to lscpu_cputype conversion
*/
#define DEF_PAT_CPUTYPE(_str, _id, _member) \
{ \
.id = (_id), \
.pattern = (_str), \
.offset = offsetof(struct lscpu_cputype, _member), \
}
static const struct cpuinfo_pattern type_patterns[] =
{
/* Sort by fields name! */
DEF_PAT_CPUTYPE( "BogoMIPS", PAT_BOGOMIPS, bogomips), /* aarch64 */
DEF_PAT_CPUTYPE( "CPU implementer", PAT_IMPLEMENTER,vendor), /* ARM and aarch64 */
DEF_PAT_CPUTYPE( "CPU part", PAT_PART, model), /* ARM and aarch64 */
DEF_PAT_CPUTYPE( "CPU revision", PAT_REVISION, revision), /* aarch64 */
DEF_PAT_CPUTYPE( "CPU variant", PAT_VARIANT, stepping), /* aarch64 */
DEF_PAT_CPUTYPE( "Features", PAT_FEATURES, flags), /* aarch64 */
DEF_PAT_CPUTYPE( "address sizes", PAT_ADDRESS_SIZES, addrsz),/* x86 */
DEF_PAT_CPUTYPE( "bogomips", PAT_BOGOMIPS, bogomips),
DEF_PAT_CPUTYPE( "bogomips per cpu", PAT_BOGOMIPS, bogomips), /* s390 */
DEF_PAT_CPUTYPE( "cpu MHz dynamic", PAT_MHZ_DYNAMIC,dynamic_mhz), /* s390 */
DEF_PAT_CPUTYPE( "cpu MHz static", PAT_MHZ_STATIC, static_mhz), /* s390 */
DEF_PAT_CPUTYPE( "cpu family", PAT_FAMILY, family),
DEF_PAT_CPUTYPE( "cpu", PAT_CPU, cpu),
DEF_PAT_CPUTYPE( "family", PAT_FAMILY, family),
DEF_PAT_CPUTYPE( "features", PAT_FEATURES, flags), /* s390 */
DEF_PAT_CPUTYPE( "flags", PAT_FLAGS, flags), /* x86 */
DEF_PAT_CPUTYPE( "max thread id", PAT_MAX_THREAD_ID, mtid), /* s390 */
DEF_PAT_CPUTYPE( "model name", PAT_MODEL_NAME, modelname),
DEF_PAT_CPUTYPE( "model", PAT_MODEL, model),
DEF_PAT_CPUTYPE( "revision", PAT_REVISION, revision),
DEF_PAT_CPUTYPE( "stepping", PAT_STEPPING, stepping),
DEF_PAT_CPUTYPE( "type", PAT_TYPE, flags), /* sparc64 */
DEF_PAT_CPUTYPE( "vendor", PAT_VENDOR, vendor),
DEF_PAT_CPUTYPE( "vendor_id", PAT_VENDOR, vendor),
};
/*
* /proc/cpuinfo to lscpu_cpu conversion
*/
#define DEF_PAT_CPU(_str, _id, _member) \
{ \
.id = (_id), \
.pattern = (_str), \
.offset = offsetof(struct lscpu_cpu, _member), \
}
static const struct cpuinfo_pattern cpu_patterns[] =
{
/* Sort by fields name! */
DEF_PAT_CPU( "cpu MHz", PAT_MHZ, mhz),
DEF_PAT_CPU( "processor", PAT_PROCESSOR, logical_id),
};
#define CPUTYPE_PATTERN_BUFSZ 32
static int cmp_pattern(const void *a0, const void *b0)
{
const struct cpuinfo_pattern
*a = (const struct cpuinfo_pattern *) a0,
*b = (const struct cpuinfo_pattern *) b0;
return strcmp(a->pattern, b->pattern);
}
static int cpuinfo_parse_line( struct lscpu_cputype *ct,
struct lscpu_cpu *cpu,
const char *str)
{
struct cpuinfo_pattern key, *pat;
const char *p, *v;
char buf[CPUTYPE_PATTERN_BUFSZ] = { 0 }, **data;
void *stru = NULL;
DBG(TYPE, ul_debugobj(ct, "parse \"%s\"", str));
if (!str || !*str)
return -EINVAL;
p = skip_blank(str);
if (!p || !*p)
return -EINVAL;
v = strchr(p, ':');
if (!v || !*v)
return -EINVAL;
/* prepare name of the field */
xstrncpy(buf, p, sizeof(buf));
buf[v - p] = '\0';
v++;
rtrim_whitespace((unsigned char *)buf);
/* search in cpu-types patterns */
key.pattern = buf;
pat = bsearch(&key, type_patterns,
ARRAY_SIZE(type_patterns),
sizeof(struct cpuinfo_pattern),
cmp_pattern);
if (pat)
stru = ct;
else {
/* search in cpu patterns */
pat = bsearch(&key, cpu_patterns,
ARRAY_SIZE(cpu_patterns),
sizeof(struct cpuinfo_pattern),
cmp_pattern);
if (pat)
stru = cpu;
}
if (!stru) {
DBG(TYPE, ul_debugobj(ct, "'%s' not found", buf));
return 1;
}
/* prepare value */
v = skip_space(v);
if (!v || !*v)
return -EINVAL;
/* copy value to struct */
switch (pat->id) {
case PAT_PROCESSOR:
cpu->logical_id = atoi(v);
break;
default:
/* set value as a string and cleanup */
strdup_to_offset(stru, pat->offset, v);
data = (char **) ((char *) stru + pat->offset);
rtrim_whitespace((unsigned char *) *data);
break;
}
return 0;
}
static void print_cputype(struct lscpu_cputype *ct, FILE *f)
{
fprintf(f, "vendor=\"%s\"\n", ct->vendor);
fprintf(f, "model=\"%s\"\n", ct->model);
fprintf(f, "flags=\"%s\"\n", ct->flags);
}
int lscpu_read_cpuinfo(struct lscpu_cxt *cxt)
{
struct lscpu_cputype *ct = NULL;
struct lscpu_cpu *cpu = NULL;
FILE *fp;
char buf[BUFSIZ];
DBG(GATHER, ul_debugobj(cxt, "reading cpuinfo"));
fp = ul_path_fopen(cxt->procfs, "r", "cpuinfo");
if (!fp)
err(EXIT_FAILURE, _("cannot open %s"), "/proc/cpuinfo");
while (fgets(buf, sizeof(buf), fp) != NULL) {
const char *p = skip_space(buf);
if (*buf && !*p) {
if (ct) {
ON_DBG(GATHER, print_cputype(ct, stdout));
//lscpu_add_cputype(&cxt->cputypes, &cxt->ncputypes, ct);
}
lscpu_unref_cputype(ct);
/* lscpu_unref_cpu(cpu);*/
ct = NULL, cpu = NULL;
continue;
}
if (!ct)
ct = lscpu_new_cputype();
/* if (!cpu)
cpu = lscpu_new_cpu();*/
cpuinfo_parse_line(ct, cpu, p);
/* TODO: else lscpu_parse_cache(cxt, buf); */
}
/*
if (ct)
lscpu_add_cputype(&cxt->cputypes, &cxt->ncputypes, ct);
if (cpu)
lscpu_add_cpu(&cxt->cputs, &cxt->ncpus, cpu);
*/
lscpu_unref_cputype(ct);
/*lscpu_unref_cpu(cpu);*/
fclose(fp);
return 0;
return 0;
}
#ifdef TEST_PROGRAM_CPUTYPE
/* TODO: move to lscpu.c */
struct lscpu_cxt *lscpu_new_context(void)
{
return xcalloc(1, sizeof(struct lscpu_cxt));
}
static void lscpu_free_context(struct lscpu_cxt *cxt)
{
size_t i;
if (!cxt)
return;
DBG(MISC, ul_debugobj(cxt, "freeing context"));
DBG(MISC, ul_debugobj(cxt, " de-initialize paths"));
ul_unref_path(cxt->syscpu);
ul_unref_path(cxt->procfs);
DBG(MISC, ul_debugobj(cxt, " freeing types"));
for (i = 0; i < cxt->ncputypes; i++)
lscpu_unref_cputype(cxt->cputypes[i]);
free(cxt->cputypes);
free(cxt);
}
int main(int argc, char **argv)
{
struct lscpu_cxt *cxt;
cxt = lscpu_new_context();
if (argc == 3 && strcmp(argv[1], "--prefix") == 0)
cxt->prefix = argv[2];
lscpu_init_debug();
context_init_paths(cxt);
lscpu_read_cpuinfo(cxt);
lscpu_free_context(cxt);
return EXIT_SUCCESS;
}
#endif /* TEST_PROGRAM_CPUTYPES */