2020-03-17 07:12:12 -05:00
|
|
|
|
2020-03-18 09:56:20 -05:00
|
|
|
#include "lscpu-api.h"
|
2020-03-17 07:30:05 -05:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
2020-03-17 07:12:12 -05:00
|
|
|
|
|
|
|
static void context_init_paths(struct lscpu_cxt *cxt)
|
|
|
|
{
|
2020-03-17 07:30:05 -05:00
|
|
|
DBG(MISC, ul_debugobj(cxt, "initialize paths"));
|
2020-03-17 07:12:12 -05:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-03-17 07:41:28 -05:00
|
|
|
struct lscpu_cputype *lscpu_new_cputype(void)
|
2020-03-17 07:12:12 -05:00
|
|
|
{
|
|
|
|
struct lscpu_cputype *ct;
|
|
|
|
|
|
|
|
ct = xcalloc(1, sizeof(struct lscpu_cputype));
|
|
|
|
ct->refcount = 1;
|
|
|
|
|
2020-03-17 07:30:05 -05:00
|
|
|
DBG(TYPE, ul_debugobj(ct, "alloc"));
|
2020-03-17 07:12:12 -05:00
|
|
|
return ct;
|
|
|
|
}
|
|
|
|
|
2020-03-17 07:41:28 -05:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-18 09:56:20 -05:00
|
|
|
/* 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,
|
2020-03-17 11:27:51 -05:00
|
|
|
};
|
|
|
|
|
2020-03-18 09:56:20 -05:00
|
|
|
/*
|
|
|
|
* /proc/cpuinfo to lscpu_cputype conversion
|
|
|
|
*/
|
|
|
|
#define DEF_PAT_CPUTYPE(_str, _id, _member) \
|
2020-03-17 11:27:51 -05:00
|
|
|
{ \
|
2020-03-18 09:56:20 -05:00
|
|
|
.id = (_id), \
|
2020-03-17 11:27:51 -05:00
|
|
|
.pattern = (_str), \
|
2020-03-18 09:56:20 -05:00
|
|
|
.offset = offsetof(struct lscpu_cputype, _member), \
|
2020-03-17 11:27:51 -05:00
|
|
|
}
|
|
|
|
|
2020-03-18 09:56:20 -05:00
|
|
|
static const struct cpuinfo_pattern type_patterns[] =
|
2020-03-17 11:27:51 -05:00
|
|
|
{
|
2020-03-18 09:56:20 -05:00
|
|
|
/* 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),
|
2020-03-17 11:27:51 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
#define CPUTYPE_PATTERN_BUFSZ 32
|
|
|
|
|
|
|
|
static int cmp_pattern(const void *a0, const void *b0)
|
|
|
|
{
|
2020-03-18 09:56:20 -05:00
|
|
|
const struct cpuinfo_pattern
|
|
|
|
*a = (const struct cpuinfo_pattern *) a0,
|
|
|
|
*b = (const struct cpuinfo_pattern *) b0;
|
2020-03-17 11:27:51 -05:00
|
|
|
return strcmp(a->pattern, b->pattern);
|
|
|
|
}
|
|
|
|
|
2020-03-18 09:56:20 -05:00
|
|
|
static int cpuinfo_parse_line( struct lscpu_cputype *ct,
|
|
|
|
struct lscpu_cpu *cpu,
|
|
|
|
const char *str)
|
2020-03-17 11:27:51 -05:00
|
|
|
{
|
2020-03-18 09:56:20 -05:00
|
|
|
struct cpuinfo_pattern key, *pat;
|
2020-03-17 11:27:51 -05:00
|
|
|
const char *p, *v;
|
|
|
|
char buf[CPUTYPE_PATTERN_BUFSZ] = { 0 }, **data;
|
2020-03-18 09:56:20 -05:00
|
|
|
void *stru = NULL;
|
2020-03-17 11:27:51 -05:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2020-03-18 09:56:20 -05:00
|
|
|
/* prepare name of the field */
|
2020-03-17 11:27:51 -05:00
|
|
|
xstrncpy(buf, p, sizeof(buf));
|
|
|
|
buf[v - p] = '\0';
|
|
|
|
v++;
|
|
|
|
|
|
|
|
rtrim_whitespace((unsigned char *)buf);
|
|
|
|
|
2020-03-18 09:56:20 -05:00
|
|
|
/* search in cpu-types patterns */
|
2020-03-17 11:27:51 -05:00
|
|
|
key.pattern = buf;
|
2020-03-18 09:56:20 -05:00
|
|
|
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),
|
2020-03-17 11:27:51 -05:00
|
|
|
cmp_pattern);
|
2020-03-18 09:56:20 -05:00
|
|
|
if (pat)
|
|
|
|
stru = cpu;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!stru) {
|
2020-03-17 11:27:51 -05:00
|
|
|
DBG(TYPE, ul_debugobj(ct, "'%s' not found", buf));
|
2020-03-18 09:56:20 -05:00
|
|
|
return 1;
|
2020-03-17 11:27:51 -05:00
|
|
|
}
|
|
|
|
|
2020-03-18 09:56:20 -05:00
|
|
|
/* prepare value */
|
2020-03-17 11:27:51 -05:00
|
|
|
v = skip_space(v);
|
|
|
|
if (!v || !*v)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2020-03-18 09:56:20 -05:00
|
|
|
/* 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;
|
|
|
|
}
|
2020-03-17 11:27:51 -05:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2020-03-18 09:56:20 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int lscpu_read_cpuinfo(struct lscpu_cxt *cxt)
|
2020-03-17 07:12:12 -05:00
|
|
|
{
|
2020-03-17 11:27:51 -05:00
|
|
|
struct lscpu_cputype *ct = NULL;
|
2020-03-18 09:56:20 -05:00
|
|
|
struct lscpu_cpu *cpu = NULL;
|
2020-03-17 11:27:51 -05:00
|
|
|
FILE *fp;
|
|
|
|
char buf[BUFSIZ];
|
|
|
|
|
2020-03-18 09:56:20 -05:00
|
|
|
DBG(GATHER, ul_debugobj(cxt, "reading cpuinfo"));
|
2020-03-17 11:27:51 -05:00
|
|
|
|
|
|
|
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);
|
2020-03-18 09:56:20 -05:00
|
|
|
/* lscpu_unref_cpu(cpu);*/
|
|
|
|
ct = NULL, cpu = NULL;
|
2020-03-17 11:27:51 -05:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!ct)
|
|
|
|
ct = lscpu_new_cputype();
|
2020-03-18 09:56:20 -05:00
|
|
|
/* if (!cpu)
|
|
|
|
cpu = lscpu_new_cpu();*/
|
2020-03-17 11:27:51 -05:00
|
|
|
|
2020-03-18 09:56:20 -05:00
|
|
|
cpuinfo_parse_line(ct, cpu, p);
|
2020-03-17 11:27:51 -05:00
|
|
|
|
|
|
|
/* TODO: else lscpu_parse_cache(cxt, buf); */
|
|
|
|
}
|
|
|
|
|
2020-03-18 09:56:20 -05:00
|
|
|
/*
|
|
|
|
if (ct)
|
|
|
|
lscpu_add_cputype(&cxt->cputypes, &cxt->ncputypes, ct);
|
|
|
|
if (cpu)
|
|
|
|
lscpu_add_cpu(&cxt->cputs, &cxt->ncpus, cpu);
|
|
|
|
*/
|
2020-03-17 11:27:51 -05:00
|
|
|
|
2020-03-18 09:56:20 -05:00
|
|
|
lscpu_unref_cputype(ct);
|
|
|
|
/*lscpu_unref_cpu(cpu);*/
|
2020-03-17 11:27:51 -05:00
|
|
|
fclose(fp);
|
2020-03-18 09:56:20 -05:00
|
|
|
|
2020-03-17 11:27:51 -05:00
|
|
|
return 0;
|
2020-03-17 07:12:12 -05:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-03-18 09:56:20 -05:00
|
|
|
|
2020-03-17 07:12:12 -05:00
|
|
|
#ifdef TEST_PROGRAM_CPUTYPE
|
2020-03-18 09:58:53 -05:00
|
|
|
/* 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);
|
|
|
|
}
|
|
|
|
|
2020-03-17 07:12:12 -05:00
|
|
|
int main(int argc, char **argv)
|
|
|
|
{
|
2020-03-17 07:41:28 -05:00
|
|
|
struct lscpu_cxt *cxt;
|
|
|
|
|
|
|
|
cxt = lscpu_new_context();
|
2020-03-17 07:12:12 -05:00
|
|
|
|
|
|
|
if (argc == 3 && strcmp(argv[1], "--prefix") == 0)
|
|
|
|
cxt->prefix = argv[2];
|
|
|
|
|
2020-03-17 07:30:05 -05:00
|
|
|
lscpu_init_debug();
|
2020-03-17 07:12:12 -05:00
|
|
|
context_init_paths(cxt);
|
|
|
|
|
2020-03-18 09:56:20 -05:00
|
|
|
lscpu_read_cpuinfo(cxt);
|
2020-03-17 07:30:05 -05:00
|
|
|
|
2020-03-17 07:41:28 -05:00
|
|
|
lscpu_free_context(cxt);
|
2020-03-17 07:12:12 -05:00
|
|
|
|
|
|
|
return EXIT_SUCCESS;
|
|
|
|
}
|
|
|
|
#endif /* TEST_PROGRAM_CPUTYPES */
|