Skip to content

Commit

Permalink
lscpu: show additional caches (s390)
Browse files Browse the repository at this point in the history
The Linux kernel exposes the cache topology via sysfs. However on
virtualized machines like s390 the cache topology contains only cpu
private caches.

For shared caches it is not known which cpus share them. The
hypervisor would have to update this information whenever a virtual
cpu would be scheduled on a different physical cpu and make the guest
aware of that change. Given that there is hardly any benefit, if it
all, this isn't done.

However it is still of interest to know about the non-private
caches. Therefore this information is available via /proc/cpuinfo at
least on s390.

This patch adds additional lines to the summary output for all shared
caches for which information can be found in /proc/cpuinfo, since we
know these aren't exposed via sysfs.

Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
  • Loading branch information
heicarst authored and karelzak committed Jun 24, 2016
1 parent 0c28f0c commit 28b1658
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 0 deletions.
70 changes: 70 additions & 0 deletions sys-utils/lscpu.c
Expand Up @@ -229,6 +229,9 @@ struct lscpu_desc {
int ncaches;
struct cpu_cache *caches;

int necaches; /* extra caches (s390) */
struct cpu_cache *ecaches;

/*
* All maps are sequentially indexed (0..ncpuspos), the array index
* does not have match with cpuX number as presented by kernel. You
Expand Down Expand Up @@ -405,6 +408,58 @@ lookup(char *line, char *pattern, char **value)
return 1;
}

/* Parse extra cache lines contained within /proc/cpuinfo but which are not
* part of the cache topology information within the sysfs filesystem.
* This is true for all shared caches on e.g. s390. When there are layers of
* hypervisors in between it is not knows which CPUs share which caches.
* Therefore information about shared caches is only available in
* /proc/cpuinfo.
* Format is:
* "cache<nr> : level=<lvl> type=<type> scope=<scope> size=<size> line_size=<lsz> associativity=<as>"
*/
static int
lookup_cache(char *line, struct lscpu_desc *desc)
{
struct cpu_cache *cache;
long long size;
char *p, type;
int level;

/* Make sure line starts with "cache<nr> :" */
if (strncmp(line, "cache", 5))
return 0;
for (p = line + 5; isdigit(*p); p++);
for (; isspace(*p); p++);
if (*p != ':')
return 0;

p = strstr(line, "scope=") + 6;
/* Skip private caches, also present in sysfs */
if (!p || strncmp(p, "Private", 7) == 0)
return 0;
p = strstr(line, "level=");
sscanf(p, "level=%d", &level);
p = strstr(line, "type=") + 5;
type = 0;
if (strncmp(p, "Data", 4) == 0)
type = 'd';
if (strncmp(p, "Instruction", 11) == 0)
type = 'i';
p = strstr(line, "size=");
sscanf(p, "size=%lld", &size);
desc->necaches++;
desc->ecaches = xrealloc(desc->ecaches,
desc->necaches * sizeof(struct cpu_cache));
cache = &desc->ecaches[desc->necaches - 1];
memset(cache, 0 , sizeof(*cache));
if (type)
xasprintf(&cache->name, "L%d%c", level, type);
else
xasprintf(&cache->name, "L%d", level);
xasprintf(&cache->size, "%lldK", size);
return 1;
}

/* Don't init the mode for platforms where we are not able to
* detect that CPU supports 64-bit mode.
*/
Expand Down Expand Up @@ -501,6 +556,7 @@ read_basicinfo(struct lscpu_desc *desc, struct lscpu_modifier *mod)
else if (lookup(buf, "bogomips per cpu", &desc->bogomips)) ; /* s390 */
else if (lookup(buf, "cpu", &desc->cpu)) ;
else if (lookup(buf, "revision", &desc->revision)) ;
else if (lookup_cache(buf, desc)) ;
else
continue;
}
Expand Down Expand Up @@ -1768,6 +1824,16 @@ print_summary(struct lscpu_desc *desc, struct lscpu_modifier *mod)
}
}

if (desc->necaches) {
char cbuf[512];

for (i = desc->necaches - 1; i >= 0; i--) {
snprintf(cbuf, sizeof(cbuf),
_("%s cache:"), desc->ecaches[i].name);
print_s(cbuf, desc->ecaches[i].size);
}
}

for (i = 0; i < desc->nnodes; i++) {
snprintf(buf, sizeof(buf), _("NUMA node%d CPU(s):"), desc->idx2nodenum[i]);
print_cpuset(buf, desc->nodemaps[i], mod->hex);
Expand Down Expand Up @@ -1928,6 +1994,10 @@ int main(int argc, char *argv[])
qsort(desc->caches, desc->ncaches,
sizeof(struct cpu_cache), cachecmp);

if (desc->ecaches)
qsort(desc->ecaches, desc->necaches,
sizeof(struct cpu_cache), cachecmp);

read_nodes(desc);
read_hypervisor(desc, mod);

Expand Down
2 changes: 2 additions & 0 deletions tests/expected/lscpu/lscpu-s390-lpar-drawer
Expand Up @@ -21,6 +21,8 @@ L1d cache: 128K
L1i cache: 96K
L2d cache: 2048K
L2i cache: 2048K
L3 cache: 65536K
L4 cache: 491520K
NUMA node0 CPU(s): 0-140
Flags: esan3 zarch stfle msa ldisp eimm dfp edat etf3eh highgprs te vx sie

Expand Down

0 comments on commit 28b1658

Please sign in to comment.