aboutsummaryrefslogtreecommitdiff
path: root/src/utils/list_cpu_features.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/utils/list_cpu_features.c')
-rw-r--r--src/utils/list_cpu_features.c506
1 files changed, 157 insertions, 349 deletions
diff --git a/src/utils/list_cpu_features.c b/src/utils/list_cpu_features.c
index c80ffc5..acda5e7 100644
--- a/src/utils/list_cpu_features.c
+++ b/src/utils/list_cpu_features.c
@@ -1,4 +1,4 @@
-// Copyright 2017 Google LLC
+// Copyright 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -12,13 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-// This program dumps current host data to the standard output.
-// Output can be text or json if the `--json` flag is passed.
-
-#include <assert.h>
-#include <stdarg.h>
-#include <stdbool.h>
-#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -37,178 +30,7 @@
#include "cpuinfo_ppc.h"
#endif
-// Design principles
-// -----------------
-// We build a tree structure containing all the data to be displayed.
-// Then depending on the output type (text or json) we walk the tree and display
-// the data accordingly.
-
-// We use a bump allocator to allocate strings and nodes of the tree,
-// Memory is not intended to be reclaimed.
-typedef struct {
- char* ptr;
- size_t size;
-} BumpAllocator;
-
-char gGlobalBuffer[64 * 1024];
-BumpAllocator gBumpAllocator = {.ptr = gGlobalBuffer,
- .size = sizeof(gGlobalBuffer)};
-
-static void internal_error() {
- fputs("internal error\n", stderr);
- exit(EXIT_FAILURE);
-}
-
-#define ALIGN 8
-
-static void assertAligned() {
- if ((uintptr_t)(gBumpAllocator.ptr) % ALIGN) internal_error();
-}
-
-static void BA_Align() {
- while (gBumpAllocator.size && (uintptr_t)(gBumpAllocator.ptr) % ALIGN) {
- --gBumpAllocator.size;
- ++gBumpAllocator.ptr;
- }
- assertAligned();
-}
-
-// Update the available memory left in the BumpAllocator.
-static void* BA_Bump(size_t size) {
- assertAligned();
- // Align size to next 8B boundary.
- size = (size + ALIGN - 1) / ALIGN * ALIGN;
- if (gBumpAllocator.size < size) internal_error();
- void* ptr = gBumpAllocator.ptr;
- gBumpAllocator.size -= size;
- gBumpAllocator.ptr += size;
- return ptr;
-}
-
-// The type of the nodes in the tree.
-typedef enum {
- NT_INVALID,
- NT_INT,
- NT_MAP,
- NT_MAP_ENTRY,
- NT_ARRAY,
- NT_ARRAY_ELEMENT,
- NT_STRING,
-} NodeType;
-
-// The node in the tree.
-typedef struct Node {
- NodeType type;
- unsigned integer;
- const char* string;
- struct Node* value;
- struct Node* next;
-} Node;
-
-// Creates an initialized Node.
-static Node* BA_CreateNode(NodeType type) {
- Node* tv = (Node*)BA_Bump(sizeof(Node));
- assert(tv);
- *tv = (Node){.type = type};
- return tv;
-}
-
-// Adds an integer node.
-static Node* CreateInt(int value) {
- Node* tv = BA_CreateNode(NT_INT);
- tv->integer = value;
- return tv;
-}
-
-// Adds a string node.
-// `value` must outlive the tree.
-static Node* CreateConstantString(const char* value) {
- Node* tv = BA_CreateNode(NT_STRING);
- tv->string = value;
- return tv;
-}
-
-// Adds a map node.
-static Node* CreateMap() { return BA_CreateNode(NT_MAP); }
-
-// Adds an array node.
-static Node* CreateArray() { return BA_CreateNode(NT_ARRAY); }
-
-// Adds a formatted string node.
-static Node* CreatePrintfString(const char* format, ...) {
- va_list arglist;
- va_start(arglist, format);
- char* const ptr = gBumpAllocator.ptr;
- const int written = vsnprintf(ptr, gBumpAllocator.size, format, arglist);
- va_end(arglist);
- if (written < 0 || written >= (int)gBumpAllocator.size) internal_error();
- return CreateConstantString((char*)BA_Bump(written));
-}
-
-// Adds a string node.
-static Node* CreateString(const char* value) {
- return CreatePrintfString("%s", value);
-}
-
-// Adds a map entry node.
-static void AddMapEntry(Node* map, const char* key, Node* value) {
- assert(map && map->type == NT_MAP);
- Node* current = map;
- while (current->next) current = current->next;
- current->next = (Node*)BA_Bump(sizeof(Node));
- *current->next = (Node){.type = NT_MAP_ENTRY, .string = key, .value = value};
-}
-
-// Adds an array element node.
-static void AddArrayElement(Node* array, Node* value) {
- assert(array && array->type == NT_ARRAY);
- Node* current = array;
- while (current->next) current = current->next;
- current->next = (Node*)BA_Bump(sizeof(Node));
- *current->next = (Node){.type = NT_ARRAY_ELEMENT, .value = value};
-}
-
-static int cmp(const void* p1, const void* p2) {
- return strcmp(*(const char* const*)p1, *(const char* const*)p2);
-}
-
-#define DEFINE_ADD_FLAGS(HasFeature, FeatureName, FeatureType, LastEnum) \
- static void AddFlags(Node* map, const FeatureType* features) { \
- size_t i; \
- const char* ptrs[LastEnum] = {0}; \
- size_t count = 0; \
- for (i = 0; i < LastEnum; ++i) { \
- if (HasFeature(features, i)) { \
- ptrs[count] = FeatureName(i); \
- ++count; \
- } \
- } \
- qsort((void*)ptrs, count, sizeof(char*), cmp); \
- Node* const array = CreateArray(); \
- for (i = 0; i < count; ++i) \
- AddArrayElement(array, CreateConstantString(ptrs[i])); \
- AddMapEntry(map, "flags", array); \
- }
-
-#if defined(CPU_FEATURES_ARCH_X86)
-DEFINE_ADD_FLAGS(GetX86FeaturesEnumValue, GetX86FeaturesEnumName, X86Features,
- X86_LAST_)
-#elif defined(CPU_FEATURES_ARCH_ARM)
-DEFINE_ADD_FLAGS(GetArmFeaturesEnumValue, GetArmFeaturesEnumName, ArmFeatures,
- ARM_LAST_)
-#elif defined(CPU_FEATURES_ARCH_AARCH64)
-DEFINE_ADD_FLAGS(GetAarch64FeaturesEnumValue, GetAarch64FeaturesEnumName,
- Aarch64Features, AARCH64_LAST_)
-#elif defined(CPU_FEATURES_ARCH_MIPS)
-DEFINE_ADD_FLAGS(GetMipsFeaturesEnumValue, GetMipsFeaturesEnumName,
- MipsFeatures, MIPS_LAST_)
-#elif defined(CPU_FEATURES_ARCH_PPC)
-DEFINE_ADD_FLAGS(GetPPCFeaturesEnumValue, GetPPCFeaturesEnumName, PPCFeatures,
- PPC_LAST_)
-#endif
-
-// Prints a json string with characters escaping.
-static void printJsonString(const char* str) {
+static void PrintEscapedAscii(const char* str) {
putchar('"');
for (; str && *str; ++str) {
switch (*str) {
@@ -227,201 +49,188 @@ static void printJsonString(const char* str) {
putchar('"');
}
-// Walks a Node and print it as json.
-static void printJson(const Node* current) {
- assert(current);
- switch (current->type) {
- case NT_INVALID:
- break;
- case NT_INT:
- printf("%d", current->integer);
- break;
- case NT_STRING:
- printJsonString(current->string);
- break;
- case NT_ARRAY:
- putchar('[');
- if (current->next) printJson(current->next);
- putchar(']');
- break;
- case NT_MAP:
- putchar('{');
- if (current->next) printJson(current->next);
- putchar('}');
- break;
- case NT_MAP_ENTRY:
- printf("\"%s\":", current->string);
- printJson(current->value);
- if (current->next) {
- putchar(',');
- printJson(current->next);
- }
- break;
- case NT_ARRAY_ELEMENT:
- printJson(current->value);
- if (current->next) {
- putchar(',');
- printJson(current->next);
- }
- break;
- }
+static void PrintVoid(void) {}
+static void PrintComma(void) { putchar(','); }
+static void PrintLineFeed(void) { putchar('\n'); }
+static void PrintOpenBrace(void) { putchar('{'); }
+static void PrintCloseBrace(void) { putchar('}'); }
+static void PrintOpenBracket(void) { putchar('['); }
+static void PrintCloseBracket(void) { putchar(']'); }
+static void PrintString(const char* field) { printf("%s", field); }
+static void PrintAlignedHeader(const char* field) { printf("%-15s : ", field); }
+static void PrintIntValue(int value) { printf("%d", value); }
+static void PrintDecHexValue(int value) {
+ printf("%3d (0x%02X)", value, value);
}
-
-// Walks a Node and print it as text.
-static void printTextField(const Node* current) {
- switch (current->type) {
- case NT_INVALID:
- break;
- case NT_INT:
- printf("%3d (0x%02X)", current->integer, current->integer);
- break;
- case NT_STRING:
- fputs(current->string, stdout);
- break;
- case NT_ARRAY:
- if (current->next) printTextField(current->next);
- break;
- case NT_MAP:
- if (current->next) {
- printf("{");
- printJson(current->next);
- printf("}");
- }
- break;
- case NT_MAP_ENTRY:
- printf("%-15s : ", current->string);
- printTextField(current->value);
- if (current->next) {
- putchar('\n');
- printTextField(current->next);
- }
- break;
- case NT_ARRAY_ELEMENT:
- printTextField(current->value);
- if (current->next) {
- putchar(',');
- printTextField(current->next);
- }
- break;
- }
+static void PrintJsonHeader(const char* field) {
+ PrintEscapedAscii(field);
+ putchar(':');
}
-static void printTextRoot(const Node* current) {
- if (current->type == NT_MAP && current->next) printTextField(current->next);
+typedef struct {
+ void (*Start)(void);
+ void (*ArrayStart)(void);
+ void (*ArraySeparator)(void);
+ void (*ArrayEnd)(void);
+ void (*PrintString)(const char* value);
+ void (*PrintValue)(int value);
+ void (*EndField)(void);
+ void (*StartField)(const char* field);
+ void (*End)(void);
+} Printer;
+
+static Printer getJsonPrinter(void) {
+ return (Printer){
+ .Start = &PrintOpenBrace,
+ .ArrayStart = &PrintOpenBracket,
+ .ArraySeparator = &PrintComma,
+ .ArrayEnd = &PrintCloseBracket,
+ .PrintString = &PrintEscapedAscii,
+ .PrintValue = &PrintIntValue,
+ .EndField = &PrintComma,
+ .StartField = &PrintJsonHeader,
+ .End = &PrintCloseBrace,
+ };
+}
+
+static Printer getTextPrinter(void) {
+ return (Printer){
+ .Start = &PrintVoid,
+ .ArrayStart = &PrintVoid,
+ .ArraySeparator = &PrintComma,
+ .ArrayEnd = &PrintVoid,
+ .PrintString = &PrintString,
+ .PrintValue = &PrintDecHexValue,
+ .EndField = &PrintLineFeed,
+ .StartField = &PrintAlignedHeader,
+ .End = &PrintVoid,
+ };
+}
+
+// Prints a named numeric value in both decimal and hexadecimal.
+static void PrintN(const Printer p, const char* field, int value) {
+ p.StartField(field);
+ p.PrintValue(value);
+ p.EndField();
+}
+
+// Prints a named string.
+static void PrintS(const Printer p, const char* field, const char* value) {
+ p.StartField(field);
+ p.PrintString(value);
+ p.EndField();
}
-static void showUsage(const char* name) {
- printf(
- "\n"
- "Usage: %s [options]\n"
- " Options:\n"
- " -h | --help Show help message.\n"
- " -j | --json Format output as json instead of plain text.\n"
- "\n",
- name);
+static int cmp(const void* p1, const void* p2) {
+ return strcmp(*(const char* const*)p1, *(const char* const*)p2);
}
-static Node* GetCacheTypeString(CacheType cache_type) {
- switch (cache_type) {
- case CPU_FEATURE_CACHE_NULL:
- return CreateConstantString("null");
- case CPU_FEATURE_CACHE_DATA:
- return CreateConstantString("data");
- case CPU_FEATURE_CACHE_INSTRUCTION:
- return CreateConstantString("instruction");
- case CPU_FEATURE_CACHE_UNIFIED:
- return CreateConstantString("unified");
- case CPU_FEATURE_CACHE_TLB:
- return CreateConstantString("tlb");
- case CPU_FEATURE_CACHE_DTLB:
- return CreateConstantString("dtlb");
- case CPU_FEATURE_CACHE_STLB:
- return CreateConstantString("stlb");
- case CPU_FEATURE_CACHE_PREFETCH:
- return CreateConstantString("prefetch");
+#define DEFINE_PRINT_FLAGS(HasFeature, FeatureName, FeatureType, LastEnum) \
+ static void PrintFlags(const Printer p, const FeatureType* features) { \
+ size_t i; \
+ const char* ptrs[LastEnum] = {0}; \
+ size_t count = 0; \
+ for (i = 0; i < LastEnum; ++i) { \
+ if (HasFeature(features, i)) { \
+ ptrs[count] = FeatureName(i); \
+ ++count; \
+ } \
+ } \
+ qsort((void*)ptrs, count, sizeof(char*), cmp); \
+ p.StartField("flags"); \
+ p.ArrayStart(); \
+ for (i = 0; i < count; ++i) { \
+ if (i > 0) p.ArraySeparator(); \
+ p.PrintString(ptrs[i]); \
+ } \
+ p.ArrayEnd(); \
}
-}
-static void AddCacheInfo(Node* root, const CacheInfo* cache_info) {
- Node* array = CreateArray();
- for (int i = 0; i < cache_info->size; ++i) {
- CacheLevelInfo info = cache_info->levels[i];
- Node* map = CreateMap();
- AddMapEntry(map, "level", CreateInt(info.level));
- AddMapEntry(map, "cache_type", GetCacheTypeString(info.cache_type));
- AddMapEntry(map, "cache_size", CreateInt(info.cache_size));
- AddMapEntry(map, "ways", CreateInt(info.ways));
- AddMapEntry(map, "line_size", CreateInt(info.line_size));
- AddMapEntry(map, "tlb_entries", CreateInt(info.tlb_entries));
- AddMapEntry(map, "partitioning", CreateInt(info.partitioning));
- AddArrayElement(array, map);
- }
- AddMapEntry(root, "cache_info", array);
-}
+#if defined(CPU_FEATURES_ARCH_X86)
+DEFINE_PRINT_FLAGS(GetX86FeaturesEnumValue, GetX86FeaturesEnumName, X86Features,
+ X86_LAST_)
+#elif defined(CPU_FEATURES_ARCH_ARM)
+DEFINE_PRINT_FLAGS(GetArmFeaturesEnumValue, GetArmFeaturesEnumName, ArmFeatures,
+ ARM_LAST_)
+#elif defined(CPU_FEATURES_ARCH_AARCH64)
+DEFINE_PRINT_FLAGS(GetAarch64FeaturesEnumValue, GetAarch64FeaturesEnumName,
+ Aarch64Features, AARCH64_LAST_)
+#elif defined(CPU_FEATURES_ARCH_MIPS)
+DEFINE_PRINT_FLAGS(GetMipsFeaturesEnumValue, GetMipsFeaturesEnumName,
+ MipsFeatures, MIPS_LAST_)
+#elif defined(CPU_FEATURES_ARCH_PPC)
+DEFINE_PRINT_FLAGS(GetPPCFeaturesEnumValue, GetPPCFeaturesEnumName, PPCFeatures,
+ PPC_LAST_)
+#endif
-static Node* CreateTree() {
- Node* root = CreateMap();
+static void PrintFeatures(const Printer printer) {
#if defined(CPU_FEATURES_ARCH_X86)
char brand_string[49];
const X86Info info = GetX86Info();
- const CacheInfo cache_info = GetX86CacheInfo();
FillX86BrandString(brand_string);
- AddMapEntry(root, "arch", CreateString("x86"));
- AddMapEntry(root, "brand", CreateString(brand_string));
- AddMapEntry(root, "family", CreateInt(info.family));
- AddMapEntry(root, "model", CreateInt(info.model));
- AddMapEntry(root, "stepping", CreateInt(info.stepping));
- AddMapEntry(root, "uarch",
- CreateString(
- GetX86MicroarchitectureName(GetX86Microarchitecture(&info))));
- AddFlags(root, &info.features);
- AddCacheInfo(root, &cache_info);
+ PrintS(printer, "arch", "x86");
+ PrintS(printer, "brand", brand_string);
+ PrintN(printer, "family", info.family);
+ PrintN(printer, "model", info.model);
+ PrintN(printer, "stepping", info.stepping);
+ PrintS(printer, "uarch",
+ GetX86MicroarchitectureName(GetX86Microarchitecture(&info)));
+ PrintFlags(printer, &info.features);
#elif defined(CPU_FEATURES_ARCH_ARM)
const ArmInfo info = GetArmInfo();
- AddMapEntry(root, "arch", CreateString("ARM"));
- AddMapEntry(root, "implementer", CreateInt(info.implementer));
- AddMapEntry(root, "architecture", CreateInt(info.architecture));
- AddMapEntry(root, "variant", CreateInt(info.variant));
- AddMapEntry(root, "part", CreateInt(info.part));
- AddMapEntry(root, "revision", CreateInt(info.revision));
- AddFlags(root, &info.features);
+ PrintS(printer, "arch", "ARM");
+ PrintN(printer, "implementer", info.implementer);
+ PrintN(printer, "architecture", info.architecture);
+ PrintN(printer, "variant", info.variant);
+ PrintN(printer, "part", info.part);
+ PrintN(printer, "revision", info.revision);
+ PrintFlags(printer, &info.features);
#elif defined(CPU_FEATURES_ARCH_AARCH64)
const Aarch64Info info = GetAarch64Info();
- AddMapEntry(root, "arch", CreateString("aarch64"));
- AddMapEntry(root, "implementer", CreateInt(info.implementer));
- AddMapEntry(root, "variant", CreateInt(info.variant));
- AddMapEntry(root, "part", CreateInt(info.part));
- AddMapEntry(root, "revision", CreateInt(info.revision));
- AddFlags(root, &info.features);
+ PrintS(printer, "arch", "aarch64");
+ PrintN(printer, "implementer", info.implementer);
+ PrintN(printer, "variant", info.variant);
+ PrintN(printer, "part", info.part);
+ PrintN(printer, "revision", info.revision);
+ PrintFlags(printer, &info.features);
#elif defined(CPU_FEATURES_ARCH_MIPS)
+ (void)&PrintN; // Remove unused function warning.
const MipsInfo info = GetMipsInfo();
- AddMapEntry(root, "arch", CreateString("mips"));
- AddFlags(root, &info.features);
+ PrintS(printer, "arch", "mips");
+ PrintFlags(printer, &info.features);
#elif defined(CPU_FEATURES_ARCH_PPC)
+ (void)&PrintN; // Remove unused function warning.
const PPCInfo info = GetPPCInfo();
const PPCPlatformStrings strings = GetPPCPlatformStrings();
- AddMapEntry(root, "arch", CreateString("ppc"));
- AddMapEntry(root, "platform", CreateString(strings.platform));
- AddMapEntry(root, "model", CreateString(strings.model));
- AddMapEntry(root, "machine", CreateString(strings.machine));
- AddMapEntry(root, "cpu", CreateString(strings.cpu));
- AddMapEntry(root, "instruction", CreateString(strings.type.platform));
- AddMapEntry(root, "microarchitecture",
- CreateString(strings.type.base_platform));
- AddFlags(root, &info.features);
+ PrintS(printer, "arch", "ppc");
+ PrintS(printer, "platform", strings.platform);
+ PrintS(printer, "model", strings.model);
+ PrintS(printer, "machine", strings.machine);
+ PrintS(printer, "cpu", strings.cpu);
+ PrintS(printer, "instruction set", strings.type.platform);
+ PrintS(printer, "microarchitecture", strings.type.base_platform);
+ PrintFlags(printer, &info.features);
#endif
- return root;
+}
+
+static void showUsage(const char* name) {
+ printf(
+ "\n"
+ "Usage: %s [options]\n"
+ " Options:\n"
+ " -h | --help Show help message.\n"
+ " -j | --json Format output as json instead of plain text.\n"
+ "\n",
+ name);
}
int main(int argc, char** argv) {
- BA_Align();
- const Node* const root = CreateTree();
- bool outputJson = false;
+ Printer printer = getTextPrinter();
int i = 1;
for (; i < argc; ++i) {
const char* arg = argv[i];
if (strcmp(arg, "-j") == 0 || strcmp(arg, "--json") == 0) {
- outputJson = true;
+ printer = getJsonPrinter();
} else {
showUsage(argv[0]);
if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0)
@@ -429,10 +238,9 @@ int main(int argc, char** argv) {
return EXIT_FAILURE;
}
}
- if (outputJson)
- printJson(root);
- else
- printTextRoot(root);
- putchar('\n');
+ printer.Start();
+ PrintFeatures(printer);
+ printer.End();
+ PrintLineFeed();
return EXIT_SUCCESS;
}