#proc #linux #parser

proc_sys_parser

此crate提供了解析Linux /proc文件到Rust结构体的例程。有其他多个crate也在做这件事,但它们要么没有选择以使其直接可用的方式处理统计信息,要么将统计信息泛化并丢失了细节。

22个版本

0.1.22 2024年6月8日
0.1.21 2024年6月8日
0.1.20 2024年3月21日
0.1.18 2024年2月9日
0.1.7 2023年12月31日

#125 in Unix API

每月 30 次下载

Apache-2.0

320KB
4K SLoC

proc_sys_parser

此crate提供了解析Linux /proc文件到Rust结构体的例程。

有其他多个crate也在做这件事,但它们要么没有选择以使其直接可用的方式处理统计信息,要么将统计信息泛化并丢失了细节。

用法

为了在您的仓库中使用此crate,请将proc_sys_parser crate添加到您的Cargo.toml,或者运行cargo add proc_sys_parser

目前,仅处理两个/proc文件

/proc/stat

/proc/stat的处理器读取CLK_TCK设置并将cpu时间的jiffies转换为毫秒。

以下是从/proc/stat获取数据的示例

use proc_sys_parser::{stat, stat::{ProcStat, CpuStat}};

let proc_stat = stat::read();

println!("{:#?}", proc_stat);

示例输出

ProcStat {
    cpu_total: CpuStat { name: "cpu", user: 8570, nice: 0, system: 7530, idle: 1710040, iowait: 2780, irq: 0, softirq: 150, steal: 0, guest: 0, guest_nice: 0 },
    cpu_individual: [CpuStat { name: "cpu0", user: 1800, nice: 0, system: 1450, idle: 283400, iowait: 460, irq: 0, softirq: 120, steal: 0, guest: 0, guest_nice: 0 },
                     CpuStat { name: "cpu1", user: 1720, nice: 0, system: 1320, idle: 284780, iowait: 580, irq: 0, softirq: 0, steal: 0, guest: 0, guest_nice: 0 },
                     CpuStat { name: "cpu2", user: 1060, nice: 0, system: 1220, idle: 285410, iowait: 510, irq: 0, softirq: 0, steal: 0, guest: 0, guest_nice: 0 },
                     CpuStat { name: "cpu3", user: 890, nice: 0, system: 990, idle: 286130, iowait: 450, irq: 0, softirq: 0, steal: 0, guest: 0, guest_nice: 0 },
                     CpuStat { name: "cpu4", user: 1400, nice: 0, system: 1280, idle: 285260, iowait: 310, irq: 0, softirq: 30, steal: 0, guest: 0, guest_nice: 0 },
                     CpuStat { name: "cpu5", user: 1680, nice: 0, system: 1250, idle: 285020, iowait: 450, irq: 0, softirq: 0, steal: 0, guest: 0, guest_nice: 0 }],
    interrupts: [184655, 0, 4500, 60546, 0, 0, 0, 2, 0, 0, 0, 70138, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 548, 0, 0, 0, 0, 0, 2, 0, 3410, 2927, 4739, 5542, 1595, 1913, 0, 0, 0, 79, 154, 208, 282, 43, 52, 0, 14842, 11679, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 1437, 0, 0, 0, 0, 0, 0],
    context_switches: 275716,
    boot_time: 1702127060,
    processes: 3472,
    processes_running: 1,
    processes_blocked: 0,
    softirq: [99012, 30, 8368, 2, 24666, 11, 0, 208, 15031, 0, 50696],
}

(为可读性进行了编辑)

/proc/schedstat

/proc/schedstat中的统计信息,即第7和第8字段中运行的CPU行调度程序和等待统计信息,在内核2.6.23/commit 425e0968a25之前以jiffies形式显示,在那之后以纳秒显示。

这意味着大多数当前系统应该使用显示此时间以纳秒为单位的内核版本。

以下是从/proc/schedstat获取数据的示例

use proc_sys_parser::{schedstat, schedstat::ProcSchedStat};

let proc_schedstat = schedstat::read();

println!("{:#?}", proc_schedstat);

示例输出

