mirror of
https://github.com/google/cpu_features.git
synced 2025-04-28 15:33:37 +02:00
[NFC] Use a tree structure in list_cpu_features
This is in preparation to include cache hierarchy in the dumped data.
This commit is contained in:
parent
b5b706cd24
commit
64b1b9090f
@ -12,6 +12,12 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// 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 <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -30,7 +36,176 @@
|
|||||||
#include "cpuinfo_ppc.h"
|
#include "cpuinfo_ppc.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void PrintEscapedAscii(const char* str) {
|
// 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 intented to be reclaimed.
|
||||||
|
typedef struct {
|
||||||
|
char* ptr;
|
||||||
|
size_t size;
|
||||||
|
} BumpAllocator;
|
||||||
|
|
||||||
|
// Allocate a buffer of size `size`.
|
||||||
|
static BumpAllocator BA_Create(size_t size) {
|
||||||
|
char* const ptr = (char*)malloc(size);
|
||||||
|
BumpAllocator BA;
|
||||||
|
if (ptr) BA = (BumpAllocator){.ptr = ptr, .size = size};
|
||||||
|
return BA;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the available memory left in the BumpAllocator.
|
||||||
|
static void* BA_Bump(BumpAllocator* BA, size_t size) {
|
||||||
|
assert(BA->size >= size);
|
||||||
|
void* ptr = BA->ptr;
|
||||||
|
BA->size -= size;
|
||||||
|
BA->ptr += size;
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The type of the nodes in the tree.
|
||||||
|
typedef enum {
|
||||||
|
TNT_INVALID,
|
||||||
|
TNT_INT,
|
||||||
|
TNT_MAP,
|
||||||
|
TNT_MAP_ENTRY,
|
||||||
|
TNT_ARRAY,
|
||||||
|
TNT_ARRAY_ELEMENT,
|
||||||
|
TNT_STRING,
|
||||||
|
} TreeValueType;
|
||||||
|
|
||||||
|
// The node in the tree.
|
||||||
|
typedef struct TreeValue {
|
||||||
|
TreeValueType type;
|
||||||
|
unsigned integer;
|
||||||
|
const char* string;
|
||||||
|
struct TreeValue* value;
|
||||||
|
struct TreeValue* next;
|
||||||
|
} TreeValue;
|
||||||
|
|
||||||
|
// Allocates a node inside a BumpAllocator.
|
||||||
|
static TreeValue* BA_TreeValue(BumpAllocator* BA, TreeValueType type) {
|
||||||
|
TreeValue* TV = (TreeValue*)BA_Bump(BA, sizeof(TreeValue));
|
||||||
|
assert(TV);
|
||||||
|
TV->type = type;
|
||||||
|
return TV;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocates an integer node inside a BumpAllocator.
|
||||||
|
static TreeValue* CreateInt(BumpAllocator* BA, int value) {
|
||||||
|
TreeValue* TV = BA_TreeValue(BA, TNT_INT);
|
||||||
|
TV->integer = value;
|
||||||
|
return TV;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocates a string node inside a BumpAllocator.
|
||||||
|
// `value` must outlive the tree.
|
||||||
|
static TreeValue* CreateConstantString(BumpAllocator* BA, const char* value) {
|
||||||
|
TreeValue* TV = BA_TreeValue(BA, TNT_STRING);
|
||||||
|
TV->string = value;
|
||||||
|
return TV;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocates a map node inside a BumpAllocator.
|
||||||
|
static TreeValue* CreateMap(BumpAllocator* BA) {
|
||||||
|
TreeValue* TV = BA_TreeValue(BA, TNT_MAP);
|
||||||
|
TV->next = NULL;
|
||||||
|
return TV;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocates an array node inside a BumpAllocator.
|
||||||
|
static TreeValue* CreateArray(BumpAllocator* BA) {
|
||||||
|
TreeValue* TV = BA_TreeValue(BA, TNT_ARRAY);
|
||||||
|
TV->next = NULL;
|
||||||
|
return TV;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocates a formatted string inside a BumpAllocator.
|
||||||
|
static TreeValue* CreatePrintfString(BumpAllocator* BA, const char* format,
|
||||||
|
...) {
|
||||||
|
va_list arglist;
|
||||||
|
va_start(arglist, format);
|
||||||
|
char* const ptr = BA->ptr;
|
||||||
|
const int written = vsnprintf(ptr, BA->size, format, arglist);
|
||||||
|
va_end(arglist);
|
||||||
|
if (written < 0 || written >= BA->size) return NULL;
|
||||||
|
return CreateConstantString(BA, (char*)BA_Bump(BA, written));
|
||||||
|
}
|
||||||
|
|
||||||
|
static TreeValue* CreateString(BumpAllocator* BA, const char* value) {
|
||||||
|
return CreatePrintfString(BA, "%s", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocates a map entry node inside a BumpAllocator.
|
||||||
|
static void AddMapEntry(BumpAllocator* BA, TreeValue* map, const char* key,
|
||||||
|
TreeValue* value) {
|
||||||
|
assert(map && map->type == TNT_MAP);
|
||||||
|
TreeValue* current = map;
|
||||||
|
while (current->next) current = current->next;
|
||||||
|
current->next = (TreeValue*)BA_Bump(BA, sizeof(TreeValue));
|
||||||
|
current->next->type = TNT_MAP_ENTRY;
|
||||||
|
current->next->string = key;
|
||||||
|
current->next->value = value;
|
||||||
|
current->next->next = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocates aan array element node inside a BumpAllocator.
|
||||||
|
static void AddArrayElement(BumpAllocator* BA, TreeValue* array,
|
||||||
|
TreeValue* value) {
|
||||||
|
assert(array && array->type == TNT_ARRAY);
|
||||||
|
TreeValue* current = array;
|
||||||
|
while (current->next) current = current->next;
|
||||||
|
current->next = (TreeValue*)BA_Bump(BA, sizeof(TreeValue));
|
||||||
|
current->next->type = TNT_ARRAY_ELEMENT;
|
||||||
|
current->next->value = value;
|
||||||
|
current->next->next = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
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(BumpAllocator* BA, TreeValue* 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); \
|
||||||
|
TreeValue* const array = CreateArray(BA); \
|
||||||
|
for (i = 0; i < count; ++i) \
|
||||||
|
AddArrayElement(BA, array, CreateConstantString(BA, ptrs[i])); \
|
||||||
|
AddMapEntry(BA, 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) {
|
||||||
putchar('"');
|
putchar('"');
|
||||||
for (; str && *str; ++str) {
|
for (; str && *str; ++str) {
|
||||||
switch (*str) {
|
switch (*str) {
|
||||||
@ -49,170 +224,80 @@ static void PrintEscapedAscii(const char* str) {
|
|||||||
putchar('"');
|
putchar('"');
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PrintVoid(void) {}
|
// Walks a TreeValue and print it as json.
|
||||||
static void PrintComma(void) { putchar(','); }
|
static void printJson(const TreeValue* current) {
|
||||||
static void PrintLineFeed(void) { putchar('\n'); }
|
assert(current);
|
||||||
static void PrintOpenBrace(void) { putchar('{'); }
|
switch (current->type) {
|
||||||
static void PrintCloseBrace(void) { putchar('}'); }
|
case TNT_INT:
|
||||||
static void PrintOpenBracket(void) { putchar('['); }
|
printf("%d", current->integer);
|
||||||
static void PrintCloseBracket(void) { putchar(']'); }
|
break;
|
||||||
static void PrintString(const char* field) { printf("%s", field); }
|
case TNT_STRING:
|
||||||
static void PrintAlignedHeader(const char* field) { printf("%-15s : ", field); }
|
printJsonString(current->string);
|
||||||
static void PrintIntValue(int value) { printf("%d", value); }
|
break;
|
||||||
static void PrintDecHexValue(int value) {
|
case TNT_ARRAY:
|
||||||
printf("%3d (0x%02X)", value, value);
|
putchar('[');
|
||||||
}
|
if (current->next) printJson(current->next);
|
||||||
static void PrintJsonHeader(const char* field) {
|
putchar(']');
|
||||||
PrintEscapedAscii(field);
|
break;
|
||||||
putchar(':');
|
case TNT_MAP:
|
||||||
}
|
putchar('{');
|
||||||
|
if (current->next) printJson(current->next);
|
||||||
typedef struct {
|
putchar('}');
|
||||||
void (*Start)(void);
|
break;
|
||||||
void (*ArrayStart)(void);
|
case TNT_MAP_ENTRY:
|
||||||
void (*ArraySeparator)(void);
|
printf("\"%s\":", current->string);
|
||||||
void (*ArrayEnd)(void);
|
printJson(current->value);
|
||||||
void (*PrintString)(const char* value);
|
if (current->next) {
|
||||||
void (*PrintValue)(int value);
|
putchar(',');
|
||||||
void (*EndField)(void);
|
printJson(current->next);
|
||||||
void (*StartField)(const char* field);
|
}
|
||||||
void (*End)(void);
|
break;
|
||||||
} Printer;
|
case TNT_ARRAY_ELEMENT:
|
||||||
|
printJson(current->value);
|
||||||
static Printer getJsonPrinter(void) {
|
if (current->next) {
|
||||||
return (Printer){
|
putchar(',');
|
||||||
.Start = &PrintOpenBrace,
|
printJson(current->next);
|
||||||
.ArrayStart = &PrintOpenBracket,
|
}
|
||||||
.ArraySeparator = &PrintComma,
|
break;
|
||||||
.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 int cmp(const void* p1, const void* p2) {
|
|
||||||
return strcmp(*(const char* const*)p1, *(const char* const*)p2);
|
|
||||||
}
|
|
||||||
|
|
||||||
#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(); \
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#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 void PrintFeatures(const Printer printer) {
|
|
||||||
#if defined(CPU_FEATURES_ARCH_X86)
|
|
||||||
char brand_string[49];
|
|
||||||
const X86Info info = GetX86Info();
|
|
||||||
FillX86BrandString(brand_string);
|
|
||||||
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();
|
|
||||||
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();
|
|
||||||
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();
|
|
||||||
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();
|
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Walks a TreeValue and print it as text.
|
||||||
|
static void printTextField(const TreeValue* current) {
|
||||||
|
switch (current->type) {
|
||||||
|
case TNT_INT:
|
||||||
|
printf("%3d (0x%02X)", current->integer, current->integer);
|
||||||
|
break;
|
||||||
|
case TNT_STRING:
|
||||||
|
fputs(current->string, stdout);
|
||||||
|
break;
|
||||||
|
case TNT_ARRAY:
|
||||||
|
if (current->next) printTextField(current->next);
|
||||||
|
break;
|
||||||
|
case TNT_MAP:
|
||||||
|
if (current->next) printJson(current->next);
|
||||||
|
break;
|
||||||
|
case TNT_MAP_ENTRY:
|
||||||
|
printf("%-15s : ", current->string);
|
||||||
|
printTextField(current->value);
|
||||||
|
if (current->next) {
|
||||||
|
putchar('\n');
|
||||||
|
printTextField(current->next);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TNT_ARRAY_ELEMENT:
|
||||||
|
printTextField(current->value);
|
||||||
|
if (current->next) {
|
||||||
|
putchar(',');
|
||||||
|
printTextField(current->next);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void printTextRoot(const TreeValue* current) {
|
||||||
|
if (current->type == TNT_MAP && current->next) printTextField(current->next);
|
||||||
|
}
|
||||||
static void showUsage(const char* name) {
|
static void showUsage(const char* name) {
|
||||||
printf(
|
printf(
|
||||||
"\n"
|
"\n"
|
||||||
@ -224,13 +309,67 @@ static void showUsage(const char* name) {
|
|||||||
name);
|
name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static TreeValue* CreateTree(BumpAllocator* BA) {
|
||||||
|
TreeValue* root = CreateMap(BA);
|
||||||
|
#if defined(CPU_FEATURES_ARCH_X86)
|
||||||
|
char brand_string[49];
|
||||||
|
const X86Info info = GetX86Info();
|
||||||
|
FillX86BrandString(brand_string);
|
||||||
|
AddMapEntry(BA, root, "arch", CreateString(BA, "x86"));
|
||||||
|
AddMapEntry(BA, root, "brand", CreateString(BA, brand_string));
|
||||||
|
AddMapEntry(BA, root, "family", CreateInt(BA, info.family));
|
||||||
|
AddMapEntry(BA, root, "model", CreateInt(BA, info.model));
|
||||||
|
AddMapEntry(BA, root, "stepping", CreateInt(BA, info.stepping));
|
||||||
|
AddMapEntry(BA, root, "uarch",
|
||||||
|
CreateString(BA, GetX86MicroarchitectureName(
|
||||||
|
GetX86Microarchitecture(&info))));
|
||||||
|
AddFlags(BA, root, &info.features);
|
||||||
|
#elif defined(CPU_FEATURES_ARCH_ARM)
|
||||||
|
const ArmInfo info = GetArmInfo();
|
||||||
|
AddMapEntry(BA, root, "arch", CreateString(BA, "ARM"));
|
||||||
|
AddMapEntry(BA, root, "implementer", CreateInt(BA, info.implementer));
|
||||||
|
AddMapEntry(BA, root, "architecture", CreateInt(BA, info.architecture));
|
||||||
|
AddMapEntry(BA, root, "variant", CreateInt(BA, info.variant));
|
||||||
|
AddMapEntry(BA, root, "part", CreateInt(BA, info.part));
|
||||||
|
AddMapEntry(BA, root, "revision", CreateInt(BA, info.revision));
|
||||||
|
AddFlags(BA, root, &info.features);
|
||||||
|
#elif defined(CPU_FEATURES_ARCH_AARCH64)
|
||||||
|
const Aarch64Info info = GetAarch64Info();
|
||||||
|
AddMapEntry(BA, root, "arch", CreateString(BA, "aarch64"));
|
||||||
|
AddMapEntry(BA, root, "implementer", CreateInt(BA, info.implementer));
|
||||||
|
AddMapEntry(BA, root, "variant", CreateInt(BA, info.variant));
|
||||||
|
AddMapEntry(BA, root, "part", CreateInt(BA, info.part));
|
||||||
|
AddMapEntry(BA, root, "revision", CreateInt(BA, info.revision));
|
||||||
|
AddFlags(BA, root, &info.features);
|
||||||
|
#elif defined(CPU_FEATURES_ARCH_MIPS)
|
||||||
|
const MipsInfo info = GetMipsInfo();
|
||||||
|
AddMapEntry(BA, root, "arch", CreateString(BA, "mips"));
|
||||||
|
AddFlags(BA, root, &info.features);
|
||||||
|
#elif defined(CPU_FEATURES_ARCH_PPC)
|
||||||
|
const PPCInfo info = GetPPCInfo();
|
||||||
|
const PPCPlatformStrings strings = GetPPCPlatformStrings();
|
||||||
|
AddMapEntry(BA, root, "arch", CreateString(BA, "ppc"));
|
||||||
|
AddMapEntry(BA, root, "platform", CreateString(BA, strings.platform));
|
||||||
|
AddMapEntry(BA, root, "model", CreateString(BA, strings.model));
|
||||||
|
AddMapEntry(BA, root, "machine", CreateString(BA, strings.machine));
|
||||||
|
AddMapEntry(BA, root, "cpu", CreateString(BA, strings.cpu));
|
||||||
|
AddMapEntry(BA, root, "instruction", CreateString(BA, strings.type.platform));
|
||||||
|
AddMapEntry(BA, root, "microarchitecture",
|
||||||
|
CreateString(BA, strings.type.base_platform));
|
||||||
|
AddFlags(BA, root, &info.features);
|
||||||
|
#endif
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
Printer printer = getTextPrinter();
|
BumpAllocator BA = BA_Create(64 * 1024);
|
||||||
|
const TreeValue* const root = CreateTree(&BA);
|
||||||
|
bool outputJson = false;
|
||||||
int i = 1;
|
int i = 1;
|
||||||
for (; i < argc; ++i) {
|
for (; i < argc; ++i) {
|
||||||
const char* arg = argv[i];
|
const char* arg = argv[i];
|
||||||
if (strcmp(arg, "-j") == 0 || strcmp(arg, "--json") == 0) {
|
if (strcmp(arg, "-j") == 0 || strcmp(arg, "--json") == 0) {
|
||||||
printer = getJsonPrinter();
|
outputJson = true;
|
||||||
} else {
|
} else {
|
||||||
showUsage(argv[0]);
|
showUsage(argv[0]);
|
||||||
if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0)
|
if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0)
|
||||||
@ -238,9 +377,10 @@ int main(int argc, char** argv) {
|
|||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
printer.Start();
|
if (outputJson)
|
||||||
PrintFeatures(printer);
|
printJson(root);
|
||||||
printer.End();
|
else
|
||||||
PrintLineFeed();
|
printTextRoot(root);
|
||||||
|
putchar('\n');
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user