1 package system
2
3 import (
4 "errors"
5 "math/bits"
6 "os"
7 "reflect"
8 "strconv"
9 "testing"
10 )
11
12 var procdata = map[string]Stat_t{
13 "4902 (gunicorn: maste) S 4885 4902 4902 0 -1 4194560 29683 29929 61 83 78 16 96 17 20 0 1 0 9126532 52965376 1903 18446744073709551615 4194304 7461796 140733928751520 140733928698072 139816984959091 0 0 16781312 137447943 1 0 0 17 3 0 0 9 0 0 9559488 10071156 33050624 140733928758775 140733928758945 140733928758945 140733928759264 0": {
14 Name: "gunicorn: maste",
15 State: 'S',
16 StartTime: 9126532,
17 },
18 "9534 (cat) R 9323 9534 9323 34828 9534 4194304 95 0 0 0 0 0 0 0 20 0 1 0 9214966 7626752 168 18446744073709551615 4194304 4240332 140732237651568 140732237650920 140570710391216 0 0 0 0 0 0 0 17 1 0 0 0 0 0 6340112 6341364 21553152 140732237653865 140732237653885 140732237653885 140732237656047 0": {
19 Name: "cat",
20 State: 'R',
21 StartTime: 9214966,
22 },
23 "12345 ((ugly )pr()cess() R 9323 9534 9323 34828 9534 4194304 95 0 0 0 0 0 0 0 20 0 1 0 9214966 7626752 168 18446744073709551615 4194304 4240332 140732237651568 140732237650920 140570710391216 0 0 0 0 0 0 0 17 1 0 0 0 0 0 6340112 6341364 21553152 140732237653865 140732237653885 140732237653885 140732237656047 0": {
24 Name: "(ugly )pr()cess(",
25 State: 'R',
26 StartTime: 9214966,
27 },
28 "24767 (irq/44-mei_me) S 2 0 0 0 -1 2129984 0 0 0 0 0 0 0 0 -51 0 1 0 8722075 0 0 18446744073709551615 0 0 0 0 0 0 0 2147483647 0 0 0 0 17 1 50 1 0 0 0 0 0 0 0 0 0 0 0": {
29 Name: "irq/44-mei_me",
30 State: 'S',
31 StartTime: 8722075,
32 },
33 "0 () I 3 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 0 0 0 0 0 0 0 0 0 0 0": {
34 Name: "",
35 State: 'I',
36 StartTime: 0,
37 },
38
39 "1 (woo hoo) S 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 ": {
40 Name: "woo hoo",
41 State: 'S',
42 StartTime: 4,
43 },
44 }
45
46 func TestParseStat(t *testing.T) {
47 for line, exp := range procdata {
48 st, err := parseStat(line)
49 if err != nil {
50 t.Errorf("input %q, unexpected error %v", line, err)
51 } else if !reflect.DeepEqual(st, exp) {
52 t.Errorf("input %q, expected %+v, got %+v", line, exp, st)
53 }
54 }
55 }
56
57 func TestParseStatBadInput(t *testing.T) {
58 cases := []struct {
59 desc, input string
60 }{
61 {
62 "no (",
63 "123 ) S 2 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 0 0 0 0 0 0 0 0 0 0 0",
64 },
65 {
66 "no )",
67 "123 ( S 2 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 0 0 0 0 0 0 0 0 0 0 0",
68 },
69 {
70 ") at end",
71 "123 (cmd) S 2 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 0 0 0 0 0 0 0 0 0 0 0)",
72 },
73 {
74 "misplaced ()",
75 "123 )one( S 2 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 0 0 0 0 0 0 0 0 0 0 0",
76 },
77 {
78 "misplaced empty ()",
79 "123 )( S 2 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 0 0 0 0 0 0 0 0 0 0 0",
80 },
81 {
82 "empty line",
83 "",
84 },
85 {
86 "short line",
87 "123 (cmd) S 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0",
88 },
89 {
90 "short line (no space after stime)",
91 "123 (cmd) S 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 42",
92 },
93 {
94 "bad stime",
95 "123 (cmd) S 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 ",
96 },
97 {
98 "bad stime 2",
99 "123 (cmd) S -1 ",
100 },
101 {
102 "a tad short",
103 "1234 (cmd) ",
104 },
105 {
106 "bad stime",
107 "123 (cmd) S 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1",
108 },
109 }
110 for _, c := range cases {
111 st, err := parseStat(c.input)
112 if err == nil {
113 t.Errorf("case %q, expected error, got nil, %+v", c.desc, st)
114 }
115 }
116 }
117
118 func BenchmarkParseStat(b *testing.B) {
119 var (
120 st, exp Stat_t
121 line string
122 err error
123 )
124
125 for i := 0; i != b.N; i++ {
126 for line, exp = range procdata {
127 st, err = parseStat(line)
128 }
129 }
130 if err != nil {
131 b.Fatal(err)
132 }
133 if !reflect.DeepEqual(st, exp) {
134 b.Fatal("wrong result")
135 }
136 }
137
138 func BenchmarkParseRealStat(b *testing.B) {
139 var (
140 st Stat_t
141 err error
142 total int
143 )
144 b.StopTimer()
145 fd, err := os.Open("/proc")
146 if err != nil {
147 b.Fatal(err)
148 }
149 defer fd.Close()
150
151 for i := 0; i != b.N; i++ {
152 count := 0
153 if _, err := fd.Seek(0, 0); err != nil {
154 b.Fatal(err)
155 }
156 names, err := fd.Readdirnames(-1)
157 if err != nil {
158 b.Fatal(err)
159 }
160 for _, n := range names {
161 pid, err := strconv.ParseUint(n, 10, bits.UintSize)
162 if err != nil {
163 continue
164 }
165 b.StartTimer()
166 st, err = Stat(int(pid))
167 b.StopTimer()
168 if err != nil {
169
170 if errors.Is(err, os.ErrNotExist) {
171 continue
172 }
173 b.Fatal(err)
174 }
175 count++
176 }
177 total += count
178 }
179 b.Logf("N: %d, parsed %d pids, last stat: %+v, err: %v", b.N, total, st, err)
180 }
181
View as plain text