lpfs/proc/
interrupts.rs

1
2//! https://github.com/torvalds/linux/blob/cef7298262e9af841fb70d8673af45caf55300a1/kernel/irq/proc.c
3//! 
4//! > <pre>
5//! > 5.2.11.  /proc/interrupts
6//! > This file records the number of interrupts per IRQ on the x86 architecture. A standard /proc/interrupts looks similar to the following:
7//! >   CPU0
8//! >   0:   80448940          XT-PIC  timer
9//! >   1:     174412          XT-PIC  keyboard
10//! >   2:          0          XT-PIC  cascade
11//! >   8:          1          XT-PIC  rtc
12//! >  10:     410964          XT-PIC  eth0
13//! >  12:      60330          XT-PIC  PS/2 Mouse
14//! >  14:    1314121          XT-PIC  ide0
15//! >  15:    5195422          XT-PIC  ide1
16//! > NMI:          0
17//! > ERR:          0
18//! > For a multi-processor machine, this file may look slightly different:
19//! > 	   CPU0       CPU1
20//! >   0: 1366814704          0          XT-PIC  timer
21//! >   1:        128        340    IO-APIC-edge  keyboard
22//! >   2:          0          0          XT-PIC  cascade
23//! >   8:          0          1    IO-APIC-edge  rtc
24//! >  12:       5323       5793    IO-APIC-edge  PS/2 Mouse
25//! >  13:          1          0          XT-PIC  fpu
26//! >  16:   11184294   15940594   IO-APIC-level  Intel EtherExpress Pro 10/100 Ethernet
27//! >  20:    8450043   11120093   IO-APIC-level  megaraid
28//! >  30:      10432      10722   IO-APIC-level  aic7xxx
29//! >  31:         23         22   IO-APIC-level  aic7xxx
30//! > NMI:          0
31//! > ERR:          0
32//! > The first column refers to the IRQ number. Each CPU in the system has its own column and its own number of interrupts per IRQ. The next column reports the type of interrupt, and the last column contains the name of the device that is located at that IRQ.
33//! > Each of the types of interrupts seen in this file, which are architecture-specific, mean something different. For x86 machines, the following values are common:
34//! > XT-PIC — This is the old AT computer interrupts.
35//! > IO-APIC-edge — The voltage signal on this interrupt transitions from low to high, creating an edge, where the interrupt occurs and is only signaled once. This kind of interrupt, as well as the IO-APIC-level interrupt, are only seen on systems with processors from the 586 family and higher.
36//! > IO-APIC-level — Generates interrupts when its voltage signal is high until the signal is low again.
37//! </pre>
38//! 
39//! -- https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/5/html/deployment_guide/s1-proc-topfiles#s2-proc-interrupts
40//! 
41//! > /proc/interrupts
42//! > This is used to record the number of interrupts per CPU per IO
43//! > device.  Since Linux 2.6.24, for the i386 and x86-64 architec‐
44//! > tures, at least, this also includes interrupts internal to the
45//! > system (that is, not associated with a device as such), such
46//! > as NMI (nonmaskable interrupt), LOC (local timer interrupt),
47//! > and for SMP systems, TLB (TLB flush interrupt), RES
48//! > (rescheduling interrupt), CAL (remote function call inter‐
49//! > rupt), and possibly others.  Very easy to read formatting,
50//! > done in ASCII.
51//! 
52//! -- http://man7.org/linux/man-pages/man5/proc.5.html
53
54define_struct! {
55    pub struct InternalInterrupt {
56        name: String,
57        /// The length of Vector equals the CPU numbers.
58        /// The first element is for CPU0, second for CPU1, and so on.
59        counts: Vec<usize>,
60        details: String,
61    } 
62}
63
64define_struct! {
65    pub struct DeviceInterrupt {
66        irq_number: usize,
67        /// The length of Vector equals the CPU numbers.
68        /// The first element is for CPU0, second for CPU1, and so on.
69        counts: Vec<usize>,
70        type_device: String,
71    }
72}
73
74define_struct! {
75    /// returned by [`interrupts()`](fn.interrupts.html)
76    pub struct Interrupts {
77        cpu_num: usize,
78        internals: Vec<InternalInterrupt>,
79        devices: Vec<DeviceInterrupt>,
80    }
81}
82
83use std::str::FromStr;
84
85impl FromStr for InternalInterrupt {
86    type Err = crate::ProcErr;
87
88    fn from_str(s: &str) -> Result<InternalInterrupt, crate::ProcErr> {
89        let columns: Vec<&str> = s.split_ascii_whitespace().collect();
90        if columns.len() < 2 {
91            return Err("require at least two clolums to parse an InternalInterrupt".into())
92        }
93        let name = columns[0].trim_end_matches(':').to_string();
94        let mut cpu_num = 0;
95        let mut counts = vec![];
96        for item in columns[1..].iter() {
97            if let Ok(n) = item.parse::<usize>() {
98                cpu_num += 1;
99                counts.push(n);
100            }else {
101                break;
102            }
103        }
104        if counts.is_empty() {
105            return Err("interrupt count not found".into());
106        }
107        let details = columns[1+cpu_num..].join(" ");
108        Ok(InternalInterrupt{
109            name, counts, details
110        })
111    }
112}
113
114impl FromStr for DeviceInterrupt {
115    type Err = crate::ProcErr;
116
117    fn from_str(s: &str) -> Result<DeviceInterrupt, Self::Err>  {
118        let columns: Vec<&str> = s.split_ascii_whitespace().collect();
119        if columns.len() < 4{
120            return Err("require at least four clolums to parse an InternalInterrupt".into())
121        }
122        let irq_number = columns[0].trim_end_matches(':').parse::<usize>()?;
123        let mut cpu_num = 0;
124        let mut counts = vec![];
125        for item in columns[1..].iter() {
126            if let Ok(n) = item.parse::<usize>() {
127                cpu_num += 1;
128                counts.push(n);
129            }else {
130                break;
131            }
132        }
133        if counts.is_empty() {
134            return Err("interrupt count not found".into());
135        }
136        let type_device = columns[1+cpu_num..].join(" ");
137        Ok(DeviceInterrupt{
138            irq_number, counts, type_device
139        })
140    }
141}
142
143impl FromStr for Interrupts {
144    type Err = crate::ProcErr;
145
146    fn from_str(s: &str) -> Result<Interrupts, Self::Err> {
147        let lines: Vec<&str> = s.lines().collect();
148        if lines.is_empty() {
149            return Err("no enough lines to parse Interrupts".into());
150        }
151        let cpu_num = lines[0].split_ascii_whitespace().count();
152        let mut internals = vec![];
153        let mut devices = vec![];
154        let mut skip_lines = 1;
155        for line in lines.iter().skip(skip_lines) {
156            if let Ok(itnl) = line.parse::<InternalInterrupt>() {
157                internals.push(itnl);
158                skip_lines += 1;
159            }else {
160                break;
161            }
162        }
163        for line in lines.iter().skip(skip_lines) {
164            let dvs = line.parse::<DeviceInterrupt>()?; 
165            devices.push(dvs);
166        }
167        Ok(Interrupts{
168            cpu_num, internals, devices
169        })
170    }
171}
172
173instance_impl! {
174    interrupts, "/proc/interrupts", Interrupts
175}
176
177#[cfg(test)]
178mod test {
179    use super::*;
180
181    #[test]
182    fn test_parse_internal1() {
183        let source = "MCP:        250   Machine check polls";
184        let correct = InternalInterrupt {
185            name: "MCP".to_string(),
186            counts: vec![250],
187            details: "Machine check polls".to_string()
188        };
189        assert_eq!(correct, source.parse::<InternalInterrupt>().unwrap())
190    }
191
192    #[test]
193    fn test_parse_internal2() {
194        let source = "MIS:          0";
195        let correct = InternalInterrupt {
196            name: "MIS".to_string(),
197            counts: vec![0],
198            details: "".to_string()
199        };
200        assert_eq!(correct, source.parse::<InternalInterrupt>().unwrap())
201    }
202
203    #[test]
204    fn test_parse_device() {
205        let source = "1:          9   IO-APIC   1-edge      i8042";
206        let correct = DeviceInterrupt {
207            irq_number: 1,
208            counts: vec![9],
209            type_device: "IO-APIC 1-edge i8042".to_string()
210        };
211        assert_eq!(correct, source.parse::<DeviceInterrupt>().unwrap());
212    }
213}