最近在实现一个Linux的性能检测工具,但是经常遇到那种很多参数的接口定义,但是我在写这些接口的时候会感到非常烦恼,那就是我需要手动定义这些类。今天基于/proc/couinfo作为数据源生成接口
首先爱你我们看一下 couinfo的文件,这个文件的结构就是这种,每个cpu的描述都是如此,以\n\n作为分割
processor : 0
vendor_id : AuthenticAMD
cpu family : 25
model : 33
model name : AMD Ryzen 9 5950X 16-Core Processor
stepping : 0
microcode : 0xa201009
cpu MHz : 3998.750
cache size : 512 KB
physical id : 0
siblings : 32
core id : 0
cpu cores : 16
apicid : 0
initial apicid : 0
fpu : yes
fpu_exception : yes
cpuid level : 16
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt pdpe1gb rdtscp lm constant_tsc rep_good nopl nonstop_tsc cpuid extd_apicid aperfmperf rapl pni pclmulqdq monitor ssse3 fma cx16 sse4_1 sse4_2 movbe popcnt aes xsave avx f16c rdrand lahf_lm cmp_legacy svm extapic cr8_legacy abm sse4a misalignsse 3dnowprefetch osvw ibs skinit wdt tce topoext perfctr_core perfctr_nb bpext perfctr_llc mwaitx cpb cat_l3 cdp_l3 hw_pstate ssbd mba ibrs ibpb stibp vmmcall fsgsbase bmi1 avx2 smep bmi2 erms invpcid cqm rdt_a rdseed adx smap clflushopt clwb sha_ni xsaveopt xsavec xgetbv1 xsaves cqm_llc cqm_occup_llc cqm_mbm_total cqm_mbm_local clzero irperf xsaveerptr rdpru wbnoinvd arat npt lbrv svm_lock nrip_save tsc_scale vmcb_clean flushbyasid decodeassists pausefilter pfthreshold avic v_vmsave_vmload vgif v_spec_ctrl umip pku ospke vaes vpclmulqdq rdpid overflow_recov succor smca fsrm
bugs : sysret_ss_attrs spectre_v1 spectre_v2 spec_store_bypass srso
bogomips : 8002.63
TLB size : 2560 4K pages
clflush size : 64
cache_alignment : 64
address sizes : 48 bits physical, 48 bits virtual
power management: ts ttp tm hwpstate eff_freq_ro [13] [14]
我们最终生成的接口为
interface Processor {
processor: string; // 处理器,也称为 CPU(中央处理器),是计算机的核心组件,负责执行指令和处理数据。
vendorId: string; // 供应商 ID,标识处理器的制造商
cpuFamily: string; // 处理器家族,表示处理器所属的系列。
model: string; // 处理器型号,表示处理器的具体规格。
modelName: string; // 处理器型号名称,通常是制造商对处理器的命名。
stepping: string; // 表示处理器的版本号。
microcode: string; // 微代码,是一组用于修改处理器行为的指令,通常用于纠正硬件错误。
cpuMHz: string; // 处理器时钟频率,表示处理器每秒钟能够执行的指令数。
cacheSize: string; // 缓存大小,表示处理器内部缓存的大小。
physicalId: string; // 物理 ID,表示处理器在物理上的编号。
siblings: string; // 兄弟姐妹,表示处理器在多处理器系统中的编号。
coreId: string; // 核心 ID,表示处理器核心的编号。
cpuCores: string; // 处理器核心数,表示处理器内部包含的核心数量。
apicid: string; // 表示处理器的高级可编程中断控制器(APIC)的 ID。
initialApicid: string; // 初始 APIC ID,表示处理器启动时的 APIC ID。
fpu: string; // 浮点单元(FPU),是处理器内部的一个硬件单元,用于执行浮点运算。
fpuException: string; // FPU 异常,表示 FPU 在执行浮点运算时引发的异常。
cpuidLevel: string; // CPUID 级别,表示处理器支持的 CPUID 指令的级别。
wp: string; // Write Protect,表示处理器是否支持写保护功能。
flags: string; // 标志,表示处理器的一些状态和特征。
bugs: string; // 错误,表示处理器存在的已知错误。
bogomips: string; // BogoMIPS,是一种衡量处理器性能的指标,表示处理器在理想情况下的性能。
TLBSize: string; // TLBSize 表示 TLB 的大小,以页面(page)为单位。
clflushSize: string; // 表示 CLFLUSH 指令的操作数大小,以字节为单位
cacheAlignment: string; // cacheAlignment 表示缓存行的大小,以字节为单位
addressSizes: string; // 地址大小指的是处理器能够处理的最大内存地址的长度
powerManagement: string; // 表示处理器是否支持电源管理功能
}
那么我们完成这种转换呢
我们处理这种数据的大致流程为
- 通过
\n\n将cpuinfo文件中的数据分割为数组 - 去除生成的空数组
- 对生成的单个数据进行分割,使用
\n完成分割 - 替换字符,将
\t字符全部去除 - 将空格单词转换为小驼峰,使用正则表达式
/( |_)(\w)/gi完成 - 通过
:分割为键值对数组 - 取出键,并拼接类型
- 输出模板
完整代码为
const filepath = path.resolve("/proc", "./cpuinfo");
const file = readFileSync(filepath).toString("utf-8");
const fileList = file
.split(`\n\n`)
.filter((item) => !!item)
.map((item) =>
item.split(`\n`).map((item) =>
item
.replaceAll("\t", "")
.replaceAll(/( |_)(\w)/gi, (x, y, z: string) => z.toUpperCase())
.split(":")
)
);
const values = fileList[0].map((item) => ` ${item[0]}: string;`).join("\n");
console.log(
`interface Processor{
${values}
}`);
输出结果如下
interface Processor{
processor: string;
vendorId: string;
cpuFamily: string;
model: string;
modelName: string;
stepping: string;
microcode: string;
cpuMHz: string;
cacheSize: string;
physicalId: string;
siblings: string;
coreId: string;
cpuCores: string;
apicid: string;
initialApicid: string;
fpu: string;
fpuException: string;
cpuidLevel: string;
wp: string;
flags: string;
bugs: string;
bogomips: string;
TLBSize: string;
clflushSize: string;
cacheAlignment: string;
addressSizes: string;
powerManagement: string;
}
使用时如下方式使用 构造 键值对转换函数
function strToObj<T>(list: string[][][]): T[] {
const l = list.map((node) => {
return node.reduce((obj, item) => {
let [key, val] = item;
let k = key as keyof T;
obj[k] = val;
return obj;
}, {} as any);
}) as T[];
return l;
}
const objList = strToObj<Processor>(fileList);
最终输出
[
{
processor: '0',
vendorId: 'AuthenticAMD',
cpuFamily: '25',
model: '33',
modelName: 'AMDRyzen95950X16-CoreProcessor',
stepping: '0',
microcode: '0xa201009',
cpuMHz: '3979.770',
cacheSize: '512KB',
physicalId: '0',
siblings: '32',
coreId: '0',
cpuCores: '16',
apicid: '0',
initialApicid: '0',
fpu: 'Yes',
fpuException: 'Yes',
cpuidLevel: '16',
wp: 'Yes',
flags: 'FpuVmeDePseTscMsrPaeMceCx8ApicSepMtrrPgeMcaCmovPatPse36ClflushMmxFxsrSseSse2HtSyscallNxMmxextFxsrOptPdpe1gbRdtscpLmConstantTscRepGood,
bugs: 'SysretSsAttrsSpectreV1SpectreV2SpecStoreBypassSrso',
bogomips: '8002.63',
TLBSize: '25604KPages',
clflushSize: '64',
cacheAlignment: '64',
addressSizes: '48BitsPhysical,48BitsVirtual',
powerManagement: 'TsTtpTmHwpstateEffFreqRo [13] [14]'
},
]