实践[nodejs] 将/proc/cpuinfo文件生成Process类型接口

231 阅读4分钟

最近在实现一个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; // 表示处理器是否支持电源管理功能
}

那么我们完成这种转换呢

我们处理这种数据的大致流程为

  1. 通过\n\n将cpuinfo文件中的数据分割为数组
  2. 去除生成的空数组
  3. 对生成的单个数据进行分割,使用\n完成分割
  4. 替换字符,将\t字符全部去除
  5. 将空格单词转换为小驼峰,使用正则表达式/( |_)(\w)/gi完成
  6. 通过:分割为键值对数组
  7. 取出键,并拼接类型
  8. 输出模板

完整代码为

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]'
  },
]