ProcSchedStat {
    version: 15,
    timestamp: 4294964691,
    cpu: [[0, 0, 0, 0, 0, 0, 0, 40178371330, 4778820750, 26299],
          [1, 0, 0, 0, 0, 0, 0, 35526916030, 3606934630, 20919],
          [2, 0, 0, 0, 0, 0, 0, 29224692150, 5614007710, 28163],
          [3, 0, 0, 0, 0, 0, 0, 23848255950, 2265375620, 26240],
          [4, 0, 0, 0, 0, 0, 0, 33846671420, 2990792870, 25605],
          [5, 0, 0, 0, 0, 0, 0, 34565043670, 2885580430, 22629]],
    domain: [[0, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
             [0, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
             [0, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
             [0, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
             [0, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
             [0, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]],
}

(为可读性进行了编辑)

cpu向量

!!请注意,包含cpu统计信息的向量将cpu编号作为向量中的第一个字段。

这意味着第7个字段(在cpu上运行的时间)和第8个字段(在cpu运行时间上等待)是向量中的第8个和第9个字段。

域向量

!!请注意,包含域统计信息的向量将域编号作为向量中的第一个字段,并将cpumask作为第二个字段。

这意味着在内核文档https://linuxkernel.org.cn/doc/Documentation/scheduler/sched-stats.txt中对字段描述的数字必须加2,才能获得向量中的正确统计数字。

/proc/meminfo

/proc/meminfo 的处理器读取文件中指定的内存区域值。这些值以千字节(kB)为单位,与原始 /proc/meminfo 文件中的值相同。

以下是从 /proc/meminfo 获取数据的示例

use proc_sys_parser::{meminfo, meminfo::ProcMemInfo};

let proc_meminfo = meminfo::read();

println!("{:#?}", proc_meminfo);

示例输出

ProcMemInfo {
    memtotal: 3997876,
    memfree: 2415136,
    memavailable: 3654096,
    buffers: 37492,
    cached: 1305568,
    swapcached: 0,
    active: 880772,
    inactive: 549432,
    active_anon: 86968,
    inactive_anon: 5196,
    active_file: 793804,
    inactive_file: 544236,
    unevictable: 4000,
    mlocked: 0,
    swaptotal: 0,
    swapfree: 0,
    zswap: 0,
    zswapped: 0,
    dirty: 0,
    writeback: 0,
    anonpages: 91144,
    mapped: 140948,
    shmem: 5020,
    kreclaimable: 56680,
    slab: 93916,
    sreclaimable: 56680,
    sunreclaim: 37236,
    kernelstack: 3256,
    shadowcallstack: 828,
    pagetables: 2884,
    secpagetables: 0,
    nfs_unstable: 0,
    bounce: 0,
    writebacktmp: 0,
    commitlimit: 1998936,
    committed_as: 944240,
    vmalloctotal: 133141626880,
    vmallocused: 14124,
    vmallocchunk: 0,
    percpu: 2280,
    hardwarecorrupted: 0,
    anonhugepages: 4096,
    shmemhugepages: 0,
    shmempmdmapped: 0,
    filehugepages: 0,
    filepmdmapped: 0,
    cmatotal: 32768,
    cmafree: 31232,
    hugepages_total: 0,
    hugepages_free: 0,
    hugepages_rsvd: 0,
    hugepages_surp: 0,
    hugepagesize: 2048,
    hugetlb: 0,
}

(为可读性进行了编辑)

/proc/diskstats

/proc/diskstats 的处理器读取块设备的统计信息。数据量以扇区为单位,在 Linux 内核中硬编码为每个扇区 512 字节。

以下是从 /proc/diskstats 获取磁盘统计信息的示例

use proc_sys_parser::{diskstats, diskstats::ProcDiskStats};

let proc_diskstats = diskstats::read();

println!("{:#?}", proc_diskstats);

示例输出

ProcDiskStats {
    disk_stats: [
            DiskStats { block_major: 7, block_minor: 0, device_name: "loop0", reads_completed_success: 11, reads_merged: 0, reads_sectors: 28, reads_time_spent_ms: 0, writes_completed_success: 0, writes_merged: 0, writes_sectors: 0, writes_time_spent_ms: 0, ios_in_progress: 0, ios_time_spent_ms: 4, ios_weighted_time_spent_ms: 0, discards_completed_success: 0, discards_merged: 0, discards_sectors: 0, discards_time_spent_ms: 0, flush_requests_completed_success: 0, flush_requests_time_spent_ms: 0 },
            DiskStats { block_major: 7, block_minor: 1, device_name: "loop1", reads_completed_success: 0, reads_merged: 0, reads_sectors: 0, reads_time_spent_ms: 0, writes_completed_success: 0, writes_merged: 0, writes_sectors: 0, writes_time_spent_ms: 0, ios_in_progress: 0, ios_time_spent_ms: 0, ios_weighted_time_spent_ms: 0, discards_completed_success: 0, discards_merged: 0, discards_sectors: 0, discards_time_spent_ms: 0, flush_requests_completed_success: 0, flush_requests_time_spent_ms: 0 },
            DiskStats { block_major: 7, block_minor: 2, device_name: "loop2", reads_completed_success: 0, reads_merged: 0, reads_sectors: 0, reads_time_spent_ms: 0, writes_completed_success: 0, writes_merged: 0, writes_sectors: 0, writes_time_spent_ms: 0, ios_in_progress: 0, ios_time_spent_ms: 0, ios_weighted_time_spent_ms: 0, discards_completed_success: 0, discards_merged: 0, discards_sectors: 0, discards_time_spent_ms: 0, flush_requests_completed_success: 0, flush_requests_time_spent_ms: 0 },
            DiskStats { block_major: 7, block_minor: 3, device_name: "loop3", reads_completed_success: 0, reads_merged: 0, reads_sectors: 0, reads_time_spent_ms: 0, writes_completed_success: 0, writes_merged: 0, writes_sectors: 0, writes_time_spent_ms: 0, ios_in_progress: 0, ios_time_spent_ms: 0, ios_weighted_time_spent_ms: 0, discards_completed_success: 0, discards_merged: 0, discards_sectors: 0, discards_time_spent_ms: 0, flush_requests_completed_success: 0, flush_requests_time_spent_ms: 0 },
            DiskStats { block_major: 7, block_minor: 4, device_name: "loop4", reads_completed_success: 0, reads_merged: 0, reads_sectors: 0, reads_time_spent_ms: 0, writes_completed_success: 0, writes_merged: 0, writes_sectors: 0, writes_time_spent_ms: 0, ios_in_progress: 0, ios_time_spent_ms: 0, ios_weighted_time_spent_ms: 0, discards_completed_success: 0, discards_merged: 0, discards_sectors: 0, discards_time_spent_ms: 0, flush_requests_completed_success: 0, flush_requests_time_spent_ms: 0 },
            DiskStats { block_major: 7, block_minor: 5, device_name: "loop5", reads_completed_success: 0, reads_merged: 0, reads_sectors: 0, reads_time_spent_ms: 0, writes_completed_success: 0, writes_merged: 0, writes_sectors: 0, writes_time_spent_ms: 0, ios_in_progress: 0, ios_time_spent_ms: 0, ios_weighted_time_spent_ms: 0, discards_completed_success: 0, discards_merged: 0, discards_sectors: 0, discards_time_spent_ms: 0, flush_requests_completed_success: 0, flush_requests_time_spent_ms: 0 },
            DiskStats { block_major: 7, block_minor: 6, device_name: "loop6", reads_completed_success: 0, reads_merged: 0, reads_sectors: 0, reads_time_spent_ms: 0, writes_completed_success: 0, writes_merged: 0, writes_sectors: 0, writes_time_spent_ms: 0, ios_in_progress: 0, ios_time_spent_ms: 0, ios_weighted_time_spent_ms: 0, discards_completed_success: 0, discards_merged: 0, discards_sectors: 0, discards_time_spent_ms: 0, flush_requests_completed_success: 0, flush_requests_time_spent_ms: 0 },
            DiskStats { block_major: 7, block_minor: 7, device_name: "loop7", reads_completed_success: 0, reads_merged: 0, reads_sectors: 0, reads_time_spent_ms: 0, writes_completed_success: 0, writes_merged: 0, writes_sectors: 0, writes_time_spent_ms: 0, ios_in_progress: 0, ios_time_spent_ms: 0, ios_weighted_time_spent_ms: 0, discards_completed_success: 0, discards_merged: 0, discards_sectors: 0, discards_time_spent_ms: 0, flush_requests_completed_success: 0, flush_requests_time_spent_ms: 0 },
            DiskStats { block_major: 253, block_minor: 0, device_name: "vda", reads_completed_success: 13534, reads_merged: 4237, reads_sectors: 1645451, reads_time_spent_ms: 3763, writes_completed_success: 10172, writes_merged: 10577, writes_sectors: 1730555, writes_time_spent_ms: 12701, ios_in_progress: 0, ios_time_spent_ms: 23356, ios_weighted_time_spent_ms: 18881, discards_completed_success: 7179, discards_merged: 0, discards_sectors: 89620507, discards_time_spent_ms: 396, flush_requests_completed_success: 3929, flush_requests_time_spent_ms: 2019 },
            DiskStats { block_major: 253, block_minor: 1, device_name: "vda1", reads_completed_success: 13192, reads_merged: 2675, reads_sectors: 1623109, reads_time_spent_ms: 3692, writes_completed_success: 10151, writes_merged: 10555, writes_sectors: 1730312, writes_time_spent_ms: 12688, ios_in_progress: 0, ios_time_spent_ms: 23324, ios_weighted_time_spent_ms: 16775, discards_completed_success: 7151, discards_merged: 0, discards_sectors: 87803128, discards_time_spent_ms: 394, flush_requests_completed_success: 0, flush_requests_time_spent_ms: 0 },
            DiskStats { block_major: 253, block_minor: 15, device_name: "vda15", reads_completed_success: 136, reads_merged: 1547, reads_sectors: 9919, reads_time_spent_ms: 20, writes_completed_success: 1, writes_merged: 0, writes_sectors: 1, writes_time_spent_ms: 0, ios_in_progress: 0, ios_time_spent_ms: 52, ios_weighted_time_spent_ms: 21, discards_completed_success: 1, discards_merged: 0, discards_sectors: 186691, discards_time_spent_ms: 0, flush_requests_completed_success: 0, flush_requests_time_spent_ms: 0 },
            DiskStats { block_major: 259, block_minor: 0, device_name: "vda16", reads_completed_success: 159, reads_merged: 15, reads_sectors: 10711, reads_time_spent_ms: 31, writes_completed_success: 20, writes_merged: 22, writes_sectors: 242, writes_time_spent_ms: 12, ios_in_progress: 0, ios_time_spent_ms: 108, ios_weighted_time_spent_ms: 46, discards_completed_success: 27, discards_merged: 0, discards_sectors: 1630688, discards_time_spent_ms: 1, flush_requests_completed_success: 0, flush_requests_time_spent_ms: 0 },
            DiskStats { block_major: 11, block_minor: 0, device_name: "sr0", reads_completed_success: 291, reads_merged: 0, reads_sectors: 75108, reads_time_spent_ms: 68, writes_completed_success: 0, writes_merged: 0, writes_sectors: 0, writes_time_spent_ms: 0, ios_in_progress: 0, ios_time_spent_ms: 156, ios_weighted_time_spent_ms: 68, discards_completed_success: 0, discards_merged: 0, discards_sectors: 0, discards_time_spent_ms: 0, flush_requests_completed_success: 0, flush_requests_time_spent_ms: 0 },
    ]
}

(为可读性进行了编辑)

/proc/net/dev

/proc/net/dev 的处理器读取网络设备的统计信息。

/proc/net/dev 的文档可在以下位置找到:[https://linuxkernel.org.cn/doc/Documentation/filesystems/proc.txt](https://linuxkernel.org.cn/doc/Documentation/filesystems/proc.txt)

以下是从 /proc/net/dev 获取数据的示例

use proc_sys_parser::{net_dev, net_dev::ProcNetDev};

let proc_net_dev = net_dev::read();

println!("{:#?}", proc_net_dev);

示例输出

ProcNetDev {
    interface: [
        InterfaceStats { name: "lo".to_string(), receive_bytes: 0, receive_packets: 0, receive_errors: 0, receive_drop: 0, receive_fifo: 0, receive_frame: 0, receive_compressed: 0, receive_multicast: 0, transmit_bytes: 0, transmit_packets: 0, transmit_errors: 0, transmit_drop: 0, transmit_fifo: 0, transmit_collisions: 0, transmit_carrier: 0, transmit_compressed: 0 },
        InterfaceStats { name: "eth0".to_string(), receive_bytes: 151013652, receive_packets: 16736, receive_errors: 0, receive_drop: 0, receive_fifo: 0, receive_frame: 0, receive_compressed: 0, receive_multicast: 0, transmit_bytes: 816228, transmit_packets: 12257, transmit_errors: 0, transmit_drop: 0, transmit_fifo: 0, transmit_collisions: 0, transmit_carrier: 0, transmit_compressed: 0 }
    ]
}

(为可读性进行了编辑)

/sys/block/<设备>

/sys/block 的处理器读取块设备目录,并解析其中的统计信息。

/sys/block 的文档可在以下位置找到:[https://linuxkernel.org.cn/doc/Documentation/ABI/testing/sysfs-block](https://linuxkernel.org.cn/doc/Documentation/ABI/testing/sysfs-block)

以下是从 /sys/block 获取数据的示例

use proc_sys_parser::block;

let block = block::read();

println!("{:#?}", block);

示例输出

SysBlock {
    block_devices: [
        BlockDevice {
            dev_block_major: 253,
            dev_block_minor: 0,
            device_name: "sda",
            discard_alignment: 0,
            stat_reads_completed_success: 9718,
            stat_reads_merged: 3826,
            stat_reads_sectors: 1052371,
            stat_reads_time_spent_ms: 3026,
            stat_writes_completed_success: 2856,
            stat_writes_merged: 2331,
            stat_writes_sectors: 312397,
            stat_writes_time_spent_ms: 1947,
            stat_ios_in_progress: 0,
            stat_ios_time_spent_ms: 6004,
            stat_ios_weighted_time_spent_ms: 5554,
            stat_discards_completed_success: Some(
                7141,
            ),
            stat_discards_merged: Some(
                0,
            ),
            stat_discards_sectors: Some(
                88014755,
            ),
            stat_discards_time_spent_ms: Some(
                276,
            ),
            stat_flush_requests_completed_success: Some(
                591,
            ),
            stat_flush_requests_time_spent_ms: Some(
                304,
            ),
            alignment_offset: 0,
            cache_type: "write back",
            diskseq: 9,
            hidden: 0,
            inflight_reads: 1,
            inflight_writes: 2,
            range: 16,
            removable: 0,
            ro: 0,
            size: 125829120,
            queue_max_hw_sectors_kb: 2147483647,
            queue_max_sectors_kb: 1280,
            queue_max_discard_segments: 1,
            queue_nr_requests: 256,
            queue_nr_zones: Some(
                0,
            ),
            queue_scheduler: "none",
            queue_rotational: 1,
            queue_dax: 0,
            queue_add_random: 0,
            queue_discard_granularity: 512,
            queue_discard_max_hw_bytes: 2147483136,
            queue_discard_max_bytes: 2147483136,
            queue_hw_sector_size: 512,
            queue_io_poll: 0,
            queue_io_poll_delay: -1,
            queue_logical_block_size: 512,
            queue_minimum_io_size: 512,
            queue_max_integrity_segments: 0,
            queue_max_segments: 254,
            queue_max_segment_size: 4294967295,
            queue_nomerges: 0,
            queue_physical_block_size: 512,
            queue_optimal_io_size: 0,
            queue_read_ahead_kb: 128,
            queue_rq_affinity: 1,
            queue_write_cache: "write back",
            queue_write_same_max_bytes: 0,
            queue_chunk_sectors: Some(
                0,
            ),
            queue_zoned: Some(
                "none",
            ),
        },
    ],
}

(为可读性进行了编辑)

许可证:Apache-2.0

依赖项

~4–6MB
~112K SLoC