From 07fd90d4f53a9d96158053d868b6fc63d09b22bb Mon Sep 17 00:00:00 2001 From: Guillaume Chatelet Date: Tue, 27 Mar 2018 15:28:40 +0200 Subject: [PATCH] Add JSON output. Fixes #24 --- CMakeLists.txt | 2 +- README.md | 7 +- src/list_cpu_features.c | 108 ----------------- src/utils/list_cpu_features.c | 222 ++++++++++++++++++++++++++++++++++ 4 files changed, 229 insertions(+), 110 deletions(-) delete mode 100644 src/list_cpu_features.c create mode 100644 src/utils/list_cpu_features.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 3dd10b0..f003768 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -74,7 +74,7 @@ add_library(CpuFeature::cpu_features ALIAS cpu_features) # program : list_cpu_features # -add_executable(list_cpu_features src/list_cpu_features.c) +add_executable(list_cpu_features src/utils/list_cpu_features.c) target_link_libraries(list_cpu_features PRIVATE cpu_features) add_executable(CpuFeature::list_cpu_features ALIAS list_cpu_features) diff --git a/README.md b/README.md index 9a3e7df..0dca3f7 100644 --- a/README.md +++ b/README.md @@ -121,7 +121,12 @@ family : 6 (0x06) model : 45 (0x2D) stepping : 7 (0x07) uarch : INTEL_SNB -flags : aes, avx, sse4_1, sse4_2, ssse3 +flags : aes,avx,cx16,smx,sse4_1,sse4_2,ssse3 +``` + +```shell +% ./build/list_cpu_features --json +{"arch":"x86","brand":" Intel(R) Xeon(R) CPU E5-1650 0 @ 3.20GHz","family":6,"model":45,"stepping":7,"uarch":"INTEL_SNB","flags":["aes","avx","cx16","smx","sse4_1","sse4_2","ssse3"]} ``` diff --git a/src/list_cpu_features.c b/src/list_cpu_features.c deleted file mode 100644 index 92b6dbc..0000000 --- a/src/list_cpu_features.c +++ /dev/null @@ -1,108 +0,0 @@ -// 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. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include -#include - -#include "cpu_features_macros.h" -#include "cpuinfo_aarch64.h" -#include "cpuinfo_arm.h" -#include "cpuinfo_mips.h" -#include "cpuinfo_x86.h" - -// Prints a named numeric value in both decimal and hexadecimal. -void PrintN(const char* field, int value) { - printf("%-15s : %3d (0x%02X)\n", field, value, value); -} - -// Prints a named string. -void PrintS(const char* field, const char* value) { - printf("%-15s : %s\n", field, value); -} - -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) \ - void PrintFlags(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(ptrs, count, sizeof(char*), cmp); \ - printf("%-15s : ", "flags"); \ - for (i = 0; i < count; ++i) { \ - if (i > 0) printf(", "); \ - printf("%s", ptrs[i]); \ - } \ - printf("\n"); \ - } - -#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_) -#endif - -int main(int argc, char** argv) { -#if defined(CPU_FEATURES_ARCH_X86) - char brand_string[49]; - const X86Info info = GetX86Info(); - FillX86BrandString(brand_string); - PrintS("arch", "x86"); - PrintS("brand", brand_string); - PrintN("family", info.family); - PrintN("model", info.model); - PrintN("stepping", info.stepping); - PrintS("uarch", GetX86MicroarchitectureName(GetX86Microarchitecture(&info))); - PrintFlags(&info.features); -#elif defined(CPU_FEATURES_ARCH_ARM) - const ArmInfo info = GetArmInfo(); - PrintS("arch", "ARM"); - PrintN("implementer", info.implementer); - PrintN("architecture", info.architecture); - PrintN("variant", info.variant); - PrintN("part", info.part); - PrintN("revision", info.revision); - PrintFlags(&info.features); -#elif defined(CPU_FEATURES_ARCH_AARCH64) - const Aarch64Info info = GetAarch64Info(); - PrintS("arch", "aarch64"); - PrintN("implementer", info.implementer); - PrintN("variant", info.variant); - PrintN("part", info.part); - PrintN("revision", info.revision); - PrintFlags(&info.features); -#elif defined(CPU_FEATURES_ARCH_MIPS) - const MipsInfo info = GetMipsInfo(); - PrintS("arch", "mips"); - PrintFlags(&info.features); -#endif - return 0; -} diff --git a/src/utils/list_cpu_features.c b/src/utils/list_cpu_features.c new file mode 100644 index 0000000..1bbe394 --- /dev/null +++ b/src/utils/list_cpu_features.c @@ -0,0 +1,222 @@ +// 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. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include + +#include "cpu_features_macros.h" +#include "cpuinfo_aarch64.h" +#include "cpuinfo_arm.h" +#include "cpuinfo_mips.h" +#include "cpuinfo_x86.h" + +static void PrintEscapedAscii(const char* str) { + putchar('"'); + for (; str && *str; ++str) { + switch (*str) { + case '\"': + case '\\': + case '/': + case '\b': + case '\f': + case '\n': + case '\r': + case '\t': + putchar('\\'); + } + putchar(*str); + } + putchar('"'); +} + +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); +} +static void PrintJsonHeader(const char* field) { + PrintEscapedAscii(field); + putchar(':'); +} + +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 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(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_) +#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) + const MipsInfo info = GetMipsInfo(); + PrintS(printer, "arch", "mips"); + PrintFlags(printer, &info.features); +#endif +} + +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) { + Printer printer = getTextPrinter(); + int i = 1; + for (; i < argc; ++i) { + const char* arg = argv[i]; + if (strcmp(arg, "-j") == 0 || strcmp(arg, "--json") == 0) { + printer = getJsonPrinter(); + } else { + showUsage(argv[0]); + if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0) + return EXIT_SUCCESS; + return EXIT_FAILURE; + } + } + printer.Start(); + PrintFeatures(printer); + printer.End(); + PrintLineFeed(); + return EXIT_SUCCESS; +}